注:WebKit在115097版本中将CSSStyleSelector重命名为StyleResolver
http://trac.webkit.org/changeset/115097
3 样式表的收集和处理
图3.2 样式表的收集等处理相关的类图
3.1 样式表的收集
在m_sheet生成完毕之后,都会调用checkLoaded方法,这个过程会通知拥有m_sheet的节点(即HTMLLinkElement或者HTMLStyleElement)表单读取完成sheetLoaded。之后相关的节点会通知Document移除正在读取的sheet,即removePendingSheet方法。如果所有样式都加载完毕则会在removePendingSheet方法内使用styleSelectorChanged方法,styleSelectorChanged方法又会去调用recalcStyleSelector方法收集生成好的CSSStyleSheet对象(包括之前生成好的)将它们保存在StyleSheetList变量m_styleSheets中,然后会去调用recalcStyle(Force)更新Style,最后会决定是否需要重排版。
相关函数
1.void Document::styleSelectorChanged(StyleSelectorUpdateFlag updateFlag)
在样式加载完毕,忽略加载样式排版,清除页面样式时调用,它会去判断是否需要重绘,调用样式收集函数,样式计算函数和排版函数。
2.void Document::recalcStyleSelector(StyleChange change)
收集之前解析好的HTMLStyleElement和HTMLLinkElement中的样式表,清除之前的CSSStyleSelector。
3.2 样式表的处理
Document::recalcStyle函数会调用CSSStyleSelector::styleForDocument为整个文档生成一个RenderStyle然后将其设置给render树的根节点,然后会去调用它的每一个子节点Element的recalcStyle函数,Element::recalcStyle函数会调用styleForRenderer(最终会调到CSSStyleSelector::styleForElement)来创建一个新的RenderStyle,然后调用setRenderStyle函数将新创建的RenderStyle设置给该节点对应的Render节点。Element::recalcStyle还会继续调用它的每一个子节点的Element的recalcStyle函数,最终会以广度优先遍历的顺序更新render树中每个节点的RenderStyle。
前面提到样式解析过程获取的结构CSSStyleSheet并不适合样式计算,我们需要根据样式规则中选择器的匹配类型将样式声明重新散列到便于处理的RuleSet结构中,这个过程是由CSSStyleSelector的构造函数来完成。
每个Document有一个CSSStyleSelector,通常会在第一次需要使用CSSStyleSelector时创建,在collectActiveStylesheets方法中会重新收集生成好的CSSStyleSheet,之后会清除CSSStyleSelector对象。在CSSStyleSelector构造函数中首先会对Document中的m_pageGroupUserSheets,m_userSheets规则集中的每一条规则调用RuleSet::addRulesFromSheet的方法添加到RuleSet的对象m_userStyle或者m_authorStyle中。然后会将Document中的m_styleSheets规则集中的每一条规则都添加到m_authorStyle中。在添加到RuleSet集合时会根据每条样式规则的选择器组中最右侧一个选择器的匹配类型将规则添加到RuleSet中对应的HashMap或者向量表中。
相关函数
1.void Document::recalcStyle(StyleChange change)
调用CSSStyleSelector::styleForDocument为整个文档生成一个RenderStyle然后将其设置给render树的根节点,然后会去调用它的每一个子节点Element的recalcStyle函数,最终计算出整棵树的RenderStyle。
2.void Element::recalcStyle(StyleChange change)
调用CSSStyleSelector::styleForElement计算每一个元素子节点的样式信息。
3.void RuleSet::addRulesFromSheet(CSSStyleSheet* sheet, const MediaQueryEvaluator& medium, CSSStyleSelector* styleSelector)
该方法主要是根据样式表StyleSheet中的每一个CSSRule的类型调用不同的处理函数进行处理,对普通的style类型,会调用addStyleRule做进一步处理,对@import类型会对其中保存的styleSheet()继续调用addRulesFromSheet方法,对@page类型会调用addPageRule将其添加到向量表m_pageRules中,对@media类型对其中的所有子StyleSheet做如上处理。
4.void RuleSet::addStyleRule(CSSStyleRule* rule)
该方法对CSSStyleRule中的selectorList()的每一个CSSSelector调用addRule方法。
5.void RuleSet::addRule(CSSStyleRule* rule, CSSSelector* sel)
该方法会根据CSSSelector中的匹配类型,如果是id,class,unknownpseudo,tag则将以CSSSelector中的字符串为key,将CSSStyleRule封装成RuleData分别保存到RuleSet的四个HashMap变量中m_idRules,m_classRules,m_shadowPseudoElementRules,m_tagRules;如果是伪类类型则保存到m_linkPseudoClassRules或者m_focusPseudoClassRules变量中。譬如:
#id1{color:red;} -->存放在m_idRules中。
.class1{color:red;} -->存放在m_classRules中。
div .class1{color:red;} -->同上。
p{color:red;} -->在m_tagRules中。
*{color:red;} -->在m_universalRules中。
RuleSet和RuleData的组织结构如下图所示:
图3.2 RuleSet的组织结构
CSSStyleSheet和RuleSet之间的联系如下图所示:
图3.3 CSSStyleSheet和RuleSet之间的联系
注意:
1.一条样式声明以RuleData的形式,根据其选择器组中最右侧的选择器的匹配方式,被散列到RuleSet中的一个hashmap或者向量表中,不会同时被散列到其中两个之中,也即是说,一个声明对应的RuleData不会即存在于m_idRules中又存在于m_tagRules中。
2.以逗号隔开的选择器列表在RuleSet中会为其创建多个RuleData,并分别散列到逗号分隔的每一个选择器组对应的hashmap或者向量表中。
转载请注明出处:http://blog.csdn.net/zhchaoo/article/details/9033513