react-native 0.72.0-rc.0 → 0.72.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/Libraries/Components/View/ReactNativeStyleAttributes.js +0 -7
  2. package/Libraries/Core/ReactNativeVersion.js +1 -1
  3. package/Libraries/Core/ReactNativeVersionCheck.js +5 -1
  4. package/Libraries/NativeComponent/BaseViewConfig.android.js +0 -8
  5. package/Libraries/NativeComponent/BaseViewConfig.ios.js +0 -8
  6. package/Libraries/ReactNative/UIManager.js +27 -1
  7. package/Libraries/Renderer/implementations/ReactFabric-dev.js +26 -3
  8. package/Libraries/Renderer/implementations/ReactFabric-prod.js +13 -1
  9. package/Libraries/Renderer/implementations/ReactFabric-profiling.js +13 -1
  10. package/Libraries/StyleSheet/StyleSheetTypes.d.ts +0 -7
  11. package/Libraries/StyleSheet/StyleSheetTypes.js +0 -74
  12. package/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m +3 -3
  13. package/React/Base/RCTVersion.m +1 -1
  14. package/React/CoreModules/RCTDevMenu.mm +3 -3
  15. package/React/Fabric/Mounting/ComponentViews/LegacyViewManagerInterop/RCTLegacyViewManagerInteropCoordinatorAdapter.mm +1 -1
  16. package/ReactAndroid/gradle.properties +1 -1
  17. package/ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.java +40 -1
  18. package/ReactAndroid/src/main/java/com/facebook/react/ReactFragment.java +22 -7
  19. package/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java +10 -0
  20. package/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java +29 -0
  21. package/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManagerListener.java +25 -2
  22. package/ReactAndroid/src/main/java/com/facebook/react/bridge/interop/InteropModuleRegistry.java +56 -0
  23. package/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java +11 -0
  24. package/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultNewArchitectureEntryPoint.kt +1 -0
  25. package/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactActivityDelegate.kt +4 -0
  26. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.java +26 -8
  27. package/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +21 -0
  28. package/ReactAndroid/src/main/java/com/facebook/react/fabric/interop/InteropEvent.java +41 -0
  29. package/ReactAndroid/src/main/java/com/facebook/react/fabric/interop/InteropEventEmitter.java +65 -0
  30. package/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountItemDispatcher.java +9 -0
  31. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java +1 -1
  32. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/ThemedReactContext.java +1 -0
  33. package/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java +32 -0
  34. package/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.java +19 -0
  35. package/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomLetterSpacingSpan.java +4 -0
  36. package/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomStyleSpan.java +4 -0
  37. package/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java +1 -5
  38. package/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +190 -134
  39. package/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +23 -10
  40. package/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundManager.java +5 -0
  41. package/ReactAndroid/src/main/jni/react/fabric/Binding.cpp +3 -0
  42. package/ReactCommon/React-rncore.podspec +12 -4
  43. package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
  44. package/ReactCommon/react/config/ReactNativeConfig.cpp +3 -0
  45. package/ReactCommon/react/renderer/components/legacyviewmanagerinterop/RCTLegacyViewManagerInteropCoordinator.h +4 -1
  46. package/ReactCommon/react/renderer/components/legacyviewmanagerinterop/RCTLegacyViewManagerInteropCoordinator.mm +49 -2
  47. package/ReactCommon/react/renderer/components/text/ParagraphLayoutManager.cpp +30 -5
  48. package/ReactCommon/react/renderer/components/text/ParagraphLayoutManager.h +12 -0
  49. package/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp +0 -21
  50. package/ReactCommon/react/renderer/components/view/YogaStylableProps.cpp +0 -49
  51. package/ReactCommon/react/renderer/components/view/YogaStylableProps.h +0 -9
  52. package/ReactCommon/react/renderer/core/CoreFeatures.cpp +1 -0
  53. package/ReactCommon/react/renderer/core/CoreFeatures.h +5 -0
  54. package/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.cpp +5 -1
  55. package/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm +112 -83
  56. package/build.gradle.kts +17 -0
  57. package/gradle.properties +1 -0
  58. package/package.json +8 -8
  59. package/scripts/cocoapods/__tests__/codegen_utils-test.rb +9 -1
  60. package/scripts/cocoapods/__tests__/jsengine-test.rb +6 -2
  61. package/scripts/cocoapods/__tests__/test_utils/podSpy.rb +2 -1
  62. package/scripts/cocoapods/codegen_utils.rb +1 -1
  63. package/scripts/cocoapods/jsengine.rb +6 -1
  64. package/sdks/hermesc/linux64-bin/hermesc +0 -0
  65. package/sdks/hermesc/osx-bin/hermesc +0 -0
  66. package/sdks/hermesc/win64-bin/hermesc.exe +0 -0
  67. package/settings.gradle.kts +30 -0
  68. package/template/android/app/build.gradle +7 -2
  69. package/template/metro.config.js +7 -13
  70. package/template/package.json +5 -3
  71. package/types/index.d.ts +4 -0
@@ -100,13 +100,23 @@ using namespace facebook::react;
100
100
  return RCTDropReactPrefixes(_componentData.name);
101
101
  }
102
102
 
103
- - (void)handleCommand:(NSString *)commandName args:(NSArray *)args reactTag:(NSInteger)tag
103
+ - (void)handleCommand:(NSString *)commandName
104
+ args:(NSArray *)args
105
+ reactTag:(NSInteger)tag
106
+ paperView:(nonnull UIView *)paperView
104
107
  {
105
108
  Class managerClass = _componentData.managerClass;
106
109
  [self _lookupModuleMethodsIfNecessary];
107
110
  RCTModuleData *moduleData = [_bridge.batchedBridge moduleDataForName:RCTBridgeModuleNameForClass(managerClass)];
108
111
  id<RCTBridgeMethod> method;
109
- if ([commandName isKindOfClass:[NSNumber class]]) {
112
+
113
+ // We can't use `[NSString intValue]` as "0" is a valid command,
114
+ // but also a falsy value. [NSNumberFormatter numberFromString] returns a
115
+ // `NSNumber *` which is NULL when it's to be NULL
116
+ // and it points to 0 when the string is @"0" (not a falsy value).
117
+ NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
118
+
119
+ if ([commandName isKindOfClass:[NSNumber class]] || [formatter numberFromString:commandName] != NULL) {
110
120
  method = moduleData ? moduleData.methods[[commandName intValue]] : _moduleMethods[[commandName intValue]];
111
121
  } else if ([commandName isKindOfClass:[NSString class]]) {
112
122
  method = moduleData ? moduleData.methodsByName[commandName] : _moduleMethodsByName[commandName];
@@ -121,12 +131,14 @@ using namespace facebook::react;
121
131
  NSArray *newArgs = [@[ [NSNumber numberWithInteger:tag] ] arrayByAddingObjectsFromArray:args];
122
132
 
123
133
  if (_bridge) {
134
+ [self _addViewToRegistry:paperView withTag:tag];
124
135
  [_bridge.batchedBridge
125
136
  dispatchBlock:^{
126
137
  [method invokeWithBridge:self->_bridge module:self->_componentData.manager arguments:newArgs];
127
138
  [self->_bridge.uiManager setNeedsLayout];
128
139
  }
129
140
  queue:RCTGetUIManagerQueue()];
141
+ [self _removeViewFromRegistryWithTag:tag];
130
142
  } else {
131
143
  // TODO T86826778 - Figure out which queue this should be dispatched to.
132
144
  [method invokeWithBridge:nil module:self->_componentData.manager arguments:newArgs];
@@ -134,6 +146,41 @@ using namespace facebook::react;
134
146
  }
135
147
 
136
148
  #pragma mark - Private
149
+ - (void)_addViewToRegistry:(UIView *)view withTag:(NSInteger)tag
150
+ {
151
+ [self _addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
152
+ if ([viewRegistry objectForKey:@(tag)] != NULL) {
153
+ return;
154
+ }
155
+ NSMutableDictionary<NSNumber *, UIView *> *mutableViewRegistry =
156
+ (NSMutableDictionary<NSNumber *, UIView *> *)viewRegistry;
157
+ [mutableViewRegistry setObject:view forKey:@(tag)];
158
+ }];
159
+ }
160
+
161
+ - (void)_removeViewFromRegistryWithTag:(NSInteger)tag
162
+ {
163
+ [self _addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
164
+ if ([viewRegistry objectForKey:@(tag)] == NULL) {
165
+ return;
166
+ }
167
+
168
+ NSMutableDictionary<NSNumber *, UIView *> *mutableViewRegistry =
169
+ (NSMutableDictionary<NSNumber *, UIView *> *)viewRegistry;
170
+ [mutableViewRegistry removeObjectForKey:@(tag)];
171
+ }];
172
+ }
173
+
174
+ - (void)_addUIBlock:(RCTViewManagerUIBlock)block
175
+ {
176
+ __weak __typeof__(self) weakSelf = self;
177
+ [_bridge.batchedBridge
178
+ dispatchBlock:^{
179
+ __typeof__(self) strongSelf = weakSelf;
180
+ [strongSelf->_bridge.uiManager addUIBlock:block];
181
+ }
182
+ queue:RCTGetUIManagerQueue()];
183
+ }
137
184
 
138
185
  // This is copy-pasta from RCTModuleData.
139
186
  - (void)_lookupModuleMethodsIfNecessary
@@ -15,6 +15,19 @@ TextMeasurement ParagraphLayoutManager::measure(
15
15
  AttributedString const &attributedString,
16
16
  ParagraphAttributes const &paragraphAttributes,
17
17
  LayoutConstraints layoutConstraints) const {
18
+ bool cacheLastTextMeasurement = CoreFeatures::cacheLastTextMeasurement;
19
+ if (cacheLastTextMeasurement &&
20
+ (layoutConstraints.maximumSize.width == availableWidth_ ||
21
+ layoutConstraints.maximumSize.width ==
22
+ cachedTextMeasurement_.size.width)) {
23
+ /* Yoga has requested measurement for this size before. Let's use cached
24
+ * value. `TextLayoutManager` might not have cached this because it could be
25
+ * using different width to generate cache key. This happens because Yoga
26
+ * switches between available width and exact width but since we already
27
+ * know exact width, it is wasteful to calculate it again.
28
+ */
29
+ return cachedTextMeasurement_;
30
+ }
18
31
  if (CoreFeatures::cacheNSTextStorage) {
19
32
  size_t newHash = folly::hash::hash_combine(
20
33
  0,
@@ -28,11 +41,23 @@ TextMeasurement ParagraphLayoutManager::measure(
28
41
  }
29
42
  }
30
43
 
31
- return textLayoutManager_->measure(
32
- AttributedStringBox(attributedString),
33
- paragraphAttributes,
34
- layoutConstraints,
35
- hostTextStorage_);
44
+ if (cacheLastTextMeasurement) {
45
+ cachedTextMeasurement_ = textLayoutManager_->measure(
46
+ AttributedStringBox(attributedString),
47
+ paragraphAttributes,
48
+ layoutConstraints,
49
+ hostTextStorage_);
50
+
51
+ availableWidth_ = layoutConstraints.maximumSize.width;
52
+
53
+ return cachedTextMeasurement_;
54
+ } else {
55
+ return textLayoutManager_->measure(
56
+ AttributedStringBox(attributedString),
57
+ paragraphAttributes,
58
+ layoutConstraints,
59
+ hostTextStorage_);
60
+ }
36
61
  }
37
62
 
38
63
  LinesMeasurements ParagraphLayoutManager::measureLines(
@@ -54,6 +54,18 @@ class ParagraphLayoutManager {
54
54
  std::shared_ptr<TextLayoutManager const> mutable textLayoutManager_{};
55
55
  std::shared_ptr<void> mutable hostTextStorage_{};
56
56
 
57
+ /* The width Yoga set as maximum width.
58
+ * Yoga sometimes calls measure twice with two
59
+ * different maximum width. One if available space.
60
+ * The other one is exact space needed for the string.
61
+ * This happens when node is dirtied but its size is not affected.
62
+ * To deal with this inefficiency, we cache `TextMeasurement` for each
63
+ * `ParagraphShadowNode`. If Yoga tries to re-measure with available width
64
+ * or exact width, we provide it with the cached value.
65
+ */
66
+ Float mutable availableWidth_{};
67
+ TextMeasurement mutable cachedTextMeasurement_{};
68
+
57
69
  size_t mutable hash_{};
58
70
  };
59
71
  } // namespace facebook::react
@@ -369,21 +369,6 @@ void YogaLayoutableShadowNode::updateYogaProps() {
369
369
  YGStyle result{baseStyle};
370
370
 
371
371
  // Aliases with precedence
372
- if (!props.inset.isUndefined()) {
373
- result.position()[YGEdgeAll] = props.inset;
374
- }
375
- if (!props.insetBlock.isUndefined()) {
376
- result.position()[YGEdgeVertical] = props.insetBlock;
377
- }
378
- if (!props.insetInline.isUndefined()) {
379
- result.position()[YGEdgeHorizontal] = props.insetInline;
380
- }
381
- if (!props.insetInlineEnd.isUndefined()) {
382
- result.position()[YGEdgeEnd] = props.insetInlineEnd;
383
- }
384
- if (!props.insetInlineStart.isUndefined()) {
385
- result.position()[YGEdgeStart] = props.insetInlineStart;
386
- }
387
372
  if (!props.marginInline.isUndefined()) {
388
373
  result.margin()[YGEdgeHorizontal] = props.marginInline;
389
374
  }
@@ -410,12 +395,6 @@ void YogaLayoutableShadowNode::updateYogaProps() {
410
395
  }
411
396
 
412
397
  // Aliases without precedence
413
- if (CompactValue(result.position()[YGEdgeBottom]).isUndefined()) {
414
- result.position()[YGEdgeBottom] = props.insetBlockEnd;
415
- }
416
- if (CompactValue(result.position()[YGEdgeTop]).isUndefined()) {
417
- result.position()[YGEdgeTop] = props.insetBlockStart;
418
- }
419
398
  if (CompactValue(result.margin()[YGEdgeTop]).isUndefined()) {
420
399
  result.margin()[YGEdgeTop] = props.marginBlockStart;
421
400
  }
@@ -136,13 +136,6 @@ void YogaStylableProps::setProp(
136
136
  static const auto defaults = YogaStylableProps{};
137
137
 
138
138
  // Aliases
139
- RAW_SET_PROP_SWITCH_CASE(inset, "inset");
140
- RAW_SET_PROP_SWITCH_CASE(insetBlock, "insetBlock");
141
- RAW_SET_PROP_SWITCH_CASE(insetBlockEnd, "insetBlockEnd");
142
- RAW_SET_PROP_SWITCH_CASE(insetBlockStart, "insetBlockStart");
143
- RAW_SET_PROP_SWITCH_CASE(insetInline, "insetInline");
144
- RAW_SET_PROP_SWITCH_CASE(insetInlineEnd, "insetInlineEnd");
145
- RAW_SET_PROP_SWITCH_CASE(insetInlineStart, "insetInlineStart");
146
139
  RAW_SET_PROP_SWITCH_CASE(marginInline, "marginInline");
147
140
  RAW_SET_PROP_SWITCH_CASE(marginInlineStart, "marginInlineStart");
148
141
  RAW_SET_PROP_SWITCH_CASE(marginInlineEnd, "marginInlineEnd");
@@ -242,48 +235,6 @@ void YogaStylableProps::convertRawPropAliases(
242
235
  const PropsParserContext &context,
243
236
  YogaStylableProps const &sourceProps,
244
237
  RawProps const &rawProps) {
245
- inset = convertRawProp(
246
- context,
247
- rawProps,
248
- "inset",
249
- sourceProps.inset,
250
- CompactValue::ofUndefined());
251
- insetBlock = convertRawProp(
252
- context,
253
- rawProps,
254
- "insetBlock",
255
- sourceProps.insetBlock,
256
- CompactValue::ofUndefined());
257
- insetBlockEnd = convertRawProp(
258
- context,
259
- rawProps,
260
- "insetBlockEnd",
261
- sourceProps.insetBlockEnd,
262
- CompactValue::ofUndefined());
263
- insetBlockStart = convertRawProp(
264
- context,
265
- rawProps,
266
- "insetBlockStart",
267
- sourceProps.insetBlockStart,
268
- CompactValue::ofUndefined());
269
- insetInline = convertRawProp(
270
- context,
271
- rawProps,
272
- "insetInline",
273
- sourceProps.insetInline,
274
- CompactValue::ofUndefined());
275
- insetInlineEnd = convertRawProp(
276
- context,
277
- rawProps,
278
- "insetInlineEnd",
279
- sourceProps.insetInlineEnd,
280
- CompactValue::ofUndefined());
281
- insetInlineStart = convertRawProp(
282
- context,
283
- rawProps,
284
- "insetInlineStart",
285
- sourceProps.insetInlineStart,
286
- CompactValue::ofUndefined());
287
238
  marginInline = convertRawProp(
288
239
  context,
289
240
  rawProps,
@@ -43,11 +43,6 @@ class YogaStylableProps : public Props {
43
43
 
44
44
  // Duplicates of existing properties with different names, taking
45
45
  // precedence. E.g. "marginBlock" instead of "marginVertical"
46
- CompactValue inset;
47
- CompactValue insetInline;
48
- CompactValue insetInlineEnd;
49
- CompactValue insetInlineStart;
50
-
51
46
  CompactValue marginInline;
52
47
  CompactValue marginInlineStart;
53
48
  CompactValue marginInlineEnd;
@@ -61,10 +56,6 @@ class YogaStylableProps : public Props {
61
56
  // BlockEnd/BlockStart map to top/bottom (no writing mode), but we preserve
62
57
  // Yoga's precedence and prefer specific edges (e.g. top) to ones which are
63
58
  // flow relative (e.g. blockStart).
64
- CompactValue insetBlock;
65
- CompactValue insetBlockEnd;
66
- CompactValue insetBlockStart;
67
-
68
59
  CompactValue marginBlockStart;
69
60
  CompactValue marginBlockEnd;
70
61
 
@@ -15,6 +15,7 @@ bool CoreFeatures::enableMapBuffer = false;
15
15
  bool CoreFeatures::blockPaintForUseLayoutEffect = false;
16
16
  bool CoreFeatures::useNativeState = false;
17
17
  bool CoreFeatures::cacheNSTextStorage = false;
18
+ bool CoreFeatures::cacheLastTextMeasurement = false;
18
19
 
19
20
  } // namespace react
20
21
  } // namespace facebook
@@ -39,6 +39,11 @@ class CoreFeatures {
39
39
  // creating it twice. Once when measuring text and once when rendering it.
40
40
  // This flag caches it inside ParagraphState.
41
41
  static bool cacheNSTextStorage;
42
+
43
+ // Yoga might measure multiple times the same Text with the same constraints
44
+ // This flag enables a caching mechanism to avoid subsequents measurements
45
+ // of the same Text with the same constrainst.
46
+ static bool cacheLastTextMeasurement;
42
47
  };
43
48
 
44
49
  } // namespace react
@@ -12,6 +12,7 @@
12
12
  #include <react/common/mapbuffer/JReadableMapBuffer.h>
13
13
  #include <react/jni/ReadableNativeMap.h>
14
14
  #include <react/renderer/attributedstring/conversions.h>
15
+ #include <react/renderer/core/CoreFeatures.h>
15
16
  #include <react/renderer/core/conversions.h>
16
17
  #include <react/renderer/mapbuffer/MapBuffer.h>
17
18
  #include <react/renderer/mapbuffer/MapBufferBuilder.h>
@@ -146,7 +147,10 @@ Size measureAndroidComponentMapBuffer(
146
147
  TextLayoutManager::TextLayoutManager(
147
148
  const ContextContainer::Shared &contextContainer)
148
149
  : contextContainer_(contextContainer),
149
- measureCache_(kSimpleThreadSafeCacheSizeCap) {}
150
+ measureCache_(
151
+ CoreFeatures::cacheLastTextMeasurement
152
+ ? 8096
153
+ : kSimpleThreadSafeCacheSizeCap) {}
150
154
 
151
155
  void *TextLayoutManager::getNativeTextLayoutManager() const {
152
156
  return self_;
@@ -52,47 +52,9 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
52
52
  textStorage = [self _textStorageForNSAttributesString:attributedString
53
53
  paragraphAttributes:paragraphAttributes
54
54
  size:maximumSize];
55
- } else {
56
- textStorage.layoutManagers.firstObject.textContainers.firstObject.size = maximumSize;
57
55
  }
58
56
 
59
- NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
60
- NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
61
- [layoutManager ensureLayoutForTextContainer:textContainer];
62
-
63
- CGSize size = [layoutManager usedRectForTextContainer:textContainer].size;
64
-
65
- size = (CGSize){RCTCeilPixelValue(size.width), RCTCeilPixelValue(size.height)};
66
-
67
- __block auto attachments = TextMeasurement::Attachments{};
68
-
69
- [textStorage
70
- enumerateAttribute:NSAttachmentAttributeName
71
- inRange:NSMakeRange(0, textStorage.length)
72
- options:0
73
- usingBlock:^(NSTextAttachment *attachment, NSRange range, BOOL *stop) {
74
- if (!attachment) {
75
- return;
76
- }
77
-
78
- CGSize attachmentSize = attachment.bounds.size;
79
- CGRect glyphRect = [layoutManager boundingRectForGlyphRange:range inTextContainer:textContainer];
80
-
81
- UIFont *font = [textStorage attribute:NSFontAttributeName atIndex:range.location effectiveRange:nil];
82
-
83
- CGRect frame = {
84
- {glyphRect.origin.x,
85
- glyphRect.origin.y + glyphRect.size.height - attachmentSize.height + font.descender},
86
- attachmentSize};
87
-
88
- auto rect = facebook::react::Rect{
89
- facebook::react::Point{frame.origin.x, frame.origin.y},
90
- facebook::react::Size{frame.size.width, frame.size.height}};
91
-
92
- attachments.push_back(TextMeasurement::Attachment{rect, false});
93
- }];
94
-
95
- return TextMeasurement{{size.width, size.height}, attachments};
57
+ return [self _measureTextStorage:textStorage];
96
58
  }
97
59
 
98
60
  - (TextMeasurement)measureAttributedString:(AttributedString)attributedString
@@ -100,10 +62,14 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
100
62
  layoutConstraints:(LayoutConstraints)layoutConstraints
101
63
  textStorage:(NSTextStorage *_Nullable)textStorage
102
64
  {
103
- return [self measureNSAttributedString:[self _nsAttributedStringFromAttributedString:attributedString]
104
- paragraphAttributes:paragraphAttributes
105
- layoutConstraints:layoutConstraints
106
- textStorage:textStorage];
65
+ if (textStorage) {
66
+ return [self _measureTextStorage:textStorage];
67
+ } else {
68
+ return [self measureNSAttributedString:[self _nsAttributedStringFromAttributedString:attributedString]
69
+ paragraphAttributes:paragraphAttributes
70
+ layoutConstraints:layoutConstraints
71
+ textStorage:nil];
72
+ }
107
73
  }
108
74
 
109
75
  - (void)drawAttributedString:(AttributedString)attributedString
@@ -111,13 +77,33 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
111
77
  frame:(CGRect)frame
112
78
  textStorage:(NSTextStorage *_Nullable)textStorage
113
79
  {
80
+ BOOL createdStorageForFrame = NO;
81
+
114
82
  if (!textStorage) {
115
83
  textStorage = [self textStorageForAttributesString:attributedString
116
84
  paragraphAttributes:paragraphAttributes
117
85
  size:frame.size];
86
+ createdStorageForFrame = YES;
118
87
  }
88
+
119
89
  NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
120
90
  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
+ }
121
107
 
122
108
  #if TARGET_OS_MACCATALYST
123
109
  CGContextRef context = UIGraphicsGetCurrentContext();
@@ -126,8 +112,8 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
126
112
  #endif
127
113
 
128
114
  NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
129
- [layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:frame.origin];
130
- [layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:frame.origin];
115
+ [layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:origin];
116
+ [layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:origin];
131
117
 
132
118
  #if TARGET_OS_MACCATALYST
133
119
  CGContextRestoreGState(context);
@@ -178,35 +164,6 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
178
164
  return paragraphLines;
179
165
  }
180
166
 
181
- - (NSTextStorage *)_textStorageForNSAttributesString:(NSAttributedString *)attributedString
182
- paragraphAttributes:(ParagraphAttributes)paragraphAttributes
183
- size:(CGSize)size
184
- {
185
- NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:size];
186
-
187
- textContainer.lineFragmentPadding = 0.0; // Note, the default value is 5.
188
- textContainer.lineBreakMode = paragraphAttributes.maximumNumberOfLines > 0
189
- ? RCTNSLineBreakModeFromEllipsizeMode(paragraphAttributes.ellipsizeMode)
190
- : NSLineBreakByClipping;
191
- textContainer.maximumNumberOfLines = paragraphAttributes.maximumNumberOfLines;
192
-
193
- NSLayoutManager *layoutManager = [NSLayoutManager new];
194
- layoutManager.usesFontLeading = NO;
195
- [layoutManager addTextContainer:textContainer];
196
-
197
- NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString];
198
-
199
- [textStorage addLayoutManager:layoutManager];
200
-
201
- if (paragraphAttributes.adjustsFontSizeToFit) {
202
- CGFloat minimumFontSize = !isnan(paragraphAttributes.minimumFontSize) ? paragraphAttributes.minimumFontSize : 4.0;
203
- CGFloat maximumFontSize = !isnan(paragraphAttributes.maximumFontSize) ? paragraphAttributes.maximumFontSize : 96.0;
204
- [textStorage scaleFontSizeToFitSize:size minimumFontSize:minimumFontSize maximumFontSize:maximumFontSize];
205
- }
206
-
207
- return textStorage;
208
- }
209
-
210
167
  - (NSTextStorage *)textStorageForAttributesString:(AttributedString)attributedString
211
168
  paragraphAttributes:(ParagraphAttributes)paragraphAttributes
212
169
  size:(CGSize)size
@@ -246,15 +203,6 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
246
203
  return nil;
247
204
  }
248
205
 
249
- - (NSAttributedString *)_nsAttributedStringFromAttributedString:(AttributedString)attributedString
250
- {
251
- auto sharedNSAttributedString = _cache.get(attributedString, [](AttributedString attributedString) {
252
- return wrapManagedObject(RCTNSAttributedStringFromAttributedString(attributedString));
253
- });
254
-
255
- return unwrapManagedObject(sharedNSAttributedString);
256
- }
257
-
258
206
  - (void)getRectWithAttributedString:(AttributedString)attributedString
259
207
  paragraphAttributes:(ParagraphAttributes)paragraphAttributes
260
208
  enumerateAttribute:(NSString *)enumerateAttribute
@@ -294,4 +242,85 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
294
242
  }];
295
243
  }
296
244
 
245
+ #pragma mark - Private
246
+
247
+ - (NSTextStorage *)_textStorageForNSAttributesString:(NSAttributedString *)attributedString
248
+ paragraphAttributes:(ParagraphAttributes)paragraphAttributes
249
+ size:(CGSize)size
250
+ {
251
+ NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:size];
252
+
253
+ textContainer.lineFragmentPadding = 0.0; // Note, the default value is 5.
254
+ textContainer.lineBreakMode = paragraphAttributes.maximumNumberOfLines > 0
255
+ ? RCTNSLineBreakModeFromEllipsizeMode(paragraphAttributes.ellipsizeMode)
256
+ : NSLineBreakByClipping;
257
+ textContainer.maximumNumberOfLines = paragraphAttributes.maximumNumberOfLines;
258
+
259
+ NSLayoutManager *layoutManager = [NSLayoutManager new];
260
+ layoutManager.usesFontLeading = NO;
261
+ [layoutManager addTextContainer:textContainer];
262
+
263
+ NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString];
264
+
265
+ [textStorage addLayoutManager:layoutManager];
266
+
267
+ if (paragraphAttributes.adjustsFontSizeToFit) {
268
+ CGFloat minimumFontSize = !isnan(paragraphAttributes.minimumFontSize) ? paragraphAttributes.minimumFontSize : 4.0;
269
+ CGFloat maximumFontSize = !isnan(paragraphAttributes.maximumFontSize) ? paragraphAttributes.maximumFontSize : 96.0;
270
+ [textStorage scaleFontSizeToFitSize:size minimumFontSize:minimumFontSize maximumFontSize:maximumFontSize];
271
+ }
272
+
273
+ return textStorage;
274
+ }
275
+
276
+ - (NSAttributedString *)_nsAttributedStringFromAttributedString:(AttributedString)attributedString
277
+ {
278
+ auto sharedNSAttributedString = _cache.get(attributedString, [](AttributedString attributedString) {
279
+ return wrapManagedObject(RCTNSAttributedStringFromAttributedString(attributedString));
280
+ });
281
+
282
+ return unwrapManagedObject(sharedNSAttributedString);
283
+ }
284
+
285
+ - (TextMeasurement)_measureTextStorage:(NSTextStorage *)textStorage
286
+ {
287
+ NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
288
+ NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
289
+ [layoutManager ensureLayoutForTextContainer:textContainer];
290
+
291
+ CGSize size = [layoutManager usedRectForTextContainer:textContainer].size;
292
+
293
+ size = (CGSize){RCTCeilPixelValue(size.width), RCTCeilPixelValue(size.height)};
294
+
295
+ __block auto attachments = TextMeasurement::Attachments{};
296
+
297
+ [textStorage
298
+ enumerateAttribute:NSAttachmentAttributeName
299
+ inRange:NSMakeRange(0, textStorage.length)
300
+ options:0
301
+ usingBlock:^(NSTextAttachment *attachment, NSRange range, BOOL *stop) {
302
+ if (!attachment) {
303
+ return;
304
+ }
305
+
306
+ CGSize attachmentSize = attachment.bounds.size;
307
+ CGRect glyphRect = [layoutManager boundingRectForGlyphRange:range inTextContainer:textContainer];
308
+
309
+ UIFont *font = [textStorage attribute:NSFontAttributeName atIndex:range.location effectiveRange:nil];
310
+
311
+ CGRect frame = {
312
+ {glyphRect.origin.x,
313
+ glyphRect.origin.y + glyphRect.size.height - attachmentSize.height + font.descender},
314
+ attachmentSize};
315
+
316
+ auto rect = facebook::react::Rect{
317
+ facebook::react::Point{frame.origin.x, frame.origin.y},
318
+ facebook::react::Size{frame.size.width, frame.size.height}};
319
+
320
+ attachments.push_back(TextMeasurement::Attachment{rect, false});
321
+ }];
322
+
323
+ return TextMeasurement{{size.width, size.height}, attachments};
324
+ }
325
+
297
326
  @end
package/build.gradle.kts CHANGED
@@ -1 +1,18 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
1
7
 
8
+ // This is the top level build.gradle.kts file used when the users
9
+ // is doing a build from source. It's triggered as the user
10
+ // will add an `includeBuild(../node_modules/react-native)` in
11
+ // their settings.gradle.kts file.
12
+ // More on this here: https://reactnative.dev/contributing/how-to-build-from-source
13
+ plugins {
14
+ id("com.android.library") version "7.4.2" apply false
15
+ id("com.android.application") version "7.4.2" apply false
16
+ id("de.undercouch.download") version "5.0.1" apply false
17
+ kotlin("android") version "1.7.22" apply false
18
+ }
package/gradle.properties CHANGED
@@ -0,0 +1 @@
1
+ android.useAndroidX=true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native",
3
- "version": "0.72.0-rc.0",
3
+ "version": "0.72.0-rc.2",
4
4
  "bin": "./cli.js",
5
5
  "description": "A framework for building native apps using React",
6
6
  "license": "MIT",
@@ -79,27 +79,27 @@
79
79
  },
80
80
  "dependencies": {
81
81
  "@jest/create-cache-key-function": "^29.2.1",
82
- "@react-native-community/cli": "11.0.0-alpha.2",
83
- "@react-native-community/cli-platform-android": "11.0.0-alpha.2",
84
- "@react-native-community/cli-platform-ios": "11.0.0-alpha.2",
82
+ "@react-native-community/cli": "11.2.1",
83
+ "@react-native-community/cli-platform-android": "11.2.1",
84
+ "@react-native-community/cli-platform-ios": "11.2.1",
85
85
  "@react-native/assets-registry": "^0.72.0",
86
86
  "@react-native/codegen": "^0.72.4",
87
87
  "@react-native/gradle-plugin": "^0.72.6",
88
88
  "@react-native/js-polyfills": "^0.72.1",
89
89
  "@react-native/normalize-colors": "^0.72.0",
90
- "@react-native/virtualized-lists": "^0.72.3",
90
+ "@react-native/virtualized-lists": "^0.72.4",
91
91
  "abort-controller": "^3.0.0",
92
92
  "anser": "^1.4.9",
93
93
  "base64-js": "^1.1.2",
94
- "deprecated-react-native-prop-types": "^4.0.0",
94
+ "deprecated-react-native-prop-types": "4.1.0",
95
95
  "event-target-shim": "^5.0.1",
96
96
  "flow-enums-runtime": "^0.0.5",
97
97
  "invariant": "^2.2.4",
98
98
  "jest-environment-node": "^29.2.1",
99
99
  "jsc-android": "^250231.0.0",
100
100
  "memoize-one": "^5.0.0",
101
- "metro-runtime": "0.75.1",
102
- "metro-source-map": "0.75.1",
101
+ "metro-runtime": "0.76.2",
102
+ "metro-source-map": "0.76.2",
103
103
  "mkdirp": "^0.5.1",
104
104
  "nullthrows": "^1.1.1",
105
105
  "pretty-format": "^26.5.2",
@@ -15,6 +15,14 @@ require_relative "./test_utils/CodegenUtilsMock.rb"
15
15
  require_relative "./test_utils/CodegenScriptPhaseExtractorMock.rb"
16
16
  require_relative "./test_utils/FileUtilsMock.rb"
17
17
 
18
+ # mocking the min_ios_version_supported function
19
+ # as it is not possible to require the original react_native_pod
20
+ # without incurring in circular deps
21
+ # TODO: move `min_ios_version_supported` to utils.rb
22
+ def min_ios_version_supported
23
+ return '12.4'
24
+ end
25
+
18
26
  class CodegenUtilsTests < Test::Unit::TestCase
19
27
  :base_path
20
28
 
@@ -527,7 +535,7 @@ class CodegenUtilsTests < Test::Unit::TestCase
527
535
  'source' => { :git => '' },
528
536
  'header_mappings_dir' => './',
529
537
  'platforms' => {
530
- 'ios' => '11.0',
538
+ 'ios' => '12.4',
531
539
  },
532
540
  'source_files' => "**/*.{h,mm,cpp}",
533
541
  'pod_target_xcconfig' => {