class RenderObject{ virtual void layout(); virtual void paint(PaintInfo); virtual void rect repaintRect(); Node* node; //the DOM node RenderStyle* style; // the computed style RenderLayer* containgLayer; //the containing z-index layer }
每个渲染者表示一个矩形区域,通常对应于一个节点的CSS盒模型,正如CSS规范里描述的一样。它包含几何信息象宽度,高度和位置等。
盒类型被与节点相关的“display”样式属性影响(参见样式计算http://taligarsiel.com/Projects/howbrowserswork1.htm#style_computation一章)。这里是一段根据显示属性,决定为DOM节点创建哪种类型的渲染对象的Webkit代码:
RenderObject* RenderObject::createObject(Node* node, RenderStyle* style) { Document* doc = node->document(); RenderArena* arena = doc->renderArena(); ... RenderObject* o = 0; switch (style->display()) { case NONE: break; case INLINE: o = new (arena) RenderInline(node); break; case BLOCK: o = new (arena) RenderBlock(node); break; case INLINE_BLOCK: o = new (arena) RenderBlock(node); break; case LIST_ITEM: o = new (arena) RenderListItem(node); break; ... } return o; }
元素类型也被考虑在内,例如form控件和表格有特殊的frame。
在Webkit里如果一个元素想创建特殊的渲染者,那它将会覆盖“createRendered”方法。这个渲染者指向包含无位置信息的样式对象。
渲染树跟DOM树的关系
渲染者对应于DOM元素,但关系并不是一对一。非可见元素不会被插入渲染树。一个例子是“head”元素。显示属性设为“none”的元素也不会在此树中出现(元素是否可见的属性为“hidden”的会出现在树中)。
有些DOM元素对应于几个可视化对象。这些通常是有复杂结构的元素,不能被单个矩形描述。例如,“select”元素有三个渲染者—一个用于显示区域,一个用于下拉列表框,一个用在按钮上。另外当文本由于宽度无法被一行容纳而分割成多行时,新行会作为另一个渲染者添加进来。
另一个多渲染者的例子是未结束的HTML。根据CSS规范一个内联元素必须包含或者只有元素,或者只有内联元素。在混合内容的情况下,会创建一个匿名块渲染者以包含内联元素。
一些对应于DOM节点的渲染者不一定在树中的相应位置。浮动和绝对位置元素没按顺序来,放在树中不同的位置,映射到实际frame上。在它们本应放置的地方是一个frame占位符。
图11:渲染树和对应的DOM树。“Viewport”是开始时包含的块。在Webkit里它是“RenderView”对象。
构造这棵树的流程
在Firefox里,表示层被注册成一个DOM更新的侦听器。表示层把frame创建委托给“FrameConstructor”,构造器解析样式(查看前述的样式计算)然后创建frame。
在Webkit里解析样式和创建渲染者的流程被称为“附加”。每个DOM节点有个“attach”方法。附加是同步的,节点插入DOM树时将调用新的“attach”方法。
处理html和body标签的过程构造了渲染树的根。根渲染对象对应于CSS规范所称的容器块—包含所有其它块的顶层块。它的尺寸是视口—浏览器窗口显示区域的大小。Firefox叫它ViewPortFrame,Webkit叫它RenderView。这些是文档中关于渲染对象的部份。树中的其它部份在DOM节点插入时生成。在http://www.w3.org/TR/CSS21/intro.html#processing-model处可以查看这个主题。
(待续)
原创文章,作者:苏葳,如需转载,请注明出处:https://www.swmemo.com/2064.html