mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Back out "Refactor conditional event emitting to the C++ layer" (#38973)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/38973 Original commit changeset: 6c00c2fcfdfd Original Phabricator Diff: D47852371 When #38674 and #38959 are combined, they cause Android apps on Fabric to crash. #38959 is the more urgent fix, so backing out #38674. ## Changelog: [General] [Fixed] - Rolling back change that broke e2e tests until we can figure out why the e2e tests are broken Reviewed By: NickGerleman Differential Revision: D48288752 fbshipit-source-id: b52e28936bbebd21bd3b2f49f9a233f295ba6248
This commit is contained in:
committed by
Facebook GitHub Bot
parent
9f7dfcc35f
commit
ae88aef12c
@@ -396,6 +396,28 @@ static void UpdateActivePointerWithUITouch(
|
||||
activePointer.modifierFlags = uiEvent.modifierFlags;
|
||||
}
|
||||
|
||||
static BOOL IsViewListeningToEvent(RCTReactTaggedView *taggedView, ViewEvents::Offset eventType)
|
||||
{
|
||||
UIView *view = taggedView.view;
|
||||
if (view && [view.class conformsToProtocol:@protocol(RCTComponentViewProtocol)]) {
|
||||
auto props = ((id<RCTComponentViewProtocol>)view).props;
|
||||
if (SharedViewProps viewProps = std::dynamic_pointer_cast<ViewProps const>(props)) {
|
||||
return viewProps->events[eventType];
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
static BOOL IsAnyViewInPathListeningToEvent(NSOrderedSet<RCTReactTaggedView *> *viewPath, ViewEvents::Offset eventType)
|
||||
{
|
||||
for (RCTReactTaggedView *taggedView in viewPath) {
|
||||
if (IsViewListeningToEvent(taggedView, eventType)) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an ActivePointer determine if it is still within the same event target tree as
|
||||
* the one which initiated the pointer gesture.
|
||||
@@ -612,7 +634,8 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithTarget : (id)target action : (SEL)act
|
||||
{
|
||||
for (const auto &activePointer : activePointers) {
|
||||
PointerEvent pointerEvent = CreatePointerEventFromActivePointer(activePointer, eventType, _rootComponentView);
|
||||
[self handleIncomingPointerEvent:pointerEvent onView:activePointer.componentView];
|
||||
NSOrderedSet<RCTReactTaggedView *> *eventPathViews = [self handleIncomingPointerEvent:pointerEvent
|
||||
onView:activePointer.componentView];
|
||||
|
||||
SharedTouchEventEmitter eventEmitter = GetTouchEmitterFromView(
|
||||
activePointer.componentView,
|
||||
@@ -625,7 +648,12 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithTarget : (id)target action : (SEL)act
|
||||
break;
|
||||
}
|
||||
case RCTPointerEventTypeMove: {
|
||||
eventEmitter->onPointerMove(pointerEvent);
|
||||
BOOL hasMoveEventListeners =
|
||||
IsAnyViewInPathListeningToEvent(eventPathViews, ViewEvents::Offset::PointerMove) ||
|
||||
IsAnyViewInPathListeningToEvent(eventPathViews, ViewEvents::Offset::PointerMoveCapture);
|
||||
if (hasMoveEventListeners) {
|
||||
eventEmitter->onPointerMove(pointerEvent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RCTPointerEventTypeEnd: {
|
||||
@@ -764,9 +792,11 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithTarget : (id)target action : (SEL)act
|
||||
PointerEvent event = CreatePointerEventFromIncompleteHoverData(
|
||||
pointerId, pointerType, clientLocation, screenLocation, offsetLocation, modifierFlags);
|
||||
|
||||
[self handleIncomingPointerEvent:event onView:targetView];
|
||||
NSOrderedSet<RCTReactTaggedView *> *eventPathViews = [self handleIncomingPointerEvent:event onView:targetView];
|
||||
SharedTouchEventEmitter eventEmitter = GetTouchEmitterFromView(targetView, offsetLocation);
|
||||
if (eventEmitter != nil) {
|
||||
BOOL hasMoveEventListeners = IsAnyViewInPathListeningToEvent(eventPathViews, ViewEvents::Offset::PointerMove) ||
|
||||
IsAnyViewInPathListeningToEvent(eventPathViews, ViewEvents::Offset::PointerMoveCapture);
|
||||
if (eventEmitter != nil && hasMoveEventListeners) {
|
||||
eventEmitter->onPointerMove(event);
|
||||
}
|
||||
}
|
||||
@@ -801,9 +831,10 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithTarget : (id)target action : (SEL)act
|
||||
|
||||
// Out
|
||||
if (prevTargetView != nil && prevTargetTaggedView.tag != targetTaggedView.tag) {
|
||||
BOOL shouldEmitOutEvent = IsAnyViewInPathListeningToEvent(currentlyHoveredViews, ViewEvents::Offset::PointerOut);
|
||||
SharedTouchEventEmitter eventEmitter =
|
||||
GetTouchEmitterFromView(prevTargetView, [_rootComponentView convertPoint:clientLocation toView:prevTargetView]);
|
||||
if (eventEmitter != nil) {
|
||||
if (shouldEmitOutEvent && eventEmitter != nil) {
|
||||
eventEmitter->onPointerOut(event);
|
||||
}
|
||||
}
|
||||
@@ -816,14 +847,20 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithTarget : (id)target action : (SEL)act
|
||||
// we reverse iterate (now from target to root), actually emitting the events.
|
||||
NSMutableOrderedSet<UIView *> *viewsToEmitLeaveEventsTo = [NSMutableOrderedSet orderedSet];
|
||||
|
||||
BOOL hasParentLeaveListener = NO;
|
||||
for (RCTReactTaggedView *taggedView in [currentlyHoveredViews reverseObjectEnumerator]) {
|
||||
UIView *componentView = taggedView.view;
|
||||
|
||||
BOOL shouldEmitEvent = componentView != nil;
|
||||
BOOL shouldEmitEvent = componentView != nil &&
|
||||
(hasParentLeaveListener || IsViewListeningToEvent(taggedView, ViewEvents::Offset::PointerLeave));
|
||||
|
||||
if (shouldEmitEvent && ![eventPathViews containsObject:taggedView]) {
|
||||
[viewsToEmitLeaveEventsTo addObject:componentView];
|
||||
}
|
||||
|
||||
if (shouldEmitEvent && !hasParentLeaveListener) {
|
||||
hasParentLeaveListener = YES;
|
||||
}
|
||||
}
|
||||
|
||||
for (UIView *componentView in [viewsToEmitLeaveEventsTo reverseObjectEnumerator]) {
|
||||
@@ -836,9 +873,10 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithTarget : (id)target action : (SEL)act
|
||||
|
||||
// Over
|
||||
if (targetView != nil && prevTargetTaggedView.tag != targetTaggedView.tag) {
|
||||
BOOL shouldEmitOverEvent = IsAnyViewInPathListeningToEvent(eventPathViews, ViewEvents::Offset::PointerOver);
|
||||
SharedTouchEventEmitter eventEmitter =
|
||||
GetTouchEmitterFromView(targetView, [_rootComponentView convertPoint:clientLocation toView:targetView]);
|
||||
if (eventEmitter != nil) {
|
||||
if (shouldEmitOverEvent && eventEmitter != nil) {
|
||||
eventEmitter->onPointerOver(event);
|
||||
}
|
||||
}
|
||||
@@ -850,10 +888,12 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithTarget : (id)target action : (SEL)act
|
||||
// or if one of its parents is listening in case those listeners care about the capturing phase. Adding the ability
|
||||
// for native to distinguish between capturing listeners and not could be an optimization to further reduce the number
|
||||
// of events we send to JS
|
||||
BOOL hasParentEnterListener = NO;
|
||||
for (RCTReactTaggedView *taggedView in [eventPathViews reverseObjectEnumerator]) {
|
||||
UIView *componentView = taggedView.view;
|
||||
|
||||
BOOL shouldEmitEvent = componentView != nil;
|
||||
BOOL shouldEmitEvent = componentView != nil &&
|
||||
(hasParentEnterListener || IsViewListeningToEvent(taggedView, ViewEvents::Offset::PointerEnter));
|
||||
|
||||
if (shouldEmitEvent && ![currentlyHoveredViews containsObject:taggedView]) {
|
||||
SharedTouchEventEmitter eventEmitter =
|
||||
@@ -862,6 +902,10 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithTarget : (id)target action : (SEL)act
|
||||
eventEmitter->onPointerEnter(event);
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldEmitEvent && !hasParentEnterListener) {
|
||||
hasParentEnterListener = YES;
|
||||
}
|
||||
}
|
||||
|
||||
[_currentlyHoveredViewsPerPointer setObject:eventPathViews forKey:@(pointerId)];
|
||||
|
||||
@@ -62,10 +62,6 @@ struct ViewEvents {
|
||||
ClickCapture = 31,
|
||||
GotPointerCapture = 32,
|
||||
LostPointerCapture = 33,
|
||||
PointerDown = 34,
|
||||
PointerDownCapture = 35,
|
||||
PointerUp = 36,
|
||||
PointerUpCapture = 37,
|
||||
};
|
||||
|
||||
constexpr bool operator[](const Offset offset) const {
|
||||
|
||||
+8
-22
@@ -616,32 +616,18 @@ static inline ViewEvents convertRawProp(
|
||||
"onClickCapture",
|
||||
sourceValue[Offset::ClickCapture],
|
||||
defaultValue[Offset::ClickCapture]);
|
||||
result[Offset::PointerDown] = convertRawProp(
|
||||
result[Offset::GotPointerCapture] = convertRawProp(
|
||||
context,
|
||||
rawProps,
|
||||
"onPointerDown",
|
||||
sourceValue[Offset::PointerDown],
|
||||
defaultValue[Offset::PointerDown]);
|
||||
result[Offset::PointerDownCapture] = convertRawProp(
|
||||
"onGotPointerCapture",
|
||||
sourceValue[Offset::GotPointerCapture],
|
||||
defaultValue[Offset::GotPointerCapture]);
|
||||
result[Offset::LostPointerCapture] = convertRawProp(
|
||||
context,
|
||||
rawProps,
|
||||
"onPointerDownCapture",
|
||||
sourceValue[Offset::PointerDownCapture],
|
||||
defaultValue[Offset::PointerDownCapture]);
|
||||
result[Offset::PointerUp] = convertRawProp(
|
||||
context,
|
||||
rawProps,
|
||||
"onPointerUp",
|
||||
sourceValue[Offset::PointerUp],
|
||||
defaultValue[Offset::PointerUp]);
|
||||
result[Offset::PointerUpCapture] = convertRawProp(
|
||||
context,
|
||||
rawProps,
|
||||
"onPointerUpCapture",
|
||||
sourceValue[Offset::PointerUpCapture],
|
||||
defaultValue[Offset::PointerUpCapture]);
|
||||
// TODO: gotPointerCapture & lostPointerCapture (causes issues with
|
||||
// RawPropsKey for some reason)
|
||||
"onLostPointerCapture",
|
||||
sourceValue[Offset::LostPointerCapture],
|
||||
defaultValue[Offset::LostPointerCapture]);
|
||||
|
||||
// PanResponder callbacks
|
||||
result[Offset::MoveShouldSetResponder] = convertRawProp(
|
||||
|
||||
+17
-168
@@ -7,80 +7,9 @@
|
||||
|
||||
#include "PointerEventsProcessor.h"
|
||||
|
||||
#include <react/renderer/components/view/ViewShadowNode.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
static ShadowNode::Shared GetShadowNodeFromEventTarget(
|
||||
jsi::Runtime &runtime,
|
||||
EventTarget const &target) {
|
||||
auto instanceHandle = target.getInstanceHandle(runtime);
|
||||
if (instanceHandle.isObject()) {
|
||||
auto handleObj = instanceHandle.asObject(runtime);
|
||||
if (handleObj.hasProperty(runtime, "stateNode")) {
|
||||
auto stateNode = handleObj.getProperty(runtime, "stateNode");
|
||||
if (stateNode.isObject()) {
|
||||
auto stateNodeObj = stateNode.asObject(runtime);
|
||||
if (stateNodeObj.hasProperty(runtime, "node")) {
|
||||
auto node = stateNodeObj.getProperty(runtime, "node");
|
||||
return shadowNodeFromValue(runtime, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool IsViewListeningToEvents(
|
||||
ShadowNode const &shadowNode,
|
||||
std::initializer_list<ViewEvents::Offset> eventTypes) {
|
||||
if (auto viewShadowNode = traitCast<ViewShadowNode const *>(&shadowNode)) {
|
||||
auto &viewProps = viewShadowNode->getConcreteProps();
|
||||
for (const ViewEvents::Offset eventType : eventTypes) {
|
||||
if (viewProps.events[eventType]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsAnyViewInPathToRootListeningToEvents(
|
||||
UIManager const &uiManager,
|
||||
ShadowNode const &shadowNode,
|
||||
std::initializer_list<ViewEvents::Offset> eventTypes) {
|
||||
// Check the target view first
|
||||
if (IsViewListeningToEvents(shadowNode, eventTypes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Retrieve the node's root & a list of nodes between the target and the root
|
||||
auto owningRootShadowNode = ShadowNode::Shared{};
|
||||
uiManager.getShadowTreeRegistry().visit(
|
||||
shadowNode.getSurfaceId(),
|
||||
[&owningRootShadowNode](ShadowTree const &shadowTree) {
|
||||
owningRootShadowNode = shadowTree.getCurrentRevision().rootShadowNode;
|
||||
});
|
||||
|
||||
if (owningRootShadowNode == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto &nodeFamily = shadowNode.getFamily();
|
||||
auto ancestors = nodeFamily.getAncestors(*owningRootShadowNode);
|
||||
|
||||
// Check for listeners from the target's parent to the root
|
||||
for (auto it = ancestors.rbegin(); it != ancestors.rend(); it++) {
|
||||
auto ¤tNode = it->first.get();
|
||||
if (IsViewListeningToEvents(currentNode, eventTypes)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static PointerEventTarget RetargetPointerEvent(
|
||||
static PointerEventTarget retargetPointerEvent(
|
||||
PointerEvent const &event,
|
||||
ShadowNode const &nodeToTarget,
|
||||
UIManager const &uiManager) {
|
||||
@@ -130,72 +59,6 @@ static ShadowNode::Shared getCaptureTargetOverride(
|
||||
return maybeTarget.lock();
|
||||
}
|
||||
|
||||
/*
|
||||
* Centralized method which determines if an event should be sent to JS by
|
||||
* inspecing the listeners in the target's view path.
|
||||
*/
|
||||
static bool ShouldEmitPointerEvent(
|
||||
ShadowNode const &targetNode,
|
||||
std::string const &type,
|
||||
UIManager const &uiManager) {
|
||||
if (type == "topPointerDown") {
|
||||
return IsAnyViewInPathToRootListeningToEvents(
|
||||
uiManager,
|
||||
targetNode,
|
||||
{ViewEvents::Offset::PointerDown,
|
||||
ViewEvents::Offset::PointerDownCapture});
|
||||
} else if (type == "topPointerUp") {
|
||||
return IsAnyViewInPathToRootListeningToEvents(
|
||||
uiManager,
|
||||
targetNode,
|
||||
{ViewEvents::Offset::PointerUp, ViewEvents::Offset::PointerUpCapture});
|
||||
} else if (type == "topPointerMove") {
|
||||
return IsAnyViewInPathToRootListeningToEvents(
|
||||
uiManager,
|
||||
targetNode,
|
||||
{ViewEvents::Offset::PointerMove,
|
||||
ViewEvents::Offset::PointerMoveCapture});
|
||||
} else if (type == "topPointerEnter") {
|
||||
// This event goes through the capturing phase in full but only bubble
|
||||
// through the target and no futher up the tree
|
||||
return IsViewListeningToEvents(
|
||||
targetNode, {ViewEvents::Offset::PointerEnter}) ||
|
||||
IsAnyViewInPathToRootListeningToEvents(
|
||||
uiManager,
|
||||
targetNode,
|
||||
{ViewEvents::Offset::PointerEnterCapture});
|
||||
} else if (type == "topPointerLeave") {
|
||||
// This event goes through the capturing phase in full but only bubble
|
||||
// through the target and no futher up the tree
|
||||
return IsViewListeningToEvents(
|
||||
targetNode, {ViewEvents::Offset::PointerLeave}) ||
|
||||
IsAnyViewInPathToRootListeningToEvents(
|
||||
uiManager,
|
||||
targetNode,
|
||||
{ViewEvents::Offset::PointerLeaveCapture});
|
||||
} else if (type == "topPointerOver") {
|
||||
return IsAnyViewInPathToRootListeningToEvents(
|
||||
uiManager,
|
||||
targetNode,
|
||||
{ViewEvents::Offset::PointerOver,
|
||||
ViewEvents::Offset::PointerOverCapture});
|
||||
} else if (type == "topPointerOut") {
|
||||
return IsAnyViewInPathToRootListeningToEvents(
|
||||
uiManager,
|
||||
targetNode,
|
||||
{ViewEvents::Offset::PointerOut,
|
||||
ViewEvents::Offset::PointerOutCapture});
|
||||
} else if (type == "topClick") {
|
||||
return IsAnyViewInPathToRootListeningToEvents(
|
||||
uiManager,
|
||||
targetNode,
|
||||
{ViewEvents::Offset::Click, ViewEvents::Offset::ClickCapture});
|
||||
}
|
||||
// This is more of an optimization method so if we encounter a type which
|
||||
// has not been specifically addressed above we should just let it through.
|
||||
return true;
|
||||
}
|
||||
|
||||
void PointerEventsProcessor::interceptPointerEvent(
|
||||
jsi::Runtime &runtime,
|
||||
EventTarget const *target,
|
||||
@@ -216,18 +79,14 @@ void PointerEventsProcessor::interceptPointerEvent(
|
||||
if (overrideTarget != nullptr &&
|
||||
overrideTarget->getTag() != eventTarget->getTag()) {
|
||||
auto retargeted =
|
||||
RetargetPointerEvent(pointerEvent, *overrideTarget, uiManager);
|
||||
retargetPointerEvent(pointerEvent, *overrideTarget, uiManager);
|
||||
|
||||
pointerEvent = retargeted.event;
|
||||
eventTarget = retargeted.target.get();
|
||||
}
|
||||
|
||||
eventTarget->retain(runtime);
|
||||
auto shadowNode = GetShadowNodeFromEventTarget(runtime, *eventTarget);
|
||||
if (shadowNode != nullptr &&
|
||||
ShouldEmitPointerEvent(*shadowNode, type, uiManager)) {
|
||||
eventDispatcher(runtime, eventTarget, type, priority, pointerEvent);
|
||||
}
|
||||
eventDispatcher(runtime, eventTarget, type, priority, pointerEvent);
|
||||
eventTarget->release(runtime);
|
||||
|
||||
// Implicit pointer capture release
|
||||
@@ -297,38 +156,28 @@ void PointerEventsProcessor::processPendingPointerCapture(
|
||||
auto activeOverrideTag = (hasActiveOverride) ? activeOverride->getTag() : -1;
|
||||
|
||||
if (hasActiveOverride && activeOverrideTag != pendingOverrideTag) {
|
||||
auto retargeted = RetargetPointerEvent(event, *activeOverride, uiManager);
|
||||
auto retargeted = retargetPointerEvent(event, *activeOverride, uiManager);
|
||||
|
||||
retargeted.target->retain(runtime);
|
||||
auto shadowNode = GetShadowNodeFromEventTarget(runtime, *retargeted.target);
|
||||
if (shadowNode != nullptr &&
|
||||
ShouldEmitPointerEvent(
|
||||
*shadowNode, "topLostPointerCapture", uiManager)) {
|
||||
eventDispatcher(
|
||||
runtime,
|
||||
retargeted.target.get(),
|
||||
"topLostPointerCapture",
|
||||
ReactEventPriority::Discrete,
|
||||
retargeted.event);
|
||||
}
|
||||
eventDispatcher(
|
||||
runtime,
|
||||
retargeted.target.get(),
|
||||
"topLostPointerCapture",
|
||||
ReactEventPriority::Discrete,
|
||||
retargeted.event);
|
||||
retargeted.target->release(runtime);
|
||||
}
|
||||
|
||||
if (hasPendingOverride && activeOverrideTag != pendingOverrideTag) {
|
||||
auto retargeted = RetargetPointerEvent(event, *pendingOverride, uiManager);
|
||||
auto retargeted = retargetPointerEvent(event, *pendingOverride, uiManager);
|
||||
|
||||
retargeted.target->retain(runtime);
|
||||
auto shadowNode = GetShadowNodeFromEventTarget(runtime, *retargeted.target);
|
||||
if (shadowNode != nullptr &&
|
||||
ShouldEmitPointerEvent(
|
||||
*shadowNode, "topGotPointerCapture", uiManager)) {
|
||||
eventDispatcher(
|
||||
runtime,
|
||||
retargeted.target.get(),
|
||||
"topGotPointerCapture",
|
||||
ReactEventPriority::Discrete,
|
||||
retargeted.event);
|
||||
}
|
||||
eventDispatcher(
|
||||
runtime,
|
||||
retargeted.target.get(),
|
||||
"topGotPointerCapture",
|
||||
ReactEventPriority::Discrete,
|
||||
retargeted.event);
|
||||
retargeted.target->release(runtime);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user