Repository navigation
PNT1-shadow: box-shadow on iOS and Android (supersedes the shadow half of #80 and #82) - #236
Open
thejackshelton wants to merge 8 commits into
Open
thejackshelton wants to merge 8 commits into
thejackshelton wants to merge 8 commits into
Conversation
…nto master The shadow engine from #80 (paint-shadow.ts, paint-aa.ts's A8 coverage blit, their tests, the paint-vector input generator and its regen step, the harness cases, the ports entries), and the compiler and native half from #82 (the box-shadow family, its computed values, one write per shadowed box, the companion-view and inset-stage emitters, the shadow-offset-1 plant, the shadow fixtures, samples and Chrome comparison tests), adapted to master's per-feature registries. New: native refusals, at the box-shadow value, of what the companion view and the shadow backdrop do not cover on master: html and body, replaced elements, inline boxes, positioned boxes (paint order without the stacking sort), and a shadow on or inside a transform or a compositing will-change. Floors appended with DRAGON_FLOOR_WRITE=1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012dJVP4456dCkJKMJUUf3xG
Commands: pnpm regen --skip lanes-host --skip tw-sweep (macos-26) and pnpm regen --only lanes-host (xcode-27), alternated to a fixed point, then pnpm regen --only tw-sweep (macos-26). Base: 89276b6 Run: https://github.com/compiled-run/dragoncss/actions/runs/37900368527
…t refuse Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012dJVP4456dCkJKMJUUf3xG
…hadow and the shadow fixtures join the identity check's post-base keys and files Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012dJVP4456dCkJKMJUUf3xG
…eported a conflict; generated files keep this side, regen rebuilds them) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012dJVP4456dCkJKMJUUf3xG
Commands: pnpm regen --skip lanes-host --skip tw-sweep (macos-26) and pnpm regen --only lanes-host (xcode-27), alternated to a fixed point, then pnpm regen --only tw-sweep (macos-26). Base: 8be7846 Run: https://github.com/compiled-run/dragoncss/actions/runs/37919424725
…eported a conflict after #232 and #233; generated files keep this side, regen rebuilds them) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012dJVP4456dCkJKMJUUf3xG
Commands: pnpm regen --skip lanes-host --skip tw-sweep (macos-26) and pnpm regen --only lanes-host (xcode-27), alternated to a fixed point, then pnpm regen --only tw-sweep (macos-26). Base: 197c05f Run: https://github.com/compiled-run/dragoncss/actions/runs/37933312205
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.
Requested by Jack · project thread
PNT1-shadow: CSS
box-shadow(outer and inset, several layers, blur, spread, offsets, colours, on rounded boxes) drawn by Dragon on iOS and Android, as Chrome 145 paints it.Supersedes the shadow half of #80 and all of #82. Both were stacked and far behind master. This PR carries their shadow content onto current
origin/masteras one branch, adapted to master's per-feature registries, the way #198 carried radius. Nothing here is stacked: the base ismaster.What changed
Engine (from #80, shadow half)
packages/layout/src/paint-shadow.ts: box-shadow layers as Blink 145 and Skia 2ab8add5 paint them: spread shapes with Blink's outset radius adjustment, the blur paths SkBlurMaskFilterImpl picks (analytic rect nine-patch, small rrect nine-patch, A8 mask plus box blur), each shadow blitted onto the backdrop its ancestors paint, encoded so the platform composite is Chrome's colour.packages/layout/src/paint-aa.ts: the A8 coverage device and SkA8_Blitter's srcover (SkBlitter_A8.cppsrcover_p, A8_row_aa).layout/test/paint-shadow.test.ts, the A8 cases inpaint-aa.test.ts), the harness'spaint:shadow:*cases, and the paint-vector inputs fromscripts/gen-paint-inputs-shadow.ts: a new regen steppaint-inputs-shadowinscripts/regen-steps/pnt1.tsafterpaint-inputs-radius, with its.gitattributesline.docs/ports.json: theSkBlitter_A8.cppentry and theAdjustedRadiusDimensionrange offloat_rounded_rect.cc(the Adobe notice is already on master;THIRD_PARTY_NOTICES.mdis regenerated from the registry).Compiler and native (from #82)
box-shadowfamily (css/properties/shadow.ts) with Chrome's parse beyond the grammar: a calculation, a viewport unit, a font-metric unit and a colour outside the subset are refused; computed values inanalysis/paint-values/shadow.ts(lengths to px, currentcolor to the colour, Chrome's serialization).box-shadowwrite per shadowed box with shadow facts (lower/paint/shadow.ts).emit/paint/shadow.ts) on both backends:dragonSetShadows; after every layout the translated paint-shadow.ts rasters the outer shadows into a companion view directly beneath the box (DragonTree.companion, already on master) and the inset shadows into the inset-shadow stage. A background write re-applies the shadows whose backdrop it changes (emit/paint/background.ts).shadow-offset-1raster plant (PLANT_CASEScalib-shadow-blur, PLANT_RULESshadow:).animation-kinds/shadow.ts: box-shadow interpolates in Chrome, so it isUNADMITTED; the state runtime refuses a shadow write by name.shadow-basic,shadow-rounded,shadow-inset,shadow-cascade,calib-shadow-blur,calib-shadow-colors(both directions) and the rejectsreject-shadow-calc,reject-shadow-viewport;fixture-groups/shadow.ts,paint-samples/shadow.ts,pnt1-shadow.test.ts(the device layers against the committed Chrome pixels),pnt1-shadow-facts.test.ts,dragon/test/paint-shadow.test.ts.GATE_CHANNEL_DELTA(allowances/shadow.tsis unchanged).New in this PR: native refusals of what the companion view and backdrop do not cover on master. Each is
DRAGON_UNSUPPORTED_VALUEat the box-shadow value, on ios and android only (web draws them itself), tested indragon/test/paint-shadow.test.ts:html/body(their background paints the canvas, which the shadow backdrop does not model);will-change: transform | opacity(the companion view is not transformed with the box, and Chrome composites the group on its own);shadow-in-group: Chrome blits the shadow into the group's raster, not onto the page backdrop).What #196 (opacity + stacking) or a follow-up must add once both land
dragonShadowViewmust move with the box and stay directly beneath it (PNT1 6/8: z-index and CSS2 Appendix E paint order on the native tree #85'sstacking.tsdid this; PNT1-effects 1/2: opacity as a native group alpha and z-index with Appendix E stacking (supersedes the opacity and stacking parts of #84-#85) #196 leaves a non-box view at its flow place).dragonShadowBackdrop(which walks superviews) misses the skipped ancestors' backgrounds; refuse that case by name, or walk the DOM parents instead.shadow-in-grouprefusal to anopacity< 1 group when opacity becomes a longhand.Changed tests (reasons)
layout/test/paint-seams.test: shadow is a filled seam, with its twoindex.tslines.dragon/test/s4b.test: box-shadow gets two shadow lists for the paint-never-reaches-layout check (colours are invalid for it).parity/test/device-lanes.test(paint plant verdict): the verdict cases run on the shadow plant's rule (shadow:) and also check that a radius-rule hit does not catch the shadow plant; the radius plant's caught case is kept.dragon/test/s4b.test(ii): box-shadow's paint-only check runs onposition: staticboxes, since ios refuses a shadow on a positioned box (this PR's refusal); every other longhand keepsposition: relative. Intent unchanged: two values of each paint longhand lower to identical layout styles.parity/test/hit-refusals-radius.ts): the rounded shadow fixtures (shadow-rounded,shadow-inset,calib-shadow-blur, both directions) joinRADIUS_OUT:hitRefusalrefuses them for their border radius, with the radius reason.hit-report.testandlanes.testread the list, so they stay exact.parity/src/hit-capture.tsidentity check:box-shadowjoins the keys added since the identity base (every capture and emitted rule gained it), and the shadow fixtures joinIDENTITY_NEW.hit-capture-identity.testgains a case proving box-shadow is stripped and a shadow-like key (text-shadow) is not.dragon/test/paint-seams-floor.json,seams-floor.json): appended withDRAGON_FLOOR_WRITE=1(box-shadow, the shadow plant and support files, and radius entries the earlier lane had not written). Nothing was removed.Outside the spec
packages/dragon/src/emit/paint/background.ts:dragonBackgroundcallsdragonShadowBackdropChanged(from PNT1 3/8: box-shadow, parsed as Chrome 145 and composited natively onto its backdrop #82).packages/dragon/src/emit/runtime/state.ts: the state runtime refusesbox-shadowby name, likeborder-radius.packages/parity/src/paint-samples/radius.ts: radius points stay clear of shadow layers (from PNT1 3/8: box-shadow, parsed as Chrome 145 and composited natively onto its backdrop #82).packages/parity/src/hit-capture.ts: the identity check's keys and new-file pattern (above).packages/translate/harness/harness.ts,scripts/gen-css-grammar.ts,packages/parity/src/device-run.ts,packages/parity/src/fixtures.ts: one registration each.What passed
Head
bbfac53b06afa50256aab435a26fae8bae8cbcec(after two catch-up merges oforigin/master, which GitHub reported conflicting in generated files only; the merge drivers kept this side and regen rebuilt them).67c5b4ea0e), run https://github.com/compiled-run/dragoncss/actions/runs/37919424725 (commitc9cf64016b), and on the final merge run https://github.com/compiled-run/dragoncss/actions/runs/37933312205 (commitbbfac53b06).box-shadow<shadow-list>,noneandinherit, ltr and rtl (6 rows per native target), arecaveaton iOS and Android with chrome-dual computed-value proofs from the six shadow fixtures, until the driver's device run adds the paint proofs;exacton web. Before this PR box-shadow wasDRAGON_UNSUPPORTED_PROPERTY.pnpm typecheck: passes onbbfac53b06.bbfac53b06: all ofpackages/dragon/testpluslayout/test/paint-shadow,paint-aa,paint-seams,paint-radius: 80 files, 1405 tests pass. (dragon/test/native-backendsneeds the toolchains; it passes on CI below.)tested bbfac53b06afa50256aab435a26fae8bae8cbcec, 24 files: all pass:pnt1-shadow(14: the device layers of every shadow fixture, both directions, every DPR, against the committed Chrome pixels withinSHADOW_CHANNEL_DELTA= the gate delta),pnt1-shadow-facts,pnt1-radius,pnt1-radius-edges,chrome-ports,registry-claims(parity),android-profile,css-escapes,device-lanes,device-run,fixture-reader,hit-capture-identity,hit-report,native-compare,paint-seams,paint-vectors-cli,pnt2-samples,samples,corpus-dpr,native-backends,native-dpr-swift,native-dpr-kotlin,paint-roots(TS = Swift = Kotlin for the translated shadow roots).lanes.test: 367 passed, 1 failed: device step pending ("every device lane ran": ios layout-vectors-device not run).pnpm pr:review 236 --once: exit 0 onbbfac53b06: CIcheckspassed, UNREVIEWED (Macroscope at its spending limit), 0 unanswered findings.Reviewed diff (outside
.macroscope/ignore.md): about 207 KB over 42 files. The compiler half needs the engine half, so splitting would leave one PR stacked on the other; it ships as one, as #198 did.🤖 Generated with Claude Code
https://claude.ai/code/session_012dJVP4456dCkJKMJUUf3xG
Generated by Claude Code