This page provides a high-level overview of the LibWeb rendering engine: how its major subsystems interact to turn raw HTML and CSS into painted pixels. It covers the DOM, CSS, Layout, and Painting subsystems and the data flows between them.
For detailed coverage of individual subsystems, see the child pages:
calc(): CSS Values and CalculationsLibWeb is the browser engine library that implements the web platform. It is responsible for:
The entry point for a rendered page is `Libraries/LibWeb/DOM/Document.cpp` which owns or coordinates all of these subsystems.
Diagram: Rendering Pipeline – Subsystems and Key C++ Types
Sources: `Libraries/LibWeb/DOM/Document.cpp` `Libraries/LibWeb/DOM/Document.h` `Libraries/LibWeb/CSS/StyleComputer.cpp` `Libraries/LibWeb/Layout/TreeBuilder.cpp` `Libraries/LibWeb/Layout/FormattingContext.cpp` `Libraries/LibWeb/Painting/PaintableBox.cpp` `Libraries/LibWeb/Painting/StackingContext.cpp` `Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp`
The DOM is a live tree of GC-managed objects rooted at DOM::Document.
| Class | File | Role |
|---|---|---|
DOM::Node | Libraries/LibWeb/DOM/Node.h | Base for all tree nodes; holds layout/paintable back-pointers |
DOM::Element | Libraries/LibWeb/DOM/Element.h | Element node; owns ComputedProperties, CascadedProperties, shadow root |
DOM::Document | Libraries/LibWeb/DOM/Document.h | Document root; owns StyleComputer, FontComputer, layout root, style scope |
DOM::ShadowRoot | Referenced from DOM::Element | Shadow DOM boundary; has its own StyleScope |
Document holds the m_layout_root (Layout::Viewport), the m_style_computer (CSS::StyleComputer), and is registered with the main-thread event loop at construction (`Libraries/LibWeb/DOM/Document.cpp531).
Document::update_style() and Document::update_layout() are the two driver methods that propagate changes through the pipeline. update_layout() calls into Layout::TreeBuilder and then the formatting context chain.
Node stores both a back-pointer to its Layout::Node (m_layout_node) and its Painting::Paintable (m_paintable), making cross-layer navigation O(1).
Sources: `Libraries/LibWeb/DOM/Document.h176-400 `Libraries/LibWeb/DOM/Document.cpp498-532 `Libraries/LibWeb/DOM/Node.h` `Libraries/LibWeb/DOM/Element.h`
CSS text is converted to rule objects by CSS::Parser::Parser (`Libraries/LibWeb/CSS/Parser/Parser.h`). The parser is split across several .cpp files:
Parser.cpp — core tokenizer and algorithm loopsRuleParsing.cpp — converts raw rules to CSSRule objectsPropertyParsing.cpp — per-property value parsingValueParsing.cpp — type-level value parsing (lengths, colors, etc.)Property metadata is driven by Properties.json (`Libraries/LibWeb/CSS/Properties.json`), which declares each property's initial value, inheritance, animation type, valid types, and shorthand expansions.
CSS::StyleComputer (`Libraries/LibWeb/CSS/StyleComputer.h`) resolves the CSS cascade for each element into a CSS::ComputedProperties object.
Diagram: Style Computation Data Flow in StyleComputer
The StyleScope maintains per-origin RuleCache objects that index rules by element id, class, tag name, and attribute for fast lookup. The cascade applies rules in order: user-agent → user → author, with !important reversals. Shorthand properties are expanded via for_each_property_expanding_shorthands().
ComputedProperties (`Libraries/LibWeb/CSS/ComputedProperties.h`) stores the final per-property values as StyleValue references, with bitfields for inherited and important flags. Animated values from KeyframeEffect overlay the base computed values at read time via property(id, WithAnimationsApplied::Yes).
Properties.json defines every supported CSS property. Each entry includes:
| Field | Meaning |
|---|---|
inherited | Whether the property inherits by default |
initial | Initial value string |
animation-type | How the property interpolates (by-computed-value, discrete, etc.) |
affects-layout | Whether changes require layout invalidation |
longhands | Sub-properties expanded from a shorthand |
valid-types | Accepted CSS value types |
Sources: `Libraries/LibWeb/CSS/StyleComputer.cpp243-403 `Libraries/LibWeb/CSS/StyleComputer.h` `Libraries/LibWeb/CSS/ComputedProperties.h` `Libraries/LibWeb/CSS/ComputedProperties.cpp` `Libraries/LibWeb/CSS/Properties.json1-300
The layout layer converts the DOM+computed-style into a positioned box tree.
Layout::TreeBuilder (`Libraries/LibWeb/Layout/TreeBuilder.cpp`) walks the DOM tree and creates Layout::Node objects according to each element's computed display value. Anonymous boxes, pseudo-elements (::before, ::after), and table-wrapper boxes are inserted here.
Layout::Node (`Libraries/LibWeb/Layout/Node.cpp`) is the base class of the layout tree. Leaf text runs become Layout::TextNode; block containers become Layout::BlockContainer; replaced elements become Layout::ReplacedBox.
Layout is performed by a hierarchy of FormattingContext subclasses. Each context operates on a subtree of the layout tree and writes results into LayoutState.
| Class | Display type handled |
|---|---|
BlockFormattingContext | display: block, display: flow-root |
InlineFormattingContext | Inline flow within a block |
FlexFormattingContext | display: flex |
GridFormattingContext | display: grid |
TableFormattingContext | display: table |
SVGFormattingContext | SVG viewports |
FormattingContext (`Libraries/LibWeb/Layout/FormattingContext.cpp`) selects and creates child contexts recursively for nested boxes.
Diagram: FormattingContext Class Hierarchy and Entry Points
LayoutState and its UsedValues struct are the write-once data store used during a layout pass. After all formatting contexts have run, LayoutState::commit() finalizes the result, copying computed box geometries into the PaintableBox objects and building the painting tree.
Sources: `Libraries/LibWeb/Layout/TreeBuilder.cpp` `Libraries/LibWeb/Layout/FormattingContext.cpp` `Libraries/LibWeb/Layout/BlockFormattingContext.cpp` `Libraries/LibWeb/Layout/GridFormattingContext.cpp` `Libraries/LibWeb/Layout/Node.cpp`
Each Layout::Box has a corresponding Painting::PaintableBox (`Libraries/LibWeb/Painting/PaintableBox.h`). These are created during LayoutState::commit() and mirror the layout tree structure.
PaintableBox stores the final absolute rectangle, scroll state, border/background data, and a back-pointer to its Layout::Box and DOM::Node.
Painting::StackingContext (`Libraries/LibWeb/Painting/StackingContext.cpp`) manages the CSS z-index and stacking order rules. Each PaintableBox that forms a new stacking context (via position, opacity < 1, transform, filter, etc.) gets a StackingContext. The stacking context tree is painted depth-first in the standard CSS painter's algorithm order (background, negative z-index children, in-flow, floats, positive z-index).
Painting is decoupled into two phases:
StackingContext::paint() uses a DisplayListRecorder to emit DisplayListCommand entries (draw rect, draw text, draw image, clip, transform, etc.) into a DisplayList.DisplayListPlayerSkia replays the DisplayList against Skia's canvas API, supporting GPU-accelerated rendering via Vulkan or Metal backends.This separation allows painting to be replayed on a background thread without re-running the layout or DOM logic.
Diagram: Paintable Tree and Painting Pipeline Classes
Sources: `Libraries/LibWeb/Painting/PaintableBox.cpp` `Libraries/LibWeb/Painting/PaintableBox.h` `Libraries/LibWeb/Painting/StackingContext.cpp` `Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp`
Changes to the DOM or CSS trigger targeted invalidation rather than full re-renders.
| Trigger | Invalidation Mechanism |
|---|---|
| Attribute change, class change | StyleInvalidator computes an InvalidationSet from the selector dependency graph and marks affected elements |
| DOM insertion/removal | Document::invalidate_layout_tree() clears layout nodes below the affected subtree |
| Animated property change | ComputedProperties::set_animated_property() overrides values; Document::update_animated_style_if_needed() re-paints without full layout |
| Scroll offset change | PaintableBox::set_scroll_offset() marks display list dirty; no layout required |
| Stacking context change | Document::invalidate_stacking_context_tree() rebuilds the stacking context hierarchy |
Document::update_style() and Document::update_layout() are the two public entry points that drive the pipeline forward. They are called by the HTML event loop's rendering update step.
Sources: `Libraries/LibWeb/DOM/Document.h362-370 `Libraries/LibWeb/DOM/Document.cpp` `Libraries/LibWeb/Painting/PaintableBox.cpp136-200
DOM::Document owns or references all pipeline components:
| Member | Type | Purpose |
|---|---|---|
m_style_computer | CSS::StyleComputer | Resolves cascade for each element |
m_font_computer | CSS::FontComputer | Resolves font stacks |
m_layout_root | Layout::Viewport | Root of the layout tree |
m_style_scope | CSS::StyleScope | Rule caches for the document |
m_style_sheets | CSS::StyleSheetList | All active style sheets |
m_style_invalidator | DOM::StyleInvalidator | Tracks which elements need style update |
Sources: `Libraries/LibWeb/DOM/Document.h263-270 `Libraries/LibWeb/DOM/Document.cpp498-531
Refresh this wiki