Skip to content

Avoid re-laying out truncated iOS Text on every draw - #59215

Open
hryhoriiK97 wants to merge 2 commits into
react:mainfrom
hryhoriiK97:ios-text-skip-noop-ellipsis-recolor
Open

hryhoriiK97 wants to merge 2 commits into
react:mainfrom
hryhoriiK97:ios-text-skip-noop-ellipsis-recolor

Conversation

@hryhoriiK97

Copy link
Copy Markdown
Contributor

Summary:

-[RCTTextLayoutManager processTruncatedAttributedText:textContainer:layoutManager:] (ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm) runs on every measure and every draw of a <Text> with numberOfLines. When the last line is truncated, it gives the ellipsis the colors of the character before it.

Current behavior. For the truncated range it removes and re-adds NSForegroundColorAttributeName and NSBackgroundColorAttributeName unconditionally. Editing the text storage discards the layout TextKit just computed, so inside drawAttributedString: the paragraph is laid out a second time before its glyphs are drawn. In the common case the range already carries those colors (any single-color <Text numberOfLines={...}>), so the edit changes nothing but still costs a full layout.

With this change. Before editing, it checks with one longestEffectiveRange lookup whether the whole truncated range already carries the attribute of the preceding character, and leaves the storage untouched when it does. A truncated range with other colors is recolored as before.

Changelog:

[IOS] [CHANGED] - Truncated Text no longer lays out again on every draw when its ellipsis already has the right color

Test Plan:

  • node scripts/clang-format.js --check on the changed file passes.
  • RNTester built with xcodebuild in Release and run on a physical iPhone 15 Pro (iOS 26.6.1).
  • Same output.
    • Screenshots of a list of 1000 single-line truncated labels in bordered cards are byte-identical in the list area with and without the change.
    • Four truncated multi-color labels (a single-color tail after a differently colored start, alternating foreground colors, alternating background colors, and a color change shortly before the cut) are byte-identical with and without the change, and each ellipsis takes the color of the character before it.
    • In the RNTester Text examples (25 screens of scrolling), screens captured at the same scroll position are byte-identical. Screens that landed a few points apart differ only in the blur under the translucent tab bar and, by 1 level, at the edge of one translucent rounded View; no text pixel differs.
  • Measurement. The two arms are the same binary with the change switched by a launch argument, in the order before, after, after, before. Taps and swipes were driven by Argent on the physical iPhone. Timed: the total time in -[RCTParagraphTextView drawRect:], and the time from the end of a mount to the CoreAnimation commit, which contains the drawing. iPhone 15 Pro, Release:
RNTester FlatList "Basic" example, 16 flings down and 16 up per launch before this PR change
text drawing per draw (about 570 draws per launch) 983 µs 510 µs −48%
text drawing per launch 561 ms 293 ms −48%
RNTester Playground, 1000 single-line truncated labels, 10 mounts per arm before this PR change
text drawing per mount 420.1 ms 115.8 ms −72%
end of mount to CoreAnimation commit 480.5 ms 173.5 ms −64%

🤖 Generated with Claude Code

processTruncatedAttributedText removed and re-added the color attributes of
the truncated range on every measure and draw. The edit discards the layout
TextKit just computed, so the paragraph was laid out again before drawing,
even when the range already had the right colors. Skip the edit when the
whole range already carries the attribute of the preceding character.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 20, 2026
@facebook-github-tools facebook-github-tools Bot added p: Software Mansion Partner: Software Mansion Partner labels Oct 20, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Oct 20, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Software Mansion Partner: Software Mansion Partner Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant