Browser Render & Paint Pipeline
How Blink turns a mutated DOM back into pixels: style recalculation, layout, compositing inputs, paint, and rasterization on the compositor. Verified against Chrome 154 Blink and cc source, including the phases the usual mental model leaves out.
What you'll explore
- 01
Style Recalculation
Blink's rendering work is a lifecycle, and DocumentLifecycle::LifecycleState is the authoritative list of its phases: kInStyleRecalc, kInPerformLayout, kInCompositingInputsUpdate, kInPrePaint, kInPaint, each with a matching Clean state. Style recalculation is the first, and it is selective rather than global. A viewport resize, for instance, marks only the elements whose computed style actually uses viewport units. The exception is documented in the source itself: if a registered custom property (@property) depends on an invalidated viewport unit, the engine gives up on being selective and marks every element in the document for recalculation, because the property can affect all of them.
- 02
Layout
Layout computes geometry, and LocalFrameView::PerformLayout is where the lifecycle advances into kInPerformLayout. Two invariants are enforced by scope objects rather than convention: script cannot run during layout, and no new layout can be scheduled from inside layout. Blink can scope layout to accumulated subtree roots, but if the LayoutView itself is dirty those roots are discarded and layout restarts from the root. Reading geometry from JavaScript is different again: it forces the whole document through style and layout first, because the getter cannot return a stale answer.
- 03
Compositing Inputs
Blink defines a phase called kInCompositingInputsUpdate, and reading that name as the place compositing gets decided is the trap. That phase does something narrow: it validates highlight markers, commits the pending selection and updates descendant-dependent flags. The compositing reasons are computed one phase later, in kInPrePaint, where the paint property tree builder calls CompositingReasonFinder::DirectReasonsForPaintProperties and writes what it returns onto paint property nodes. In neither phase is a layer allocated. Layerization is the compositor's decision, taken later from the paint artifact. Separately, LayerTreeHost::SetNeedsCommit requests that the main thread's layer tree be synchronized across to the compositor thread; it is a scheduling request on the main thread, not a GPU operation.
- 04
Paint
Paint runs in kInPaint and produces paint artifacts. It is preceded by a phase the usual four-step model omits entirely: kInPrePaint, where, in the source's own words, the data needed by painting is prepared, paint property trees are built and paint invalidations are issued. Paint's opacity shortcut is narrower than it sounds. An element whose opacity falls below kMinimumVisibleOpacity is not skipped: its layer paints as usual, wrapped for the remainder of that paint in a scope marking the chunks it produces effectively invisible. Three declarations opt out of even that much — a non-initial backdrop-filter, will-change: opacity, or a currently running opacity animation, the last so that starting the animation does not jank.
- 05
Rasterization on the Compositor
This section has no DocumentLifecycle state, and that absence is the point: rasterization is not part of the document lifecycle at all. It happens in cc, on the compositor and raster threads, after the commit. GPU rasterization is also not a given but the third rung of a ladder negotiated with the GPU process. With no worker context provider, cc falls back to software raster and software compositing. With a context but GPU tile rasterization unavailable or disabled, it does GPU compositing with software raster. Only past both checks does it set use_gpu_rasterization.
Validated against Chromium / Blink + cc chromium-154.0.8037.57 — third_party/blink/renderer/core/dom/document_lifecycle.h and friends. Every simulated behavior cites a real source function, and a server-side correlation engine computes how each layer's state cascades into the next. See the methodology →
This module is part of zerohop Pro — it unlocks alongside the full kata library, progress tracking, and weak-area analysis.