Skip to content

fix(dom): update a hoisted paint child instead of appending a copy - #99

Open
pathscale wants to merge 2 commits into
masterfrom
fix/hoisted-paint-child-duplicate
Open

pathscale wants to merge 2 commits into
masterfrom
fix/hoisted-paint-child-duplicate

Conversation

@pathscale

Copy link
Copy Markdown
Owner

The bug

place_hoisted_fixed joins an ancestor stacking context that is already built, which its own doc comment says outright:

Descendants are flushed before their parent's hoisting pass, so an ancestor's context is already built and sorted by the time this runs.

It then pushed unconditionally. An incremental resolve that re-flushes the same node reaches that list again and appends a second entry for the same child, so the box paints twice.

Every other push site is safe: they build a fresh context for the node being flushed, and paint_children is clear()ed first. Only this cross-context join writes into a list that already exists.

Corroborating evidence already in the tree: correct_hoisted_fixed_positions iterates every entry matching a node_id rather than finding one. It was written for duplicates that were already reachable.

The symptom

A pill menu whose shadow darkened each time the pointer crossed it, ~11.8k changed pixels per pass. The DOM and layout stayed flat, because the duplication only ever existed in the paint list. Nearby frames also slowed enough to miss timing budgets.

Any position: fixed element in a nested stacking context is affected, not just menus.

The fix

Find and replace the existing entry; append only when absent.

Testing

Reproduced and verified in AgencyZero's ps-qa suite, which has a dedicated check for exactly this (pillmenu-effort-shadow-does-not-stack, expect: PixelsHold).

Trigger was toggling glass blur or opacity first, then hovering the menu:

Sequence Before After
theme group, then shadow check fail, 11785 px pass
after theme-glass-blur fail pass
after theme-glass-opacity fail pass
after theme-glass-blur-restores fail, 5493 px pass
full suite 311/312 312/312, exit 0

The fix also cleared two theme timeout failures, which were duplicate paint entries making those frames slow. One defect, surfacing differently depending on timing, which is why it read as flaky.

`place_hoisted_fixed` joins an ancestor stacking context that is already
built, so an incremental resolve that re-flushes the same node reached it
again and pushed a second entry for one child. Two entries paint the same
box twice.

The visible symptom was a pill menu whose shadow darkened every time the
pointer crossed it, roughly 11.8k pixels per pass, with the DOM and the
layout still flat because the duplication only ever existed in this paint
list. Frames also slowed enough to miss timing budgets in nearby checks.

`correct_hoisted_fixed_positions` already loops over every entry matching
a node id rather than finding one, which is the same duplication seen
from the other side.

Find and replace the existing entry, append only when absent.
Publishes the hoisted paint child fix. `blitz-net` carries its own
version since 0.4.10 (see the cookie provider work), so the workspace
bump does not collide with it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant