Skip to content

Text: keep the last line when Yoga's pixel-grid rounding leaves the box a float step short - #58974

Open
ybelakov wants to merge 1 commit into
react:mainfrom
ybelakov:fix/text-last-line-pixel-grid
Open

ybelakov wants to merge 1 commit into
react:mainfrom
ybelakov:fix/text-last-line-pixel-grid

Conversation

@ybelakov

@ybelakov ybelakov commented Oct 9, 2026

Copy link
Copy Markdown

Summary:

Fixes #58970.

A wrapped <Text> whose box crosses y = 2048 in the scroll content on a 3x iOS screen draws one line short: the last line is laid out as a clipped single line. Two things combine:

  1. Yoga rounds the frame to the pixel grid, but roundLayoutResultsToPixelGrid subtracts the two rounded edges as floats. With the top below 2048 and the bottom above, the edges are quantized with different steps and the height comes out one float step short: 43.9998779296875 instead of 44 for two lines of lineHeight: 22. Fix proposed in Yoga: Round node dimensions in double so far-off nodes keep their full size yoga#2037.
  2. The paragraph hands that height straight to TextKit, both for drawing (RCTParagraphComponentView) and for onTextLayout (ParagraphShadowNode::layout). Two lines need 44.0, so TextKit treats the second line as not fitting, and RCTTextLayoutManager sets NSLineBreakByClipping on the container when numberOfLines is unset, so the last visible line is laid out without wrapping.

This change hardens the React Native side so that a height a hair off the pixel grid can never drop a line, whether or not the Yoga fix lands: before laying out, drawing or measuring lines, the paragraph's height is snapped back onto the grid when it is within 0.01px of it, and rounded up otherwise. A container is never made smaller, so nothing that fits today stops fitting. Heights already on the grid are unchanged.

  • ParagraphShadowNode.cpp: snapHeightToPixelGrid applied to the content size used for onTextLayout and attachment layout (only on the non-prepared-layout path; rawContentSize() is already exact).
  • RCTParagraphComponentView.mm: RCTParagraphTextFrame applied to the frame used for drawing, hit testing and accessibility.

Changelog:

[IOS] [FIXED] - Text no longer drops its last line when Yoga's pixel-grid rounding leaves its box a float step short (boxes crossing y = 2048 on 3x screens)

Test Plan:

Reproducer: #58972 (RNTester playground with 12 two-line texts around y = 2048).

Before, on an iPhone 16 Pro simulator with React Native built from source: the boxes at 2028+1/3 and 2028+2/3 show only their first line and log

box top=2028.3333333333333: 1 line(s)
box top=2028.3333333333333: height 43.9998779296875

After, with this change (Yoga unchanged, so the box is still 43.9998779296875 tall): every box shows both lines and onTextLayout reports 2 lines for all twelve. Screenshots below.

Also checked that text with an explicit height smaller than its content still clips as before (the snap only moves a height that is within 0.01px of the grid, and never shrinks one).

…ox a float step short

Yoga rounds a node's frame to the pixel grid but subtracts the rounded edges
as floats, so far from the origin a paragraph's height can come out a float
step under the grid value it was measured at (43.9998 for two lines of 22 at
y = 2048 on a 3x screen). Given that height, TextKit treats the last line as
not fitting and lays it out clipped. Snap such a height back onto the grid
before drawing and before measuring lines; anything else rounds up, so a
container is never made smaller.

Fixes react#58970.
@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 9, 2026
@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 9, 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. 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.

iOS: Text drops its last line when its box crosses y = 2048 on a 3x screen (Yoga float rounding)

1 participant