From beb3fcda34395b165070c2b8f34d51fddde1d62a Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 1 Jun 2018 09:36:25 -0700 Subject: [PATCH] Fabric: The first version of event dispatching pipeline Summary: This is the first attempt to implement some base part of event dispatching pipeline from end-to-end. Even when it is working, all this is still incomplete and generally up in the air. We are still messing proper implementation of event queue, priority, and synchronization of react reconciliation process with event scheduling. Reviewed By: fkgozali Differential Revision: D8212271 fbshipit-source-id: 92f9427d14726441c70ffff294ac95eeb004152a --- .../fabric/core/events/EventDispatcher.h | 8 +++-- .../fabric/core/events/EventHandlers.cpp | 32 ++++++++++++++++++- .../fabric/core/events/EventHandlers.h | 10 ++++-- ReactCommon/fabric/uimanager/Scheduler.cpp | 8 +++-- ReactCommon/fabric/uimanager/Scheduler.h | 2 +- .../uimanager/SchedulerEventDispatcher.cpp | 30 +++++++++++++++-- .../uimanager/SchedulerEventDispatcher.h | 21 ++++++++++-- 7 files changed, 97 insertions(+), 14 deletions(-) diff --git a/ReactCommon/fabric/core/events/EventDispatcher.h b/ReactCommon/fabric/core/events/EventDispatcher.h index 354e35ed477..40e5184a212 100644 --- a/ReactCommon/fabric/core/events/EventDispatcher.h +++ b/ReactCommon/fabric/core/events/EventDispatcher.h @@ -28,12 +28,16 @@ class EventDispatcher { public: + virtual EventTarget createEventTarget(const InstanceHandle &instanceHandle) const = 0; + + virtual void releaseEventTarget(const EventTarget &eventTarget) const = 0; + /* * Dispatches "raw" event using some event-delivery infrastructure. */ virtual void dispatchEvent( - const InstanceHandle &instanceHandle, - const std::string &name, + const EventTarget &eventTarget, + const std::string &type, const folly::dynamic &payload, const EventPriority &priority ) const = 0; diff --git a/ReactCommon/fabric/core/events/EventHandlers.cpp b/ReactCommon/fabric/core/events/EventHandlers.cpp index 6980b3e7c10..3d4ecc80488 100644 --- a/ReactCommon/fabric/core/events/EventHandlers.cpp +++ b/ReactCommon/fabric/core/events/EventHandlers.cpp @@ -17,6 +17,10 @@ EventHandlers::EventHandlers(const InstanceHandle &instanceHandle, const Tag &ta tag_(tag), eventDispatcher_(eventDispatcher) {} +EventHandlers::~EventHandlers() { + releaseEventTargetIfNeeded(); +} + void EventHandlers::dispatchEvent( const std::string &type, const folly::dynamic &payload, @@ -27,13 +31,39 @@ void EventHandlers::dispatchEvent( return; } + createEventTargetIfNeeded(); + // Mixing `target` into `payload`. assert(payload.isObject()); folly::dynamic extendedPayload = folly::dynamic::object("target", tag_); extendedPayload.merge_patch(payload); // TODO(T29610783): Reconsider using dynamic dispatch here. - eventDispatcher->dispatchEvent(instanceHandle_, type, extendedPayload, priority); + eventDispatcher->dispatchEvent(eventTarget_, type, extendedPayload, priority); +} + +void EventHandlers::createEventTargetIfNeeded() const { + std::lock_guard lock(mutex_); + + if (eventTarget_) { + return; + } + + auto &&eventDispatcher = eventDispatcher_.lock(); + assert(eventDispatcher); + eventTarget_ = eventDispatcher->createEventTarget(instanceHandle_); +} + +void EventHandlers::releaseEventTargetIfNeeded() const { + std::lock_guard lock(mutex_); + + if (!eventTarget_) { + return; + } + + auto &&eventDispatcher = eventDispatcher_.lock(); + assert(eventDispatcher); + eventDispatcher->releaseEventTarget(eventTarget_); } } // namespace react diff --git a/ReactCommon/fabric/core/events/EventHandlers.h b/ReactCommon/fabric/core/events/EventHandlers.h index f2ae16fd6f0..b55db7dc7e4 100644 --- a/ReactCommon/fabric/core/events/EventHandlers.h +++ b/ReactCommon/fabric/core/events/EventHandlers.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include #include @@ -20,8 +21,6 @@ class EventHandlers; using SharedEventHandlers = std::shared_ptr; - - /* * Base class for all particular typed event handlers. * Stores `InstanceHandle` identifying a particular component and the pointer @@ -32,8 +31,8 @@ using SharedEventHandlers = std::shared_ptr; class EventHandlers { public: - virtual ~EventHandlers() = default; EventHandlers(const InstanceHandle &instanceHandle, const Tag &tag, const SharedEventDispatcher &eventDispatcher); + virtual ~EventHandlers(); protected: @@ -49,9 +48,14 @@ protected: private: + void createEventTargetIfNeeded() const; + void releaseEventTargetIfNeeded() const; + InstanceHandle instanceHandle_; Tag tag_; std::weak_ptr eventDispatcher_; + mutable EventTarget eventTarget_ {nullptr}; + mutable std::mutex mutex_; }; } // namespace react diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index d20e1f1b0a8..5a488f4da47 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -23,10 +23,14 @@ namespace facebook { namespace react { Scheduler::Scheduler() { - eventDispatcher_ = std::make_shared(); - auto componentDescriptorRegistry = ComponentDescriptorFactory::buildRegistry(eventDispatcher_); + auto &&eventDispatcher = std::make_shared(); + auto &&componentDescriptorRegistry = ComponentDescriptorFactory::buildRegistry(eventDispatcher); + uiManager_ = std::make_shared(componentDescriptorRegistry); uiManager_->setDelegate(this); + + eventDispatcher->setUIManager(uiManager_); + eventDispatcher_ = eventDispatcher; } Scheduler::~Scheduler() { diff --git a/ReactCommon/fabric/uimanager/Scheduler.h b/ReactCommon/fabric/uimanager/Scheduler.h index b63fbf666e2..6b6fae79dc1 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.h +++ b/ReactCommon/fabric/uimanager/Scheduler.h @@ -73,7 +73,7 @@ private: SchedulerDelegate *delegate_; std::shared_ptr uiManager_; std::unordered_map shadowTreeRegistry_; - std::shared_ptr eventDispatcher_; + SharedSchedulerEventDispatcher eventDispatcher_; }; } // namespace react diff --git a/ReactCommon/fabric/uimanager/SchedulerEventDispatcher.cpp b/ReactCommon/fabric/uimanager/SchedulerEventDispatcher.cpp index ad9f4413636..5cd608667b6 100644 --- a/ReactCommon/fabric/uimanager/SchedulerEventDispatcher.cpp +++ b/ReactCommon/fabric/uimanager/SchedulerEventDispatcher.cpp @@ -10,13 +10,37 @@ namespace facebook { namespace react { +// TODO(T29874519): Get rid of "top" prefix once and for all. +/* + * Capitalizes the first letter of the event type and adds "top" prefix + * (e.g. "layout" becames "topLayout"). + */ +static std::string normalizeEventType(const std::string &type) { + std::string prefixedType = type; + prefixedType[0] = toupper(prefixedType[0]); + prefixedType.insert(0, "top"); + return prefixedType; +} + +void SchedulerEventDispatcher::setUIManager(std::shared_ptr uiManager) { + uiManager_ = uiManager; +} + +EventTarget SchedulerEventDispatcher::createEventTarget(const InstanceHandle &instanceHandle) const { + return uiManager_->createEventTarget(instanceHandle); +} + +void SchedulerEventDispatcher::releaseEventTarget(const EventTarget &eventTarget) const { + uiManager_->releaseEventTarget(eventTarget); +} + void SchedulerEventDispatcher::dispatchEvent( - const InstanceHandle &instanceHandle, - const std::string &name, + const EventTarget &eventTarget, + const std::string &type, const folly::dynamic &payload, const EventPriority &priority ) const { - // Some future magic here. + uiManager_->dispatchEvent(eventTarget, normalizeEventType(type), payload); } } // namespace react diff --git a/ReactCommon/fabric/uimanager/SchedulerEventDispatcher.h b/ReactCommon/fabric/uimanager/SchedulerEventDispatcher.h index 17cd7610951..d7f6e190c0f 100644 --- a/ReactCommon/fabric/uimanager/SchedulerEventDispatcher.h +++ b/ReactCommon/fabric/uimanager/SchedulerEventDispatcher.h @@ -9,11 +9,16 @@ #include #include +#include #include namespace facebook { namespace react { +class SchedulerEventDispatcher; + +using SharedSchedulerEventDispatcher = std::shared_ptr; + /* * Concrete EventDispatcher. */ @@ -22,12 +27,24 @@ class SchedulerEventDispatcher final: public: + void setUIManager(std::shared_ptr uiManager); + +#pragma mark - EventDispatcher + + EventTarget createEventTarget(const InstanceHandle &instanceHandle) const override; + + void releaseEventTarget(const EventTarget &eventTarget) const override; + void dispatchEvent( - const InstanceHandle &instanceHandle, - const std::string &name, + const EventTarget &eventTarget, + const std::string &type, const folly::dynamic &payload, const EventPriority &priority ) const override; + +private: + + std::shared_ptr uiManager_; }; } // namespace react