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 + -
显示快捷键?