个人主页https://xugaoxiang.com,微信公众号: Dev_Club 或者搜索 程序员Club
全部博文(229)
分类: LINUX
2011-02-24 22:39:08
In the previous entry I talked about the basic structure of a CSS box. In this article I’m going to talk about subclasses of RenderBox
and about the concepts of block and inline.
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 are p and div.
An inline flow is an object that is designed to be part of a line. Example inline flow elements in HTML are a, b, i and span.
In WebCore, there are three renderer classes that cover block and inline flows. RenderBlock
, RenderInline
and their common superclass RenderFlow
.
An inline flow can be changed to a block flow (and vice versa) using the CSS display property.
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. A replaced 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.
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.
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 from RenderBlock
. 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 on RenderObject
instead. The isReplaced
method can be used to ask if an object is a replaced element.
bool isReplaced() const
Images, plugins, frames and applets all inherit from a common
subclass that implements replaced element behavior. This class is RenderReplaced
.
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.
div { display: inline-block }
Tables in HTML are block-level by default. However they can also be made into inlines using the CSS display property with a value of inline-table.
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.
Raw text is represented using the RenderText
class. Text is always considered inline by WebCore, since it is always placed on lines.
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).
bool isInline() const
One of the common mistakes people make when working with the render tree is assuming that isInline
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.
To ask if an object is actually a block or inline flow, the following methods should be used.
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.
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.
bool isInlineBlockOrInlineTable() const
Block flows have a simple invariant regarding their children that the render tree always obeys. That rule can be summarized as follows:
All in-flow children of a block flow must be blocks, or all in-flow children of a block flow must be 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
from isInline
or they must all return false from isInline
. The render tree will change its structure as needed to preserve this invariant.
The childrenInline
method is used to ask whether the children of a block flow are inlines or blocks.
bool childrenInline() const
Children of inline flows have an even simpler invariant that must be maintained.
All in-flow children of an inline flow must be inlines.
In order to preserve the block flow child invariant (only inline children or only block children), the render tree will construct objects called anonymous blocks. Consider the following example:
Some text
Some more text
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:
Some text
Some more text
The isAnonymousBlock
method can be used to ask if a renderer is an anonymous 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 in RenderBlock
is the function that performs this adjustment.
void makeChildrenNonInline(RenderObject *insertionPoint)
One of the nastiest constructs you will see in HTML is when a block is placed inside an inline flow. Here is an example:
Italic only italic and bold
Wow, a block!
Wow, another block!
More italic and bold text More italic text
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.
Italic only italic and bold
Wow, a block!
Wow, another block!
More italic and bold text More italic text
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 a continuation chain.
RenderFlow* continuation() const
bool isInlineContinuation() const
The first bold renderer in the pre block is the one that can be obtained from the b
DOM element using the element’s renderer()
method. This renderer has as its continuation()
the middle anonymous block. The middle anonymous block has as its continuation()
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.
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 its continuation()
to the italic renderer in the post block.
The function that performs the recursive splitting of inline flows
and that creates the continuation chain connections is called splitFlow
and is in RenderInline.cpp
.
chinaunix网友2011-03-06 16:11:46
很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com