LFC Display Tree¶
Layout Formatting Context display tree and related functionality (aka "LFC Display").
The display tree is intended to be a fully-resolved, isolated tree that is suitable for painting and hit-testing.
Fully-resolved means that all style values have been resolved to the values use for painting. For example, colors in the display tree are those which result from the application of visited link rules, and from the application of
Isolated means that a display tree is a stand-alone data structure that can be painted without reference to data structures share with layout. For example, the display tree does not use
RenderStyle once built, but constructs its own display styles at tree-building time.
All the geometry in the display tree is already in painting coordinates: pixel snapping happens at tree building time.
In general the tree has been designed to push as much of the complexity to tree-building time as possible, so that painting is fast.
The tree objects themselves are intentionally lightweight, mostly data-only objects. Complex tree-walking code lives in external objects that know how to do certain things, like paint the box tree.
Boxes in the display tree are intended to be fairly generic, and not have properties which are very CSS- or SVG-specific. It's hoped that SVG and CSS rendering share many of the same box classes.
There isn't necessarily a 1:1 relationship between
Display::Box. The display tree may elide boxes that paint nothing, or may create extra boxes for functionality like scrolling.
Represents a presentation of a display tree. Is the entry point for hit-testing.
FrameView owns a
Owns the hierarchy of
Display::Box objects via
Display::StackingItem objects, and associated tree-related data structures. It should be possible for a
Display::Tree to exist independently of a
Display::TreeBuilder is a short-lived class that knows how to build a
Display::Box tree from a
LayoutState and style. It maintains various bits of state in a stack as it's building the display tree in order to track containing blocks etc.
Display::TreeBuilder knows about hierarchy, not geometry.
Display::BoxFactory actually creates the
Display::Box objects and their related objects like
Display::BoxGeometry. It exists to keep the style and geometry code out of
Display::TreeBuilder. It only ever deals with a single box at a time.
Display::Box is the basic building block for the display tree; it represents some rectangular region, often with painted content. There are subclasses for text, images etc.
Display::Box has sibling pointers and a parent pointer.
Display::ContainerBox is used for boxes with children, so has a pointer to its first child.
The hierarchy of
Display::Box objects forms a tree, but it's not a complete tree, because each
Display::StackingItem owns a part of the tree, and the box objects in those subtrees are not connected.
This class exists to represent parts of the box tree that are painted atomically, as specified in CSS 2.2 Appendix E. There is always a
Display::StackingItem at the root (via which the
Display::Tree owns the actual box tree), and CSS positioning and other styles which cause CSS stacking context trigger the creation of a
Display::StackingItem objects that represent CSS stacking contexts have positive and negative z-order lists which contain owning references to the descendant
Display::StackingItem objects. These lists are built and sorted at tree-building time.
Display::Style is the display tree's equivalent of
RenderStyle but with some important differences. Every
Display::Box has a
Display::Style, so it should be relatively small. It must only contain data that is independent of box geometry; i.e. it must not contain any
Length values (which can hide things like
calc() values that must have been already resolved). It should be shareable between boxes with the same appearance, but possibly different sizes. All colors should be their final used values, i.e. after resolving
visitedDependentColor() and applying
Display::BoxRareGeometry / Display::BoxDecorationData¶
These classes store geometry-dependent data specific to a single
Display::Box, and are only allocated for boxes that have the relevant styles (like visible borders, or border-radius).
Display::BoxDecorationData stores information about backgrounds and borders.
Display::BoxRareGeometry stores border-radius (here because a box with overflow:hidden clips to its border-radius even without any border), and transforms.
Display::CSSPainter knows how to walk the trees of
Display::StackingItem and their
Display::Box objects in order to implement CSS painting. It knows how to apply clipping, opacity and filters.
For painting individual boxes,
Display::CSSPainter makes use of
Display::BoxDecorationPainter which knows how to paint CSS borders and backgrounds.
Display::CSSPainter objects exist on the stack only during painting; they are not long-lived.
It's intended that SVG would be painted by a
Display::SVGPainter class at some point.
Hit-testing is very similar to painting, so that code lives in
Display::CSSPainter too. Maybe it needs a different name.
The entry point to painting some subset of the display tree is a
paintContents() paint callback. Eventually the display tree will be presented via a hierarchy of GraphicsLayers; for now, there is a single GraphicsLayer at the root.
To paint the tree, the static
CSSPainter::paintTree() function is called, and
Display::CSSPainter traverses the
Display::StackingItem hierarchy and paints their
Display::Box objects, making use of
Display::BoxDecorationPainter on boxes with box decorations.
At CSS/SVG boundaries a new painter object will be created on the stack to paint the inner content.
GraphicsContext is passed around as an argument to painting functions, wrapped up in a
PaintingContext struct that also has the
deviceScaleFactor and will probably include a dirty rect.
Note: this is subject to change. The code needs to make it hard to use the absolute rects in the wrong way.
Display boxes store their position and size as an absolute (i.e. document-relative)
FloatRect (already pixel-snapped). CSS box-model boxes, which have things like borders and border-radius, also store rects for their padding and content boxes. Thus no paint offsets have to be tracked during painting.
Some boxes act as coordinate boundaries; namely those with transforms, and those which are affected by scrolling. The "absolute" rects are computed before accounting for scrolling and transforms, so code that needs to map a box's rect into view coordinate will need to take those into account.
Clipping is a source of complexity in the display tree because CSS clipping does not trigger CSS stacking context; the clipping tree follows the containing block tree, which is different from paint order. For painting normal in-flow content we can just apply clipping at paint time, but when painting out-of-flow content, we have to be able to compute the clip from ancestors. Such out-of-flow content is always represented by the root box of a
At tree-building time
Display::TreeBuilder keeps track of containing blocks, so for boxes which initiate out-of-order painting (i.e. those which are the root box of a
Display::BoxFactory can ask the containing block for the clip that should be applied.
Clips are store in
Display::BoxClip which tracks an intersection rect, and, if necessary, a set of rounded rects needed to apply border-radius clips from ancestors.
Display::BoxClip objects are shared between parent/child
Display::BoxModelObject objects that share the same clip (i.e. have no overflow of their own).
Note: this is preliminary
overflow:scroll is represented with a hierarchy of three display boxes:
container box scrolling container box scrolled contents box
(and possibly additional boxes for scrollbars and the scroll corner).
The container box exists to paint box decorations on the scrolling element. The "scrolling container" box has geometry of the container's content box, and exists to represent the scroll offset. The "scrolled contents" box paints the scrolled content, and has the size of the layout overflow.
It is a goal of the display tree that scrolling should not invalidate any geometry on the subtree (thus avoiding post-scroll tree walks to fix up geometry, which are known to be a source of performance issues in rendering code).
Note: explain how scrolling interacts with positioned elements.
Note: write me