diff --git a/packages/react-native/Libraries/Text/Text/NSTextStorage+FontScaling.m b/packages/react-native/Libraries/Text/Text/NSTextStorage+FontScaling.m index c92b2e94c6a1..83e5f82076e2 100644 --- a/packages/react-native/Libraries/Text/Text/NSTextStorage+FontScaling.m +++ b/packages/react-native/Libraries/Text/Text/NSTextStorage+FontScaling.m @@ -7,6 +7,8 @@ #import "NSTextStorage+FontScaling.h" +#import + typedef NS_OPTIONS(NSInteger, RCTTextSizeComparisonOptions) { RCTTextSizeComparisonSmaller = 1 << 0, RCTTextSizeComparisonLarger = 1 << 1, @@ -87,8 +89,10 @@ - (RCTTextSizeComparisonOptions)compareToSize:(CGSize)size thresholdRatio:(CGFlo CGSize measuredSize = [layoutManager usedRectForTextContainer:textContainer].size; - // Does it fit the size? - BOOL fitsSize = size.width >= measuredSize.width && size.height >= measuredSize.height; + // Does it fit the size? Yoga's pixel-grid rounding can leave the height a float ULP short of + // the line height (#52642), so a shortfall smaller than one physical pixel still counts as fitting. + CGFloat heightTolerance = 1.0 / RCTScreenScale(); + BOOL fitsSize = size.width >= measuredSize.width && size.height + heightTolerance > measuredSize.height; CGSize thresholdSize = (CGSize){ size.width * thresholdRatio, diff --git a/packages/rn-tester/js/examples/Text/TextExample.ios.js b/packages/rn-tester/js/examples/Text/TextExample.ios.js index e367974e3da2..b0ded7dd8cfb 100644 --- a/packages/rn-tester/js/examples/Text/TextExample.ios.js +++ b/packages/rn-tester/js/examples/Text/TextExample.ios.js @@ -278,6 +278,39 @@ class AdjustingFontSize extends React.Component< } } +function FontSizeToFitWithLineHeightRow({index}: {index: number}) { + const [height, setHeight] = React.useState(null); + return ( + + setHeight(e.nativeEvent.layout.height)} + style={{fontSize: 12, lineHeight: 20, width: 200}}> + {'Should not shrink ' + (index + 1)} + + + {height == null ? '' : String(height)} + + + ); +} + +// Rows after a 0.5pt separator: on a 3x screen some get a frame a float ULP short of lineHeight (#52642). +function FontSizeToFitWithLineHeightExample(): React.Node { + const rows = []; + for (let i = 0; i < 10; i++) { + rows.push(); + } + return ( + + + {rows} + + ); +} + class TextBaseLineLayoutExample extends React.Component<{}, unknown> { render(): React.Node { const texts = []; @@ -1424,6 +1457,13 @@ const examples = [ return ; }, }, + { + title: 'Font Size Adjustment with lineHeight', + name: 'adjustsFontSizeToFitLineHeight', + render: function (): React.Node { + return ; + }, + }, { title: 'Text Align with RTL', name: 'textAlign',