WebKit之CSS处理流程(4)

原帖地址 ; http://blog.csdn.net/zhchaoo/article/details/9050517

注:WebKit在115097版本中将CSSStyleSelector重命名为StyleResolver

http://trac.webkit.org/changeset/115097


4  RenderStyle的计算


4.1 样式计算相关的类图

4.1  样式计算的总体流程

    RenderStyle的计算是在CSSStyleSelector::styleForElement()中完成的。

    一个页面可以包含着多个样式表,而对于页面上的某一个可绘制的元素来说,由于它所处的文档层次不同,即使是同一个标签都可能具有不同的显示样式。

    当文档中的某一个元素需要获取其显示样式时,它最终会调用CSSStyleSelector的接口方法styleForElement()来获取最终的RenderStyle

    一个HTML页面元素的最终样式计算流程如下:

1. 调用CSSStyleSelector::initElement()函数和CSSStyleSelector::initForStyleResolve(),初始化CSSStyleSelector当前的处理节点。CSSStyleSelector::initElement会将m_elementm_styledElement都设置为当前节点。initForStyleResolve会清空样式计算相关的数据结构,如m_stylem_matchedDelsm_pendingImagePropertiesm_ruleList等。

2. 如果当前处理节点有父RenderStyle,则当前处理的节点的RenderStyle继承父RenderStyle。设置RenderStyle是否为链接元素等。

3. 调用CSSStyleSelector::ensureDefaultStyleSheetsForElement()设置默认的RenderStyle。如果元素的默认RenderStyle已经设置了,则不重新设置。

4. 然后如果resolveForRootDefault则调用CSSStyleSelector::matchUARules()匹配默认的样式,否则调用CSSStyleSelector::matchAllRules()函数,该函数首先会调用matchUARules()匹配默认样式,然后搜索用户定义的样式、Mapped的属性样式、作者的样式、最后搜索元素内嵌的样式。将匹配的样式按顺序存储在m_matchedDecls中。

5. 对于浏览器默认样式,用户定义的样式(m_userStyle),作者样式(m_authorStyle)的搜索过程,是通过调用CSSStyleSelector::matchRules方法来完成的。具体过程是首先清空m_matchedRules。依次根据元素的ID,元素定义的class,元素的伪类,元素的Tag名字,通用样式依次搜索匹配的样式。每一个搜索步骤是通过CSSStyleSelector::matchRulesForList方法来获取所匹配的CSSStyle集合。将匹配的结果缓存在m_matchedRules中,然后对m_matchedRules中的规则进行排序,并将排好序的属性申明加入到m_matchedDecls中。

5.1. CSSStyleSelector::matchRulesForList的处理流程是从对应的向量表Vector<RuleData>中遍历,如果它的某一个样式对应的选择器组能够匹配当前元素的特征(通过checkSelector方法进行判别),那么将这条规则添加到已匹配的规则列表中(即m_matchedRules中)。

6. 调用CSSStyleSelector::applyMatchedDeclarations 方法,而该方法又会调用applyDeclarations方法,从已匹配的规则列表中提取出一个个CSSMutableStyleDeclaration对象,将CSSMutableStyleDeclaration中符合显示相关的CSSProperty来构建最终的RenderStyle,并返回。提取CSSMutableStyleDeclaration对象的顺序是:提取不重要的浏览器定义的不重要的,提取用户定义的不重要的,提取作者定义的不重要的,提取作者定义的重要的,提取用户定义的重要的,提取浏览器定义的重要的。通过这个提取顺序,实现了CSS的优先级关系。

7. 最后调用CSSStyleSelector::initElement(0)清楚设置的元素信息等,为下一次样式计算做准备。

4.2  样式的匹配

    样式匹配过程的主流程是由CSSStyleSelector::mathAllRules函数来完成,它会调用CSSStyleSelector::matchRules函数按照样式表的级联顺序对defaultStylem_userRulesm_authorRules三个RuleSet集合中的样式进行匹配以及检查HTML标签中的属性和内联样式;在具体匹配某一个RuleSet是通过调用CSSStyleSelector::matchRulesForList匹配RuleSet中存放样式规则的部分子集合(这里会根据元素的特性,如idclass和是否链接/焦点等来决定匹配RuleSet中的哪一部分子集),在判断一条样式规则是否和当前的元素匹配时是通过CSSStyleSelector::checkSelector函数检查选择器是否和当前元素匹配来完成。

    下图是样式匹配的概述图:


4.2 样式匹配概述图

相关函数

1.void CSSStyleSelector::matchAllRules(MatchResult& result)

    该函数按如下顺序检查之前整理好的样式集和mappedAttribute:首先匹配用户定义的样式集m_userStyle,检查HTML标签中的mapped attributes,检查附加的additional mapped declarations(表格和表格单元中的附加属性),匹配作者样式集m_authorStyle,最后检查内联样式属性。样式集中的属性通过matchRules匹配添加,其它属性直接通过addMatchedDeclaration函数添加。

2.void CSSStyleSelector::matchRules(RuleSet* rules, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules)

    该函数首先清空m_matchedRules变量为本次匹配做准备。然后按顺序以元素的idclassshadowPseudoIdkeyRuleSetm_idRulesm_classRulesm_shadowPseudoElementRules变量中搜索对应的RuleData向量表并调用matchRulesForList函数检查向量表中的RuleData是否匹配(如果元素有idclass或者shadowPseudoId);接着同样用matchRulesForList函数处理m_linkPseudoClassRulesm_focusPseudoClassRulesm_tagRulesm_universalRules中的RuleData。这时,本次匹配的规则都在m_matchedRules变量中,对其中的规则排序,最后调用addMatchedDeclaration函数将匹配结果保存在m_matchedDels变量中。

3.void CSSStyleSelector::matchRulesForList(const Vector<RuleData>* rules, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules) 

    该函数会去进一步检查matchRule初步匹配出来的RuleData向量表中的每一个RuleData是否是该元素的匹配样式,对每一个RuleData首先调用CSSStyleSelector::checkSelector函数检查选择器是否匹配,如果匹配则进一步检查,然后将该RuleData添加到m_matchedRules中。

4.inline bool CSSStyleSelector::checkSelector(const RuleData& ruleData)

    该函数会根据CSSSelectorm_relation类型走不同的匹配流程,如对于CSSSelector::Descendant后代类型会从当前元素开始沿着它到根结点的路径查找是否和当前选择器匹配,如果匹配,查询CSSSelector是否是TagHistory中的最后一个,如果是则整个过程匹配成功,如果不是,继续取选择器组中下一个CSSSelector重复上述匹配过程。匹配到根节点而选择器组中还有选择器则认为匹配失败。它的时间复杂度可以认为是O(n)=m+n;其中m是选择器组中选择器的个数,n是当前匹配的节点的深度。


4.2.1  匹配规则的排序

前面介绍了样式表的级联顺序,这里介绍同等级别的声明的排序,WebKit将根据specifity以及它们被定义时的顺序进行排序。Html可视化属性将被转换为匹配的css声明,它们被视为最低优先级的作者规则。

Specifity

    Css2规范中定义的选择符specifity如下:

² 如果声明来自style属性,而不是一个选择器的规则,则计1,否则计0(=a)

² 计算选择器中id属性的数量(=b)

² 计算选择器中class及伪类的数量(=c)

² 计算选择器中元素名及伪元素的数量(=d)

    连接a-b-c-d四个数量(用一个大基数的计算系统)将得到specifity。这里使用的基数由分类中最高的基数定义。例如,如果a14,可以使用16进制。不同情况下,a17时,则需要使用阿拉伯数字17作为基数,这种情况可能在这个选择符时发生html body div div (选择符中有17个标签,一般不太可能)

排序规则

WebKit对同级别的声明采用std::sort来排序,排序的标准由compareRules函数定义:

static inline bool compareRules(const RuleData* r1, const RuleData* r2)

{

    unsigned specificity1 = r1->specificity();

    unsigned specificity2 = r2->specificity();

    return (specificity1 == specificity2) ? r1->position() < r2->position() : specificity1 < specificity2;

}

    根据matchAllRules函数对级联样式的处理顺序,样式匹配最终保存在m_matchedDecls中的结果是按浏览器默认样式,用户定义的样式,网页作者定义的样式的顺序存放匹配的样式规则,同级样式又是按specifityposition来排序,MatchResult中保存各级样式在m_matchedDecls中的起始和结束为止(-1表示不存在该级样式)

4.3  样式的比较

Element::recalcStyle函数在调用CSSStyleSelector::styleForElement计算获取了元素的新样式RenderStyle之后会去和元素当前的样式进行比较,比较的结果是以下几种之一:NoChange, NoInheritInheritDetachForce。针对不同的比较结果会去采取不同的操作,例如可能会去reattach当前节点。


4.4  样式的应用

     在完成了样式匹配和排序之后, 就需要将排好序的匹配样式m_matchedDecls应用到RenderStyle中, 这个步骤主要通过applyDeclarations函数来完成。

在应用样式时需要分四次进行,WebKit定义了一部分高优先级的属性, 它们是会被其他样式属性依赖的样式属性,它们的属性ID被定义为小于‘line-height’的属性ID, 这样的属性包括‘line-height’目前有20个,除了‘line-height’主要是字体和缩放。应用顺序如下:

1. 高优先级的非important属性

2. 高优先级的important属性

3. 普通优先级的非important属性

4. 普通优先级的important属性

在具体应用每一条属性时是通过CSSStyleSelector::applyProperty函数来进行。 它根据不同的属性ID对属性值作相应的处理并最终设置到RenderStyle中。

在最后样式应用完毕之后还需要调用CSSStyleSelector::adjustRenderStyle 函数对得到的RenderStyle样式进行一些调整, 主要是按照标准对样式进行修订。例如,在quirk模式下,table标签必须是display:table的样式,如果样式表中制定了其它样式,那么在CSSStyleSelector::adjustRenderStyle函数中就会对它进行调整,将其设置为table样式。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值