In a previous article we’ve seen that the rendering tree is in charge of representing the visual nodes of the html element so that they can be displayed on screen.
The rendering tree layouts all its elements, giving them all an x and y coordinate relative to the origin of the document. Rendered nodes in an HTML document are also given a z-axis ordering so that they can overlap in a predictable way.
In an HTML document, there are 2 ways to control the z-ordering of a node :
- Nodes which are the most deeply nested in the document markup will be rendered on top of their parent node by default. This is the « tree order » way.
- Nodes z-ordering can be forced via the CSS « z-index » style, allowing element to be displayed on top or below parent or sibling elements. For this to apply, the node needs to have a non « static » value for its « position » style.
The Layer tree
The layer tree is owned by the rendering tree in the same way that the rendering tree is owned by the DOM tree. The layer tree is always sparser than the rendering tree. The layer tree is always constituted of at least one root element, owned by the rendering tree’s root element.
In the same way that each DOM node may create a corresponding node in the rendering tree or not, each node in the rendering tree can create a node in the layer tree, simply refered to as a layer.
With this added data tree, the document is now represented as a pile of overlapping layers, the top layers being the ones « closest » to the eye of the user.
Not all node in the rendering tree create their own layer. Here is a non-exhaustive list of conditions creating a new layer :
- The node has a non-static « position » style (relative, absolute or fixed)
- The node is transparent (because of the « opacity » style).
- The node had transformations applied to it (because of the « transform » style).
As a rule of thumb, a new layer is created for an element which can overlap other elements.
The layer tree, like the rendering tree, follows the DOM tree order, meaning that it loosely matches the structure of the rendering and DOM tree (loosely as there is not a 1-to-1 relation between the rendering tree and layer tree nodes).
As a consequence, the layer tree structure represents the first way of controlling the z-ordering of the document (the « tree order » way), the stacking context tree representing the « z-index » way.
The stacking context tree
The stacking context tree represents the z-ordering of the document as defined by « z-index » styles. Each layer in the layer tree belongs to a stacking context. Each layer either creates its own stacking context or use the one of its parent.
A layer creates its own stacking context when it is « positioned » (has a non « static » « position » style) and a non « auto » « z-index » style. When a layer creates its own stacking context, it then places it in the stacking context tree according to the value of its « z-index ». For instance, stacking context created with a negative z-index value will be placed before stacking context created with a positive « z-index » value.
There is at least one stacking context created by the root layer.
By combining the layer tree and the stacking context tree we can represent both the « tree order » z-ordering and the « z-index » z-ordering.
Sequencing the document’s rendering
When a rendering of the document’s occurs, the stacking context and the layer tree collaborate to sequence the rendering of the rendering tree. The rendering tree needs to be painted starting from back to front to respect z-ordering.
When a document starts rendering, it first calls a rendering method on the root stacking context. The root stacking context in turn calls a rendering method :
- first on its negative child stacking context
- then on the layer which created the stacking context. The layer in turn calls the rendering method on each layer sharing the same stacking context, in tree order.
- then on its positive child stacking context
When the rendering method of a layer is called, it calls the rendering method of the rendering tree node which created it, which in turn renders all rendering tree node belonging to the same layer.
This insures that the whole document is rendered recursively.
Scrolling and clipping
The layer tree is also in charge of the document’s scrolling. Scrolling happens when the height of the document is superior to the height of the viewport (typically the browser’s window).
Any HTMLElement can be made scrollable too via the « overflow » CSS style. The layer tree is in charge of determining for each layer wether it can be scrolled and/or wether it is clipped. It then need to find the clipped and scrollable bounds of the layer.
An HTMLElement which can be clipped or scrolled because of the « overflow » style will always create a layer.
The layer tree is implemented in the « layer » package located in the « core » package. The main class there is the LayerRenderer class. It manages the rendering of layer and its relation to a stacking context among other things.
In the same package the ScrollableView class manages all scrolling related task and is inherited by the LayerRenderer.
The stacking context tree is in the « stacking » package. It contains only a StackingContext class and its implementation is pretty simple.