Chromium Compositing: Paint Chunks and Property Trees
This article provides an overview of the critical roles that paint chunks and property trees play within the Chromium web browser's rendering pipeline. It explains how property trees decouple visual effects and scrolling from the complex Document Object Model (DOM) hierarchy, how paint chunks group drawing commands together, and how the browser's compositor combines these two data structures to efficiently divide a web page into GPU-accelerated layers for smooth rendering and scrolling.
The Shift to CompositeAfterPaint
To understand paint chunks and property trees, you must first understand their context within Chromium's architecture, specifically the system known as CompositeAfterPaint (part of the broader RenderingNG architecture).
Historically, Chromium decided which HTML elements needed their own GPU compositing layers before painting the page. This caused bugs and performance bottlenecks because the browser had to guess how elements would overlap and animate. Today, Chromium paints the page into a flat list of lightweight recording data first, and only decides how to break the page into GPU layers after the paint phase. Paint chunks and property trees are the exact mechanisms that make this possible.
What are Property Trees?
In the past, calculating an element's final screen position, clipping boundaries, or opacity required traversing a massive, tangled layout tree. Chromium solved this by introducing Property Trees during the "Pre-Paint" phase of the rendering pipeline.
Instead of one complex hierarchy, the browser extracts spatial and visual relationships into four flat, specialized trees:
- Transform Tree: Defines 2D and 3D CSS transforms, hardware-accelerated animations, and positional offsets.
- Clip Tree: Defines rectangular and rounded clipping
boundaries, such as those created by
overflow: hidden. - Effect Tree: Defines pixel-level visual effects, including opacity, CSS filters (like blur), masks, and blend modes.
- Scroll Tree: Defines scrollable areas, how they nest inside one another, and their current scroll offsets.
Every visual element on a web page is assigned a Property Tree State. This state is simply a tuple of four pointers—one pointing to its respective node in the Transform, Clip, Effect, and Scroll trees.
What are Paint Chunks?
During the "Paint" phase, Chromium walks the layout tree and generates Display Items. A Display Item is a low-level drawing instruction, such as "draw a blue border" or "draw this string of text." Display items do not contain actual pixels; they are fast, lightweight recordings of how to draw the pixels later.
A Paint Chunk is a contiguous sequence of these Display Items that share the exact same Property Tree State.
As Chromium records Display Items, it groups them into a single Paint
Chunk. The moment the browser encounters an element that alters the
Property Tree State—for example, a <div> with an
opacity: 0.5 or a new CSS transform—it closes
the current Paint Chunk and starts a new one with the updated Property
Tree State. The final output of the Paint phase is simply an ordered
list of Paint Chunks and the four Property Trees.
How They Drive the Compositing Pipeline
Once the Paint phase concludes, the compositing pipeline takes over. Paint chunks and property trees work together to execute two major tasks: Layerization and Compositor-Thread Animation.
1. Layerization (Merging and Splitting)
Because creating a separate GPU texture (layer) for every single Paint Chunk would quickly exhaust the device's video memory, the compositor must group Paint Chunks into a smaller number of Composited Layers.
The compositor iterates through the list of Paint Chunks and compares their Property Tree States:
- Splitting: If a Paint Chunk is tied to a Transform Tree node with an active animation, or a Scroll Tree node that the user can actively scroll, the compositor isolates that Paint Chunk into its own dedicated GPU layer.
- Merging: If two adjacent Paint Chunks have compatible Property Tree States (e.g., they don't animate independently and exist in the same coordinate space), the compositor merges them into a single layer to save memory.
2. Fast Animations and Scrolling
Once the Paint Chunks are merged into layers and rasterized into pixels on the GPU, the Property Trees are sent over to the browser's Compositor Thread.
This separation is what makes modern web browsing feel smooth even when the Main Thread is bogged down by heavy JavaScript:
- When a user scrolls the page, the Compositor Thread simply updates the offset values inside the Scroll Tree and Transform Tree.
- When a CSS opacity animation runs, the Compositor Thread updates the value in the Effect Tree.
Because the Paint Chunks have already been turned into GPU textures, the browser does not need to re-layout or re-paint the page. The compositor simply takes the existing textures derived from the Paint Chunks and composites them onto the screen using the newly updated math from the Property Trees.