Repository navigation
Share iOS text measurements that differ only in unused constraints - #59527
Open
hryhoriiK97 wants to merge 1 commit into
Open
hryhoriiK97 wants to merge 1 commit into
hryhoriiK97 wants to merge 1 commit into
Conversation
The native iOS measurement depends only on the maximum width, and the result is clamped to the full constraints after the cache, so the minimum size and the maximum height are left out of the cache key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Visual regression1 visual difference(s) at android: no capture ios
|
Contributor
Author
|
I checked the iOS screenshot for |
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.



Summary:
On iOS,
TextLayoutManager::measurelooks up each Text measurement inTextMeasureCache, keyed by the attributed string, the paragraph attributes and the fullLayoutConstraints.Current behavior. The native measurement (
-[RCTTextLayoutManager measureNSAttributedString:…]) only reads the maximum width: it lays the text out in a container of{maximumSize.width, CGFLOAT_MAX}. The minimum size and the maximum height don't change the result, andmeasureclamps the result to the full constraints after the cache. But they are part of the cache key, so measurements that differ only in them miss the cache and lay the same text out again with TextKit.This happens when Yoga measures a Text more than once in a layout pass. For example, a Text in a wrapping row is measured twice with an at-most width and once with an exact width. The two at-most measurements have the same maximum width but different constraints otherwise, so both miss for new text.
With this change. The cache key leaves out the minimum size and the maximum height. Measurements that only differ in them share an entry. The native measurement still receives the original constraints, and the clamp after the cache still uses them, so every caller gets the same size as before.
Android already ignores the maximum height for the same reason (
platform/android/.../TextLayoutManager.cpp: "We assume max height will have no effect on measurement, so we override it … to enable cache reuse"). On iOS the minimum size can be left out too, because the native measurement never reads it.Changelog:
[IOS] [CHANGED] - Text measurements that differ only in the minimum size or maximum height share a cache entry
Test Plan:
xcodebuildin Release and run on a physical iPhone 15 Pro (iOS 26.6.1), frommainat 4420343.<Text>labels in a wrapping row (flexDirection: 'row', flexWrap: 'wrap'), 10 rounds per run, and updating the text of the same 1,000 labels 30 times per run. Time fromsetStateto the layout effect, which includes React rendering, layout and text measurement. "Before" and the first "this PR" runs are the same binary with the cache key switched by a launch argument (local only, not part of this PR); the last "this PR" run of each row is a build of exactly this change. The presses were driven by Argent on the physical iPhone. Medians per run:clang-format, which needsdotslash.🤖 Generated with Claude Code