Skip to content

Commit 22b7063

Browse files
committed
chore(fabric, text): Refactor macOS implementation to use contentView
1 parent c5b4e07 commit 22b7063

File tree

1 file changed

+42
-64
lines changed

1 file changed

+42
-64
lines changed

packages/react-native/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm

+42-64
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,22 @@
3333
// ParagraphTextView is an auxiliary view we set as contentView so the drawing
3434
// can happen on top of the layers manipulated by RCTViewComponentView (the parent view)
3535
@interface RCTParagraphTextView : RCTUIView // [macOS]
36+
#else // [macOS
37+
// On macOS, we also defer drawing to an NSTextView,
38+
// in order to get more native behaviors like text selection.
39+
@interface RCTParagraphTextView : NSTextView // [macOS]
40+
#endif // macOS]
3641

3742
@property (nonatomic) ParagraphShadowNode::ConcreteState::Shared state;
3843
@property (nonatomic) ParagraphAttributes paragraphAttributes;
3944
@property (nonatomic) LayoutMetrics layoutMetrics;
4045

46+
#if TARGET_OS_OSX // [macOS]
47+
/// UIKit compatibility shim that simply calls `[self setNeedsDisplay:YES]`
48+
- (void)setNeedsDisplay;
49+
#endif
50+
4151
@end
42-
#else // [macOS
43-
#if TARGET_OS_OSX // [macOS
44-
// On macOS, we defer drawing to an NSTextView rather than a plan NSView, in order
45-
// to get more native behaviors like text selection. We make sure this NSTextView
46-
// does not take focus.
47-
@interface RCTParagraphComponentUnfocusableTextView : NSTextView
48-
@end
49-
#endif // macOS]
5052

5153
#if !TARGET_OS_OSX // [macOS]
5254
@interface RCTParagraphComponentView () <UIEditMenuInteractionDelegate>
@@ -62,10 +64,8 @@ @implementation RCTParagraphComponentView {
6264
RCTParagraphComponentAccessibilityProvider *_accessibilityProvider;
6365
#if !TARGET_OS_OSX // [macOS]
6466
UILongPressGestureRecognizer *_longPressGestureRecognizer;
65-
RCTParagraphTextView *_textView;
66-
#else // [macOS
67-
RCTParagraphComponentUnfocusableTextView *_textView;
6867
#endif // macOS]
68+
RCTParagraphTextView *_textView;
6969
}
7070

7171
- (instancetype)initWithFrame:(CGRect)frame
@@ -77,15 +77,14 @@ - (instancetype)initWithFrame:(CGRect)frame
7777
self.opaque = NO;
7878
_textView = [RCTParagraphTextView new];
7979
_textView.backgroundColor = RCTUIColor.clearColor; // [macOS]
80-
self.contentView = _textView;
8180
#else // [macOS
8281
// Make the RCTParagraphComponentView accessible and available in the a11y hierarchy.
8382
self.accessibilityElement = YES;
8483
self.accessibilityRole = NSAccessibilityStaticTextRole;
8584
// Fix blurry text on non-retina displays.
8685
self.canDrawSubviewsIntoLayer = YES;
8786
// The NSTextView is responsible for drawing text and managing selection.
88-
_textView = [[RCTParagraphComponentUnfocusableTextView alloc] initWithFrame:self.bounds];
87+
_textView = [[RCTParagraphTextView alloc] initWithFrame:self.bounds];
8988
// The RCTParagraphComponentUnfocusableTextView is only used for rendering and should not appear in the a11y hierarchy.
9089
_textView.accessibilityElement = NO;
9190
_textView.usesFontPanel = NO;
@@ -98,6 +97,7 @@ - (instancetype)initWithFrame:(CGRect)frame
9897
self.contentView = _textView;
9998
self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
10099
#endif // macOS]
100+
self.contentView = _textView;
101101
}
102102

103103
return self;
@@ -164,12 +164,9 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &
164164
- (void)updateState:(const State::Shared &)state oldState:(const State::Shared &)oldState
165165
{
166166
_state = std::static_pointer_cast<const ParagraphShadowNode::ConcreteState>(state);
167-
#if !TARGET_OS_OSX // [macOS]
168167
_textView.state = _state;
169168
[_textView setNeedsDisplay];
170169
[self setNeedsLayout];
171-
[self _updateTextView];
172-
#endif // macOS]
173170
}
174171

175172
- (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
@@ -178,53 +175,10 @@ - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
178175
// Using stored `_layoutMetrics` as `oldLayoutMetrics` here to avoid
179176
// re-applying individual sub-values which weren't changed.
180177
[super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:_layoutMetrics];
181-
#if !TARGET_OS_OSX // [macOS]
182178
_textView.layoutMetrics = _layoutMetrics;
183179
[_textView setNeedsDisplay];
184180
[self setNeedsLayout];
185-
#else // [macOS
186-
[self _updateTextView];
187-
#endif // macOS]
188-
}
189-
190-
#if TARGET_OS_OSX // [macOS
191-
- (void)_updateTextView
192-
{
193-
if (!_state) {
194-
return;
195-
}
196-
197-
auto textLayoutManager = _state->getData().paragraphLayoutManager.getTextLayoutManager();
198-
199-
if (!textLayoutManager) {
200-
return;
201-
}
202-
203-
RCTTextLayoutManager *nativeTextLayoutManager =
204-
(RCTTextLayoutManager *)unwrapManagedObject(textLayoutManager->getNativeTextLayoutManager());
205-
206-
CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
207-
208-
NSTextStorage *textStorage = [nativeTextLayoutManager getTextStorageForAttributedString:_state->getData().attributedString paragraphAttributes:_paragraphAttributes frame:frame];
209-
210-
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
211-
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
212-
213-
[_textView replaceTextContainer:textContainer];
214-
215-
NSArray<NSLayoutManager *> *managers = [[textStorage layoutManagers] copy];
216-
for (NSLayoutManager *manager in managers) {
217-
[textStorage removeLayoutManager:manager];
218-
}
219-
220-
_textView.minSize = frame.size;
221-
_textView.maxSize = frame.size;
222-
_textView.frame = frame;
223-
_textView.textStorage.attributedString = textStorage;
224-
225-
[self setNeedsDisplay];
226181
}
227-
#endif // macOS]
228182

229183
- (void)prepareForRecycle
230184
{
@@ -427,11 +381,13 @@ - (void)copy:(id)sender
427381
return RCTParagraphComponentView.class;
428382
}
429383

430-
#if !TARGET_OS_OSX // [macOS]
431384
@implementation RCTParagraphTextView {
385+
#if !TARGET_OS_OSX // [macOS]
432386
CAShapeLayer *_highlightLayer;
387+
#endif // macOS]
433388
}
434389

390+
435391
- (void)drawRect:(CGRect)rect
436392
{
437393
if (!_state) {
@@ -449,6 +405,7 @@ - (void)drawRect:(CGRect)rect
449405

450406
CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
451407

408+
#if !TARGET_OS_OSX // [macOS]
452409
[nativeTextLayoutManager drawAttributedString:_state->getData().attributedString
453410
paragraphAttributes:_paragraphAttributes
454411
frame:frame
@@ -466,12 +423,33 @@ - (void)drawRect:(CGRect)rect
466423
self->_highlightLayer = nil;
467424
}
468425
}];
426+
#else // [macOS
427+
NSTextStorage *textStorage = [nativeTextLayoutManager getTextStorageForAttributedString:_state->getData().attributedString paragraphAttributes:_paragraphAttributes size:frame.size];
428+
429+
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
430+
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
431+
432+
[self replaceTextContainer:textContainer];
433+
434+
NSArray<NSLayoutManager *> *managers = [[textStorage layoutManagers] copy];
435+
for (NSLayoutManager *manager in managers) {
436+
[textStorage removeLayoutManager:manager];
437+
}
438+
439+
self.minSize = frame.size;
440+
self.maxSize = frame.size;
441+
self.frame = frame;
442+
[[self textStorage] setAttributedString:textStorage];
443+
444+
[super drawRect:rect];
445+
#endif
469446
}
470447

471-
@end
472-
#else // [macOS
473448
#if TARGET_OS_OSX // [macOS
474-
@implementation RCTParagraphComponentUnfocusableTextView
449+
- (void)setNeedsDisplay
450+
{
451+
[self setNeedsDisplay:YES];
452+
}
475453

476454
- (BOOL)canBecomeKeyView
477455
{
@@ -487,6 +465,6 @@ - (BOOL)resignFirstResponder
487465

488466
return [super resignFirstResponder];
489467
}
468+
#endif // macOS]
490469

491470
@end
492-
#endif // macOS]

0 commit comments

Comments
 (0)