WebCore Rendering II -- Blocks and Inlines

 

原文链接:http://www.webkit.org/blog/115/webcore-rendering-ii-blocks-and-inlines/

译文:

 Posted by Dave Hyatt on Thursday, August 9th, 2007 at 2:59 pm

在上一篇文章中,我介绍了CSS box的基本结构,在这篇文章中,我将继续介绍RenderBox的子类和关于blockinline的概念。

block flow被设计为一个box用来包含lines或者包含其他垂直堆叠的blocks。举例来说,pdiv都是HTML中的block flow 元素。

inline flow被设计为一种对象,他是line的一部分。 举例来说,are a, b, i and span是HTML中的inline flow元素

在WebCore中,有三个类覆盖了block and inline flows,他们是:RenderBlock和RenderInline和他们共同的父类RenderFlow。

RenderFlow.h
RenderBlock.h
RenderInline.h

inline flow通过CSS显示属性可以被转为block flow。

div { display: inline }
span { display: block }

除了block和inline flows,还有一种元素表现的像block或inline一样,这就是replaced 元素。replaced元素的rendering是一种不被CSS所指定的元素。这类元素的内容如何被render被留给这个元素自己处理。 replaced 元素的例子:images, from controls, iframes, plugins和applets。

一个replaced元素也能够是block-level或者inline-level。当replaced元素表现的像是一个block时,它将被垂直摆放,但它代表他自己的段落。当replaced元素表现为一个inline时,它将是段落中的一部分line。 缺省状态下replaced元素是inline。

Form controls实际上时奇怪的特例,虽然他们是replaced 元素,但在引擎实现时,controls实际是RenderBlock的子类。作为一个结果,replaced的概念不能只局限于一个从REnderBlock派生的共同的子类,因此他们被RenderObject中的一个bit位来表示,isReplaced方法能够用来判定一个对象是否是replaced元素。

bool isReplaced() const

Images, plugins, frames and applets都继承与一个共同的子类RenderReplaced,RenderPlaced类实现了replaced元素的各种行为。

RenderReplaced.h

The Inline Block

在CSS中最让人困惑的一个对象就是inline-block。inline blocks是一种block flows被设计线型摆放。实际上,他们外表像inline replaced元素,但内部是block flows。CSS中的现实属性能够用来创建inline blocks。inline blocks将被返回true如果调用isReplaced。

div { display: inline-block }

Tables

HTML中的表格缺省条件下是block-level。但可以通过设置CSS显示属性inline-table,使得他成为inlines。

table { display: inline-table }

需要再次说明的是,从外部看,inline-table像是一个inline replaced元素(如果调用isReplaced将返回true),但在内部这个对象依然是一个表格。

在WebCore中,RenderTable类表示一个表格,他继承自RenderBlock的原因将在后面的positioning部分介绍。

RenderTable.h

Text

Raw text使用RenderText类来表示,Text总是被WebCore认为是inline,因为他们总是被放置在line上。

RenderText.h

获取 Block和Inline 信息

最常用的用来获取一个对象是block vs. inline的方法是isInline函数,这个方法查询一个对象是否设计作为line的一部分,他不关心元素的内部实质。(举例来说,text, image, an inline flow, an inline-block or an inline-table都将返回true)

bool isInline() const

人们在使用render tree时常犯的一个错误就是假设像text或者inline replaced这样的元素isInline意味着一个inline flow,然而甚至对inline-blocks 和 inline-tables这类对象这个方法也返回true。

决定一个对象实际上是一个block或inline flow,下面的方法应该使用下面的方法:

bool isInlineFlow() const
bool isBlockFlow() const

上述方法实际上是查询一个对象的内部来做决定,哪inline-block做例子来说,他依然是一个block flow,不是一个inline flow。他表面上是一个inline,内部是一个block flow

确切的类的类型可以通过下面的方法来查询:

bool isRenderBlock() const
bool isRenderInline() const

isRenderBlock方法在context of positioning中是非常有用的,因为block flows和tables扮演着positioned对象的容器。

bool isInlineBlockOrInlineTable() const

Children of Block Flows

block flows有一个总被遵守的简单不变的关于他们孩子的规则,这个规则可以简单总结如下:

一个block flow的全部in-flow孩子一定是blocks,或者一个block的全部in-flow孩子全部都是inlines。

换句话说,一旦你排除floating and positioned 元素,在render tree上一个block flow的所有孩子调用isInline时要嘛全返回true,要嘛全返回false。为了遵循这个规则,render tree需要改变他的结构。

childrenInline 方法被用来查询一个block flow的孩子是inline 或者blocks。

bool childrenInline() const

Children of Inline Flows

inline flows的孩子有个更简单的不变规则:

一个inline flow的所有in-flow孩子必须是inlines。

Anonymous Blocks

render tree将创建anonymous blocks为了保持上面的规则,考虑下面的例子:

<div>
Some text
<div>
Some more text
</div>
</div>

在上面的例子中,外部的div有两个孩子:一些text和另一个div。第一个孩子是inline,但第二个孩子是block,这种组合违反了全部是inline或者全部是block的规则,因此render tree将创建一个匿名block flow来封装text,使得render tree变成下面的样子:

<div>
<anonymous block>
Some text
</anonymous block>
<div>
Some more text
</div>
</div>

isAnonymousBlock方法可以返回是否renderer是一个匿名block flow。

bool isAnonymousBlock() const

void makeChildrenNonInline(RenderObject *insertionPoint)

无论何时,一个拥有inline和block子节点的block flow被作为子节点加入到render tree当中时,匿名blocks将根据需要被创建去封装所有inlines。连续的inlines将共享同一个匿名block,使得匿名block的数量保持在最低。RenderBlock类的makeChildrenNonInline方法完成这个调整。

Blocks inside Inline Flows

有时HTML文件的内容非常不合理,例如block被放置在inline flow当中,下面是一个例子:

<i>Italic only <b>italic and bold
<div>
Wow, a block!
</div>
<div>
Wow, another block!
</div>
More italic and bold text</b> More italic text</i>

两个div标签违反了规则,按照规则,黑体标签元素的所有孩子必须都是inlines。render tree不得不花费一系列相对复杂的步骤来纠正这棵树。三个匿名block将被创建,第一个匿名block hold住div标签前面的全部inlines,第二个匿名block hold住div标签。第三个匿名blockhold住div后面的全部inlines。

<anonymous pre block>
<i>Italic only <b>italic and bold</b></i>
</anonymous pre block>
<anonymous middle block>
<div>
Wow, a block!
</div>
<div>
Wow, another block!
</div>
</anonymous middle block>
<anonymous post block>
<i><b>More italic and bold text</b> More italic text</i>
</anonymous post block>

注意黑体和斜体renderers不得不被分成两个render objects,因为他们分别出在前面的匿名block和后面的匿名block当中。在这个DOM黑体元素的案例当中,他的孩子在前面的block,然后在中间的block,最后在后面的block,render tree通过一个延续链(continuation chain)来连接这些对象。

RenderFlow* continuation() const
bool isInlineContinuation() const

在pre block中的第一个黑体renderer能够通过调用DOM元素b的renderer方法来得到,这个renderer有一个continuation()方法来得到中间的匿名block。中间的匿名block也有一个continuation()方法来获得第二个黑体renderer。通过这种办法,对于那些需要访问DOM元素的孩子的renderer的代码,仍然可以相对简单的实现。

在上面的例子中,DOM元素i也被分裂,他的孩子都在pre和post blocks中,因此只要一个连接就可以实现,在pre block中的斜体renderer设置他的continuation()方法指向post block的renderer。

这个完成递归的分裂inline flows并且创建连续链的方法叫做splitFlow,位于RenderIine.cpp当中。

 

---------------------------------------------------中英对照版--------------------------------------------------

 

Posted by Dave Hyatt on Thursday, August 9th, 2007 at 2:59 pm

In the previous entry I talked about the basic structure of a CSS box. In this article I’m going to talk about subclasses ofRenderBox and about the concepts ofblock andinline.

在上一篇文章中,我介绍了CSS box的基本结构,在这篇文章中,我将继续介绍RenderBox的子类和关于blockinline的概念。

A block flow is a box designed either to contain lines (e.g., a paragraph) or to contain other blocks that it stacks vertically. Example block flow elements in HTML arep anddiv.

block flow被设计为一个box用来包含lines或者包含其他垂直堆叠的blocks。举例来说,pdiv都是HTML中的block flow 元素。

An inline flow is an object that is designed to be part of a line. Example inline flow elements in HTML area,b,i andspan.

inline flow被设计为一种对象,他是line的一部分。 举例来说,are a, b, i and span是HTML中的inline flow元素

In WebCore, there are three renderer classes that cover block and inline flows.RenderBlock,RenderInline and their common superclassRenderFlow.

在WebCore中,有三个类覆盖了block and inline flows,他们是:RenderBlock和RenderInline和他们共同的父类RenderFlow。

RenderFlow.h
RenderBlock.h
RenderInline.h

An inline flow can be changed to a block flow (and vice versa) using the CSS display property.

inline flow通过CSS显示属性可以被转为block flow。

div { display: inline }
span { display: block }

In addition to block and inline flows, there is another kind of element that can act as a block or inline: the replaced element. Areplaced element is an element whose rendering is unspecified by CSS. How the contents of the object render is left up to the element itself. Examples of replaced elements are images, form controls, iframes, plugins and applets.

除了block和inline flows,还有一种元素表现的像block或inline一样,这就是replaced 元素。replaced元素的rendering是一种不被CSS所指定的元素。这类元素的内容如何被render被留给这个元素自己处理。 replaced 元素的例子:images, from controls, iframes, plugins和applets。

A replaced element can also be either block-level or inline-level. When a replaced element acts as a block, it will get stacked vertically as though it represents its own paragraph. When a replaced element acts as an inline, it will be part of a line inside a paragraph. Replaced elements are inline by default.

一个replaced元素也能够是block-level或者inline-level。当replaced元素表现的像是一个block时,它将被垂直摆放,但它代表他自己的段落。当replaced元素表现为一个inline时,它将是段落中的一部分line。 缺省状态下replaced元素是inline。

Form controls are actually a strange special case. They are still replaced elements, but because they are implemented by the engine, controls actually ultimately subclass fromRenderBlock. As a result, the concept of being replaced can’t really be confined to a single common subclass, and is therefore represented as a bit onRenderObject instead. TheisReplaced method can be used to ask if an object is a replaced element.

Form controls实际上时奇怪的特例,虽然他们是replaced 元素,但在引擎实现时,controls实际是RenderBlock的子类。作为一个结果,replaced的概念不能只局限于一个从REnderBlock派生的共同的子类,因此他们被RenderObject中的一个bit位来表示,isReplaced方法能够用来判定一个对象是否是replaced元素。

bool isReplaced() const

Images, plugins, frames and applets all inherit from a common subclass that implements replaced element behavior. This class isRenderReplaced.

Images, plugins, frames and applets都继承与一个共同的子类RenderReplaced,RenderPlaced类实现了replaced元素的各种行为。

RenderReplaced.h

The Inline Block

One of the most confusingly named objects in CSS is the inline-block. Inline blocks are block flows that are designed to sit on a line. In effect they are like inline replaced elements on the outside, but on the inside they are block flows. The display property in CSS can be used to create inline blocks. Inline blocks will report true if asked if they are replaced.

在CSS中最让人困惑的一个对象就是inline-block。inline blocks是一种block flows被设计线型摆放。实际上,他们外表像inline replaced元素,但内部是block flows。CSS中的现实属性能够用来创建inline blocks。inline blocks将被返回true如果调用isReplaced。

div { display: inline-block }

Tables

Tables in HTML are block-level by default. However they can also be made into inlines using the CSS display property with a value ofinline-table.

HTML中的表格缺省条件下是block-level。但可以通过设置CSS显示属性inline-table,使得他成为inlines。

table { display: inline-table }

Again, from the outside an inline-table is like an inline replaced element (and will return true from isReplaced), but on the inside the object is still just a table.

In WebCore the RenderTable class represents a table. It inherits from RenderBlock for reasons that will be covered in the positioning section later.

需要再次说明的是,从外部看,inline-table像是一个inline replaced元素(如果调用isReplaced将返回true),但在内部这个对象依然是一个表格。

在WebCore中,RenderTable类表示一个表格,他继承自RenderBlock的原因将在后面的positioning部分介绍。

RenderTable.h

Text

Raw text is represented using the RenderText class. Text is always considered inline by WebCore, since it is always placed on lines.

Raw text使用RenderText类来表示,Text总是被WebCore认为是inline,因为他们总是被放置在line上。

RenderText.h

Getting Block and Inline Information

获取 Block和Inline 信息

 

The most basic method for obtaining block vs. inline status is the isInline function. This method asks if an object is designed to be part of a line. It does not care what the interior of the element is (e.g., text, image, an inline flow, an inline-block or an inline-table).

最常用的用来获取一个对象是block vs. inline的方法是isInline函数,这个方法查询一个对象是否设计作为line的一部分,他不关心元素的内部实质。(举例来说,text, image, an inline flow, an inline-block or an inline-table都将返回true)

bool isInline() const

One of the common mistakes people make when working with the render tree is assuming thatisInline means an object is always an inline flow, text or an inline replaced element. However because of inline-blocks and inline-tables, this method can return true even for these objects.

人们在使用render tree时常犯的一个错误就是假设像text或者inline replaced这样的元素isInline意味着一个inline flow,然而甚至对inline-blocks 和 inline-tables这类对象这个方法也返回true。

To ask if an object is actually a block or inline flow, the following methods should be used.

决定一个对象实际上是一个block或inline flow,下面的方法应该使用下面的方法:

bool isInlineFlow() const
bool isBlockFlow() const

These methods are essentially asking questions about the interior of the object. An inline-block for example is still a block flow and not an inline flow. It is inline on the outside, but on the inside it is a block flow.

上述方法实际上是查询一个对象的内部来做决定,哪inline-block做例子来说,他依然是一个block flow,不是一个inline flow。他表面上是一个inline,内部是一个block flow

The exact class type can be queried for blocks and inlines using the following methods.

确切的类的类型可以通过下面的方法来查询:

bool isRenderBlock() const
bool isRenderInline() const

The isRenderBlock method is useful in the context of positioning, since both block flows and tables act as positioned object containers.

To ask if an object is specifically an inline block or inline table, the isInlineBlockOrInlineTable method can be used.

isRenderBlock方法在context of positioning中是非常有用的,因为block flows和tables扮演着positioned对象的容器。

bool isInlineBlockOrInlineTable() const

Children of Block Flows

Block flows have a simple invariant regarding their children that the render tree always obeys. That rule can be summarized as follows:

block flows有一个总被遵守的简单不变的关于他们孩子的规则,这个规则可以简单总结如下:

All in-flow children of a block flow must be blocks, or all in-flow children of a block flow must be inlines.

一个block flow的全部in-flow孩子一定是blocks,或者一个block的全部in-flow孩子全部都是inlines。

In other words, once you exclude floating and positioned elements, all of the children of a block flow in the render tree must return true fromisInline or they must all return false fromisInline. The render tree will change its structure as needed to preserve this invariant.

换句话说,一旦你排除floating and positioned 元素,在render tree上一个block flow的所有孩子调用isInline时要嘛全返回true,要嘛全返回false。为了遵循这个规则,render tree需要改变他的结构。

The childrenInline method is used to ask whether the children of a block flow are inlines or blocks.

childrenInline 方法被用来查询一个block flow的孩子是inline 或者blocks。

bool childrenInline() const

Children of Inline Flows

Children of inline flows have an even simpler invariant that must be maintained.

inline flows的孩子有个更简单的不变规则:

All in-flow children of an inline flow must be inlines.

一个inline flow的所有in-flow孩子必须是inlines。

Anonymous Blocks

In order to preserve the block flow child invariant (only inline children or only block children), the render tree will construct objects calledanonymous blocks. Consider the following example:

render tree将创建anonymous blocks为了保持上面的规则,考虑下面的例子:

<div>
Some text
<div>
Some more text
</div>
</div>

In the above example, the outer div has two children: some text and another div. The first child is an inline, but the second child is a block. Because this combination of children violates the all-inline or all-block child rule, the render tree will construct an anonymous block flow to wrap the text. The render tree therefore becomes:

在上面的例子中,外部的div有两个孩子:一些text和另一个div。第一个孩子是inline,但第二个孩子是block,这种组合违反了全部是inline或者全部是block的规则,因此render tree将创建一个匿名block flow来封装text,使得render tree变成下面的样子:

<div>
<anonymous block>
Some text
</anonymous block>
<div>
Some more text
</div>
</div>

The isAnonymousBlock method can be used to ask if a renderer is an anonymous block flow.

isAnonymousBlock方法可以返回是否renderer是一个匿名block flow。

bool isAnonymousBlock() const

Whenever a block flow has inline children and a block object suddenly tries to insert itself as a child, anonymous blocks will be created as needed to wrap all of the inlines. Contiguous inlines will share a single common anonymous block, so the number of anonymous blocks can be kept to a minimum. The makeChildrenNonInline method inRenderBlock is the function that performs this adjustment.

void makeChildrenNonInline(RenderObject *insertionPoint)

无论何时,一个拥有inline和block子节点的block flow被作为子节点加入到render tree当中时,匿名blocks将根据需要被创建去封装所有inlines。连续的inlines将共享同一个匿名block,使得匿名block的数量保持在最低。RenderBlock类的makeChildrenNonInline方法完成这个调整。

Blocks inside Inline Flows

One of the nastiest constructs you will see in HTML is when a block is placed inside an inline flow. Here is an example:

有时HTML文件的内容非常不合理,例如block被放置在inline flow当中,下面是一个例子:

<i>Italic only <b>italic and bold
<div>
Wow, a block!
</div>
<div>
Wow, another block!
</div>
More italic and bold text</b> More italic text</i>

The two divs violate the invariant that all of the children of the bold element must be inlines. The render tree has to perform a rather complicated series of steps in order to fix up the tree. Three anonymous blocks are constructed. The first block holds all of the inlines that come before the divs. The second anonymous block holds the divs. The third anonymous block holds all of the inlines that come after the divs.

两个div标签违反了规则,按照规则,黑体标签元素的所有孩子必须都是inlines。render tree不得不花费一系列相对复杂的步骤来纠正这棵树。三个匿名block将被创建,第一个匿名block hold住div标签前面的全部inlines,第二个匿名block hold住div标签。第三个匿名blockhold住div后面的全部inlines。

<anonymous pre block>
<i>Italic only <b>italic and bold</b></i>
</anonymous pre block>
<anonymous middle block>
<div>
Wow, a block!
</div>
<div>
Wow, another block!
</div>
</anonymous middle block>
<anonymous post block>
<i><b>More italic and bold text</b> More italic text</i>
</anonymous post block>

Notice that the bold and italic renderers had to split into two render objects, since they are in both the anonymous pre block and the anonymous post block. In the case of the bold DOM element, its children are in the pre block, but then continue into the middle block and then finally continue into the post block. The render tree connects these objects via acontinuation chain.

注意黑体和斜体renderers不得不被分成两个render objects,因为他们分别出在前面的匿名block和后面的匿名block当中。在这个DOM黑体元素的案例当中,他的孩子在前面的block,然后在中间的block,最后在后面的block,render tree通过一个延续链(continuation chain)来连接这些对象。

RenderFlow* continuation() const
bool isInlineContinuation() const

The first bold renderer in the pre block is the one that can be obtained from theb DOM element using the element’srenderer() method. This renderer has as itscontinuation() the middle anonymous block. The middle anonymous block has as itscontinuation() the second bold renderer. In this way code that needs to examine the renderers that represent the children of the DOM element can still do so relatively easily.

在pre block中的第一个黑体renderer能够通过调用DOM元素b的renderer方法来得到,这个renderer有一个continuation()方法来得到中间的匿名block。中间的匿名block也有一个continuation()方法来获得第二个黑体renderer。通过这种办法,对于那些需要访问DOM元素的孩子的renderer的代码,仍然可以相对简单的实现。

In the above example the i DOM element also split. Its children are all in the pre and post blocks, and therefore only one connection is needed. The italic renderer in the pre block sets itscontinuation() to the italic renderer in the post block.

在上面的例子中,DOM元素i也被分裂,他的孩子都在pre和post blocks中,因此只要一个连接就可以实现,在pre block中的斜体renderer设置他的continuation()方法指向post block的renderer。

The function that performs the recursive splitting of inline flows and that creates the continuation chain connections is calledsplitFlow and is inRenderInline.cpp.

这个完成递归的分裂inline flows并且创建连续链的方法叫做splitFlow,位于RenderIine.cpp当中。

 

你可能感兴趣的:(WebCore Rendering II -- Blocks and Inlines)