Skip to content

Commit 48716aa

Browse files
committed
Refactor conditional event emitting to the C++ layer (#38674)
Summary: Pull Request resolved: #38674 Changelog: [Internal] - Refactor conditional pointer event emitting to the C++ layer Some background: early on in the implementation of Pointer Events a concern was brought up that events related to hovering pointers could saturate the JS thread if they were fired all the time unconditionally, so as a mitigation we would check in native to see if listeners in the tree were listening for those events and only fire them if there were listeners. Now since we're going to be moving some of the event derivation logic to the C++ layer we need to receive all the events — but recreate the conditional firing in the C++ layer so we can still avoid saturating the JS thread. That's what this diff does. The only change I see being potentially contraversial is the fact that I needed a way to turn an `EventTarget` (the only information I receive regarding which node the event is firing on) to its cooresponding `ShadowNode` which I did in the method `GetShadowNodeFromEventTarget`. It essentially does the exact same thing the `getNodeFromInternalInstanceHandle` method in `ReactNativePublicCompat.js`, but in C++ against the JSI API. I don't know if there's a better way to do this but this was the best one I came up with that actually works. Reviewed By: NickGerleman Differential Revision: D47852371 fbshipit-source-id: d2a0a460df985051d406240b5345f45781ab164b
1 parent 3e6e7f2 commit 48716aa

File tree

4 files changed

+202
-77
lines changed

4 files changed

+202
-77
lines changed

packages/react-native/React/Fabric/RCTSurfacePointerHandler.mm

Lines changed: 8 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -396,28 +396,6 @@ static void UpdateActivePointerWithUITouch(
396396
activePointer.modifierFlags = uiEvent.modifierFlags;
397397
}
398398

399-
static BOOL IsViewListeningToEvent(RCTReactTaggedView *taggedView, ViewEvents::Offset eventType)
400-
{
401-
UIView *view = taggedView.view;
402-
if (view && [view.class conformsToProtocol:@protocol(RCTComponentViewProtocol)]) {
403-
auto props = ((id<RCTComponentViewProtocol>)view).props;
404-
if (SharedViewProps viewProps = std::dynamic_pointer_cast<ViewProps const>(props)) {
405-
return viewProps->events[eventType];
406-
}
407-
}
408-
return NO;
409-
}
410-
411-
static BOOL IsAnyViewInPathListeningToEvent(NSOrderedSet<RCTReactTaggedView *> *viewPath, ViewEvents::Offset eventType)
412-
{
413-
for (RCTReactTaggedView *taggedView in viewPath) {
414-
if (IsViewListeningToEvent(taggedView, eventType)) {
415-
return YES;
416-
}
417-
}
418-
return NO;
419-
}
420-
421399
/**
422400
* Given an ActivePointer determine if it is still within the same event target tree as
423401
* the one which initiated the pointer gesture.
@@ -634,8 +612,7 @@ - (void)_dispatchActivePointers:(std::vector<ActivePointer>)activePointers event
634612
{
635613
for (const auto &activePointer : activePointers) {
636614
PointerEvent pointerEvent = CreatePointerEventFromActivePointer(activePointer, eventType, _rootComponentView);
637-
NSOrderedSet<RCTReactTaggedView *> *eventPathViews = [self handleIncomingPointerEvent:pointerEvent
638-
onView:activePointer.componentView];
615+
[self handleIncomingPointerEvent:pointerEvent onView:activePointer.componentView];
639616

640617
SharedTouchEventEmitter eventEmitter = GetTouchEmitterFromView(
641618
activePointer.componentView,
@@ -648,12 +625,7 @@ - (void)_dispatchActivePointers:(std::vector<ActivePointer>)activePointers event
648625
break;
649626
}
650627
case RCTPointerEventTypeMove: {
651-
BOOL hasMoveEventListeners =
652-
IsAnyViewInPathListeningToEvent(eventPathViews, ViewEvents::Offset::PointerMove) ||
653-
IsAnyViewInPathListeningToEvent(eventPathViews, ViewEvents::Offset::PointerMoveCapture);
654-
if (hasMoveEventListeners) {
655-
eventEmitter->onPointerMove(pointerEvent);
656-
}
628+
eventEmitter->onPointerMove(pointerEvent);
657629
break;
658630
}
659631
case RCTPointerEventTypeEnd: {
@@ -792,11 +764,9 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer
792764
PointerEvent event = CreatePointerEventFromIncompleteHoverData(
793765
pointerId, pointerType, clientLocation, screenLocation, offsetLocation, modifierFlags);
794766

795-
NSOrderedSet<RCTReactTaggedView *> *eventPathViews = [self handleIncomingPointerEvent:event onView:targetView];
767+
[self handleIncomingPointerEvent:event onView:targetView];
796768
SharedTouchEventEmitter eventEmitter = GetTouchEmitterFromView(targetView, offsetLocation);
797-
BOOL hasMoveEventListeners = IsAnyViewInPathListeningToEvent(eventPathViews, ViewEvents::Offset::PointerMove) ||
798-
IsAnyViewInPathListeningToEvent(eventPathViews, ViewEvents::Offset::PointerMoveCapture);
799-
if (eventEmitter != nil && hasMoveEventListeners) {
769+
if (eventEmitter != nil) {
800770
eventEmitter->onPointerMove(event);
801771
}
802772
}
@@ -831,10 +801,9 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer
831801

832802
// Out
833803
if (prevTargetView != nil && prevTargetTaggedView.tag != targetTaggedView.tag) {
834-
BOOL shouldEmitOutEvent = IsAnyViewInPathListeningToEvent(currentlyHoveredViews, ViewEvents::Offset::PointerOut);
835804
SharedTouchEventEmitter eventEmitter =
836805
GetTouchEmitterFromView(prevTargetView, [_rootComponentView convertPoint:clientLocation toView:prevTargetView]);
837-
if (shouldEmitOutEvent && eventEmitter != nil) {
806+
if (eventEmitter != nil) {
838807
eventEmitter->onPointerOut(event);
839808
}
840809
}
@@ -847,20 +816,14 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer
847816
// we reverse iterate (now from target to root), actually emitting the events.
848817
NSMutableOrderedSet<UIView *> *viewsToEmitLeaveEventsTo = [NSMutableOrderedSet orderedSet];
849818

850-
BOOL hasParentLeaveListener = NO;
851819
for (RCTReactTaggedView *taggedView in [currentlyHoveredViews reverseObjectEnumerator]) {
852820
UIView *componentView = taggedView.view;
853821

854-
BOOL shouldEmitEvent = componentView != nil &&
855-
(hasParentLeaveListener || IsViewListeningToEvent(taggedView, ViewEvents::Offset::PointerLeave));
822+
BOOL shouldEmitEvent = componentView != nil;
856823

857824
if (shouldEmitEvent && ![eventPathViews containsObject:taggedView]) {
858825
[viewsToEmitLeaveEventsTo addObject:componentView];
859826
}
860-
861-
if (shouldEmitEvent && !hasParentLeaveListener) {
862-
hasParentLeaveListener = YES;
863-
}
864827
}
865828

866829
for (UIView *componentView in [viewsToEmitLeaveEventsTo reverseObjectEnumerator]) {
@@ -873,10 +836,9 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer
873836

874837
// Over
875838
if (targetView != nil && prevTargetTaggedView.tag != targetTaggedView.tag) {
876-
BOOL shouldEmitOverEvent = IsAnyViewInPathListeningToEvent(eventPathViews, ViewEvents::Offset::PointerOver);
877839
SharedTouchEventEmitter eventEmitter =
878840
GetTouchEmitterFromView(targetView, [_rootComponentView convertPoint:clientLocation toView:targetView]);
879-
if (shouldEmitOverEvent && eventEmitter != nil) {
841+
if (eventEmitter != nil) {
880842
eventEmitter->onPointerOver(event);
881843
}
882844
}
@@ -888,12 +850,10 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer
888850
// or if one of its parents is listening in case those listeners care about the capturing phase. Adding the ability
889851
// for native to distinguish between capturing listeners and not could be an optimization to further reduce the number
890852
// of events we send to JS
891-
BOOL hasParentEnterListener = NO;
892853
for (RCTReactTaggedView *taggedView in [eventPathViews reverseObjectEnumerator]) {
893854
UIView *componentView = taggedView.view;
894855

895-
BOOL shouldEmitEvent = componentView != nil &&
896-
(hasParentEnterListener || IsViewListeningToEvent(taggedView, ViewEvents::Offset::PointerEnter));
856+
BOOL shouldEmitEvent = componentView != nil;
897857

898858
if (shouldEmitEvent && ![currentlyHoveredViews containsObject:taggedView]) {
899859
SharedTouchEventEmitter eventEmitter =
@@ -902,10 +862,6 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer
902862
eventEmitter->onPointerEnter(event);
903863
}
904864
}
905-
906-
if (shouldEmitEvent && !hasParentEnterListener) {
907-
hasParentEnterListener = YES;
908-
}
909865
}
910866

911867
[_currentlyHoveredViewsPerPointer setObject:eventPathViews forKey:@(pointerId)];

packages/react-native/ReactCommon/react/renderer/components/view/primitives.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ struct ViewEvents {
6262
ClickCapture = 31,
6363
GotPointerCapture = 32,
6464
LostPointerCapture = 33,
65+
PointerDown = 34,
66+
PointerDownCapture = 35,
67+
PointerUp = 36,
68+
PointerUpCapture = 37,
6569
};
6670

6771
constexpr bool operator[](const Offset offset) const {

packages/react-native/ReactCommon/react/renderer/components/view/propsConversions.h

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -616,18 +616,32 @@ static inline ViewEvents convertRawProp(
616616
"onClickCapture",
617617
sourceValue[Offset::ClickCapture],
618618
defaultValue[Offset::ClickCapture]);
619-
result[Offset::GotPointerCapture] = convertRawProp(
619+
result[Offset::PointerDown] = convertRawProp(
620620
context,
621621
rawProps,
622-
"onGotPointerCapture",
623-
sourceValue[Offset::GotPointerCapture],
624-
defaultValue[Offset::GotPointerCapture]);
625-
result[Offset::LostPointerCapture] = convertRawProp(
622+
"onPointerDown",
623+
sourceValue[Offset::PointerDown],
624+
defaultValue[Offset::PointerDown]);
625+
result[Offset::PointerDownCapture] = convertRawProp(
626626
context,
627627
rawProps,
628-
"onLostPointerCapture",
629-
sourceValue[Offset::LostPointerCapture],
630-
defaultValue[Offset::LostPointerCapture]);
628+
"onPointerDownCapture",
629+
sourceValue[Offset::PointerDownCapture],
630+
defaultValue[Offset::PointerDownCapture]);
631+
result[Offset::PointerUp] = convertRawProp(
632+
context,
633+
rawProps,
634+
"onPointerUp",
635+
sourceValue[Offset::PointerUp],
636+
defaultValue[Offset::PointerUp]);
637+
result[Offset::PointerUpCapture] = convertRawProp(
638+
context,
639+
rawProps,
640+
"onPointerUpCapture",
641+
sourceValue[Offset::PointerUpCapture],
642+
defaultValue[Offset::PointerUpCapture]);
643+
// TODO: gotPointerCapture & lostPointerCapture (causes issues with
644+
// RawPropsKey for some reason)
631645

632646
// PanResponder callbacks
633647
result[Offset::MoveShouldSetResponder] = convertRawProp(

0 commit comments

Comments
 (0)