Conversation
Paint-tree construction (paint_children + stacking contexts) moves out of flush_styles_to_layout into build_paint_tree, which runs after layout and transforms when Taffy has recorded every hoisted box's containing block. This replaces the two-writer model (flush builds, attach_hoisted_children patches) with one damage-gated pass. Paint ownership now follows DOM stacking-context ancestry, with geometry still derived from the containing-block chain at use-time: - z-indexed boxes (in-flow or out-of-flow) go to the nearest DOM ancestor stacking context; - z-index:auto out-of-flow boxes bubble up from their DOM parent and are claimed either by their containing block (spliced into its paint_children in tree order) or by an intervening stacking context root (as a z:0 entry with a compensating offset). Clean subtrees are skipped in incremental mode: their stacking-context contributions (sc_contribution_cache) and the boxes bubbling out of them (new oof_bubble_cache) are replayed. Removes attach_hoisted_children, innermost_paint_effect_ancestor, is_before_in_tree_order, oof_containing_blocks and containing_block_claims. Also: - fixed-position entries of a stacking context get the same viewport-scroll compensation as fixed paint_children (they previously scrolled with the document), and the compensation is now only applied when the containing block is the root (a fixed box inside a transformed scroller scrolls with it, matching browsers); - opacity/filter layers extend their clip to the stacking context's content_area so hoisted entries outside the border box are not lost.
Contributor
|
I'll fix CI failures and address comments from users with write access that start with 'DevinAI' or '@devin'.
|
A stacking context root that paints a box whose containing block lies above it must not clip it with its own overflow clip: draw hoisted entries outside the clip layer and push the clip around each entry only when the node is on its containing-block chain. Also stop applying flex `order` to out-of-flow children (they are not items), which changed their paint order. Fixes WPT css/css-position/position-fixed-scroll-nested-fixed and css/css-flexbox/flexbox-paint-ordering-003.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Stacked on #803 (targets its branch; the diff is the two commits on top). Implements the "single post-layout paint-tree pass" from the #803 review: paint-list construction moves out of
flush_styles_to_layout(which now only clears Taffy caches / sorts flex+gridlayout_childrenbyorder) into one damage-gatedbuild_paint_treethat runs afterresolve_layout+resolve_transforms, when Taffy has recorded every hoisted box'soof_containing_block. This replaces the two-writer model (flush buildspaint_children/stacking contexts before layout,attach_hoisted_childrenpatches them after) and deletesattach_hoisted_children,innermost_paint_effect_ancestor,is_before_in_tree_order, theoof_containing_blocksregistry andNode::containing_block_claims.Ownership rule (browser-style: paint owner follows DOM stacking-context ancestry, geometry follows the containing-block chain via the existing use-time
hoisted_child_position):Incremental mode skips clean subtrees exactly as #803's flush did, replaying
sc_contribution_cacheplus a newNode::oof_bubble_cache(the boxes that bubbled out of the subtree; their CB is re-read live fromoof_containing_block, so a CB change above the clean subtree is picked up without invalidating it). Both the DOM parent and the CB of a hoisted box are DOM ancestors of it, so any change to where it hoists dirties every node whose lists it can appear in.Behaviour changes vs #803 (all verified against Chrome with pixel probes, now committed as
tests/blitz-tests/tests/oof_paint_ownership.rs):position:fixedinside az-indexancestor paints inside that ancestor's stacking context instead of escaping to the root (was a regression vsmain).opacity(or any SC) stays in that SC instead of escaping to the CB's SC.position:fixedno longer scrolls with the document: stacking-context entries now get the same viewport-scroll compensation aspaint_children(Node::fixed_child_scroll_compensation, threaded throughhit_innertoo). The compensation is applied only when the CB is the root: a fixed box inside a transformed scroller scrolls with it (matches Chrome; previously pinned).effect_layer_clipby the SC'scontent_area, so hoisted entries outside the border box are painted (previously clipped away in bothmainand Make paint-placement maintenance incremental (O(damage), not O(tree)) #803).build_paint_treeruns afterresolve_transforms, so a transform gained this frame makes the node an SC root this frame rather than next.Node::clips_hoisted_child). A box captured by an SC root below its CB (e.g.fixedinside aposition:fixed; overflow:autoscroller) is therefore no longer clipped/scrolled by that root. Clip-only layers are cheap in vello; this adds at most one per hoisted entry of a clipping SC root. Side effect: negative-z entries now paint before the node's own inline content/images (Appendix E step 3 before 4), previously after.Node::order()returns 0 for out-of-flow children:orderonly applies to flex/grid items, and sortinglayout_childrenby it changed the paint order of abspos children of a flex container.Not changed (pre-existing, out of scope): Appendix E step‑8 interleaving of z:auto positioned descendants across nesting levels, z-indexed descendants escaping a non-SC
overflow:hiddenancestor, and general per-item clip chains (only the owning SC root's clip is skipped here, not clips of intermediate non-CB ancestors).Testing
cargo test --workspace,cargo clippy --workspace,cargo fmt --allclean.oof_paint_ownership.rs(11 pixel/hit tests incl. an incremental CB-toggle test) passes; the existingpaint_order.rs/oof_dynamic_cb.rssuites still pass.css/css-position css/CSS2/{positioning,zindex,stacking-context,abspos} css/css-transforms css/filter-effects css/css-grid/{abspos,grid-items} css/css-flexbox(22,495 subtests) pluscss/css-masking css/css-overflow css/css-inline css/css-contain css/css-anchor-position css/css-break css/css-images css/css-pseudo css/CSS2/backgrounds: +2 / −1. (The CI WPT block below diffs againstmain, so it also includes Make paint-placement maintenance incremental (O(damage), not O(tree)) #803's own changes; every "newly failing" test there fails identically on the Make paint-placement maintenance incremental (O(damage), not O(tree)) #803 branch.)css-flexbox/order/order-abs-children-painting-order.html,css-transforms/transform-containing-block-and-scrolling-area-for-fixed.html.filter-effects/filtered-inline-is-container.html. Not a paint regression: Make paint-placement maintenance incremental (O(damage), not O(tree)) #803 attached the fixed/abs boxes to the inline#filterspan's stacking context, which is never painted (verified: the boxes were missing from the Make paint-placement maintenance incremental (O(damage), not O(tree)) #803 render), so the test matched its ref by accident. They are now painted, at the wrong position because Blitz's layout doesn't treat a filtered inline as a containing block (separate layout issue).WPT results
Subtests: 1982 newly passing, 42 newly failing (net +1940). Timeouts: +1.
Full diff (243 changed tests)
Generated by the WPT workflow.
Link to Devin session: https://dioxus.staging.devinenterprise.com/sessions/42a17ab185fd42b8bb6c11ce389518f5
Open in Devin Desktop: https://dioxus.staging.devinenterprise.com/desktop/session/42a17ab185fd42b8bb6c11ce389518f5?variant=devin-insiders
Requested by: @nicoburns