Skip to content

fix(compose): honor ordinary draw modifiers in view dispatch - #112

Merged
bytemain merged 1 commit into
staging2from
mingqi/task183-draw-modifier-view-bridge
Aug 3, 2026
Merged

fix(compose): honor ordinary draw modifiers in view dispatch#112
bytemain merged 1 commit into
staging2from
mingqi/task183-draw-modifier-view-bridge

Conversation

@bytemain

@bytemain bytemain commented Aug 3, 2026

Copy link
Copy Markdown
Member

Summary

  • delegate the view-aware DrawModifierNode.draw(view) default to the ordinary draw() contract
  • preserve explicit view-aware overrides for native-backed draw modifiers
  • add counterfactual tests for ordinary fallback and explicit view-aware precedence

Incident evidence

Task Tencent-TDS#183 VC1000134 physical Huawei evidence showed Modifier.drawWithContent placement callback running 18 times while its draw callback remained at zero. Source review found LayoutNodeDrawScope dispatches draw(kView), but ordinary modifiers such as DrawWithContentModifier, indication, and lazy item animation override only draw(); the old default skipped those overrides and called drawContent() directly.

This PR repairs the framework dispatch contract. It does not claim the white-screen product root cause: Mobile PixelCopy lifetime remains a separate diagnostic gap, and a fresh physical carrier is still required.

Validation

  • git diff --check
  • hosted Compose/common matrix required; no local Gradle/Konan on the shared Mac

Signed-off-by: MingQi raft-mobile-mingqi@mail.build

@bytemain

bytemain commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

SOURCE/TEST PASS (diagnostic tooth) — sole full exact 784df4a297d6b4d83bd4e07bbc961fd91061469b

SHA correction: announced prefix 784df4a27a61e532… is not the PR object. Dual-read refs/pull/112/head / gh headRefOid = 784df4a297d6b4d83bd4e07bbc961fd91061469b only.

Identity

field value
head 784df4a297d6b4d83bd4e07bbc961fd91061469b
parent / staging2 c5730e286ba1134a4a479c7e212376a915cde450
tree 88451fa5b3e7953c062ce97dc4ecf3eb1cceebbe
paths 2 +71/-1
stable patch-id d73ff6458e5ebee31a57d7ff34bbce6e5726eb0
sign-off MingQi
PR OPEN / MERGEABLE

Dispatch / recursion — PASS

  • Production change is one line: default ContentDrawScope.draw(view) goes from drawContent()draw() (no-arg ordinary path).
  • No mutual recursion: default draw() is empty {} and does not call draw(view). Ordinary-only overrides implement draw(); explicit draw(view) overrides (Background/Border/Painter/Alpha/DrawBehind) still take precedence and never enter the new default body.
  • Unit teeth lock: ordinary draw() runs once under draw(view) dispatch; explicit view override runs alone (ordinaryDraws=0).

Residual semantics (non-blocker for this diagnostic tooth)

Bare DrawModifierNode that overrides neither method previously still painted children via default drawContent(); after this change that bare path is a no-op until an ordinary draw() (typically drawWithContent) supplies drawContent(). Existing production view-aware overrides are unchanged. This is the intended “honor ordinary draw modifiers” tradeoff for the diagnostic tooth — not a product root-cause close.

Non-claims

Verdict: SOURCE/TEST PASS on full exact 784df4a297d6b4d83bd4e07bbc961fd91061469b (dispatch+recursion only).

@bytemain
bytemain marked this pull request as draft August 3, 2026 12:55
@bytemain
bytemain force-pushed the mingqi/task183-draw-modifier-view-bridge branch from ff49485 to 95eaef2 Compare August 3, 2026 13:03
Signed-off-by: MingQi <raft-mobile-mingqi@mail.build>
@bytemain
bytemain force-pushed the mingqi/task183-draw-modifier-view-bridge branch from 95eaef2 to bfa1a1d Compare August 3, 2026 13:09
@bytemain

bytemain commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

SOURCE/TEST PASS (diagnostic dispatch) — sole exact bfa1a1d388426118e6d0ed9e81a49e89a0e65979

Zero-inheritance. Prior exacts 784df4a297d6… / ff49485b… / 95eaef2e… and formal 5166479253 are VOID.

Identity

field value
head bfa1a1d388426118e6d0ed9e81a49e89a0e65979
parent / staging2 c5730e286ba1134a4a479c7e212376a915cde450
tree e2d109bf7144f06794590b98982f823dd8cba793
commits 1 (single-commit identity)
paths 4 +267/-2
stable patch-id 62fb5a7e31da4c6b53fac0625241497af4373cdf
sign-off MingQi

Default-method / recursion — PASS

draw() default        → drawContent()   // bare passthrough (LiquidGlass*)
draw(view) default    → draw()          // honor ordinary overrides
  • No mutual recursion: ordinary default never re-enters draw(view).
  • bare nodes: view path → draw()drawContent() once (unit tooth).
  • ordinary-only: ordinary and view-aware dispatch both hit draw() (equivalence tooth).
  • explicit draw(view): precedence only (Background/Border/Painter/Alpha untouched).

Production wiring — PASS

tools/check-draw-modifier-view-dispatch.py (required source-contracts):

  • parses live LayoutNodeDrawScope.drawDirect body with comment/string mask
  • requires exactly one draw(kView) and forbids ordinary draw() bypass
  • self-test rejects ordinary / removed / comment-only mutants
  • local --self-test + live check both pass on this tree

Non-claims

Verdict: SOURCE/TEST PASS on exact bfa1a1d388426118e6d0ed9e81a49e89a0e65979.

@bytemain
bytemain marked this pull request as ready for review August 3, 2026 13:25
@bytemain
bytemain merged commit 461bbe5 into staging2 Aug 3, 2026
6 checks passed
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