diff --git a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm index 35aa4119b81..368c3341055 100644 --- a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm +++ b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm @@ -52,8 +52,6 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi textStorage = [self _textStorageForNSAttributesString:attributedString paragraphAttributes:paragraphAttributes size:maximumSize]; - } else { - textStorage.layoutManagers.firstObject.textContainers.firstObject.size = maximumSize; } return [self _measureTextStorage:textStorage]; @@ -79,13 +77,33 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi frame:(CGRect)frame textStorage:(NSTextStorage *_Nullable)textStorage { + BOOL createdStorageForFrame = NO; + if (!textStorage) { textStorage = [self textStorageForAttributesString:attributedString paragraphAttributes:paragraphAttributes size:frame.size]; + createdStorageForFrame = YES; } + NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject; NSTextContainer *textContainer = layoutManager.textContainers.firstObject; + CGPoint origin = frame.origin; + + if (!createdStorageForFrame) { + CGRect rect = [layoutManager usedRectForTextContainer:textContainer]; + static auto threshold = 1.0 / RCTScreenScale() + 0.01; // Size of a pixel plus some small threshold. + + // `rect`'s width is stored in double precesion. + // `frame`'s width is also in double precesion but was stored as float in Yoga previously, precesion was lost. + if (std::abs(RCTCeilPixelValue(rect.size.width) - frame.size.width) < threshold) { + // `textStorage` passed to this method was used to calculate size of frame. If that's the case, it's + // width is the same as frame's width. Origin must be adjusted, otherwise glyhps will be painted in wrong + // place. + // We could create new `NSTextStorage` for the specific frame, but that is expensive. + origin.x -= RCTCeilPixelValue(rect.origin.x); + } + } #if TARGET_OS_MACCATALYST CGContextRef context = UIGraphicsGetCurrentContext(); @@ -94,8 +112,8 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi #endif NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer]; - [layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:frame.origin]; - [layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:frame.origin]; + [layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:origin]; + [layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:origin]; #if TARGET_OS_MACCATALYST CGContextRestoreGState(context);