Repository navigation
Conversation
…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.
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:
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:roundLayoutResultsToPixelGridsubtracts 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.9998779296875instead of44for two lines oflineHeight: 22. Fix proposed in Yoga: Round node dimensions in double so far-off nodes keep their full size yoga#2037.RCTParagraphComponentView) and foronTextLayout(ParagraphShadowNode::layout). Two lines need 44.0, so TextKit treats the second line as not fitting, andRCTTextLayoutManagersetsNSLineBreakByClippingon the container whennumberOfLinesis 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:snapHeightToPixelGridapplied to the content size used foronTextLayoutand attachment layout (only on the non-prepared-layout path;rawContentSize()is already exact).RCTParagraphComponentView.mm:RCTParagraphTextFrameapplied 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/3and2028+2/3show only their first line and logAfter, with this change (Yoga unchanged, so the box is still 43.9998779296875 tall): every box shows both lines and
onTextLayoutreports 2 lines for all twelve. Screenshots below.Also checked that text with an explicit
heightsmaller 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).