📄 cssstyleselector.cpp
字号:
/** * This file is part of the CSS implementation for KDE. * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * Copyright (C) 2004 Apple Computer, Inc. * * 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. */#include "css/cssstyleselector.h"#include "rendering/render_style.h"#include "css/css_stylesheetimpl.h"#include "css/css_ruleimpl.h"#include "css/css_valueimpl.h"#include "css/csshelper.h"#include "rendering/render_object.h"#include "html/html_documentimpl.h"#include "html/html_elementimpl.h"#include "xml/dom_elementimpl.h"#include "dom/css_rule.h"#include "dom/css_value.h"#include "khtml_factory.h"#include "khtmlpart_p.h"using namespace khtml;using namespace DOM;#include "css/cssproperties.h"#include "css/cssvalues.h"#include "misc/khtmllayout.h"#include "khtml_settings.h"#include "misc/htmlhashes.h"#include "misc/helper.h"#include "misc/loader.h"#include "rendering/font.h"#include "khtmlview.h"#include "khtml_part.h"#include <kstandarddirs.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>#include <stdlib.h>// #define STYLE_SHARING_STATS 1#define HANDLE_INHERIT(prop, Prop) \if (isInherit) \{\ style->set##Prop(parentStyle->prop());\ return;\}#define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \HANDLE_INHERIT(prop, Prop) \else if (isInitial) \ style->set##Prop(RenderStyle::initial##Prop());#define HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(prop, Prop, Value) \HANDLE_INHERIT(prop, Prop) \else if (isInitial) \ style->set##Prop(RenderStyle::initial##Value());#define HANDLE_INHERIT_COND(propID, prop, Prop) \if (id == propID) \{\ style->set##Prop(parentStyle->prop());\ return;\}#define HANDLE_INITIAL_COND(propID, Prop) \if (id == propID) \{\ style->set##Prop(RenderStyle::initial##Prop());\ return;\}#define HANDLE_INITIAL_COND_WITH_VALUE(propID, Prop, Value) \if (id == propID) \{\ style->set##Prop(RenderStyle::initial##Value());\ return;\}namespace khtml {CSSRuleSet *CSSStyleSelector::defaultStyle = 0;CSSRuleSet *CSSStyleSelector::defaultQuirksStyle = 0;CSSRuleSet *CSSStyleSelector::defaultPrintStyle = 0;CSSStyleSheetImpl *CSSStyleSelector::defaultSheet = 0;RenderStyle* CSSStyleSelector::styleNotYetAvailable = 0;CSSStyleSheetImpl *CSSStyleSelector::quirksSheet = 0;static CSSStyleSelector::Encodedurl *encodedurl = 0;static PseudoState pseudoState;CSSStyleSelector::CSSStyleSelector( DocumentImpl* doc, QString userStyleSheet, StyleSheetListImpl *styleSheets, const KURL &url, bool _strictParsing ){ init(); view = doc->view(); strictParsing = _strictParsing; settings = view ? view->part()->settings() : 0; if(!defaultStyle) loadDefaultStyle(settings); m_medium = view ? view->mediaType() : QString("all"); m_userStyle = 0; m_userSheet = 0; paintDeviceMetrics = doc->paintDeviceMetrics(); // FIXME: This sucks! The user sheet is reparsed every time! if ( !userStyleSheet.isEmpty() ) { m_userSheet = new DOM::CSSStyleSheetImpl(doc); m_userSheet->parseString( DOMString( userStyleSheet ) ); m_userStyle = new CSSRuleSet(); m_userStyle->addRulesFromSheet( m_userSheet, m_medium ); } // add stylesheets from document m_authorStyle = new CSSRuleSet(); QPtrListIterator<StyleSheetImpl> it(styleSheets->styleSheets); for (; it.current(); ++it) if (it.current()->isCSSStyleSheet()) m_authorStyle->addRulesFromSheet(static_cast<CSSStyleSheetImpl*>(it.current()), m_medium); //kdDebug( 6080 ) << "number of style sheets in document " << authorStyleSheets.count() << endl; //kdDebug( 6080 ) << "CSSStyleSelector: author style has " << authorStyle->count() << " elements"<< endl; KURL u = url; 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( CSSStyleSheetImpl *sheet ){ init(); if(!defaultStyle) loadDefaultStyle(); KHTMLView *view = sheet->doc()->view(); m_medium = view ? view->mediaType() : QString("all"); m_authorStyle = new CSSRuleSet(); m_authorStyle->addRulesFromSheet( sheet, m_medium );}void CSSStyleSelector::init(){ element = 0; settings = 0; paintDeviceMetrics = 0; m_matchedRuleCount = m_matchedDeclCount = m_tmpRuleCount = 0;}CSSStyleSelector::~CSSStyleSelector(){ delete m_authorStyle; delete m_userStyle; delete m_userSheet;}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 ); // Collect only strict-mode rules. defaultStyle = new CSSRuleSet(); defaultStyle->addRulesFromSheet( defaultSheet, "screen" ); defaultPrintStyle = new CSSRuleSet(); defaultPrintStyle->addRulesFromSheet( defaultSheet, "print" ); } { QFile f(locate( "data", "khtml/css/quirks.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() ); DOMString str(style); quirksSheet = new DOM::CSSStyleSheetImpl((DOM::CSSStyleSheetImpl * ) 0); quirksSheet->parseString( str ); // Collect only quirks-mode rules. defaultQuirksStyle = new CSSRuleSet(); defaultQuirksStyle->addRulesFromSheet( quirksSheet, "screen" ); } //kdDebug() << "CSSStyleSelector: default style has " << defaultStyle->count() << " elements"<< endl;}void CSSStyleSelector::addMatchedRule(CSSRuleData* rule){ if (m_matchedRules.size() <= m_matchedRuleCount) m_matchedRules.resize(2*m_matchedRules.size()+1); m_matchedRules[m_matchedRuleCount++] = rule;}void CSSStyleSelector::addMatchedDeclaration(CSSStyleDeclarationImpl* decl){ if (m_matchedDecls.size() <= m_matchedDeclCount) m_matchedDecls.resize(2*m_matchedDecls.size()+1); m_matchedDecls[m_matchedDeclCount++] = decl;}void CSSStyleSelector::matchRules(CSSRuleSet* rules, int& firstRuleIndex, int& lastRuleIndex){ m_matchedRuleCount = 0; firstRuleIndex = lastRuleIndex = -1; if (!rules || !element) return; // We need to collect the rules for id, class, tag, and everything else into a buffer and // then sort the buffer. if (element->hasID()) matchRulesForList(rules->getIDRules(element->getIDAttribute().implementation()), firstRuleIndex, lastRuleIndex); if (element->hasClass()) { for (const AtomicStringList* singleClass = element->getClassList(); singleClass; singleClass = singleClass->next()) matchRulesForList(rules->getClassRules(singleClass->string().implementation()), firstRuleIndex, lastRuleIndex); } matchRulesForList(rules->getTagRules((void*)(int)localNamePart(element->id())), firstRuleIndex, lastRuleIndex); matchRulesForList(rules->getUniversalRules(), firstRuleIndex, lastRuleIndex); // If we didn't match any rules, we're done. if (m_matchedRuleCount == 0) return; // Sort the set of matched rules. sortMatchedRules(0, m_matchedRuleCount); // Now transfer the set of matched rules over to our list of decls. for (unsigned i = 0; i < m_matchedRuleCount; i++) addMatchedDeclaration(m_matchedRules[i]->rule()->declaration());}void CSSStyleSelector::matchRulesForList(CSSRuleDataList* rules, int& firstRuleIndex, int& lastRuleIndex){ if (!rules) return; for (CSSRuleData* d = rules->first(); d; d = d->next()) { CSSStyleRuleImpl* rule = d->rule(); Q_UINT16 cssTagId = localNamePart(element->id()); Q_UINT16 tag = localNamePart(d->selector()->tag); if ((cssTagId == tag || tag == anyLocalName) && checkSelector(d->selector(), element)) { // If the rule has no properties to apply, then ignore it. CSSStyleDeclarationImpl* decl = rule->declaration(); if (!decl) continue; // If we're matching normal rules, set a pseudo bit if // we really just matched a pseudo-element. if (dynamicPseudo != RenderStyle::NOPSEUDO && pseudoStyle == RenderStyle::NOPSEUDO) style->setHasPseudoStyle(dynamicPseudo); else { // Update our first/last rule indices in the matched rules array. lastRuleIndex = m_matchedDeclCount + m_matchedRuleCount; if (firstRuleIndex == -1) firstRuleIndex = m_matchedDeclCount + m_matchedRuleCount; // Add this rule to our list of matched rules. addMatchedRule(d); } } }}bool operator >(CSSRuleData& r1, CSSRuleData& r2){ int spec1 = r1.selector()->specificity(); int spec2 = r2.selector()->specificity(); return (spec1 == spec2) ? r1.position() > r2.position() : spec1 > spec2; }bool operator <=(CSSRuleData& r1, CSSRuleData& r2){ return !(r1 > r2);}void CSSStyleSelector::sortMatchedRules(uint start, uint end){ if (start >= end || (end-start == 1)) return; // Sanity check. if (end - start <= 6) { // Apply a bubble sort for smaller lists. for (uint i = end-1; i > start; i--) { bool sorted = true; for (uint j = start; j < i; j++) { CSSRuleData* elt = m_matchedRules[j];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -