浏览器-06 HTML和CSS解析2
选择器
- 其实现由
CSSSelector
类来完成; CSSSelector
的作用是储存从解析器生成的结果信息;- 这里匹配指的是当需要为每个
DOM
中的节点计算样式时,WebKit
需要根据当前的节点信息来从规则列表中找到能够符合调节的规则,并把规则中的属性列表提取出来生成节点的样式信息;
应用到具体元素上
-
StyleResolver
是管理类,负责根据样式规则为每一个Document
中的元素匹配相应的样式属性,和Document
节点一一对应;即当WebKit
为每个Document
创建一个StyleResolver
对象,就为所有该Document
中的节点计算样式,并将其结果保存到RenderStyle
对象中;大致步骤
* 创建一个新的RenderStyle
对象从它的父亲那里继承它的一切可以继承的属性;
* 如果是link
类元素,设置link
属性;
* 从已知规则中找到匹配到的属性
* 将匹配到的属性应用到RenderStyle
对象中;
* 为该DOM
元素的RenderStyle
做一些修正工作;
* 清理StyleResolver
,为下次匹配请求做准备; -
RenderStyle
是元素所有样式属性的内部表示;为了节约空间,WebKit
将属性分为常用属性和非常用属性;非常用属性会进行分组合并,并且仅在需要时创建;该对象在被StyleResolver
创建后由该元素所对应的RenderObject
所拥有; -
元素在匹配生成其样式属性值之后,
RenderStyle
对象被RenderObject
所获得,这个触发一个重新绘制的动作,WebKit
此时可以根据样式属性值来计算它的布局和显示;
JavaScript
设置样式
- 大致过程:
JavaScript
引擎调用设置属性值的公共处理函数,然后该函数调用属性值解析函数; - 将解析后的信息设置到元素的
style
属性的样式中,设置该元素需要重新计算style
和invalidate
它的style
属性; - 在这之后,重新绘制请求被处理时,
WebKit
先会重新计算布局,而后在渲染相应的区域;
CSS3 变形(transform)、变换(transition)和动画(animation)
- 上面例子的三种树结构中:元素
P
的内容会被包在中间的RenderLayer
中,Div
元素的内容会被会包单独的最下面的RenderLayer
中,因为Div
元素的需要做CSS
的3D
变形;
RenderLayer
会有一个后端存储空间,Chromium
中是一个FrameBuffer
,该层会转成一个Texture
,那些CSS3
的变形,变换和动画效果将作用于该Texture
上,而后绘制在网页的framebuffer
中;- 变形比较简单,
WebKit
和Chromium
内部有一个Matrix
来表示平移,旋转,缩放和扭曲等变形,因为OpenGL
有直接对变形的支持,所以只需创建响应的OpenGL
变换操作即可; - 变换和动画的实现大致相同,前面解析的过程一样,其结果会保存于
Animation
对象中;
* 在chromium
的实现中,chromium compositor
中有两个主要类对其提供支持,一个是CCLayerAnimationController
,一个是CCActiveAnimation
;
* 前者是控制动画的行为,后者则是包动画相关参数和状态;
WebKit布局 (Layout)
概述
- 在渲染每个元素之前,渲染引擎必须知道它的位置大小等布局信息;计算这些信息的过程称之为布局;
- 布局计算介于
DOM
树、Render
树的创建和元素渲染之间; - 布局根据其计算的范围大致可以分为:
* 第一类是对整个Render
树进行的计算;
* 第二类是对Render
树中某个子树 的计算,常见于文本元素或者是overflow:auto
块的计算,这种情况一般是其子树布局的改变不会影响其周围元素的 布局,因而不需要重新计算更大范围内的布局;
箱子模型
CSS
布局计算是基于箱子模型的,其基本构成是一个矩形区域,包了外边距,内边距,边框和内容;
包含块
-
当需要计算元素
box
的位置和大小的时,需要计算它和另外一个矩形区域的相对位置,这个矩形区域称为该元素
的包块;
* 根元素的包块称为初始包块,通常它的大小就是可视区域(viewport
)的大小;
* 对于其他位置属性设置为static
或者relative
元素,它的包块就是的最近的祖先的箱子模型中的内容区域;
* 如果元素的位置属性为fixed
,其脱离文档,固定在可视区域的某个特定位置;
* 如果元素的位置属性为absolute
,其包块由最近的包属性absolute
,relative
或者fixed
的祖先决定,具体规则:
* 如果其是一个inline
元素,那么元素的包块是该包祖先的第一个和最后一个inline
盒子的内边距的区域;
* 否则,则是由该祖先的内边距所包围的区域; -
webkit
中理解:
*Render
节点的包块是该节点的负责决定该节点的祖先节点对应的块区域;
* 根节点RenderView
表示的就是初始包块,其初始大小始终是可视区域的大小;
布局计算
- 布局计算的相关信息都保存在
RenderStyle
对象中,该对象属于Render
节点; RenderStyle
就是包各个样式的属性值;同时,Render
节点也包一个位数组,该数组会保存一些用来表示是否需要重新计算布局等信息;- 计算布局的主要由
RenderObject
中的layout
方法来完成:
* 首先,layout
会判断Render
节点是否需要重新计算,通常这通过检查位数组中的相应标记位,子节点是否需要计算布局等来确定;
* 一般来说,初始显示,:可视区域变化,样式值变化(如动画,JavaScript
操作样式值)等都会需要重新计算布局;
* 其次,它会遍历其每一个子节点,依次计算它们的布局;
* 然后,对于每一个元素,它会实现自己的layout
方法,根据特定的算法来计算该类型元素的布局;
* 如果页面元素定义了其自己的宽高,那么webkit
按照其定义的宽高来确定其大小,而对于象文本节点这样的Inline
元素则需要结合其字体大小及文字的多少等来确定其对应的宽高;
* 如果页面元素所确定的宽高超过了布局容器包块所能提供的宽高,同时其overflow
属性为visible
或auto
,则会提供滚动条来保证显示其所有内容;
* 除非定义了页面元素 的宽高,一般说来页面元素的宽高是在布局的时候通过相关计算得出来;