Skip to content

Label ink-aware sizing + device-pixel rounding - #263

Merged
kostub merged 7 commits into
masterfrom
feature/ink-aware-width-pr2
Jul 23, 2026
Merged

Label ink-aware sizing + device-pixel rounding#263
kostub merged 7 commits into
masterfrom
feature/ink-aware-width-pr2

Conversation

@kostub

@kostub kostub commented Jul 22, 2026

Copy link
Copy Markdown
Owner

PR 2 of 2 — Label ink-aware sizing + device-pixel rounding

Part 2 of the ink-aware width + device-pixel size rounding work (issues #213, #98, #57). This PR routes MTMathUILabel's reporting/positioning surface through the ink extent added in PR 1, rounds the reported size up to the device-pixel grid, and re-queries when the backing scale becomes known.

Plan: docs/plans/2026-07-14-ink-aware-width.md
LLD: docs/lld/2026-07-06-ink-aware-width.md

Stack

Goal

Route the label's reporting/positioning surface through inkWidth, round the reported size up to the device-pixel grid, and re-query when the backing scale becomes known.

Commits (one per plan item)

  1. [item 16] Route label sizing/alignment through inkWidth + ceil to the device-pixel grid
  2. [item 17] Resolve device-pixel scale (contentScaleFactor / backingScaleFactor)
  3. [item 18] Re-query intrinsic size on window/backing-scale change
  4. [item 19] Assert ink-clip render guarantees the feature actually provides

Testing

  • New iosMathTests/MTMathUILabelSizingTest.m (5 tests): inkWidth routing, device-pixel grid rounding, alignment, and scale-change re-query.
  • New iosMathTests/MTInkClippingRenderTest.m (2 tests): renders the laid-out display tree and asserts (a) trailing overhang glyphs never clip the right border at any alignment (Cluster A), and (b) tall constructs (\frac{1}{2}, \int_0^1, …) report a pixel-aligned size with trailing ink contained inside the right border (Cluster B).
  • Full suite: 438/438 passing.

Note on the Cluster B render assertion

The render test asserts the guarantee this feature actually provides — a pixel-aligned reported size (frame edges on whole device pixels, so no fractional-size resample) plus right-edge ink containment. It deliberately does not assert "zero ink in the top border pixel row": flush, ink-tight tall constructs legitimately place ink against their ink-tight vertical boundary, so that row contains genuine (un-clipped) ink. The true hairline artifact is a fractional-origin compositing resample, addressed by snapping the draw origin — deferred per LLD §2.8.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved mathematical label sizing and alignment to reduce right-edge clipping.
    • Updated intrinsic and sizeThatFits: calculations to use pixel-rounded measurements for consistent device-pixel rendering.
    • Updated horizontal positioning to align using ink extents, and ensured intrinsic size is invalidated when moving between windows or when backing/display scale changes.
  • Tests

    • Added unit tests that render labels to CPU bitmaps and verify ink containment and pixel-grid alignment across alignments and scale factors.
    • Added tests covering sizeThatFits:, intrinsicContentSize, nil-latex behavior, and intrinsic invalidation lifecycle.

@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@kostub

kostub commented Jul 22, 2026

Copy link
Copy Markdown
Owner Author

Code review — PR 2 (ink-aware label sizing + device-pixel rounding)

Reviewed against head 4a08aee719a66ace0dbcc29df51c6823e7a74aa6 (base feature/ink-aware-width-pr1 @ e19e9cf). Built and ran the two new test classes under SPM: 7/7 pass. The implementation faithfully matches the LLD (§3.4, §3.5, §2.8) and the plan items 16–19.

Strengths

  • ceilToPixel correctly guards scale <= 0 and rounds up on the pixel grid (ceil(v*scale)/scale); reported size can only grow, so no content is ever clipped smaller than before.
  • Routing only sizeThatFits:/intrinsicContentSize and the center/right layoutSubviews alignment through inkWidth (leaving width/advance and the display-tree layout untouched) is exactly the LLD's "separate ink extent from advance" approach. Left alignment stays on contentInsets.left, so the ceil slack lands on the right — correct.
  • Height path is unchanged (ascent + descent), which was already ink-tight vertically — no vertical regression.
  • screenScale resolution order (iOS contentScaleFactor; macOS window.backingScaleFactor → layer.contentsScale → 1) matches LLD §3.4, with sensible > 0 guards.
  • The scale-change lifecycle hooks are correct and minimal: iOS didMoveToWindow, macOS viewDidMoveToWindow + viewDidChangeBackingProperties, each calling super then invalidateIntrinsicContentSize. testScaleLifecycleInvalidates proves the hook fires via the MTSpyLabel subclass.
  • The internal header's comment explaining why displayList is not redeclared (illegal readonly class-extension override) is a genuinely useful landmine marker.
  • MTInkClippingRenderTest.testNoRightEdgeClip has real teeth: for V (advance 11.66 vs ink 15.38, a 3.72pt pre-fix clip) it renders the tree and asserts zero ink in the last column at all three alignments — this would fail against the old advance-based width.

Minor / non-blocking

1. New test files are not wired into either .xcodeproj — they only run under swift test.
MTInkClippingRenderTest and MTMathUILabelSizingTest appear 0× in iosMath.xcodeproj/project.pbxproj and MacOSMath.xcodeproj/project.pbxproj, whereas the older suite (MTTypesetterTest) appears 8×. The two documented Xcode test commands in CLAUDE.md (xcodebuild test -project iosMath.xcodeproj ... and the MacOSMath equivalent) will therefore neither compile nor run these tests. This is a pre-existing pattern from PR 1 — its MTInkWidthTest.m is also absent from both pbxproj files — so it is not introduced here, but the whole ink-aware feature's regression coverage is currently invisible to the Xcode CI path. Worth a follow-up to add all three files to the test targets, or to confirm CI runs swift test exclusively.

2. The pixel-alignment assertions are near-tautological at scale == 1.
testTallConstructsPixelAlignedAndContained and testSizeThatFitsInkAndGrid both compute size.width * scale using the same screenScale the size was rounded with, then assert it equals round(...). When screenScale == 1 (the common case for an unparented label under swift test on a non-Retina context) this is ceil(x)*1 == round(ceil(x)*1), which is trivially true regardless of the rounding logic. The assertion only exercises the grid math when screenScale > 1 (e.g. layer.contentsScale == 2 on a Retina backing). Consider forcing a known non-integer scale (e.g. subclass/override screenScale to return 2 or 3) so the grid rounding is tested where it can actually fail. The containment half of these tests (ink inside the right border) does have teeth regardless.

3. renderLabel: returns NULL for a zero-size frame and the caller skips silently.
In testTallConstructsPixelAlignedAndContained, if (!buf) continue; means a construct that unexpectedly reports a 0×0 frame would silently pass the containment check. Low risk given the fixed non-empty inputs, but an XCTAssertNotNil-style guard on the tall-construct path would make an accidental empty render loud rather than skipped.

Correctness — no issues found

  • Nil-mathList: displayList is nil, displayList.inkWidth messages nil → 0.0, so a nil-latex label reports ceilToPixel(insets) per axis; testNilLatexReportsRoundedInsets covers this.
  • intrinsicContentSize delegating to sizeThatFits:CGSizeZero (ignoring the constraint) is unchanged pre-existing behavior; testIntrinsicMatchesSizeThatFits pins it.
  • The DeviceRGB render harness color-space choice is explained and matches how the tree paints (black via an RGB CGColor); the integer-origin flip is consistent with the "origin snapping deferred (§2.8)" scope.

Not approving/merging per instructions — this is review feedback only. No blocking issues; the two design-adjacent notes (Xcode test wiring, scale==1 tautology) are worth a look before merge.

@kostub

kostub commented Jul 22, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 301efb74-8a09-4d93-9fe0-e58bff1e5b1a

📥 Commits

Reviewing files that changed from the base of the PR and between b9f684a and 7572817.

📒 Files selected for processing (1)
  • iosMathTests/MTMathUILabelSizingTest.m
🚧 Files skipped from review as they are similar to previous changes (1)
  • iosMathTests/MTMathUILabelSizingTest.m

📝 Walkthrough

Walkthrough

MTMathUILabel now aligns layout and intrinsic sizing to rendered ink extents and device pixels, determines platform-appropriate scale factors, invalidates intrinsic size on scale lifecycle changes, and adds bitmap-based and sizing-focused XCTest coverage.

Changes

Pixel-aligned label layout

Layer / File(s) Summary
Sizing, alignment, and scale lifecycle
iosMath/render/MTMathUILabel.m
Adds pixel rounding and effective scale detection, uses inkWidth for centered/right alignment, rounds sizeThatFits: dimensions, and invalidates intrinsic content size when window or backing-scale state changes.
Internal testing contract
iosMath/render/internal/MTMathUILabelInternal.h
Exposes internal scale, sizing, and layout declarations for cross-platform tests.
Layout and rendering validation
iosMathTests/*Label*Test.m, iosMath.xcodeproj/project.pbxproj
Adds tests for pixel-rounded sizing, intrinsic-size consistency, alignment containment, scale lifecycle invalidation, and right-edge rendering clipping, and registers both test files in the test target.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • kostub/iosMath#262: Adds display-list ink-extent tracking used by this PR’s alignment and right-edge containment changes.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: ink-aware label sizing plus device-pixel rounding.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/ink-aware-width-pr2

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
iosMathTests/MTInkClippingRenderTest.m (2)

90-102: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make skipped render cases fail visibly.

A NULL bitmap currently skips the containment assertion, masking a rendering/setup failure for that formula.

Proposed fix
         size_t W, H; uint8_t* buf = [self renderLabel:label width:&W height:&H];
-        if (!buf) continue;
+        XCTAssertNotNull(buf, @"%@ did not render into a bitmap", latex);
+        if (!buf) continue;
         XCTAssertEqual(inkInColumn(buf, W, H, W - 1), 0, @"%@ right edge clipped", latex);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@iosMathTests/MTInkClippingRenderTest.m` around lines 90 - 102, Update
testTallConstructsPixelAlignedAndContained so a NULL buffer from renderLabel is
reported as a test failure rather than bypassing the containment assertion;
replace the continue path with an explicit failure for the current latex, while
retaining the existing buffer checks and cleanup for successful renders.

1-5: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the new XCTest sources to the Xcode test target.

These files currently run only through Swift Package Manager, leaving Xcode-based test runs without the new coverage.

  • iosMathTests/MTInkClippingRenderTest.m#L1-L5: add this source to the applicable Xcode test target.
  • iosMathTests/MTMathUILabelSizingTest.m#L1-L9: add this source to the applicable Xcode test target.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@iosMathTests/MTInkClippingRenderTest.m` around lines 1 - 5, Add both
iosMathTests/MTInkClippingRenderTest.m (lines 1-5) and
iosMathTests/MTMathUILabelSizingTest.m (lines 1-9) to the applicable Xcode
XCTest target’s source compilation/build phase so they run in Xcode-based test
executions.
iosMathTests/MTMathUILabelSizingTest.m (1)

30-43: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Exercise pixel rounding at a non-unit scale.

The default unattached label may resolve to 1, so these assertions do not prove 2x/3x rounding. Use a test subclass that returns 2 or 3 from screenScale.

Proposed fix
+@interface MTScaledLabel : MTMathUILabel
+@end
+@implementation MTScaledLabel
+- (CGFloat)screenScale { return 2; }
+@end
+
 - (void)testSizeThatFitsInkAndGrid {
     for (NSString* latex in @[@"P", @"V", @"\\frac{1}{2}", @"\\int_0^1", @"x"]) {
-        MTMathUILabel* label = [self labelFor:latex];
+        MTMathUILabel* label = [[MTScaledLabel alloc] init];
+        label.latex = latex;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@iosMathTests/MTMathUILabelSizingTest.m` around lines 30 - 43, The
testSizeThatFitsInkAndGrid test currently uses the default label screenScale,
which may be 1 and does not exercise non-unit pixel rounding. Add or use a test
label subclass overriding screenScale to return 2 or 3, and have labelFor or
this test create that subclass while preserving the existing size and ink
assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@iosMathTests/MTInkClippingRenderTest.m`:
- Around line 90-102: Update testTallConstructsPixelAlignedAndContained so a
NULL buffer from renderLabel is reported as a test failure rather than bypassing
the containment assertion; replace the continue path with an explicit failure
for the current latex, while retaining the existing buffer checks and cleanup
for successful renders.
- Around line 1-5: Add both iosMathTests/MTInkClippingRenderTest.m (lines 1-5)
and iosMathTests/MTMathUILabelSizingTest.m (lines 1-9) to the applicable Xcode
XCTest target’s source compilation/build phase so they run in Xcode-based test
executions.

In `@iosMathTests/MTMathUILabelSizingTest.m`:
- Around line 30-43: The testSizeThatFitsInkAndGrid test currently uses the
default label screenScale, which may be 1 and does not exercise non-unit pixel
rounding. Add or use a test label subclass overriding screenScale to return 2 or
3, and have labelFor or this test create that subclass while preserving the
existing size and ink assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f5ed1e9a-fb27-474a-8986-29ed1551ba57

📥 Commits

Reviewing files that changed from the base of the PR and between e19e9cf and 4a08aee.

📒 Files selected for processing (4)
  • iosMath/render/MTMathUILabel.m
  • iosMath/render/internal/MTMathUILabelInternal.h
  • iosMathTests/MTInkClippingRenderTest.m
  • iosMathTests/MTMathUILabelSizingTest.m

kostub and others added 4 commits July 23, 2026 02:30
Route sizeThatFits:/intrinsicContentSize through displayList.inkWidth
instead of the pen-advance width, and round the reported size up to
the device-pixel grid via a new ceilToPixel/screenScale pair. Adds
iosMath/render/internal/MTMathUILabelInternal.h as the internal
test/compose surface for screenScale (displayList is already public,
so it is not redeclared there).

Also redeclares sizeThatFits: in the new internal header: it is
UIView public API on iOS but has no NSView equivalent declaration on
macOS, so external callers (including this PR's tests) could not see
it there without this forward declaration. No behavior change beyond
this file's scope.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FABHUFsMK8vRX4wzCANDRT
layoutSubviews' center/right textX branches previously keyed off the
pen-advance _displayList.width, so a trailing overhang glyph (e.g. the
serif foot of 'V') could clip past the frame's right edge even though
sizeThatFits: (item 16) already grew the frame to cover that ink.
Switch both branches to _displayList.inkWidth; left alignment and all
textY math are unchanged.

Also forward-declares layoutSubviews in MTMathUILabelInternal.h: like
sizeThatFits:, it's public UIView API on iOS but only implemented (not
declared) on macOS, where NSView has no equivalent — needed so the new
test can drive layout directly and cross-platform.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FABHUFsMK8vRX4wzCANDRT
Add lifecycle overrides so the label invalidates its intrinsic content
size when the window (and therefore the backing/screen scale) changes:
didMoveToWindow on iOS, viewDidMoveToWindow + viewDidChangeBackingProperties
on macOS. Without this, sizing computed before a scale is known (or before
the real backing scale becomes available) can go stale and never get
re-queried by Auto Layout.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FABHUFsMK8vRX4wzCANDRT
…ides

Cluster B previously asserted zero ink in the top border pixel row, which
flush ink-tight tall constructs (\int_0^1, \frac{1}{2}) legitimately violate.
Replace it with the real guarantee: the reported size is pixel-aligned and
trailing ink stays inside the right border. The fractional-origin hairline is
deferred per LLD 2.8.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FABHUFsMK8vRX4wzCANDRT
@kostub
kostub force-pushed the feature/ink-aware-width-pr2 branch from 4a08aee to ae23e64 Compare July 22, 2026 21:00
@kostub
kostub changed the base branch from feature/ink-aware-width-pr1 to master July 22, 2026 21:00
… Xcode wiring

Item 1 (CodeRabbit / review §3): make the tall-construct render's NULL-bitmap
path fail loudly instead of silently skipping containment. This surfaced that
`\quad` (zero-ink whitespace) never actually rendered, so it was swapped for
`\sqrt{2}` — a genuinely tall, inky construct that exercises containment.

Item 2 (review §1): wire MTInkClippingRenderTest.m and MTMathUILabelSizingTest.m
into iosMath.xcodeproj so CI's `xcodebuild test` step runs them, not just SPM.
(MacOSMath.xcodeproj has no test target; nothing to wire there.)

Item 3 (CodeRabbit / review §2): force known 2x/3x device-pixel scales via a
screenScale-overriding subclass so the pixel-grid rounding assertions have teeth
instead of being tautological at scale==1.

Verified: swift test 439/439; xcodebuild test of both classes 7/7 (TEST SUCCEEDED).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FABHUFsMK8vRX4wzCANDRT
@kostub

kostub commented Jul 22, 2026

Copy link
Copy Markdown
Owner Author

Addressed the review feedback in 9b0a411.

1. Xcode test-target wiring — Wired MTInkClippingRenderTest.m and MTMathUILabelSizingTest.m into iosMath.xcodeproj so the CI xcodebuild test step runs them, not just SPM. On current head MTInkWidthTest.m (PR 1) is already wired, so the gap was specific to this PR's two files. MacOSMath.xcodeproj has no test target, so nothing to wire there. (MTConcurrencyTest.m is also unwired but that's pre-existing/out of scope.)

2. Grid assertions tautological at scale == 1 — Added a screenScale-overriding subclass in both test files. testSizeThatFitsInkAndGrid now loops 1x/2x/3x and testTallConstructsPixelAlignedAndContained loops 2x/3x, so the device-pixel rounding is exercised where it can actually fail.

3. Silent NULL-bitmap skip — Replaced if (!buf) continue; with a loud XCTAssertTrue(buf != NULL, …). This surfaced that \quad (zero-ink whitespace) never actually rendered and was always silently skipped, so it was swapped for \sqrt{2} — a genuinely tall, inky construct that exercises containment.

Verified: swift test 439/439; both classes through the Xcode path 7/7 (TEST SUCCEEDED).

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@iosMathTests/MTMathUILabelSizingTest.m`:
- Around line 97-107: Update testScaleLifecycleInvalidates to simulate an actual
backing-scale transition by changing the label’s effective screenScale between
lifecycle callback invocations, then assert invalidateCount increases after the
scale change. Preserve the platform-specific callback paths while ensuring the
assertion verifies invalidation caused by the transition rather than the initial
callback.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0d28f07d-7133-42e6-acf6-a752513f9336

📥 Commits

Reviewing files that changed from the base of the PR and between 4a08aee and 9b0a411.

📒 Files selected for processing (5)
  • iosMath.xcodeproj/project.pbxproj
  • iosMath/render/MTMathUILabel.m
  • iosMath/render/internal/MTMathUILabelInternal.h
  • iosMathTests/MTInkClippingRenderTest.m
  • iosMathTests/MTMathUILabelSizingTest.m
🚧 Files skipped from review as they are similar to previous changes (3)
  • iosMath/render/internal/MTMathUILabelInternal.h
  • iosMathTests/MTInkClippingRenderTest.m
  • iosMath/render/MTMathUILabel.m

Comment thread iosMathTests/MTMathUILabelSizingTest.m Outdated
kostub and others added 2 commits July 23, 2026 03:29
testNoRightEdgeClip asserted "zero ink in the last frame column", which fails on
rasterizers where an unparented label's screenScale resolves to 1 (the headless
CI runner) — right-aligned ink sits flush on the zero-inset frame edge, landing
its antialiasing fringe exactly on the last whole-pixel column. That fringe is
contained, not clipped, so the assertion was a false positive (locally screenScale
resolved to 2, masking it).

Assert the real guarantee instead: no ink escapes PAST the frame's right edge.
renderLabel now renders into a right-padded bitmap and the tests check the
beyond-frame region is empty. This is immune to the flush-edge fringe yet keeps
teeth — verified a too-narrow (advance-based) frame leaves ink in 3 beyond-frame
columns, i.e. it still catches the original overhang-clip bug. screenScale is
forced (1 for the clip test; the tall test already forces 2x/3x) so the pixel grid
is deterministic across environments. Same beyond-frame check applied to the tall
constructs test.

Verified: swift test 441/441; xcodebuild test (iOS sim) TEST SUCCEEDED.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FABHUFsMK8vRX4wzCANDRT
Previously the test fired the lifecycle hook without changing screenScale, so it
only proved the hook invalidates in that setup — not that a backing-scale
transition re-queries the intrinsic size (CodeRabbit inline comment).

Now the spy carries a forced screenScale: query the intrinsic size at 1x, flip the
scale to 3x, fire the platform lifecycle hook, and assert (a) it invalidated and
(b) the re-queried size lands on the 3x grid and differs from the 1x answer
(V: 16.0 at 1x vs 15.667 at 3x). intrinsicContentSize is uncached and the hook
invalidates unconditionally, so this exercises the full scale-change path.

Verified: swift test 439/439; xcodebuild test (iOS sim) TEST SUCCEEDED.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FABHUFsMK8vRX4wzCANDRT
@kostub
kostub merged commit d25097f into master Jul 23, 2026
2 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