chromium/third_party/blink/renderer/core/dom/WhitespaceLayoutObjects.md

# Whitespace LayoutObjects

Text nodes which only contain whitespaces sometimes have a layout object and
sometimes they don't. This document tries to explain why and how these layout
objects are created.

## Why

For layout purposes, whitespace nodes are sometimes significant, but not
always. In Blink, we try to create as few of them as possible to save memory,
and save CPU by having fewer layout objects to traverse.

### Inline flow

Whitespace typically matters in an inline flow context. Example:

    <span>A</span> </span>B</span>

If we didn't create a LayoutObject for the whitespace node between the two
spans, we would have rendered the markup above as "AB" as the span layout
objects would have been siblings in the layout tree.

### Block flow

Whitespace typically doesn't matter in a block flow context. Example:

    <div>A</div> <div>B</div>

In the example above, the whitespace node between the divs would not contribute
to layout/rendering. Hence, we can skip creating a LayoutText for it.

### Out-of-flow

Out-of-flow elements like absolutely positioned elements do not affect inline
or block in-flow layout. That means we can skip such elements when considering
the need for whitespace layout objects.

Example:

    <div><span style="position:absolute">A</span> </span>B</span></div>

In the example above, we don't need to create a whitespace layout object since
it will be the first in-flow child of the block, and will not contribute to the
layout/rendering.

Example:

    <span>A</span> <span style="position:absolute">Z</span> <span>B</span>

In the example above, we need to create a whitespace layout object to separate
the A and B in the rendering. However, we only need to create a layout object
for one of the whitespace nodes as whitespace collapse.

### Preformatted text and editing

Some values of the CSS white-space property will cause whitespace to not
collapse and affect layout and rendering also in block layout. In those cases
we always create layout objects for whitespace nodes.

Whitespace nodes are also significant in editing mode.

## How

We decide if we need to attach or re-attach the layout tree for a text node as
part of the layout tree rebuild. A layout tree rebuild starts at the
documentElement by calling Element::RebuildLayoutTree.

### RebuildLayoutTree

The Element::RebuildLayoutTree traversal happens in the flat tree order
traversing children from right to left (see RebuildChildrenLayoutTrees in the
ContainerNode class). We keep track of the last seen text node in an instance
of the WhitespaceAttacher class which is passed to the various traversal
methods.

Important methods:

    WhitespaceAttacher::*
    Element::RebuildLayoutTree
    ContainerNode::RebuildChildrenLayoutTrees

### Attaching a layout tree

Once we encounter a node which needs re-attachment during RebuildLayoutTree, we
do a Node::AttachLayoutTree for that sub-tree. AttachLayoutTree attaches nodes
in the flat tree order, but as opposed to RebuildLayoutTree, siblings are
attached from left to right. In order to decide if a whitespace Text node needs
a LayoutObject or not, we keep track of the previous in-flow layout tree
sibling in the AttachContext passed to AttachLayoutTree.

When a sub-tree has been (re-)attached, we know which is the last in-flow
LayoutObject of that subtree (normally the root, unless the root is
display:contents or display:none). This last in-flow layout object, stored in
the AttachContext, is passed into the WhitespaceAttacher to see if a sub-sequent
whitespace node needs to be re-attached due to a different display type for the
root of the (re-)attached subtree. See following sub-section.

Important methods:

    Text::AttachLayoutTree()
    Text::TextLayoutObjectIsNeeded()

#### Re-attaching whitespace layout objects

When the computed display value changes, the requirement for whitespace
siblings may change.

Example:

    <span style="position:absolute">A</span> <span>B</span>

Initially, we don't need a layout object for the whitespace above. If we change
the position of the first span to static, we need a layout object for the
whitespace. During layout tree rebuild, we keep track of the last text node
sibling in the WhitespaceAttacher. The text node is reset when we encounter a
node with an in-flow layout box. Remember that we traverse from right to left.
That means we have stored the whitespace node above in the WhitespaceAttacher
when we re-attach the left-most span. After re-attachment we re-attach the
stored text node based on passing the first span with its LayoutObject as
previous in-flow into WhitespaceAttacher::DidReattachElement.

DidReattachElement will re-attach whitespace siblings as necessary.

#### Known issues

    https://crbug.com/750758