Fabric: Introducing UIManagerCommitHook, unified way to alter commits

Summary:
The new UIManagerCommitHook can be used to implement commit-atering features without modifying the core.
E.g. State Reconciation seems can be implemented as a coomit hook but first we will use it for a new feature called Timeline (see the coming diffs).

Changelog: [Internal] Fabric-specific internal change.

Reviewed By: sammy-SC

Differential Revision: D25221312

fbshipit-source-id: dbe41b475bc8b36e1780d81447ab43b32758bdff
This commit is contained in:
Valentin Shergin
2020-12-18 16:01:30 -08:00
committed by Facebook GitHub Bot
parent d2ae775bf7
commit fb4e06b1a5
3 changed files with 83 additions and 0 deletions
@@ -10,6 +10,7 @@
#include <react/renderer/core/ShadowNodeFragment.h>
#include <react/renderer/debug/SystraceSection.h>
#include <react/renderer/graphics/Geometry.h>
#include <react/renderer/uimanager/UIManagerCommitHook.h>
#include <glog/logging.h>
@@ -330,13 +331,40 @@ ShadowTreeRegistry const &UIManager::getShadowTreeRegistry() const {
return shadowTreeRegistry_;
}
void UIManager::registerCommitHook(
UIManagerCommitHook const &commitHook) const {
std::unique_lock<better::shared_mutex> lock(commitHookMutex_);
assert(
std::find(commitHooks_.begin(), commitHooks_.end(), &commitHook) ==
commitHooks_.end());
commitHook.commitHookWasRegistered(*this);
commitHooks_.push_back(&commitHook);
}
void UIManager::unregisterCommitHook(
UIManagerCommitHook const &commitHook) const {
std::unique_lock<better::shared_mutex> lock(commitHookMutex_);
auto iterator =
std::find(commitHooks_.begin(), commitHooks_.end(), &commitHook);
assert(iterator != commitHooks_.end());
commitHooks_.erase(iterator);
commitHook.commitHookWasUnregistered(*this);
}
#pragma mark - ShadowTreeDelegate
RootShadowNode::Unshared UIManager::shadowTreeWillCommit(
ShadowTree const &shadowTree,
RootShadowNode::Shared const &oldRootShadowNode,
RootShadowNode::Unshared const &newRootShadowNode) const {
std::shared_lock<better::shared_mutex> lock(commitHookMutex_);
auto resultRootShadowNode = newRootShadowNode;
for (auto const *commitHook : commitHooks_) {
resultRootShadowNode = commitHook->shadowTreeWillCommit(
shadowTree, oldRootShadowNode, resultRootShadowNode);
}
return resultRootShadowNode;
}
@@ -25,6 +25,7 @@ namespace facebook {
namespace react {
class UIManagerBinding;
class UIManagerCommitHook;
class UIManager final : public ShadowTreeDelegate {
public:
@@ -67,6 +68,12 @@ class UIManager final : public ShadowTreeDelegate {
std::function<void(UIManagerBinding const &uiManagerBinding)> callback)
const;
/*
* Registers and unregisters a commit hook.
*/
void registerCommitHook(UIManagerCommitHook const &commitHook) const;
void unregisterCommitHook(UIManagerCommitHook const &commitHook) const;
#pragma mark - ShadowTreeDelegate
void shadowTreeDidFinishTransaction(
@@ -167,6 +174,9 @@ class UIManager final : public ShadowTreeDelegate {
// determine whether a commit should be cancelled. Only to be used
// inside UIManagerBinding.
std::atomic_uint_fast8_t completeRootEventCounter_{0};
mutable better::shared_mutex commitHookMutex_;
mutable std::vector<UIManagerCommitHook const *> commitHooks_;
};
} // namespace react
@@ -0,0 +1,45 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/renderer/components/root/RootShadowNode.h>
namespace facebook {
namespace react {
class ShadowTree;
class UIManager;
/*
* Implementing a commit hook allows to observe and alter Shadow Tree commits.
*/
class UIManagerCommitHook {
public:
/*
* Called right after the commit hook is registered or unregistered.
*/
virtual void commitHookWasRegistered(UIManager const &uiManager) const
noexcept = 0;
virtual void commitHookWasUnregistered(UIManager const &uiManager) const
noexcept = 0;
/*
* Called right before a `ShadowTree` commits a new tree.
* The semantic of the method corresponds to a method of the same name
* from `ShadowTreeDelegate`.
*/
virtual RootShadowNode::Unshared shadowTreeWillCommit(
ShadowTree const &shadowTree,
RootShadowNode::Shared const &oldRootShadowNode,
RootShadowNode::Unshared const &newRootShadowNode) const noexcept = 0;
virtual ~UIManagerCommitHook() noexcept = default;
};
} // namespace react
} // namespace facebook