we (web engine): Experimental web browser project to understand the limits of Claude

Incremental layout with dirty bit propagation #140

open opened by pierrelf.com

Summary#

Add a dirty-bit system to the layout engine so that only modified subtrees are re-laid-out, instead of recomputing the entire layout tree on every frame.

Background#

Currently, layout() in crates/layout/src/lib.rs rebuilds the complete layout box tree and runs compute_layout() over every node on every render. For interactive pages with JS-driven DOM mutations, this is wasteful — most of the tree hasn't changed.

Acceptance Criteria#

  • Add dirty: bool flag to LayoutBox (or a separate dirty-bit map keyed by NodeId)
  • Define dirty propagation rules:
    • When a DOM node's style changes → mark its layout box dirty
    • When a DOM node is added/removed → mark parent dirty
    • When textContent changes → mark containing box dirty
    • Dirty propagates upward: a dirty child marks ancestors dirty (up to the containing block)
  • compute_layout() skips clean subtrees — if a box and all descendants are clean, reuse cached dimensions/positions
  • Implement mark_dirty(node_id) API callable from JS DOM bindings and style resolution
  • Handle cases that invalidate layout globally: viewport resize, font loading, display changes
  • Incremental re-layout produces identical results to full re-layout (correctness invariant)
  • All existing layout tests pass
  • Add tests: mutate one node in a large tree, verify only the dirty subtree is re-laid-out (count layout invocations or add metrics)

Implementation Notes#

  • A simple approach: keep the previous LayoutBox tree, diff against the new styled tree, and only re-layout dirty subtrees
  • Alternatively: maintain a persistent layout tree that's mutated in-place, with dirty bits
  • Margin collapsing complicates things: a dirty child may affect sibling margins. Consider re-laying-out the entire block formatting context when any child is dirty
  • Flexbox/grid containers should re-layout all children if any child is dirty (their sizing is interdependent)
  • Start conservative (mark more dirty than necessary) and optimize later

Dependencies#

None — independent of JS engine work.

Phase#

Phase 15: Performance

sign up or login to add to the discussion
Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:meotu43t6usg4qdwzenk4s2t/sh.tangled.repo.issue/3mi4zyts6jk2i