cssstyleselector.cpp
来自「monqueror一个很具有参考价值的源玛」· C++ 代码 · 共 1,977 行 · 第 1/5 页
CPP
1,977 行
/** * This file is part of the CSS implementation for KDE. * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * $Id: cssstyleselector.cpp,v 1.2 2002/01/28 04:31:02 leon Exp $ */#include <qfile.h>#include <qtextstream.h>//#include <qfontdatabase.h>//#include <qfontinfo.h>#include <qvaluelist.h>#include <qstring.h>#include <qdatetime.h>#include <assert.h>#include "render_interface.h"#include "mgcolor.h"#include "mgrect.h"#include "cssstyleselector.h"#include "render_style.h"#include "css_stylesheetimpl.h"#include "css_ruleimpl.h"#include "css_valueimpl.h"#include "csshelper.h"#include "html_documentimpl.h"#include "html_baseimpl.h"#include "css_rule.h"#include "css_value.h"#include "cssproperties.h"#include "cssvalues.h"#include "khtmllayout.h"#include "mghtml_settings.h"#include "htmlhashes.h"#include "html_headimpl.h"#include "mgfontinfo.h"#include "mghtmlview.h"#include "mghtml_part.h"#include "kcharsets.h"#include "kdebug.h"#include "kurl.h"using namespace khtml;using namespace DOM;CSSStyleSelectorList *CSSStyleSelector::defaultStyle = 0;CSSStyleSelectorList *CSSStyleSelector::userStyle = 0;CSSStyleSheetImpl *CSSStyleSelector::defaultSheet = 0;CSSStyleSheetImpl *CSSStyleSelector::userSheet = 0;enum PseudoState { PseudoUnknown, PseudoNone, PseudoLink, PseudoVisited };static PseudoState pseudoState;CSSStyleSelector::CSSStyleSelector(DocumentImpl * /*doc*/){ // ### parse the xml for processing instructions containing style sheet info authorStyle = new CSSStyleSelectorList();}CSSStyleSelector::CSSStyleSelector(HTMLDocumentImpl *doc){ if(!defaultStyle) loadDefaultStyle(doc->view()->part()->settings()); authorStyle = new CSSStyleSelectorList(); // ### go through DOM tree for style elements NodeImpl *test = doc->html(); // should be html element if(!test) return; test = test->firstChild(); if(!test) return; while(test && (test->id() != ID_HEAD)) test = test->nextSibling(); if(test) { HTMLHeadElementImpl *head = static_cast<HTMLHeadElementImpl *>(test); // all LINK and STYLE elements have to be direct children of the HEAD element test = head->firstChild(); while(test) { if(test->id() == ID_LINK) { HTMLLinkElementImpl *link = static_cast<HTMLLinkElementImpl *>(test); authorStyle->append(link->sheet()); } else if(test->id() == ID_STYLE) { HTMLStyleElementImpl *style = static_cast<HTMLStyleElementImpl *>(test); authorStyle->append(style->sheet()); } test = test->nextSibling(); } } HTMLElementImpl *e = doc->body(); if(e && e->id() == ID_BODY) { HTMLBodyElementImpl *body = static_cast<HTMLBodyElementImpl *>(e); if(body->sheet()) { authorStyle->append(body->sheet()); } }}CSSStyleSelector::CSSStyleSelector(StyleSheetImpl *sheet){ if(!defaultStyle) loadDefaultStyle(); authorStyle = new CSSStyleSelectorList(); authorStyle->append(sheet);}CSSStyleSelector::~CSSStyleSelector(){ delete authorStyle;}void CSSStyleSelector::addSheet(StyleSheetImpl *sheet){ authorStyle->append(sheet);}void CSSStyleSelector::setUserStyle(StyleSheetImpl *sheet){ if(userStyle) delete userStyle; userStyle = new CSSStyleSelectorList(); userStyle->append(sheet);}void CSSStyleSelector::loadDefaultStyle(const MGHTMLSettings *s){ if(defaultStyle) return; QString path( "html4.css" ); QFile f( path ); f.open(IO_ReadOnly); QTextStream t( &f ); QString style = t.read(); if(s) { style += s->settingsToCSS(); } DOMString str(style); defaultSheet = new DOM::CSSStyleSheetImpl((DOM::CSSStyleSheetImpl *)0); defaultSheet->parseString( str ); defaultStyle = new CSSStyleSelectorList(); defaultStyle->append(defaultSheet);}void CSSStyleSelector::clear(){ delete defaultStyle; delete userStyle; delete defaultSheet; delete userSheet; defaultStyle = 0; userStyle = 0; defaultSheet = 0; userSheet = 0;}RenderStyle *CSSStyleSelector::styleForElement(ElementImpl *e, MGHTMLPart* part){ CSSOrderedPropertyList *propsToApply = new CSSOrderedPropertyList(); // the higher the offset or important number, the later the rules get applied. pseudoState = PseudoUnknown; if(defaultStyle) defaultStyle->collect(propsToApply, e, 0x00100000); // no important rules here // important rules from user styles are higher than important rules from author styles. // for non important rules the order is reversed if(userStyle) userStyle->collect(propsToApply, e, 0x00200000, 0x04000000); if(authorStyle) authorStyle->collect(propsToApply, e, 0x00400000, 0x01000000); // these count as author rules, and come after all other style sheets if(e->styleRules()) propsToApply->append(e->styleRules(), 0x00800000, 0x02000000); propsToApply->sort(); RenderStyle *style; if(e->parentNode()) { assert(e->parentNode()->style() != 0); style = new RenderStyle(e->parentNode()->style()); } else style = new RenderStyle(); for(int i = 0; i < (int)propsToApply->count(); i++) { applyRule(style, propsToApply->at(i)->prop, e, part); } delete propsToApply; return style;}// ----------------------------------------------------------------------CSSOrderedRule::CSSOrderedRule(DOM::CSSStyleRuleImpl *r, DOM::CSSSelector *s, int _index){ rule = r; if(rule) r->ref(); index = _index; selector = s;}CSSOrderedRule::~CSSOrderedRule(){ if(rule) rule->deref();}bool CSSOrderedRule::checkSelector(DOM::ElementImpl *e){ CSSSelector *sel = selector; NodeImpl *n = e; // first selector has to match if(!checkOneSelector(sel, e)) return false; // check the subselectors CSSSelector::Relation relation = sel->relation; while((sel = sel->tagHistory)) { if(!n->isElementNode()) return false; switch(relation) { case CSSSelector::Descendant: { bool found = false; while(!found) { n = n->parentNode(); if(!n || !n->isElementNode()) return false; ElementImpl *elem = static_cast<ElementImpl *>(n); if(checkOneSelector(sel, elem)) found = true; } break; } case CSSSelector::Child: { n = n->parentNode(); if(!n || !n->isElementNode()) return false; ElementImpl *elem = static_cast<ElementImpl *>(n); if(!checkOneSelector(sel, elem)) return false; break; } case CSSSelector::Sibling: { n = n->previousSibling(); if(!n || !n->isElementNode()) return false; ElementImpl *elem = static_cast<ElementImpl *>(n); if(!checkOneSelector(sel, elem)) return false; break; } case CSSSelector::SubSelector: { //kdDebug() << "CSSOrderedRule::checkSelector" << endl; ElementImpl *elem = static_cast<ElementImpl *>(n); if(!checkOneSelector(sel, elem)) return false; //kdDebug() << "CSSOrderedRule::checkSelector: passed" << endl; break; } } relation = sel->relation; } return true;}static void checkPseudoState( DOM::ElementImpl *e ){ if( e->getAttribute(ATTR_HREF).isNull() ) { pseudoState = PseudoNone; return; } pseudoState = PseudoLink;}bool CSSOrderedRule::checkOneSelector(DOM::CSSSelector *sel, DOM::ElementImpl *e){ if(!e || !e->isHTMLElement()) { // ### no support for xml elements at the moment return false; } if(e->id() != sel->tag && sel->tag != -1) return false; if(sel->attr) { DOMString value = e->getAttribute(sel->attr); if(value.isNull()) return false; // attribute is not set switch(sel->match) { case CSSSelector::Exact: if(strcasecmp(sel->value, value)) return false; break; case CSSSelector::Set: break; case CSSSelector::List: { //kdDebug( 6080 ) << "checking for list match" << endl; QString str = value.string(); QString selStr = sel->value.string(); int pos = str.find(selStr, 0, false); if(pos == -1) return false; if(pos && str[pos-1] != ' ') return false; pos += selStr.length(); if(pos < (int)str.length() && str[pos] != ' ') return false; break; } case CSSSelector::Hyphen: { // ### still doesn't work. FIXME //kdDebug( 6080 ) << "checking for hyphen match" << endl; QString str = value.string(); if(str.find(sel->value.string(), 0, false) != 0) return false; // ### could be "bla , sdfdsf" too. Parse out spaces int pos = sel->value.length() + 1; while(pos < (int)str.length() && sel->value[pos] == ' ') pos++; if(pos < (int)str.length() && sel->value[pos] != ',') return false; break; } case CSSSelector::Pseudo: case CSSSelector::None: break; } } if(sel->match == CSSSelector::Pseudo) { //kdDebug() << "CSSOrderedRule::pseudo" << endl; // Pseudo elements. We need to check first child here. No dynamic pseudo // elements for the moment if(sel->value == ":first-child") { if(e->parentNode()->firstChild() != e) return false; } else if(sel->value == ":link") { if ( pseudoState == PseudoUnknown ) checkPseudoState( e ); if ( pseudoState == PseudoLink ) return true; else return false; } else if ( sel->value == ":visited" ) { if ( pseudoState == PseudoUnknown ) checkPseudoState( e ); if ( pseudoState == PseudoVisited ) return true; else return false; } else return false; } // ### add the rest of the checks... return true;}// -----------------------------------------------------------------CSSStyleSelectorList::CSSStyleSelectorList() : QList<CSSOrderedRule>(){ setAutoDelete(true);}CSSStyleSelectorList::~CSSStyleSelectorList(){}int CSSStyleSelectorList::compareItems(QCollection::Item i1, QCollection::Item i2){ CSSOrderedRule *r1 = static_cast<CSSOrderedRule *>(i1); CSSOrderedRule *r2 = static_cast<CSSOrderedRule *>(i2);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?