Repository navigation
fix(core): a mover's ::before and ::after outside its box stay in the blur - #7295
Conversation
… blur Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Verdict: APPROVE · 0 blocker · 0 important · 2 nits · head a02c5ffe
Single input to both tiers, grow-only, so a wrong pseudo box can cost crop area but not cut pixels the old box kept. CI, regression and Windows render verification are green on this head (Flake gate included).
Scope
Read the full diff plus grownBox/contentBox callers and mover discovery. Did not re-run the "four cases fail without the change" claim locally (needs Chrome); CI runs the un-pinned cases green. No prior reviews.
— Claude
| function pseudoBox(el: HTMLElement, which: "::before" | "::after"): Box | null { | ||
| const cs = getComputedStyle(el, which); | ||
| if (NO_CONTENT.has(cs.content) || !POSITIONED.has(cs.position)) return null; | ||
| const left = parseFloat(cs.left) + el.clientLeft; |
There was a problem hiding this comment.
nit: the most common oversized pseudo is probably a centred halo — left: 50%; top: 50%; width: 160%; transform: translate(-50%, -50%). Ignoring the pseudo's transform puts this box w/2, h/2 down-right of the painted one, so the top/left of the halo is still cut. Mapping the four corners through cs.transform about cs.transformOrigin (or at least worth a Limits bullet naming this idiom) would cover it.
|
|
||
| function pseudoBox(el: HTMLElement, which: "::before" | "::after"): Box | null { | ||
| const cs = getComputedStyle(el, which); | ||
| if (NO_CONTENT.has(cs.content) || !POSITIONED.has(cs.position)) return null; |
There was a problem hiding this comment.
nit: the wrong-frame limit isn't just fixed. An absolute pseudo resolves against the mover only when the mover is a containing block. On the !ownTransform path of contentBox a mover can be position: static with no transform (moved by layout, e.g. animated margin), and left/top then belong to an ancestor. A single check that el is positioned or has a transform/will-change/filter would cover both this and the fixed case in the Limits list.
…view Adopts heygen-com#7294 (line_unread findings carry the measured frames), heygen-com#7271 (blur mutes discrete callbacks instead of undoing them), heygen-com#7293 (the filter tier's svg keeps the last child), heygen-com#7292 (a mover holding a fixed child stays sharp), heygen-com#7288 (auto motion blur draws with the filter tier) and heygen-com#7298 (Shift no longer re-renders the timeline). The fork's seek recovery in captureMotionBlur stays. Defers heygen-com#7134 (no packages/share) and heygen-com#7295 (needs the heygen-com#7080 crop pipeline). Watermark advances to 66cbabc. Co-authored-by: Miguel Ángel <miguel.sierra@heygen.com> Co-authored-by: Vance Ingalls <vance@heygen.com> Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What
A mover's
::beforeor::afterdrawn outside the mover's own box was cut off in both blur tiers (sweep defect D: 3480 and 3346 px differ from the 32-sample oracle for capture, 1248 for the filter tier).grownBoxgrew the blur box over the mover's text and its child elements but not over generated content, and both the capture crop and the filter region take their size from that box.pseudoBox(el, which)now returns the pseudo-element's box in the mover's own local px: null unless computedcontentis notnone/normalandpositionisabsoluteorfixed; otherwise[left, top, left + width, top + height]from the resolved px, offset by the mover'sclientLeft/clientTop, ignoring the pseudo's own transform and margins.autoor non-finite values skip the pseudo rather than guessing.grownBoxgrows with both pseudo-elements of the mover itself, not its descendants. One change at the single input to both tiers.Tests
pseudo-aftersweep cases (capture and filter) lose theirbugfields andS.D_CAPTURE/S.D_FILTERand pass as ordinaryinsidechecks. A new text-freepseudo-beforefixture adds the mirrored case (a::beforeto the left of the box) for both tiers.pseudoBoxreturn null fails exactly those four. Engine sweep 19/19,src/services/captureMotionBlur154/154, corecaptureMotionBlur212/212 on Chrome 153. The sweep file is 19.3 s idle locally on main and 23.5 to 26 s with the two new cases, against the Flake gate's 120 s per run.pseudoBox: jsdom ignores the pseudo argument and returnscontent: normal,position: static, so the browser cases are the coverage.Limits
getComputedStyle(el, pseudo)reads per mover per frame (212 for a 106-mover film), on a style that is already clean at that point.position: fixedpseudo of a mover that is not a containing block for fixed descendants resolves against the viewport, so its box is in the wrong frame: same family as defect F. The worst case is an over-grown crop (capture turns blur off for that mover throughmaxCropArea; the filter tier has no area guard).display: nonepseudo with authored px geometry still grows the box (costs a larger crop, no wrong pixels).width: autopseudos (Chrome returns used px for them).🤖 Generated with Claude Code