转载: WebCore渲染之一:基础

(转载自: http://www.cnblogs.com/jz1108/archive/2012/07/02/2573045.html

文档树

网页会被解析成一个包含若干结点的树形结构,即文档对象模型(DOM)。树中所有结点的基类为Node。

Node.h

结点被划分为若干类型。与渲染代码相关的结点类型包括:

  • Document(文档类):树的根节点总为文档。有三个文档相关的类:Document、HTMLDocument和SVGDocument。第一个用来表示除SVG文档以外的所有XML文档。第二个继承自Document,只表示HTML文档。第三个也继承自Document,用来表示SVG文档(涉及:Document.hHTMLDocument.h)。
  • Elements(元素类):在HTML或XML代码中的标签最终会变为元素。从渲染角度看,元素是一个具有标记名的结点,可用来在渲染时转换为某个特定的子类,从而获取其数据。(涉及:Element.h
  • Text(文本):元素之间的纯文本会被转化为一个文本结点。文本结点负责存储纯文本信息,渲染树可通过它来获取数据(涉及:Text.h)。

渲染树

渲染树是渲染过程的核心。渲染树和DOM树很像,都是树形结构,树中的每个元素可对应到文档、元素或者文本结点。渲染树还能包含一些DOM树中没有的结点。

渲染树结点的基类为RenderObject。

RenderObject.h

DOM结点所对应的RenderObject对象可通过Node的renderer()方法获得。

RenderObject* renderer() const

以下方法是遍历渲染树最常用的:

RenderObject* firstChild() const;
RenderObject* lastChild() const;
RenderObject* previousSibling() const;
RenderObject* nextSibling() const;

下面的例子我们循环访问了一个渲染结点的子结点。这在渲染树的代码中很常见。

for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
    ...
}

创建渲染树

渲染结点通过一个叫做attachment的过程创建出来。随着文档被解析、DOM结点被添加,一个叫做attach的方法会被DOM结点调用来创建每个渲染结点。

void attach()

attach方法为DOM结点计算样式信息。如果元素CSS的display属性为none,或者元素是某个display为none的元素的子元素,那么渲染结点就不会被创建。结点相关的子类与CSS的display属性一起决定了该创建什么样的渲染结点。

Attach是一个自顶向下的递归过程。一个父结点的渲染结点的创建总会早于其子结点的渲染结点的创建。

销毁渲染树

在DOM结点被移除时或者整个文档被销毁时(比如关闭页面),渲染结点会随之销毁。此时DOM结点的detach方法就会被调用,用来销毁渲染结点。

void detach()

Detach是一个自底向上的递归操作。子结点的渲染结点会先于其父节点销毁。

获取样式信息

在attach过程中,DOM会通过CSS获取元素样式信息。结果会存储在RenderStyle对象中。

RenderStyle.h

每个WebKit支持的CSS属性都可通过该对象查询。RenderStyles对象是引用计数的对象,如果DOM结点创建了一个渲染结点,那么它将调用渲染结点的setStyle方法将样式信息与之关联。

void setStyle(RenderStyle*)

渲染结点增加了一个对样式对象的引用,该引用将一直被维护除非结点获得一个新样式或者被销毁。

RenderStyle可通过RenderObject的style()方法获得。

RenderStyle* style() const

CSS盒模型

RenderObject中的一个主要子类为RenderBox,该子类表示遵循CSS盒模型的对象,这些对象会有自己的border(边框)、padding(内边距)、margin(外边距)、width(宽)和height(高)。不过现在一些没有遵循CSS盒模型的对象也继承于RenderBox(例如:SVG对象)。这个问题以后会在重构渲染树的过程中修复。

CSS 2.1规范的这幅图描述了CSS盒模型的各个部分。下面的方法可用来获取边框和内外边距。RenderStyle只有在获取原始样式信息时用到,因为RenderObject的计算结果会有很大差别(特别是表格元素,它可以将单元格的padding属性覆盖,表格之间的边框也可以重叠在一起)。

复制代码
int marginTop() const;
int marginBottom() const;
int marginLeft() const;
int marginRight() const;

int paddingTop() const;
int paddingBottom() const;
int paddingLeft() const;
int paddingRight() const;

int borderTop() const;
int borderBottom() const;
int borderLeft() const;
int borderRight() const;
复制代码

width()和height()方法给出宽度和高度(包含边框的)。

int width() const;
int height() const;

client box包含了边框和滚动条,padding也包括:

int clientLeft() const { return borderLeft(); }
int clientTop() const { return borderTop(); }
int clientWidth() const;
int clientHeight() const;

content box用来描述不包含border和padding的CSS盒子:

IntRect contentBox() const;
int contentWidth() const { return clientWidth() - paddingLeft() - paddingRight(); }
int contentHeight() const { return clientHeight() - paddingTop() - paddingBottom(); }

当盒子出现滚动条时,它被放在border和padding之间。滚动条的大小被包含在client width和client height中。滚动条不算在content box内。滚动条的大小以及当前滚动的位置可通过RenderObject获取。这个问题后续在单独章节中再详细说明。

int scrollLeft() const;
int scrollTop() const;
int scrollWidth() const;
int scrollHeight() const;

盒子还有x和y的位置属性。这些位置相对于元素的父元素,父元素来决定盒子该放置在什么地方。这个规则存在许多例外情况,这也是渲染树中最令人困惑的地方。

int xPos() const;
int yPos() const;
原文地址:https://www.cnblogs.com/zjfazc/p/2573626.html