Fabric: Introducing `ShadowTree`
Summary: ShadowTree is an abstraction around (commited) root shadow node and managing its lifecycle. Reviewed By: mdvacca Differential Revision: D7857049 fbshipit-source-id: 8d530e0366fc703e4aef4ec88dd8ea990dafaaf1
This commit is contained in:
parent
2bb41031ba
commit
a879842033
|
@ -19,7 +19,6 @@ namespace react {
|
|||
|
||||
Scheduler::Scheduler() {
|
||||
auto componentDescriptorRegistry = std::make_shared<ComponentDescriptorRegistry>();
|
||||
|
||||
componentDescriptorRegistry->registerComponentDescriptor(std::make_shared<ViewComponentDescriptor>());
|
||||
componentDescriptorRegistry->registerComponentDescriptor(std::make_shared<ParagraphComponentDescriptor>());
|
||||
componentDescriptorRegistry->registerComponentDescriptor(std::make_shared<TextComponentDescriptor>());
|
||||
|
@ -34,12 +33,29 @@ Scheduler::~Scheduler() {
|
|||
}
|
||||
|
||||
void Scheduler::registerRootTag(Tag rootTag) {
|
||||
auto rootShadowNode = std::make_shared<RootShadowNode>(rootTag, rootTag, nullptr);
|
||||
rootNodeRegistry_.insert({rootTag, rootShadowNode});
|
||||
auto &&shadowTree = std::make_shared<ShadowTree>(rootTag);
|
||||
shadowTree->setDelegate(this);
|
||||
shadowTreeRegistry_.insert({rootTag, shadowTree});
|
||||
}
|
||||
|
||||
void Scheduler::unregisterRootTag(Tag rootTag) {
|
||||
rootNodeRegistry_.erase(rootTag);
|
||||
auto &&iterator = shadowTreeRegistry_.find(rootTag);
|
||||
auto &&shadowTree = iterator->second;
|
||||
assert(shadowTree);
|
||||
shadowTree->setDelegate(nullptr);
|
||||
shadowTreeRegistry_.erase(iterator);
|
||||
}
|
||||
|
||||
Size Scheduler::measure(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
|
||||
auto &&shadowTree = shadowTreeRegistry_.at(rootTag);
|
||||
assert(shadowTree);
|
||||
return shadowTree->measure(layoutConstraints, layoutContext);
|
||||
}
|
||||
|
||||
void Scheduler::constraintLayout(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) {
|
||||
auto &&shadowTree = shadowTreeRegistry_.at(rootTag);
|
||||
assert(shadowTree);
|
||||
return shadowTree->constraintLayout(layoutConstraints, layoutContext);
|
||||
}
|
||||
|
||||
#pragma mark - Delegate
|
||||
|
@ -48,53 +64,25 @@ void Scheduler::setDelegate(SchedulerDelegate *delegate) {
|
|||
delegate_ = delegate;
|
||||
}
|
||||
|
||||
SchedulerDelegate *Scheduler::getDelegate() {
|
||||
SchedulerDelegate *Scheduler::getDelegate() const {
|
||||
return delegate_;
|
||||
}
|
||||
|
||||
#pragma mark - ShadowTreeDelegate
|
||||
|
||||
void Scheduler::shadowTreeDidCommit(const SharedShadowTree &shadowTree, const TreeMutationInstructionList &instructions) {
|
||||
if (delegate_) {
|
||||
delegate_->schedulerDidComputeMutationInstructions(shadowTree->getRootTag(), instructions);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UIManagerDelegate
|
||||
|
||||
void Scheduler::uiManagerDidFinishTransaction(Tag rootTag, const SharedShadowNodeUnsharedList &rootChildNodes) {
|
||||
SharedRootShadowNode oldRootShadowNode = rootNodeRegistry_[rootTag];
|
||||
assert(oldRootShadowNode);
|
||||
|
||||
SharedRootShadowNode newRootShadowNode =
|
||||
std::make_shared<RootShadowNode>(oldRootShadowNode, nullptr, SharedShadowNodeSharedList(rootChildNodes));
|
||||
|
||||
auto nonConstOldRootShadowNode = std::const_pointer_cast<RootShadowNode>(oldRootShadowNode);
|
||||
auto nonConstNewRootShadowNode = std::const_pointer_cast<RootShadowNode>(newRootShadowNode);
|
||||
|
||||
LayoutContext layoutContext = LayoutContext();
|
||||
|
||||
LOG(INFO) << "Old Shadow Tree: \n" << oldRootShadowNode->getDebugDescription();
|
||||
LOG(INFO) << "New Shadow Tree *before* layout: \n" << newRootShadowNode->getDebugDescription();
|
||||
|
||||
nonConstNewRootShadowNode->layout(layoutContext);
|
||||
|
||||
nonConstNewRootShadowNode->sealRecursive();
|
||||
|
||||
LOG(INFO) << "New Shadow Tree *after* layout: \n" << nonConstNewRootShadowNode->getDebugDescription();
|
||||
|
||||
TreeMutationInstructionList instructions = TreeMutationInstructionList();
|
||||
|
||||
calculateMutationInstructions(
|
||||
instructions,
|
||||
oldRootShadowNode,
|
||||
oldRootShadowNode->ShadowNode::getChildren(),
|
||||
newRootShadowNode->ShadowNode::getChildren()
|
||||
);
|
||||
|
||||
LOG(INFO) << "TreeMutationInstructionList:";
|
||||
|
||||
for (auto instruction : instructions) {
|
||||
LOG(INFO) << "Instruction: " << instruction.getDebugDescription();
|
||||
}
|
||||
|
||||
rootNodeRegistry_[rootTag] = newRootShadowNode;
|
||||
|
||||
if (delegate_) {
|
||||
delegate_->schedulerDidComputeMutationInstructions(rootTag, instructions);
|
||||
}
|
||||
auto &&iterator = shadowTreeRegistry_.find(rootTag);
|
||||
auto &&shadowTree = iterator->second;
|
||||
assert(shadowTree);
|
||||
return shadowTree->complete(rootChildNodes);
|
||||
}
|
||||
|
||||
void Scheduler::uiManagerDidCreateShadowNode(const SharedShadowNode &shadowNode) {
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <fabric/core/LayoutConstraints.h>
|
||||
#include <fabric/uimanager/SchedulerDelegate.h>
|
||||
#include <fabric/uimanager/UIManagerDelegate.h>
|
||||
#include <fabric/uimanager/ShadowTree.h>
|
||||
#include <fabric/uimanager/ShadowTreeDelegate.h>
|
||||
#include <fabric/view/ViewShadowNode.h>
|
||||
#include <fabric/view/RootShadowNode.h>
|
||||
|
||||
|
@ -20,18 +22,21 @@ class FabricUIManager;
|
|||
* Scheduler coordinates Shadow Tree updates and event flows.
|
||||
*/
|
||||
class Scheduler:
|
||||
public UIManagerDelegate {
|
||||
public UIManagerDelegate,
|
||||
public ShadowTreeDelegate {
|
||||
|
||||
public:
|
||||
Scheduler();
|
||||
virtual ~Scheduler();
|
||||
|
||||
#pragma mark - Root Nodes Managerment
|
||||
Scheduler();
|
||||
~Scheduler();
|
||||
|
||||
#pragma mark - Shadow Tree Management
|
||||
|
||||
void registerRootTag(Tag rootTag);
|
||||
void unregisterRootTag(Tag rootTag);
|
||||
|
||||
void setLayoutConstraints(Tag rootTag, LayoutConstraints layoutConstraints);
|
||||
Size measure(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const;
|
||||
void constraintLayout(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext);
|
||||
|
||||
#pragma mark - Delegate
|
||||
|
||||
|
@ -41,13 +46,17 @@ public:
|
|||
* the pointer before being destroyed.
|
||||
*/
|
||||
void setDelegate(SchedulerDelegate *delegate);
|
||||
SchedulerDelegate *getDelegate();
|
||||
SchedulerDelegate *getDelegate() const;
|
||||
|
||||
#pragma mark - UIManagerDelegate
|
||||
|
||||
void uiManagerDidFinishTransaction(Tag rootTag, const SharedShadowNodeUnsharedList &rootChildNodes) override;
|
||||
void uiManagerDidCreateShadowNode(const SharedShadowNode &shadowNode) override;
|
||||
|
||||
#pragma mark - ShadowTreeDelegate
|
||||
|
||||
void shadowTreeDidCommit(const SharedShadowTree &shadowTree, const TreeMutationInstructionList &instructions) override;
|
||||
|
||||
#pragma mark - Deprecated
|
||||
|
||||
/*
|
||||
|
@ -56,13 +65,10 @@ public:
|
|||
std::shared_ptr<FabricUIManager> getUIManager_DO_NOT_USE();
|
||||
|
||||
private:
|
||||
|
||||
SchedulerDelegate *delegate_;
|
||||
std::shared_ptr<FabricUIManager> uiManager_;
|
||||
|
||||
/*
|
||||
* All commited `RootShadowNode` instances to differentiate against.
|
||||
*/
|
||||
std::unordered_map<Tag, SharedRootShadowNode> rootNodeRegistry_;
|
||||
std::unordered_map<Tag, SharedShadowTree> shadowTreeRegistry_;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include "ShadowTree.h"
|
||||
|
||||
#include <fabric/core/LayoutContext.h>
|
||||
#include <fabric/core/LayoutPrimitives.h>
|
||||
|
||||
#include "ShadowTreeDelegate.h"
|
||||
#include "Differentiator.h"
|
||||
#include "TreeMutationInstruction.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
ShadowTree::ShadowTree(Tag rootTag):
|
||||
rootTag_(rootTag) {
|
||||
|
||||
rootShadowNode_ = std::make_shared<RootShadowNode>(
|
||||
rootTag,
|
||||
rootTag,
|
||||
nullptr,
|
||||
RootShadowNode::defaultSharedProps()
|
||||
);
|
||||
}
|
||||
|
||||
Tag ShadowTree::getRootTag() const {
|
||||
return rootTag_;
|
||||
}
|
||||
|
||||
#pragma mark - Layout
|
||||
|
||||
Size ShadowTree::measure(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
|
||||
auto newRootShadowNode = cloneRootShadowNode(layoutConstraints, layoutContext);
|
||||
newRootShadowNode->layout();
|
||||
return newRootShadowNode->getLayoutMetrics().frame.size;
|
||||
}
|
||||
|
||||
void ShadowTree::constraintLayout(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) {
|
||||
auto newRootShadowNode = cloneRootShadowNode(layoutConstraints, layoutContext);
|
||||
complete(newRootShadowNode);
|
||||
}
|
||||
|
||||
#pragma mark - Commiting
|
||||
|
||||
UnsharedRootShadowNode ShadowTree::cloneRootShadowNode(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
|
||||
auto oldRootShadowNode = rootShadowNode_;
|
||||
auto &&props = std::make_shared<RootProps>(*oldRootShadowNode->getProps());
|
||||
props->applyLayoutConstraints(layoutConstraints);
|
||||
props->applyLayoutContext(layoutContext);
|
||||
auto newRootShadowNode = std::make_shared<RootShadowNode>(oldRootShadowNode, props, nullptr);
|
||||
return newRootShadowNode;
|
||||
}
|
||||
|
||||
void ShadowTree::complete(const SharedShadowNodeUnsharedList &rootChildNodes) {
|
||||
auto oldRootShadowNode = rootShadowNode_;
|
||||
auto newRootShadowNode =
|
||||
std::make_shared<RootShadowNode>(oldRootShadowNode, nullptr, SharedShadowNodeSharedList(rootChildNodes));
|
||||
|
||||
complete(newRootShadowNode);
|
||||
}
|
||||
|
||||
void ShadowTree::complete(UnsharedRootShadowNode newRootShadowNode) {
|
||||
SharedRootShadowNode oldRootShadowNode = rootShadowNode_;
|
||||
|
||||
newRootShadowNode->layout();
|
||||
|
||||
newRootShadowNode->sealRecursive();
|
||||
|
||||
TreeMutationInstructionList instructions = TreeMutationInstructionList();
|
||||
|
||||
calculateMutationInstructions(
|
||||
instructions,
|
||||
oldRootShadowNode,
|
||||
oldRootShadowNode->ShadowNode::getChildren(),
|
||||
newRootShadowNode->ShadowNode::getChildren()
|
||||
);
|
||||
|
||||
if (commit(newRootShadowNode)) {
|
||||
if (delegate_) {
|
||||
delegate_->shadowTreeDidCommit(shared_from_this(), instructions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ShadowTree::commit(const SharedRootShadowNode &newRootShadowNode) {
|
||||
std::lock_guard<std::mutex> lock(commitMutex_);
|
||||
|
||||
if (newRootShadowNode->getSourceNode() != rootShadowNode_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rootShadowNode_ = newRootShadowNode;
|
||||
return true;
|
||||
}
|
||||
|
||||
#pragma mark - Delegate
|
||||
|
||||
void ShadowTree::setDelegate(ShadowTreeDelegate *delegate) {
|
||||
delegate_ = delegate;
|
||||
}
|
||||
|
||||
ShadowTreeDelegate *ShadowTree::getDelegate() const {
|
||||
return delegate_;
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -0,0 +1,87 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include <fabric/core/LayoutConstraints.h>
|
||||
#include <fabric/core/ReactPrimitives.h>
|
||||
#include <fabric/core/ShadowNode.h>
|
||||
#include <fabric/uimanager/ShadowTreeDelegate.h>
|
||||
#include <fabric/view/RootShadowNode.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class ShadowTree;
|
||||
|
||||
using SharedShadowTree = std::shared_ptr<ShadowTree>;
|
||||
|
||||
/*
|
||||
* Represents the shadow tree and its lifecycle.
|
||||
*/
|
||||
class ShadowTree final:
|
||||
public std::enable_shared_from_this<ShadowTree> {
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
* Creates a new shadow tree instance with given `rootTag`.
|
||||
*/
|
||||
ShadowTree(Tag rootTag);
|
||||
|
||||
/*
|
||||
* Returns the rootTag associated with the shadow tree (the tag of the
|
||||
* root shadow node).
|
||||
*/
|
||||
Tag getRootTag() const;
|
||||
|
||||
#pragma mark - Layout
|
||||
|
||||
/*
|
||||
* Measures the shadow tree with given `layoutConstraints` and `layoutContext`.
|
||||
* Can be called from any thread, side-effect-less.
|
||||
*/
|
||||
Size measure(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const;
|
||||
|
||||
/*
|
||||
* Applies given `layoutConstraints` and `layoutContext` and commit
|
||||
* the new shadow tree.
|
||||
* Can be called from any thread.
|
||||
*/
|
||||
void constraintLayout(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext);
|
||||
|
||||
#pragma mark - Application
|
||||
|
||||
/*
|
||||
* Create a new shadow tree with given `rootChildNodes` and commit.
|
||||
* Can be called from any thread.
|
||||
*/
|
||||
void complete(const SharedShadowNodeUnsharedList &rootChildNodes);
|
||||
|
||||
#pragma mark - Delegate
|
||||
|
||||
/*
|
||||
* Sets and gets the delegate.
|
||||
* The delegate is stored as a raw pointer, so the owner must null
|
||||
* the pointer before being destroyed.
|
||||
*/
|
||||
void setDelegate(ShadowTreeDelegate *delegate);
|
||||
ShadowTreeDelegate *getDelegate() const;
|
||||
|
||||
private:
|
||||
|
||||
UnsharedRootShadowNode cloneRootShadowNode(const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const;
|
||||
void complete(UnsharedRootShadowNode newRootShadowNode);
|
||||
bool commit(const SharedRootShadowNode &newRootShadowNode);
|
||||
|
||||
const Tag rootTag_;
|
||||
SharedRootShadowNode rootShadowNode_;
|
||||
ShadowTreeDelegate *delegate_;
|
||||
mutable std::mutex commitMutex_ {};
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fabric/uimanager/TreeMutationInstruction.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class ShadowTree;
|
||||
|
||||
/*
|
||||
* Abstract class for ShadowTree's delegate.
|
||||
*/
|
||||
class ShadowTreeDelegate {
|
||||
public:
|
||||
|
||||
/*
|
||||
* Called right after Shadow Tree commit a new state of the the tree.
|
||||
*/
|
||||
virtual void shadowTreeDidCommit(const std::shared_ptr<ShadowTree> &shadowTree, const TreeMutationInstructionList &instructions) = 0;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
Loading…
Reference in New Issue