cssstyleselector.cpp

来自「将konqueror浏览器移植到ARM9 2410中」· C++ 代码 · 共 1,995 行 · 第 1/5 页

CPP
1,995
字号
/** * 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.169.2.4 2001/11/01 18:56:45 mueller Exp $ */#include "cssstyleselector.h"#include "rendering/render_style.h"#include "css_stylesheetimpl.h"#include "css_ruleimpl.h"#include "css_valueimpl.h"#include "csshelper.h"#include "html/html_documentimpl.h"#include "xml/dom_elementimpl.h"#include "dom/css_rule.h"#include "dom/css_value.h"#include "khtml_factory.h"using namespace khtml;using namespace DOM;#include "cssproperties.h"#include "cssvalues.h"#include "misc/khtmllayout.h"#include "khtml_settings.h"#include "misc/htmlhashes.h"#include "misc/helper.h"#include "khtmlview.h"#include "khtml_part.h"#include "khtml_settings.h"#include <kstddirs.h>#include <kcharsets.h>#include <kglobal.h>#include <qfile.h>#include <qfontdatabase.h>#include <qfontinfo.h>#include <qvaluelist.h>#include <qstring.h>#include <kdebug.h>#include <kurl.h>#include <qdatetime.h>#include <assert.h>#include <qpaintdevicemetrics.h>#include <qintcache.h>CSSStyleSelectorList *CSSStyleSelector::defaultStyle = 0;CSSStyleSheetImpl *CSSStyleSelector::defaultSheet = 0;enum PseudoState { PseudoUnknown, PseudoNone, PseudoLink, PseudoVisited};static PseudoState pseudoState;static int dynamicState;static RenderStyle::PseudoId dynamicPseudo;static int usedDynamicStates;static int selectorDynamicState;static CSSStyleSelector::Encodedurl *encodedurl;CSSStyleSelector::CSSStyleSelector(DocumentImpl * doc){    strictParsing = doc->parseMode() == DocumentImpl::Strict;    if(!defaultStyle) loadDefaultStyle(doc->view()?doc->view()->part()->settings():0);    selectors = 0;    selectorCache = 0;    properties = 0;    userStyle = 0;    userSheet = 0;    if ( !doc->userStyleSheet().isEmpty() ) {        userSheet = new DOM::CSSStyleSheetImpl((DOM::CSSStyleSheetImpl *)0);        userSheet->parseString( DOMString( doc->userStyleSheet() ) );        userStyle = new CSSStyleSelectorList();        userStyle->append(userSheet);    }    // add stylesheets from document    authorStyle = new CSSStyleSelectorList();    StyleSheetListImpl* ss = doc->styleSheets();    for ( QListIterator<StyleSheetImpl> it( ss->styleSheets ); it.current(); ++it ) 	    authorStyle->append( it.current());    buildLists();    //kdDebug( 6080 ) << "number of style sheets in document " << authorStyleSheets.count() << endl;    //kdDebug( 6080 ) << "CSSStyleSelector: author style has " << authorStyle->count() << " elements"<< endl;    KURL u = doc->baseURL().string();    u.setQuery( QString::null );    u.setRef( QString::null );    encodedurl.file = u.url();    int pos = encodedurl.file.findRev('/');    encodedurl.path = encodedurl.file;    if ( pos > 0 ) {	encodedurl.path.truncate( pos );	encodedurl.path += '/';    }    u.setPath( QString::null );    encodedurl.host = u.url();    //kdDebug() << "CSSStyleSelector::CSSStyleSelector encoded url " << encodedurl.path << endl;}CSSStyleSelector::CSSStyleSelector(StyleSheetImpl *sheet){    if(!defaultStyle) loadDefaultStyle();    authorStyle = new CSSStyleSelectorList();    authorStyle->append(sheet);}CSSStyleSelector::~CSSStyleSelector(){    clearLists();    delete authorStyle;    delete userStyle;    delete userSheet;}void CSSStyleSelector::addSheet(StyleSheetImpl *sheet){    authorStyle->append(sheet);}void CSSStyleSelector::loadDefaultStyle(const KHTMLSettings *s){    if(defaultStyle) return;    QFile f(locate( "data", "khtml/css/html4.css" ) );    f.open(IO_ReadOnly);    QCString file( f.size()+1 );    int readbytes = f.readBlock( file.data(), f.size() );    f.close();    if ( readbytes >= 0 )        file[readbytes] = '\0';    QString style = QString::fromLatin1( file.data() );    if(s)	style += s->settingsToCSS();    DOMString str(style);    defaultSheet = new DOM::CSSStyleSheetImpl((DOM::CSSStyleSheetImpl *)0);    defaultSheet->parseString( str );    defaultStyle = new CSSStyleSelectorList();    defaultStyle->append(defaultSheet);    //kdDebug() << "CSSStyleSelector: default style has " << defaultStyle->count() << " elements"<< endl;}void CSSStyleSelector::clear(){    delete defaultStyle;    delete defaultSheet;    defaultStyle = 0;    defaultSheet = 0;}static bool strictParsing;RenderStyle *CSSStyleSelector::styleForElement(ElementImpl *e, int state){    // this is a bit hacky, but who cares....    ::strictParsing = strictParsing;    ::dynamicState = state;    ::usedDynamicStates = StyleSelector::None;    ::encodedurl = &encodedurl;    ::pseudoState = PseudoUnknown;    CSSOrderedPropertyList *propsToApply = new CSSOrderedPropertyList;    CSSOrderedPropertyList *pseudoProps = new CSSOrderedPropertyList;    // try to sort out most style rules as early as possible.    int id = e->id();    int smatch = 0;    int schecked = 0;    for ( unsigned int i = 0; i < selectors_size; i++ ) {	int tag = selectors[i]->tag;	if ( id == tag || tag == -1 ) {	    ++schecked;	    checkSelector( i, e );	    if ( selectorCache[i].state == Applies ) {		++smatch;		//qDebug("adding property" );		for ( unsigned int p = 0; p < selectorCache[i].props_size; p += 2 )		    for ( unsigned int j = 0; j < (unsigned int )selectorCache[i].props[p+1]; ++j )			static_cast<QList<CSSOrderedProperty>*>(propsToApply)->append( properties[selectorCache[i].props[p]+j] );	    } else if ( selectorCache[i].state == AppliesPseudo ) {		for ( unsigned int p = 0; p < selectorCache[i].props_size; p += 2 )		    for ( unsigned int j = 0; j < (unsigned int) selectorCache[i].props[p+1]; ++j ) {			static_cast<QList<CSSOrderedProperty>*>(pseudoProps)->append(  properties[selectorCache[i].props[p]+j] );			properties[selectorCache[i].props[p]+j]->pseudoId = (RenderStyle::PseudoId) selectors[i]->pseudoId;		    }	    }	}	else	    selectorCache[i].state = Invalid;    }    //qDebug( "styleForElement( %s )", e->tagName().string().latin1() );    //qDebug( "%d selectors, %d checked,  %d match,  %d properties ( of %d )",    //selectors_size, schecked, smatch, propsToApply->count(), properties_size );    // inline style declarations, after all others. non css hints    // count as author rules, and come before all other style sheets, see hack in append()    if(e->styleRules())	addInlineDeclarations( e->styleRules(), propsToApply );    propsToApply->sort();    pseudoProps->sort();    RenderStyle* style = new RenderStyle();    if(e->parentNode()) {        assert(e->parentNode()->style() != 0);        style->inheritFrom(e->parentNode()->style());    }    //qDebug("applying properties, count=%d", propsToApply->count() );    // we can't apply style rules without a view(). This    // tends to happen on delayed destruction of widget Renderobjects    KHTMLView* v = e->ownerDocument()->view();    if ( v && v->part() ) {        if ( propsToApply->count() != 0 ) {            CSSOrderedProperty *ordprop = propsToApply->first();            while( ordprop ) {                //qDebug("property %d has spec %x", ordprop->prop->m_id, ordprop->priority );                applyRule( style, ordprop->prop, e );                ordprop = propsToApply->next();            }        }        if ( pseudoProps->count() != 0 ) {            //qDebug("%d applying %d pseudo props", e->id(), pseudoProps->count() );            CSSOrderedProperty *ordprop = pseudoProps->first();            while( ordprop ) {                RenderStyle *pseudoStyle;                pseudoStyle = style->addPseudoStyle(ordprop->pseudoId);                if ( pseudoStyle )                    applyRule(pseudoStyle, ordprop->prop, e);                ordprop = pseudoProps->next();            }        }    }    if ( usedDynamicStates & StyleSelector::Hover )	style->setHasHover();    if ( usedDynamicStates & StyleSelector::Focus )	style->setHasFocus();    if ( usedDynamicStates & StyleSelector::Active )	style->setHasActive();    delete propsToApply;    delete pseudoProps;    return style;}void CSSStyleSelector::addInlineDeclarations(DOM::CSSStyleDeclarationImpl *decl,					     CSSOrderedPropertyList *list ){    QList<CSSProperty> *values = decl->values();    if(!values) return;    int len = values->count();    if ( inlineProps.size() < (uint)len )	inlineProps.resize( len+1 );    CSSOrderedProperty *array = (CSSOrderedProperty *)inlineProps.data();    for(int i = 0; i < len; i++)    {        CSSProperty *prop = values->at(i);	Source source = Inline;        if( prop->m_bImportant ) source = InlineImportant;	if( prop->nonCSSHint ) source = NonCSSHint;	bool first;        // give special priority to font-xxx, color properties        switch(prop->m_id)        {        case CSS_PROP_FONT_SIZE:        case CSS_PROP_FONT:        case CSS_PROP_COLOR:        case CSS_PROP_BACKGROUND_IMAGE:            // these have to be applied first, because other properties use the computed            // values of these porperties.	    first = true;            break;        default:            first = false;            break;        }	array->prop = prop;	array->pseudoId = RenderStyle::NOPSEUDO;	array->selector = 0;	array->position = i;	array->priority = (!first << 30) | (source << 24);	static_cast<QList<CSSOrderedProperty>*>(list)->append( array );	array++;    }}static bool subject;void CSSStyleSelector::checkSelector(int selIndex, DOM::ElementImpl *e){    dynamicPseudo = RenderStyle::NOPSEUDO;    selectorDynamicState = StyleSelector::None;    NodeImpl *n = e;    selectorCache[ selIndex ].state = Invalid;    CSSSelector *sel = selectors[ selIndex ];    // we have the subject part of the selector    subject = true;    // hack. We can't allow :hover, as it would trigger a complete relayout with every mouse event.    bool single = false;    if ( sel->tag == -1 )	single = true;    // first selector has to match    if(!checkOneSelector(sel, e)) return;    // check the subselectors    CSSSelector::Relation relation = sel->relation;    while((sel = sel->tagHistory))    {	single = false;        if(!n->isElementNode()) return;        switch(relation)        {        case CSSSelector::Descendant:        {            bool found = false;            while(!found)            {		subject = false;                n = n->parentNode();                if(!n || !n->isElementNode()) return;                ElementImpl *elem = static_cast<ElementImpl *>(n);                if(checkOneSelector(sel, elem)) found = true;            }            break;        }        case CSSSelector::Child:        {		subject = false;            n = n->parentNode();            if(!n || !n->isElementNode()) return;            ElementImpl *elem = static_cast<ElementImpl *>(n);            if(!checkOneSelector(sel, elem)) return;            break;        }        case CSSSelector::Sibling:        {		subject = false;            n = n->previousSibling();	    while( n && !n->isElementNode() )		n = n->previousSibling();            if( !n ) return;            ElementImpl *elem = static_cast<ElementImpl *>(n);            if(!checkOneSelector(sel, elem)) return;            break;        }        case CSSSelector::SubSelector:	{	    //kdDebug() << "CSSOrderedRule::checkSelector" << endl;	    ElementImpl *elem = static_cast<ElementImpl *>(n);	    // a selector is invalid if something follows :first-xxx	    if ( dynamicPseudo == RenderStyle::FIRST_LINE ||		 dynamicPseudo == RenderStyle::FIRST_LETTER ) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?