Summary#
Implement a style sharing cache that reuses computed styles across elements with identical styling inputs, avoiding redundant cascade resolution.
Background#
Currently, resolve_styles() in crates/style/src/computed.rs runs the full cascade (collect matching rules → sort by specificity → apply declarations) for every element on every render. Many elements on a typical page share identical styles (e.g., list items, table cells, paragraphs). A style sharing cache detects these cases and reuses the computed style.
Acceptance Criteria#
- Define a style cache key based on the inputs that determine computed style:
- Set of matching rule indices (or a hash of matched selectors + specificity)
- Inline style attribute (if any)
- Inherited style from parent (pointer equality or hash)
- Element's tag name and namespace
-
StyleCachestruct: maps cache keys toArc<ComputedStyle>(orRc<ComputedStyle>) - During
resolve_styles(), before running the cascade for an element:- Compute the cache key
- Check the cache — if hit, clone the
Arcand skip cascade resolution - If miss, run the cascade, store result in cache, return
- Cache is scoped per style resolution pass (cleared between renders, or use generation counters)
- Sharing works for inherited properties: if parent style is shared, children can share too
- All existing style/layout/render tests pass
- Add tests verifying cache hit rates on documents with repeated structures (e.g.,
<ul>with many<li>elements)
Implementation Notes#
- The key insight: two elements with the same matched rules, same inline styles, and same inherited parent will always produce the same computed style
- Hashing the matched rule set is efficient — rules already carry specificity and source order
Arc<ComputedStyle>enables zero-cost sharing; clone is just a refcount bump- Custom properties (
var()) complicate sharing — elements with different custom property environments can't share even if rules match. Include custom property state in the cache key. - Start simple: cache on (matched_rules_hash, inline_style_hash, parent_style_ptr). Refine if needed.
Dependencies#
None — independent of JS/layout work.
Phase#
Phase 15: Performance