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