webkit内核源代码导读5: CSS如何作用到Render树上
来源:互联网 发布:手机淘宝在哪看等级 编辑:程序博客网 时间:2024/05/04 15:31
本章的目的,主要说明CSS相关的类和关系,还不能做到对其过程和原理的探究。后期我们慢慢会涉及。
CSS的主要作用,是修饰DOM的外观和排版的,它必须和Render--DOM的渲染对象结合起来。
在Render中,有一个重要的对象,是RenderStyle。这个RenderStyle是从CSS中创建出来的。
RenderStyle和StyleResolver
RenderStyle保存了Render树绘制所需要的全部信息。至于Render树如何使用Render,这里我们不仔细探索,我想重点探索一下StyleResolver。
StyleResolver将CSS的内容转换为RenderStyle,有几个函数是重点关注的:
PassRefPtr<RenderStyle> styleForElement(Element*, RenderStyle* parentStyle = 0, StyleSharingBehavior = AllowStyleSharing, RuleMatchingBehavior = MatchAllRules, RenderRegion* regionForStyling = 0); ...... PassRefPtr<RenderStyle> pseudoStyleForElement(PseudoId, Element*, RenderStyle* parentStyle); PassRefPtr<RenderStyle> styleForPage(int pageIndex); PassRefPtr<RenderStyle> defaultStyleForElement(); PassRefPtr<RenderStyle> styleForText(Text*); static PassRefPtr<RenderStyle> styleForDocument(Document*, CSSFontSelector* = 0);这里面几个styleForXXX函数,是产生RenderStyle的重要地方。
StyleResolver的关系
StyleResolver是Document的子对象。Document负责创建它,别的数据想要使用StyleResolver,需要调用 document()->styleResolver();
在Document.h中 (class Document)
StyleResolver* styleResolver() { if (!m_styleResolver) createStyleResolver(); return m_styleResolver.get(); }
StyleResolver的styleForXXX系列函数会在不同的地方调用。例如,styleForElement,会在Element::styleForRender中调用,而Element::styleForRender则会在recalcStyle(包括Document::recalcStyle和Element::recalcStyle)中调用。
recalcStyle函数是当CSS发生变化的时候被调用。例如,Document::updateStyleIfNeeded。因为调用的地方很多,不再一一列举。只需明白:当style发生变化后,就会引起recalcStyle
styleForElement:CSS选择和匹配
回到StyleResolver中看styleForElement,我们看看CSS的Selector是如何工作的。
styleForElement的代码片段
//将元素暂时保存在StyleResolver类中1534 1535 initElement(element);1536 initForStyleResolve(element, defaultParent);....//进行规则匹配1570 MatchResult matchResult;1571 if (matchingBehavior == MatchOnlyUserAgentRules)1572 matchUARules(matchResult);1573 else1574 matchAllRules(matchResult, matchingBehavior != MatchAllRulesExcludingSMIL);1575 //将获取的规则映射到RenderStyle中1576 applyMatchedProperties(matchResult, element);
选择和匹配的关键函数在matchUARules和matchAllRules两个函数中。
这里关键看函数matchUARules。该函数有两个重载,下面这个是最终实现
825 void StyleResolver::matchUARules(MatchResult& result, RuleSet* rules) 826 { 827 m_matchedRules.clear(); 828 829 result.ranges.lastUARule = result.matchedProperties.size() - 1; 830 collectMatchingRules(rules, result.ranges.firstUARule, result.ranges.lastUARule, false); 831 832 sortAndTransferMatchedRules(result); 833 }
注意函数collectMatchRules和sortAndTransferMatchedRules。这两个函数,一个是收集选装的规则,一个是对规则进行排序。
那么,RuleSet是什么呢?
RuleSet就代表一个CSS规则,CSS规则包括CSS选择子和CSS描述。例如
p { background : red; }
这就是一个RuleSet。
RuleSet的定义中,有几个成员变量值得一看:
class RuleSet ... {.....132 AtomRuleMap m_idRules;133 AtomRuleMap m_classRules;134 AtomRuleMap m_tagRules;135 AtomRuleMap m_shadowPseudoElementRules;...};
显然,这几个是对应CSS的id, class, tag等选择子的,这几个选择子是最经常使用的,因此,webkit把他们单独拿出来做了优化。
那么collectMatchRules也就不难实现了。具体的实现,我们不再详细说明了。
对于sortAndTransferMatchedRules将获取到的ruleset进行排序,以保证正确的匹配顺序,否则,会引起CSS的显示错误。它是按照CSS的标准文档进行排序的,这一点,我们以后在详细考虑。
RuleSet的来源
RuleSet的来源很多,包括默认的RuleSet,这些是浏览器定义的。Author的RuleSet,这些是网页的作者定义的。对于Element,还有来自Element本身的规则。
Element的RuleSet来源
只有继承自StyledElement的Element才能提供RuleSet。这些就是所谓的内联CSS,如,
<p background="red"> ...<p style="background:red;">...这样形式的CSS。
这类CSS的生成,是在StyledElement::rebuildPresentationAttributeStyle中完成的。该函数会在element的AttributeData发生变化后,调用。我们看,该函数是如何生成CSS的RuleSet的:
void StyledElement::rebuildPresentationAttributeStyle(){..... RefPtr<StylePropertySet> style; if (cacheHash && cacheIterator->value) { style = cacheIterator->value->value; presentationAttributeCacheCleaner().didHitPresentationAttributeCache(); } else { style = StylePropertySet::create(isSVGElement() ? SVGAttributeMode : CSSQuirksMode); unsigned size = attributeCount(); for (unsigned i = 0; i < size; ++i) { const Attribute* attribute = attributeItem(i); collectStyleForPresentationAttribute(*attribute, style.get()); } } // ImmutableElementAttributeData doesn't store presentation attribute style, so make sure we have a MutableElementAttributeData. ElementAttributeData* attributeData = mutableAttributeData(); attributeData->m_presentationAttributeStyleIsDirty = false; attributeData->setPresentationAttributeStyle(style->isEmpty() ? 0 : style);....
请关注:collectStyleForPresentationAttribute函数和attributeData->setProsentationAttributeStyle两个函数。
collectStyleForPresentationAttribute函数是个虚函数,需要被子类实现。子类需要判断那些属性是style属性,然后将他们的值生成为StyleProperty对象。
attributeData是Element保存属性的对象,这个对象为 ElementAttributeData。
这个类使用了一些技巧,以节省内存,这一点在阅读时,需要注意。
StyleResolver通过调用StyledElement::presentationAttributeStyle->ElementAttributeData::presentationAttributeStyle()函数,得到上面setProsentationAttributeStyle的结果。
AuthorStyle的来源
StyleResolver::m_authorStyle保存了当前网页相关的样式。所有的style元素和link元素引入的css都保存在这里。
那么,它是怎么做到呢? 它来自于Document::styleResolverChanged函数。这个函数被很多地方调用,当CSS改变的时候,或者发生页面大小变化等的时候,该函数会被触发。
这个调用序列是:
Document::styleResolverChanged -> DocumentStyleSheetCollection::updateActiveStyleSheets -> StyleResolver::appendAuthorStyleSheets
至此,CSS的解析的大略已经基本完成了。
- webkit内核源代码导读5: CSS如何作用到Render树上
- webkit内核源代码导读
- webkit内核源代码导读4: CSS之解析
- webkit内核源代码导读2: FrameLoader的初步分析
- webkit内核源代码导读3:HTML的解析过程
- webkit内核源代码导读1:前言及webcore最基本的类
- WebKit 内核源代码分析 ( 四 )
- WebKit内核源代码分析(3)
- WebKit 内核源代码分析 ( 四 )
- WebKit 内核源代码分析 ( 四 )
- WebKit内核源代码分析(五)
- WebKit 内核源代码分析 ( 四 )
- WebKit内核源代码分析(一)
- WebKit 内核源代码分析 ( 四 )
- WebKit内核源代码分析(五)
- WebKit 内核源代码分析 ( 四 )
- WebKit内核源代码分析(五)
- WebKit 内核源代码分析(四)
- VS2010快捷键大全
- Linux下Jdk的配置
- SQL SERVER无法连接到服务器的解决方法
- Redis
- Oracle 游标应用实例
- webkit内核源代码导读5: CSS如何作用到Render树上
- 突破点/灵感来自何方
- boost::asio::deadline_timer
- 用VMware Workstation创建虚拟机的方法与步骤。
- QuartZ Cron表达式
- 升级ADT 22 引发的错误
- jsp自定义标签
- XML和XMLSocket(三) -- SmartFoxServer简介
- 关于Java中的paint,repaint,update三个方法的关系