Skip to content

Commit 2af1da4

Browse files
rubennortefacebook-github-bot
authored andcommitted
Add legacy layout methods from Fabric to DOM native module (#43659)
Summary: Pull Request resolved: #43659 Changelog: [internal] This adds an implementation for the legacy layout measurement methods in React Native (`measure`, `measureInWindow` and `measureLayout`) in the DOM native module, so we can clean up the API from the `nativeFabricUIManager` binding. Reviewed By: javache Differential Revision: D55368141 fbshipit-source-id: 196d4d29be3b78ffc22fdc136be6e0cf5ab9dd26
1 parent ff392b0 commit 2af1da4

File tree

4 files changed

+229
-8
lines changed

4 files changed

+229
-8
lines changed

packages/react-native/ReactCommon/react/nativemodule/dom/NativeDOM.cpp

Lines changed: 92 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ std::shared_ptr<facebook::react::TurboModule> NativeDOMModuleProvider(
2121
return std::make_shared<facebook::react::NativeDOM>(std::move(jsInvoker));
2222
}
2323

24-
namespace {
25-
using namespace facebook::react;
24+
namespace facebook::react {
25+
26+
#pragma mark - Private helpers
2627

27-
RootShadowNode::Shared getCurrentShadowTreeRevision(
28+
static RootShadowNode::Shared getCurrentShadowTreeRevision(
2829
facebook::jsi::Runtime& runtime,
2930
SurfaceId surfaceId) {
3031
auto& uiManager =
@@ -33,13 +34,14 @@ RootShadowNode::Shared getCurrentShadowTreeRevision(
3334
return shadowTreeRevisionProvider->getCurrentRevision(surfaceId);
3435
}
3536

36-
facebook::react::PointerEventsProcessor& getPointerEventsProcessorFromRuntime(
37-
facebook::jsi::Runtime& runtime) {
37+
static facebook::react::PointerEventsProcessor&
38+
getPointerEventsProcessorFromRuntime(facebook::jsi::Runtime& runtime) {
3839
return facebook::react::UIManagerBinding::getBinding(runtime)
3940
->getPointerEventsProcessor();
4041
}
4142

42-
std::vector<facebook::jsi::Value> getArrayOfInstanceHandlesFromShadowNodes(
43+
static std::vector<facebook::jsi::Value>
44+
getArrayOfInstanceHandlesFromShadowNodes(
4345
const ShadowNode::ListOfShared& nodes,
4446
facebook::jsi::Runtime& runtime) {
4547
// JSI doesn't support adding elements to an array after creation,
@@ -56,9 +58,8 @@ std::vector<facebook::jsi::Value> getArrayOfInstanceHandlesFromShadowNodes(
5658

5759
return nonNullInstanceHandles;
5860
}
59-
} // namespace
6061

61-
namespace facebook::react {
62+
#pragma mark - NativeDOM
6263

6364
NativeDOM::NativeDOM(std::shared_ptr<CallInvoker> jsInvoker)
6465
: NativeDOMCxxSpec(std::move(jsInvoker)) {}
@@ -244,6 +245,8 @@ std::string NativeDOM::getTagName(
244245
return dom::getTagName(*shadowNode);
245246
}
246247

248+
#pragma mark - Pointer events
249+
247250
bool NativeDOM::hasPointerCapture(
248251
jsi::Runtime& rt,
249252
jsi::Value shadowNodeValue,
@@ -269,4 +272,85 @@ void NativeDOM::releasePointerCapture(
269272
pointerId, shadowNodeFromValue(rt, shadowNodeValue).get());
270273
}
271274

275+
#pragma mark - Legacy RN layout APIs
276+
277+
void NativeDOM::measure(
278+
jsi::Runtime& rt,
279+
jsi::Value shadowNodeValue,
280+
jsi::Function callback) {
281+
auto shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
282+
auto currentRevision =
283+
getCurrentShadowTreeRevision(rt, shadowNode->getSurfaceId());
284+
if (currentRevision == nullptr) {
285+
callback.call(rt, {0, 0, 0, 0, 0, 0});
286+
return;
287+
}
288+
289+
auto measureRect = dom::measure(currentRevision, *shadowNode);
290+
291+
callback.call(
292+
rt,
293+
{jsi::Value{rt, measureRect.x},
294+
jsi::Value{rt, measureRect.y},
295+
jsi::Value{rt, measureRect.width},
296+
jsi::Value{rt, measureRect.height},
297+
jsi::Value{rt, measureRect.pageX},
298+
jsi::Value{rt, measureRect.pageY}});
299+
}
300+
301+
void NativeDOM::measureInWindow(
302+
jsi::Runtime& rt,
303+
jsi::Value shadowNodeValue,
304+
jsi::Function callback) {
305+
auto shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
306+
auto currentRevision =
307+
getCurrentShadowTreeRevision(rt, shadowNode->getSurfaceId());
308+
if (currentRevision == nullptr) {
309+
callback.call(rt, {0, 0, 0, 0});
310+
return;
311+
}
312+
313+
auto rect = dom::measureInWindow(currentRevision, *shadowNode);
314+
callback.call(
315+
rt,
316+
{jsi::Value{rt, rect.x},
317+
jsi::Value{rt, rect.y},
318+
jsi::Value{rt, rect.width},
319+
jsi::Value{rt, rect.height}});
320+
}
321+
322+
void NativeDOM::measureLayout(
323+
jsi::Runtime& rt,
324+
jsi::Value shadowNodeValue,
325+
jsi::Value relativeToShadowNodeValue,
326+
jsi::Function onFail,
327+
jsi::Function onSuccess) {
328+
auto shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
329+
auto relativeToShadowNode =
330+
shadowNodeFromValue(rt, relativeToShadowNodeValue);
331+
auto currentRevision =
332+
getCurrentShadowTreeRevision(rt, shadowNode->getSurfaceId());
333+
if (currentRevision == nullptr) {
334+
onFail.call(rt);
335+
return;
336+
}
337+
338+
auto maybeRect =
339+
dom::measureLayout(currentRevision, *shadowNode, *relativeToShadowNode);
340+
341+
if (!maybeRect) {
342+
onFail.call(rt);
343+
return;
344+
}
345+
346+
auto rect = maybeRect.value();
347+
348+
onSuccess.call(
349+
rt,
350+
{jsi::Value{rt, rect.x},
351+
jsi::Value{rt, rect.y},
352+
jsi::Value{rt, rect.width},
353+
jsi::Value{rt, rect.height}});
354+
}
355+
272356
} // namespace facebook::react

packages/react-native/ReactCommon/react/nativemodule/dom/NativeDOM.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,23 @@ class NativeDOM : public NativeDOMCxxSpec<NativeDOM> {
8888
jsi::Runtime& rt,
8989
jsi::Value shadowNodeValue,
9090
double pointerId);
91+
92+
// Legacy layout APIs
93+
94+
void
95+
measure(jsi::Runtime& rt, jsi::Value shadowNodeValue, jsi::Function callback);
96+
97+
void measureInWindow(
98+
jsi::Runtime& rt,
99+
jsi::Value shadowNodeValue,
100+
jsi::Function callback);
101+
102+
void measureLayout(
103+
jsi::Runtime& rt,
104+
jsi::Value shadowNodeValue,
105+
jsi::Value relativeToShadowNodeValue,
106+
jsi::Function onFail,
107+
jsi::Function onSuccess);
91108
};
92109

93110
} // namespace facebook::react

packages/react-native/src/private/webapis/dom/nodes/specs/NativeDOM.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,29 @@ import type {TurboModule} from '../../../../../../Libraries/TurboModule/RCTExpor
1717
import * as TurboModuleRegistry from '../../../../../../Libraries/TurboModule/TurboModuleRegistry';
1818
import nullthrows from 'nullthrows';
1919

20+
export type MeasureInWindowOnSuccessCallback = (
21+
x: number,
22+
y: number,
23+
width: number,
24+
height: number,
25+
) => void;
26+
27+
export type MeasureOnSuccessCallback = (
28+
x: number,
29+
y: number,
30+
width: number,
31+
height: number,
32+
pageX: number,
33+
pageY: number,
34+
) => void;
35+
36+
export type MeasureLayoutOnSuccessCallback = (
37+
left: number,
38+
top: number,
39+
width: number,
40+
height: number,
41+
) => void;
42+
2043
export interface Spec extends TurboModule {
2144
+getParentNode: (
2245
shadowNode: mixed /* ShadowNode */,
@@ -76,6 +99,24 @@ export interface Spec extends TurboModule {
7699
shadowNode: mixed /* ShadowNode */,
77100
pointerId: number,
78101
) => void;
102+
103+
/**
104+
* Legacy layout APIs
105+
*/
106+
107+
+measure: (shadowNode: mixed, callback: MeasureOnSuccessCallback) => void;
108+
109+
+measureInWindow: (
110+
shadowNode: mixed,
111+
callback: MeasureInWindowOnSuccessCallback,
112+
) => void;
113+
114+
+measureLayout: (
115+
shadowNode: mixed,
116+
relativeNode: mixed,
117+
onFail: () => void,
118+
onSuccess: MeasureLayoutOnSuccessCallback,
119+
) => void;
79120
}
80121

81122
const RawNativeDOM = (TurboModuleRegistry.get<Spec>('NativeDOMCxx'): ?Spec);
@@ -271,6 +312,27 @@ export interface RefinedSpec {
271312
+setPointerCapture: (shadowNode: ShadowNode, pointerId: number) => void;
272313

273314
+releasePointerCapture: (shadowNode: ShadowNode, pointerId: number) => void;
315+
316+
/**
317+
* Legacy layout APIs
318+
*/
319+
320+
+measure: (
321+
shadowNode: ShadowNode,
322+
callback: MeasureOnSuccessCallback,
323+
) => void;
324+
325+
+measureInWindow: (
326+
shadowNode: ShadowNode,
327+
callback: MeasureInWindowOnSuccessCallback,
328+
) => void;
329+
330+
+measureLayout: (
331+
shadowNode: ShadowNode,
332+
relativeNode: ShadowNode,
333+
onFail: () => void,
334+
onSuccess: MeasureLayoutOnSuccessCallback,
335+
) => void;
274336
}
275337

276338
const NativeDOM: RefinedSpec = {
@@ -380,6 +442,27 @@ const NativeDOM: RefinedSpec = {
380442
pointerId,
381443
);
382444
},
445+
446+
/**
447+
* Legacy layout APIs
448+
*/
449+
450+
measure(shadowNode, callback) {
451+
return nullthrows(RawNativeDOM).measure(shadowNode, callback);
452+
},
453+
454+
measureInWindow(shadowNode, callback) {
455+
return nullthrows(RawNativeDOM).measureInWindow(shadowNode, callback);
456+
},
457+
458+
measureLayout(shadowNode, relativeNode, onFail, onSuccess) {
459+
return nullthrows(RawNativeDOM).measureLayout(
460+
shadowNode,
461+
relativeNode,
462+
onFail,
463+
onSuccess,
464+
);
465+
},
383466
};
384467

385468
export default NativeDOM;

packages/react-native/src/private/webapis/dom/nodes/specs/__mocks__/NativeDOMMock.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ import type {
1313
InternalInstanceHandle,
1414
Node,
1515
} from '../../../../../../../Libraries/Renderer/shims/ReactNativeTypes';
16+
import type {
17+
MeasureInWindowOnSuccessCallback,
18+
MeasureLayoutOnSuccessCallback,
19+
MeasureOnSuccessCallback,
20+
} from '../NativeDOM';
1621
import typeof NativeDOM from '../NativeDOM';
1722

1823
import {
@@ -371,6 +376,38 @@ const NativeDOMMock: NativeDOM = {
371376
ensureHostNode(node);
372377
return 'RN:' + fromNode(node).viewName;
373378
}),
379+
380+
/**
381+
* Legacy layout APIs
382+
*/
383+
384+
measure: jest.fn((node: Node, callback: MeasureOnSuccessCallback): void => {
385+
ensureHostNode(node);
386+
387+
callback(10, 10, 100, 100, 0, 0);
388+
}),
389+
390+
measureInWindow: jest.fn(
391+
(node: Node, callback: MeasureInWindowOnSuccessCallback): void => {
392+
ensureHostNode(node);
393+
394+
callback(10, 10, 100, 100);
395+
},
396+
),
397+
398+
measureLayout: jest.fn(
399+
(
400+
node: Node,
401+
relativeNode: Node,
402+
onFail: () => void,
403+
onSuccess: MeasureLayoutOnSuccessCallback,
404+
): void => {
405+
ensureHostNode(node);
406+
ensureHostNode(relativeNode);
407+
408+
onSuccess(1, 1, 100, 100);
409+
},
410+
),
374411
};
375412

376413
export default NativeDOMMock;

0 commit comments

Comments
 (0)