Skip to content

Commit 921bbb6

Browse files
sammy-SCkelset
authored andcommitted
Correct offset when drawing text to TextStorage coordinate system. (facebook#36771)
Summary: Pull Request resolved: facebook#36771 Changelog: [internal] Previously, when `NSTextStorage` was cached, we were not accounting for case where text which was aligned to centre or left, was used to size its container. The result was that it was painted outside of its container, therefore invisible. To fix this, we adjust the offset to make sure text is painted correctly. This bug only happens if: - Text is not aligned to left in right to left writing system. - The canvas where text is drawn is not stretched to full width of its parent. - The offset needs to be large enough for this to matter, otherwise the text is just slightly off. - Because of the caching mechanism, it had to be a piece of text that was rendered before. Otherwise it would work. This complexity is worth the trouble to avoid invalidation of layout inside NSTextContainer, which is expensive. Reviewed By: cipolleschi Differential Revision: D44624085 fbshipit-source-id: 1bb8ef88933a49b478a2606dba6bf16b4e728b2b
1 parent 6d6b6a8 commit 921bbb6

File tree

1 file changed

+22
-4
lines changed
  • packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager

1 file changed

+22
-4
lines changed

packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@ - (TextMeasurement)measureNSAttributedString:(NSAttributedString *)attributedStr
5252
textStorage = [self _textStorageForNSAttributesString:attributedString
5353
paragraphAttributes:paragraphAttributes
5454
size:maximumSize];
55-
} else {
56-
textStorage.layoutManagers.firstObject.textContainers.firstObject.size = maximumSize;
5755
}
5856

5957
return [self _measureTextStorage:textStorage];
@@ -79,13 +77,33 @@ - (void)drawAttributedString:(AttributedString)attributedString
7977
frame:(CGRect)frame
8078
textStorage:(NSTextStorage *_Nullable)textStorage
8179
{
80+
BOOL createdStorageForFrame = NO;
81+
8282
if (!textStorage) {
8383
textStorage = [self textStorageForAttributesString:attributedString
8484
paragraphAttributes:paragraphAttributes
8585
size:frame.size];
86+
createdStorageForFrame = YES;
8687
}
88+
8789
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
8890
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
91+
CGPoint origin = frame.origin;
92+
93+
if (!createdStorageForFrame) {
94+
CGRect rect = [layoutManager usedRectForTextContainer:textContainer];
95+
static auto threshold = 1.0 / RCTScreenScale() + 0.01; // Size of a pixel plus some small threshold.
96+
97+
// `rect`'s width is stored in double precesion.
98+
// `frame`'s width is also in double precesion but was stored as float in Yoga previously, precesion was lost.
99+
if (std::abs(RCTCeilPixelValue(rect.size.width) - frame.size.width) < threshold) {
100+
// `textStorage` passed to this method was used to calculate size of frame. If that's the case, it's
101+
// width is the same as frame's width. Origin must be adjusted, otherwise glyhps will be painted in wrong
102+
// place.
103+
// We could create new `NSTextStorage` for the specific frame, but that is expensive.
104+
origin.x -= RCTCeilPixelValue(rect.origin.x);
105+
}
106+
}
89107

90108
#if TARGET_OS_MACCATALYST
91109
CGContextRef context = UIGraphicsGetCurrentContext();
@@ -94,8 +112,8 @@ - (void)drawAttributedString:(AttributedString)attributedString
94112
#endif
95113

96114
NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
97-
[layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:frame.origin];
98-
[layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:frame.origin];
115+
[layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:origin];
116+
[layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:origin];
99117

100118
#if TARGET_OS_MACCATALYST
101119
CGContextRestoreGState(context);

0 commit comments

Comments
 (0)