Webkit内核探究——Webkit CSS实现

  • Post author:
  • Post category:其他




前言


CSS



Webkit

中的实现属于相对独立的一个模块,注意这里说的是相对。


CSS



Webkit

中的作用自然是不言而喻的,在

Web

早期,文档的结构和样式还未分离的那个时代,

HTML

担负了文档的结构和样式这两个双重任 务,即

HTML

既负责文档的结构,同时文档的样式也通过

HTML

中通过标签的属性来指定。可想而知,在那个时候

HMTL

页面的开发和使用比起现在而言是多 么的不便。

不过仔细想想,这恐怕与当时的技术发展程度有着很大大关,首先,那个时候互联网远不像现在这样普及,另外,网页也远不如现在这样复杂,不像现在, 可以说,世界上信息的主要传播方式是以网页形式出现的,没数据说明,但我觉得至少趋势是这样的。 就这样,互联网在不断的前进之中,直到后来

CSS

的出现,大大的改进了

Web

的开发模式,从此,文档的结构和样式被清晰的一分为二。

HTML

主要负责文档 的结构,而

CSS

则担负着文档的样式指定。

关于

CSS

的介绍网上已经有很多了,在这里将主要从

Webkit

实现的角度对其进行介绍。



1、CSS是什么


CSS



Cascading Style Sheets

的缩写,按照官方定义,它可以被认为是一个样式表语言

,它允许用户通过它来为结构化文档(HTML文档)指定样式。通过使用CSS用户可以将文档的内容和样式分离,从而简化Web页面的开发和维护。

既然说它是一个样式表语言,那么它就有相应的语法规则,规定了如何如何来书写一个样式表,让其作用与文档内容达到书写者想要的外观。

CSS

的语法规 则是比较简单的, 自顶向下的来看,一个级联样式表(

CSS

)是由一系列的规则(

ruler

)组成的, 每一条规则又是由一个选择器(

selector

)和若干条声明(

Declearation

)组成的。每条声明(

Declearation

)又是一个键值 对,由属性(

property

)和值(

value

)来组成,如下图所示。

在这里插入图片描述

从这里可以看到,语法是很简单的,使用起来也确实很简单。注意,我在这里只是说使用简单,就跟铅笔一样,谁都会用,铅笔的使用当然是简单的不能再简 单了,但是就是这样普通的工具,在专业人士和普通人的手里所能创造出的东西是截然不同的。所以我想说的是,你能很快的学会如何使用

CSS

并不代表你编织出 漂亮的网页,它只是一个工具,能发挥到什么程度还得看人。

转回来,从其简单的语法来看,似乎是只要简单的将其转化为对应的程序设计模型即可,但实际中,

CSS

的实现还是比较复杂的,其复杂性就在于,

CSS

本身的复杂程度,它定义了一系列的规则来决定为哪些元素来指定样式,以及样式的继承关系,哪些是继承的,哪些是非继承的,以及作用于同一个元素的多个样式 的叠加,还有就是它对所有能指定的样式都有完整的对应的属性集。所以从实现的角度来看,一个完整的,兼容于标准的

CSS

实现,需要顾及到的东西还是很多 的。



2、CSS实现模型


webkit css

部分的实现代码为于目录

webcore/css

中,算是

webkit

中一个相对独立的模块,下面类图是我为了更好的了解

css

实现所作,大致勾勒出了

CSS

的内部实现。

在这里插入图片描述

用户所书写的

css

文档,最终会转化为

webkit

内部的模型表示,这里有几个比较重要的类。



3、CSS默认样式表



Webkit CSS

的实现可以看到,即使你不指定任何样式表,实际上当

CSS

模块运作起来的时候,它都会载入几张默认的样式表,要知道,在

CSSStyleSelector

的构造函数中,总是会调用

loadDefaultStyle()

这个函数,其作用就是载入默认的样式表。

这些默认的样式表包含了一些

HTML

元素的最基本的样式信息。相信在使用

css

的用户中,大多数人都不会在对

指定样式的时候 会为其添加一条

display:block

吧,是啊,几乎所有使用

css html

的人都知道

div

是一个块级元素,所以没人会多此一举,但是通过了解其

CSS

模块的具体实现,我们可以知道,这些个默认的样式表其实就已经为我们 指定了一系列我们认为的想当然的规则。

这四个默认样式表是:

  • html4UserAgentStyleSheet。
  • quirksUserAgentStyleSheet。
  • svgUserAgentStyleSheet。
  • sourceUserAgentStyleSheet。

额,从名字上大致也能够了解1, 2了吧,它们不是以文件形式存储,而是在CSS中以字符数组的形式出现,也就是说作为数据编到代码里面去了,应该是考虑到每次都要使用默认样式表而为了减少I/O造成的性能损失。

为了说明我前面所说的,这些默认样式表描述的都是些个关于HTML元素的最基本的信息,还是来看个例子吧,

比如说

html4UserAgentStyleSheet

,从名字上可以看到,这张应该就是传说中的浏览器默认样式表了。看看都有些啥吧,这里只截取个片段。

 html {
 2     display: block
 3  }
 4 
 5 head {
 6     display: none
 7  }
 8 
 9 meta {
10     display: none
11  }
12 
13 title {
14     display: none
15  }
16 
17 link {
18     display: none
19  }
20 
21 style {
22     display: none
23  }
24 
25 script {
26     display: none
27  }
28 
29 body {
30     display: block;
31     margin: 8px
32  }
33 
34 p {
35     display: block;
36     margin: 1.0__qem 0px
37  }
38 
39 div {
40     display: block
41  }
42 
43 layer {
44     display: block
45  }

从上面可以看出,真就是些最基本的属性的指定,如果没有这些默认值指定的话,用户还得自行添加这些规则,那会很麻烦。

其他几张表在此不作分析。



4、CSS解析


CSS

使用的时候,只需要将按照其语法规范,书写一个规则集合,然后保存为一个**.css

文件,在

html

中引用即可,当然这里使用的是外部样式表的方式,只是使用

CSS

的一种方式,在这里我不打算讨论

CSS**的几种使用方式,所以都按外部的来。

那么这种按照语法规则书写的

CSS

样式表式如何转换为

Webkit

内部的

CSS

模型的呢,这自然需要通过词法语法分析。在这里,

Webkit

使用了 自动代码生成工具生成了相应的代码,也就是说词法分析和语法分析这部分代码是自动生成的,但它们不够完整,然后我们需要自己写一些配合性的代码才能让真个

CSS

模块工作起来,说的再白一些,就是需要我们自己是写一些函数让那些个自动生成的代码来

Call Back

,用过其他各类解析器的朋友们应该很熟悉这个吧。如果谁对这部分代码有兴趣,可以研究一下。我倒是曾经为找一个跨平台的

bug

调过这部分代码,结 构还是蛮简单的,代码看起来稍多了些。入口是

yylex



yyparse

,有兴趣可以自己看看。

那么

Webkit

中实现的这些个

Call Back

们在哪里呢?就在

CSSParser

中了,显然,刨去生成的代码不说,需要手工完成的

CSS

解析代码部分就是这个了。

CSS

的一些解析功能的入口 也在此处,它们会调用

lex

,

parse

等生成代码。相对的,生成代码中需要的

Call Back

也需要在这里实现。

举例来说,现在可以来看一个较大单位的回调函数的实现,

createStyleRule()

,该函数将在一般性的规则需要被建立的时候调用。

  CSSRule* CSSParser::createStyleRule(CSSSelector* selector)
  {
     CSSStyleRule* rule = 0;
       if (selector) {
         rule = new CSSStyleRule(styleElement);
          m_parsedStyleObjects.append(rule);
          rule->setSelector(sinkFloatingSelector(selector));
          rule->setDeclaration(new CSSMutableStyleDeclaration(rule, parsedProperties, numParsedProperties));
    }
     clearProperties();
     return rule;
 }

从该函数的实现可以很清楚的看到,解析器达到某条件需要创建一个

CSSStyleRule

的时候将调用该函数,该函数的功能是创建一个

CSSStyleRule

,并将其添加已解析的样式对象列表

m_parsedStyleObjects

中去,这里的对象就是指的

Rule

。那么如此一来, 经过这样一番解析后,作为输入的样式表中的所有

Style Rule

将被转化为

Webkit

的内部模型对象

CSSStyleRule

对象,存储在

m_parsedStyleObjects

中,它是一个Vector。

像这样的函数还有

createCharsetRule



createImportRule



createMediaRule

等等,它们的作用大体上和

createStyleRule

类似,都是为创建

Rule

而准备的,只不过是不同类型的

Rule

了解了上面这些,大体上能够就能够了解

CSS

解析式怎么运作的。但是我们解析所要的结果是什么?通过调用

CSSStyleSheet



parseString

函数,上

CSS

解析过程将启动,解析完一遍后,所有的

Rule

都将存储在对应的

CSSStyleSheet

对象中。但是这个时候的 规则依然是不易于处理的,需要将之转换为

CSSRuleSet



CSSRuleSet

提供了一个

addRulesFromSheet

方法,能将

CSSStyleSheet

中的

rule

转换为

CSSRuleSet

中的

rule

,这样所有的纯样式规则都会放存储在对应的集合当中,这种集合的抽象就是

CSSRuleSet

。以后就可以基于这些个

CSSRuleSet

来决定每个页面中的元素的样式了,后面会有介绍。



5、CSS如何作用于Render Tree

所谓的作用于

Render Tree

其实是指基于上面的解析成果来为相应的

Render Object

来指定特定的样式,这个样式的抽象就是

RenderStyle



版权声明:本文为qq_44918090原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。