Fabric: ShadowNodeFamily, the first steps

Summary:
ShadowNodeFamily is a new concept that allows us to implement an efficient way to solve the problem of finding a path to some ancestor node (practically reimplement ShadowNode::constructAncestorPath() in some efficient way).

This diff is the first one in the series. It introduces a new class and moves some data into it.

Reviewed By: JoshuaGross

Differential Revision: D14416947

fbshipit-source-id: c93865a8929a2128498e34d3589487696aac6283
This commit is contained in:
Valentin Shergin 2019-03-18 23:38:11 -07:00 коммит произвёл Facebook Github Bot
Родитель e0bbdbc040
Коммит 28e89e5081
9 изменённых файлов: 131 добавлений и 41 удалений

Просмотреть файл

@ -23,20 +23,25 @@ SharedShadowNodeSharedList ShadowNode::emptySharedShadowNodeSharedList() {
return emptySharedShadowNodeSharedList; return emptySharedShadowNodeSharedList;
} }
bool ShadowNode::sameFamily(const ShadowNode &first, const ShadowNode &second) {
return first.family_ == second.family_;
}
#pragma mark - Constructors #pragma mark - Constructors
ShadowNode::ShadowNode( ShadowNode::ShadowNode(
const ShadowNodeFragment &fragment, const ShadowNodeFragment &fragment,
const ComponentDescriptor &componentDescriptor) const ComponentDescriptor &componentDescriptor)
: tag_(fragment.tag), : props_(fragment.props),
rootTag_(fragment.rootTag),
props_(fragment.props),
eventEmitter_(fragment.eventEmitter),
children_( children_(
fragment.children ? fragment.children fragment.children ? fragment.children
: emptySharedShadowNodeSharedList()), : emptySharedShadowNodeSharedList()),
state_(fragment.state), state_(fragment.state),
componentDescriptor_(componentDescriptor), family_(std::make_shared<ShadowNodeFamily const>(
fragment.tag,
fragment.rootTag,
fragment.eventEmitter,
componentDescriptor)),
childrenAreShared_(true), childrenAreShared_(true),
revision_(1) { revision_(1) {
assert(props_); assert(props_);
@ -46,10 +51,7 @@ ShadowNode::ShadowNode(
ShadowNode::ShadowNode( ShadowNode::ShadowNode(
const ShadowNode &sourceShadowNode, const ShadowNode &sourceShadowNode,
const ShadowNodeFragment &fragment) const ShadowNodeFragment &fragment)
: tag_(sourceShadowNode.tag_), : props_(fragment.props ? fragment.props : sourceShadowNode.props_),
rootTag_(sourceShadowNode.rootTag_),
props_(fragment.props ? fragment.props : sourceShadowNode.props_),
eventEmitter_(fragment.eventEmitter),
children_( children_(
fragment.children ? fragment.children : sourceShadowNode.children_), fragment.children ? fragment.children : sourceShadowNode.children_),
localData_( localData_(
@ -58,7 +60,7 @@ ShadowNode::ShadowNode(
state_( state_(
fragment.state ? fragment.state fragment.state ? fragment.state
: sourceShadowNode.getCommitedState()), : sourceShadowNode.getCommitedState()),
componentDescriptor_(sourceShadowNode.componentDescriptor_), family_(sourceShadowNode.family_),
childrenAreShared_(true), childrenAreShared_(true),
revision_(sourceShadowNode.revision_ + 1) { revision_(sourceShadowNode.revision_ + 1) {
// `tag`, `surfaceId`, and `eventEmitter` cannot be changed with cloning. // `tag`, `surfaceId`, and `eventEmitter` cannot be changed with cloning.
@ -72,7 +74,7 @@ ShadowNode::ShadowNode(
} }
UnsharedShadowNode ShadowNode::clone(const ShadowNodeFragment &fragment) const { UnsharedShadowNode ShadowNode::clone(const ShadowNodeFragment &fragment) const {
return componentDescriptor_.cloneShadowNode(*this, fragment); return family_->componentDescriptor_.cloneShadowNode(*this, fragment);
} }
#pragma mark - Getters #pragma mark - Getters
@ -81,24 +83,24 @@ const SharedShadowNodeList &ShadowNode::getChildren() const {
return *children_; return *children_;
} }
SharedProps ShadowNode::getProps() const { const SharedProps &ShadowNode::getProps() const {
return props_; return props_;
} }
SharedEventEmitter ShadowNode::getEventEmitter() const { const SharedEventEmitter &ShadowNode::getEventEmitter() const {
return eventEmitter_; return family_->eventEmitter_;
} }
Tag ShadowNode::getTag() const { Tag ShadowNode::getTag() const {
return tag_; return family_->tag_;
} }
Tag ShadowNode::getRootTag() const { SurfaceId ShadowNode::getSurfaceId() const {
return rootTag_; return family_->surfaceId_;
} }
const ComponentDescriptor &ShadowNode::getComponentDescriptor() const { const ComponentDescriptor &ShadowNode::getComponentDescriptor() const {
return componentDescriptor_; return family_->componentDescriptor_;
} }
const State::Shared &ShadowNode::getState() const { const State::Shared &ShadowNode::getState() const {
@ -175,7 +177,7 @@ void ShadowNode::cloneChildrenIfShared() {
} }
void ShadowNode::setMounted(bool mounted) const { void ShadowNode::setMounted(bool mounted) const {
eventEmitter_->setEnabled(mounted); family_->eventEmitter_->setEnabled(mounted);
if (mounted && state_) { if (mounted && state_) {
state_->commit(*this); state_->commit(*this);
} }
@ -229,7 +231,7 @@ SharedDebugStringConvertibleList ShadowNode::getDebugChildren() const {
SharedDebugStringConvertibleList ShadowNode::getDebugProps() const { SharedDebugStringConvertibleList ShadowNode::getDebugProps() const {
return props_->getDebugProps() + return props_->getDebugProps() +
SharedDebugStringConvertibleList{ SharedDebugStringConvertibleList{
debugStringConvertibleItem("tag", folly::to<std::string>(tag_))}; debugStringConvertibleItem("tag", folly::to<std::string>(getTag()))};
} }
#endif #endif

Просмотреть файл

@ -17,6 +17,7 @@
#include <react/core/Props.h> #include <react/core/Props.h>
#include <react/core/ReactPrimitives.h> #include <react/core/ReactPrimitives.h>
#include <react/core/Sealable.h> #include <react/core/Sealable.h>
#include <react/core/ShadowNodeFamily.h>
#include <react/core/State.h> #include <react/core/State.h>
#include <react/debug/DebugStringConvertible.h> #include <react/debug/DebugStringConvertible.h>
@ -47,6 +48,12 @@ class ShadowNode : public virtual Sealable,
static SharedShadowNodeSharedList emptySharedShadowNodeSharedList(); static SharedShadowNodeSharedList emptySharedShadowNodeSharedList();
/*
* Returns `true` if nodes belong to the same family (they were cloned one
* from each other or from the same source node).
*/
static bool sameFamily(const ShadowNode &first, const ShadowNode &second);
#pragma mark - Constructors #pragma mark - Constructors
/* /*
@ -77,11 +84,11 @@ class ShadowNode : public virtual Sealable,
virtual ComponentHandle getComponentHandle() const = 0; virtual ComponentHandle getComponentHandle() const = 0;
virtual ComponentName getComponentName() const = 0; virtual ComponentName getComponentName() const = 0;
const SharedShadowNodeList &getChildren() const; SharedProps const &getProps() const;
SharedProps getProps() const; SharedShadowNodeList const &getChildren() const;
SharedEventEmitter getEventEmitter() const; SharedEventEmitter const &getEventEmitter() const;
Tag getTag() const; Tag getTag() const;
Tag getRootTag() const; SurfaceId getSurfaceId() const;
/* /*
* Returns a concrete `ComponentDescriptor` that manages nodes of this type. * Returns a concrete `ComponentDescriptor` that manages nodes of this type.
@ -155,10 +162,7 @@ class ShadowNode : public virtual Sealable,
#endif #endif
protected: protected:
Tag tag_;
Tag rootTag_;
SharedProps props_; SharedProps props_;
SharedEventEmitter eventEmitter_;
SharedShadowNodeSharedList children_; SharedShadowNodeSharedList children_;
SharedLocalData localData_; SharedLocalData localData_;
State::Shared state_; State::Shared state_;
@ -171,10 +175,9 @@ class ShadowNode : public virtual Sealable,
void cloneChildrenIfShared(); void cloneChildrenIfShared();
/* /*
* A reference to a concrete `ComponentDescriptor` that manages nodes of this * Pointer to a family object that this shadow node belongs to.
* type.
*/ */
const ComponentDescriptor &componentDescriptor_; ShadowNodeFamily::Shared family_;
/* /*
* Indicates that `children` list is shared between nodes and need * Indicates that `children` list is shared between nodes and need

Просмотреть файл

@ -0,0 +1,24 @@
/**
* 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.
*/
#include "ShadowNodeFamily.h"
namespace facebook {
namespace react {
ShadowNodeFamily::ShadowNodeFamily(
Tag tag,
SurfaceId surfaceId,
SharedEventEmitter const &eventEmitter,
ComponentDescriptor const &componentDescriptor)
: tag_(tag),
surfaceId_(surfaceId),
eventEmitter_(eventEmitter),
componentDescriptor_(componentDescriptor) {}
} // namespace react
} // namespace facebook

Просмотреть файл

@ -0,0 +1,61 @@
/**
* 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 <memory>
#include <react/core/EventEmitter.h>
#include <react/core/ReactPrimitives.h>
namespace facebook {
namespace react {
class ComponentDescriptor;
/*
* Represents all things that shadow nodes from the same family have in common.
* To be used inside `ShadowNode` class *only*.
*/
class ShadowNodeFamily {
public:
using Shared = std::shared_ptr<ShadowNodeFamily const>;
using Weak = std::weak_ptr<ShadowNodeFamily const>;
ShadowNodeFamily(
Tag tag,
SurfaceId surfaceId,
SharedEventEmitter const &eventEmitter,
ComponentDescriptor const &componentDescriptor);
private:
friend ShadowNode;
/*
* Deprecated.
*/
Tag const tag_;
/*
* Identifier of a running Surface instance.
*/
SurfaceId const surfaceId_;
/*
* `EventEmitter` associated with all nodes of the family.
*/
SharedEventEmitter const eventEmitter_;
/*
* Reference to a concrete `ComponentDescriptor` that manages nodes of this
* type.
*/
ComponentDescriptor const &componentDescriptor_;
};
} // namespace react
} // namespace facebook

Просмотреть файл

@ -34,7 +34,7 @@ TEST(ComponentDescriptorTest, createShadowNode) {
node->getComponentName().c_str(), TestShadowNode::Name().c_str()); node->getComponentName().c_str(), TestShadowNode::Name().c_str());
ASSERT_STREQ(node->getComponentName().c_str(), "Test"); ASSERT_STREQ(node->getComponentName().c_str(), "Test");
ASSERT_EQ(node->getTag(), 9); ASSERT_EQ(node->getTag(), 9);
ASSERT_EQ(node->getRootTag(), 1); ASSERT_EQ(node->getSurfaceId(), 1);
ASSERT_STREQ(node->getProps()->nativeId.c_str(), "abc"); ASSERT_STREQ(node->getProps()->nativeId.c_str(), "abc");
} }
@ -54,7 +54,7 @@ TEST(ComponentDescriptorTest, cloneShadowNode) {
ASSERT_STREQ(cloned->getComponentName().c_str(), "Test"); ASSERT_STREQ(cloned->getComponentName().c_str(), "Test");
ASSERT_EQ(cloned->getTag(), 9); ASSERT_EQ(cloned->getTag(), 9);
ASSERT_EQ(cloned->getRootTag(), 1); ASSERT_EQ(cloned->getSurfaceId(), 1);
ASSERT_STREQ(cloned->getProps()->nativeId.c_str(), "abc"); ASSERT_STREQ(cloned->getProps()->nativeId.c_str(), "abc");
} }

Просмотреть файл

@ -41,7 +41,7 @@ TEST(ShadowNodeTest, handleShadowNodeCreation) {
ASSERT_FALSE(node->getSealed()); ASSERT_FALSE(node->getSealed());
ASSERT_STREQ(node->getComponentName().c_str(), "Test"); ASSERT_STREQ(node->getComponentName().c_str(), "Test");
ASSERT_EQ(node->getTag(), 9); ASSERT_EQ(node->getTag(), 9);
ASSERT_EQ(node->getRootTag(), 1); ASSERT_EQ(node->getSurfaceId(), 1);
ASSERT_EQ(node->getEventEmitter(), nullptr); ASSERT_EQ(node->getEventEmitter(), nullptr);
ASSERT_EQ(node->getChildren().size(), 0); ASSERT_EQ(node->getChildren().size(), 0);
@ -67,7 +67,7 @@ TEST(ShadowNodeTest, handleShadowNodeSimpleCloning) {
ASSERT_STREQ(node->getComponentName().c_str(), "Test"); ASSERT_STREQ(node->getComponentName().c_str(), "Test");
ASSERT_EQ(node->getTag(), 9); ASSERT_EQ(node->getTag(), 9);
ASSERT_EQ(node->getRootTag(), 1); ASSERT_EQ(node->getSurfaceId(), 1);
ASSERT_EQ(node->getEventEmitter(), nullptr); ASSERT_EQ(node->getEventEmitter(), nullptr);
} }
@ -154,7 +154,7 @@ TEST(ShadowNodeTest, handleCloneFunction) {
// Both nodes have same content. // Both nodes have same content.
ASSERT_EQ(firstNode->getTag(), firstNodeClone->getTag()); ASSERT_EQ(firstNode->getTag(), firstNodeClone->getTag());
ASSERT_EQ(firstNode->getRootTag(), firstNodeClone->getRootTag()); ASSERT_EQ(firstNode->getSurfaceId(), firstNodeClone->getSurfaceId());
ASSERT_EQ(firstNode->getProps(), firstNodeClone->getProps()); ASSERT_EQ(firstNode->getProps(), firstNodeClone->getProps());
} }

Просмотреть файл

@ -218,8 +218,8 @@ ShadowViewMutationList calculateShadowViewMutations(
const ShadowNode &newRootShadowNode) { const ShadowNode &newRootShadowNode) {
SystraceSection s("calculateShadowViewMutations"); SystraceSection s("calculateShadowViewMutations");
// Root shadow nodes must have same tag. // Root shadow nodes must be belong the same family.
assert(oldRootShadowNode.getTag() == newRootShadowNode.getTag()); assert(ShadowNode::sameFamily(oldRootShadowNode, newRootShadowNode));
ShadowViewMutationList mutations; ShadowViewMutationList mutations;

Просмотреть файл

@ -281,7 +281,7 @@ void Scheduler::uiManagerDidCreateShadowNode(
if (delegate_) { if (delegate_) {
auto shadowView = ShadowView(*shadowNode); auto shadowView = ShadowView(*shadowNode);
delegate_->schedulerDidRequestPreliminaryViewAllocation( delegate_->schedulerDidRequestPreliminaryViewAllocation(
shadowNode->getRootTag(), shadowView); shadowNode->getSurfaceId(), shadowView);
} }
} }

Просмотреть файл

@ -98,7 +98,7 @@ void UIManager::setNativeProps(
}); });
shadowTreeRegistry_->visit( shadowTreeRegistry_->visit(
shadowNode->getRootTag(), [&](const ShadowTree &shadowTree) { shadowNode->getSurfaceId(), [&](const ShadowTree &shadowTree) {
shadowTree.tryCommit( shadowTree.tryCommit(
[&](const SharedRootShadowNode &oldRootShadowNode) { [&](const SharedRootShadowNode &oldRootShadowNode) {
return oldRootShadowNode->clone(shadowNode, newShadowNode); return oldRootShadowNode->clone(shadowNode, newShadowNode);
@ -116,7 +116,7 @@ LayoutMetrics UIManager::getRelativeLayoutMetrics(
if (!ancestorShadowNode) { if (!ancestorShadowNode) {
shadowTreeRegistry_->visit( shadowTreeRegistry_->visit(
shadowNode.getRootTag(), [&](const ShadowTree &shadowTree) { shadowNode.getSurfaceId(), [&](const ShadowTree &shadowTree) {
shadowTree.tryCommit( shadowTree.tryCommit(
[&](const SharedRootShadowNode &oldRootShadowNode) { [&](const SharedRootShadowNode &oldRootShadowNode) {
ancestorShadowNode = oldRootShadowNode.get(); ancestorShadowNode = oldRootShadowNode.get();
@ -158,7 +158,7 @@ void UIManager::updateState(
}); });
shadowTreeRegistry_->visit( shadowTreeRegistry_->visit(
shadowNode->getRootTag(), [&](const ShadowTree &shadowTree) { shadowNode->getSurfaceId(), [&](const ShadowTree &shadowTree) {
shadowTree.tryCommit( shadowTree.tryCommit(
[&](const SharedRootShadowNode &oldRootShadowNode) { [&](const SharedRootShadowNode &oldRootShadowNode) {
return oldRootShadowNode->clone(shadowNode, newShadowNode); return oldRootShadowNode->clone(shadowNode, newShadowNode);