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
This commit is contained in:
Valentin Shergin 2018-06-01 09:36:25 -07:00 committed by Facebook Github Bot
parent 0fc5a91889
commit beb3fcda34
7 changed files with 97 additions and 14 deletions

View File

@ -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;

View File

@ -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<std::mutex> lock(mutex_);
if (eventTarget_) {
return;
}
auto &&eventDispatcher = eventDispatcher_.lock();
assert(eventDispatcher);
eventTarget_ = eventDispatcher->createEventTarget(instanceHandle_);
}
void EventHandlers::releaseEventTargetIfNeeded() const {
std::lock_guard<std::mutex> lock(mutex_);
if (!eventTarget_) {
return;
}
auto &&eventDispatcher = eventDispatcher_.lock();
assert(eventDispatcher);
eventDispatcher->releaseEventTarget(eventTarget_);
}
} // namespace react

View File

@ -7,6 +7,7 @@
#pragma once
#include <memory>
#include <mutex>
#include <folly/dynamic.h>
#include <fabric/core/EventDispatcher.h>
@ -20,8 +21,6 @@ class EventHandlers;
using SharedEventHandlers = std::shared_ptr<const EventHandlers>;
/*
* 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<const EventHandlers>;
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<const EventDispatcher> eventDispatcher_;
mutable EventTarget eventTarget_ {nullptr};
mutable std::mutex mutex_;
};
} // namespace react

View File

@ -23,10 +23,14 @@ namespace facebook {
namespace react {
Scheduler::Scheduler() {
eventDispatcher_ = std::make_shared<SchedulerEventDispatcher>();
auto componentDescriptorRegistry = ComponentDescriptorFactory::buildRegistry(eventDispatcher_);
auto &&eventDispatcher = std::make_shared<SchedulerEventDispatcher>();
auto &&componentDescriptorRegistry = ComponentDescriptorFactory::buildRegistry(eventDispatcher);
uiManager_ = std::make_shared<FabricUIManager>(componentDescriptorRegistry);
uiManager_->setDelegate(this);
eventDispatcher->setUIManager(uiManager_);
eventDispatcher_ = eventDispatcher;
}
Scheduler::~Scheduler() {

View File

@ -73,7 +73,7 @@ private:
SchedulerDelegate *delegate_;
std::shared_ptr<FabricUIManager> uiManager_;
std::unordered_map<Tag, SharedShadowTree> shadowTreeRegistry_;
std::shared_ptr<SchedulerEventDispatcher> eventDispatcher_;
SharedSchedulerEventDispatcher eventDispatcher_;
};
} // namespace react

View File

@ -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<const FabricUIManager> 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

View File

@ -9,11 +9,16 @@
#include <fabric/core/EventDispatcher.h>
#include <fabric/core/EventPrimitives.h>
#include <fabric/uimanager/FabricUIManager.h>
#include <folly/dynamic.h>
namespace facebook {
namespace react {
class SchedulerEventDispatcher;
using SharedSchedulerEventDispatcher = std::shared_ptr<const SchedulerEventDispatcher>;
/*
* Concrete EventDispatcher.
*/
@ -22,12 +27,24 @@ class SchedulerEventDispatcher final:
public:
void setUIManager(std::shared_ptr<const FabricUIManager> 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<const FabricUIManager> uiManager_;
};
} // namespace react