Fabric/Text: ConcreteViewShadowNode - base class for all `View`-like shadow nodes

Summary: Quite trivial split ViewShadowNode into concrete class and templace class.

Reviewed By: fkgozali

Differential Revision: D7595017

fbshipit-source-id: b1ac1dfa187e5cfd0a34fbf84b3e1ae308bb0c99
This commit is contained in:
Valentin Shergin 2018-04-26 17:51:29 -07:00 committed by Facebook Github Bot
parent bd91eaf664
commit f72df7a6e7
3 changed files with 173 additions and 168 deletions

View File

@ -0,0 +1,167 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* 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 <fabric/core/ConcreteShadowNode.h>
#include <fabric/core/LayoutableShadowNode.h>
#include <fabric/core/ShadowNode.h>
#include <fabric/debug/DebugStringConvertibleItem.h>
#include <fabric/view/AccessibleShadowNode.h>
#include <fabric/view/ViewProps.h>
#include <fabric/view/YogaLayoutableShadowNode.h>
namespace facebook {
namespace react {
/*
* Template for all <View>-like classes (classes which have all same props
* as <View> and similar basic behaviour).
* For example: <Paragraph>, <Image>, but not <Text>, <RawText>.
*/
template <typename ViewPropsT>
class ConcreteViewShadowNode:
public ConcreteShadowNode<ViewPropsT>,
public AccessibleShadowNode,
public YogaLayoutableShadowNode {
static_assert(std::is_base_of<ViewProps, ViewPropsT>::value, "ViewPropsT must be a descendant of ViewProps");
static_assert(std::is_base_of<YogaStylableProps, ViewPropsT>::value, "ViewPropsT must be a descendant of YogaStylableProps");
static_assert(std::is_base_of<AccessibilityProps, ViewPropsT>::value, "ViewPropsT must be a descendant of AccessibilityProps");
public:
using ConcreteViewProps = ViewPropsT;
using SharedConcreteViewProps = std::shared_ptr<const ViewPropsT>;
using SharedConcreteViewShadowNode = std::shared_ptr<const ConcreteViewShadowNode>;
ConcreteViewShadowNode(
const Tag &tag,
const Tag &rootTag,
const InstanceHandle &instanceHandle,
const SharedViewProps &props = ConcreteViewShadowNode::defaultSharedProps(),
const SharedShadowNodeSharedList &children = ShadowNode::emptySharedShadowNodeSharedList(),
const ShadowNodeCloneFunction &cloneFunction = nullptr
):
ConcreteShadowNode<ViewPropsT>(
tag,
rootTag,
instanceHandle,
props,
children,
cloneFunction
),
AccessibleShadowNode(
props
),
YogaLayoutableShadowNode(
props,
children
) {};
ConcreteViewShadowNode(
const SharedConcreteViewShadowNode &shadowNode,
const SharedViewProps &props = nullptr,
const SharedShadowNodeSharedList &children = nullptr
):
ConcreteShadowNode<ViewPropsT>(
shadowNode,
props,
children
),
AccessibleShadowNode(
shadowNode,
props
),
YogaLayoutableShadowNode(
shadowNode,
props,
children
) {};
void appendChild(const SharedShadowNode &child) {
ensureUnsealed();
ShadowNode::appendChild(child);
auto yogaLayoutableChild = std::dynamic_pointer_cast<const YogaLayoutableShadowNode>(child);
if (yogaLayoutableChild) {
YogaLayoutableShadowNode::appendChild(yogaLayoutableChild);
}
}
SharedLayoutableShadowNode cloneAndReplaceChild(const SharedLayoutableShadowNode &child) override {
ensureUnsealed();
auto childShadowNode = std::dynamic_pointer_cast<const ShadowNode>(child);
assert(childShadowNode);
auto childShadowNodeClone = childShadowNode->clone();
// This is overloading of `SharedLayoutableShadowNode::cloneAndReplaceChild`,
// the method is used to clone some node as a preparation for future mutation
// caused by relayout.
// Because those changes are not requested by UIManager, they add a layer
// of node generation (between the committed stage and new proposed stage).
// That additional layer confuses the Diffing algorithm which uses
// `sourceNode` for referencing the previous (aka committed) stage
// of the tree to produce mutation instructions.
// In other words, if we don't compensate this change here,
// the Diffing algorithm will compare wrong trees
// ("new-but-not-laid-out-yet vs. new" instead of "committed vs. new").
auto nonConstChildShadowNodeClone = std::const_pointer_cast<ShadowNode>(childShadowNodeClone);
nonConstChildShadowNodeClone->shallowSourceNode();
ShadowNode::replaceChild(childShadowNode, childShadowNodeClone);
return std::dynamic_pointer_cast<const LayoutableShadowNode>(childShadowNodeClone);
}
#pragma mark - Equality
bool operator==(const ShadowNode& rhs) const override {
if (!ShadowNode::operator==(rhs)) {
return false;
}
auto &&other = static_cast<const ConcreteViewShadowNode&>(rhs);
return getLayoutMetrics() == other.getLayoutMetrics();
}
#pragma mark - DebugStringConvertible
SharedDebugStringConvertibleList getDebugProps() const override {
SharedDebugStringConvertibleList list = {};
auto basePropsList = ShadowNode::getDebugProps();
std::move(basePropsList.begin(), basePropsList.end(), std::back_inserter(list));
list.push_back(std::make_shared<DebugStringConvertibleItem>("layout", "", YogaLayoutableShadowNode::getDebugProps()));
return list;
}
private:
#pragma mark - LayoutableShadowNode
SharedLayoutableShadowNodeList getLayoutableChildNodes() const override {
SharedLayoutableShadowNodeList sharedLayoutableShadowNodeList = {};
for (auto child : *ShadowNode::children_) {
const SharedLayoutableShadowNode layoutableShadowNode = std::dynamic_pointer_cast<const LayoutableShadowNode>(child);
if (!layoutableShadowNode) {
continue;
}
sharedLayoutableShadowNodeList.push_back(layoutableShadowNode);
}
return sharedLayoutableShadowNodeList;
}
};
} // namespace react
} // namespace facebook

View File

@ -7,138 +7,12 @@
#include "ViewShadowNode.h"
#include <algorithm>
#include <fabric/debug/DebugStringConvertibleItem.h>
namespace facebook {
namespace react {
#pragma mark - Constructors
ViewShadowNode::ViewShadowNode(
const Tag &tag,
const Tag &rootTag,
const InstanceHandle &instanceHandle,
const SharedViewProps &props,
const SharedShadowNodeSharedList &children,
const ShadowNodeCloneFunction &cloneFunction
):
ConcreteShadowNode(
tag,
rootTag,
instanceHandle,
props,
children,
cloneFunction
),
AccessibleShadowNode(
props
),
YogaLayoutableShadowNode(
props,
children
) {};
ViewShadowNode::ViewShadowNode(
const SharedViewShadowNode &shadowNode,
const SharedViewProps &props,
const SharedShadowNodeSharedList &children
):
ConcreteShadowNode(
shadowNode,
props,
children
),
AccessibleShadowNode(
shadowNode,
props
),
YogaLayoutableShadowNode(
shadowNode,
props,
children
) {};
ComponentName ViewShadowNode::getComponentName() const {
return ComponentName("View");
}
void ViewShadowNode::appendChild(const SharedShadowNode &child) {
ensureUnsealed();
ShadowNode::appendChild(child);
auto yogaLayoutableChild = std::dynamic_pointer_cast<const YogaLayoutableShadowNode>(child);
if (yogaLayoutableChild) {
YogaLayoutableShadowNode::appendChild(yogaLayoutableChild);
}
}
#pragma mark - YogaLayoutableShadowNode
SharedLayoutableShadowNodeList ViewShadowNode::getLayoutableChildNodes() const {
SharedLayoutableShadowNodeList sharedLayoutableShadowNodeList = {};
for (auto child : *children_) {
const SharedLayoutableShadowNode layoutableShadowNode = std::dynamic_pointer_cast<const LayoutableShadowNode>(child);
if (!layoutableShadowNode) {
continue;
}
sharedLayoutableShadowNodeList.push_back(layoutableShadowNode);
}
return sharedLayoutableShadowNodeList;
}
SharedLayoutableShadowNode ViewShadowNode::cloneAndReplaceChild(const SharedLayoutableShadowNode &child) {
ensureUnsealed();
auto childShadowNode = std::dynamic_pointer_cast<const ShadowNode>(child);
assert(childShadowNode);
auto childShadowNodeClone = childShadowNode->clone();
// This is overloading of `SharedLayoutableShadowNode::cloneAndReplaceChild`,
// the method is used to clone some node as a preparation for future mutation
// caused by relayout.
// Because those changes are not requested by UIManager, they add a layer
// of node generation (between the committed stage and new proposed stage).
// That additional layer confuses the Diffing algorithm which uses
// `sourceNode` for referencing the previous (aka committed) stage
// of the tree to produce mutation instructions.
// In other words, if we don't compensate this change here,
// the Diffing algorithm will compare wrong trees
// ("new-but-not-laid-out-yet vs. new" instead of "committed vs. new").
auto nonConstChildShadowNodeClone = std::const_pointer_cast<ShadowNode>(childShadowNodeClone);
nonConstChildShadowNodeClone->shallowSourceNode();
ShadowNode::replaceChild(childShadowNode, childShadowNodeClone);
return std::dynamic_pointer_cast<const LayoutableShadowNode>(childShadowNodeClone);
}
#pragma mark - Equality
bool ViewShadowNode::operator==(const ShadowNode& rhs) const {
if (!ShadowNode::operator==(rhs)) {
return false;
}
auto &&other = static_cast<const ViewShadowNode&>(rhs);
return getLayoutMetrics() == other.getLayoutMetrics();
}
#pragma mark - DebugStringConvertible
SharedDebugStringConvertibleList ViewShadowNode::getDebugProps() const {
SharedDebugStringConvertibleList list = {};
auto basePropsList = ShadowNode::getDebugProps();
std::move(basePropsList.begin(), basePropsList.end(), std::back_inserter(list));
list.push_back(std::make_shared<DebugStringConvertibleItem>("layout", "", YogaLayoutableShadowNode::getDebugProps()));
return list;
}
} // namespace react
} // namespace facebook

View File

@ -7,12 +7,10 @@
#pragma once
#include <fabric/core/ConcreteShadowNode.h>
#include <fabric/core/LayoutableShadowNode.h>
#include <fabric/core/ShadowNode.h>
#include <fabric/view/AccessibleShadowNode.h>
#include <memory>
#include <fabric/view/ViewProps.h>
#include <fabric/view/YogaLayoutableShadowNode.h>
#include <fabric/view/ConcreteViewShadowNode.h>
namespace facebook {
namespace react {
@ -21,48 +19,14 @@ class ViewShadowNode;
using SharedViewShadowNode = std::shared_ptr<const ViewShadowNode>;
class ViewShadowNode:
public ConcreteShadowNode<ViewProps>,
public AccessibleShadowNode,
public YogaLayoutableShadowNode {
static_assert(std::is_base_of<YogaStylableProps, ViewProps>::value, "ViewProps must be a descendant of YogaStylableProps");
static_assert(std::is_base_of<AccessibilityProps, ViewProps>::value, "ViewProps must be a descendant of AccessibilityProps");
class ViewShadowNode final:
public ConcreteViewShadowNode<ViewProps> {
public:
ViewShadowNode(
const Tag &tag,
const Tag &rootTag,
const InstanceHandle &instanceHandle,
const SharedViewProps &props = ViewShadowNode::defaultSharedProps(),
const SharedShadowNodeSharedList &children = ShadowNode::emptySharedShadowNodeSharedList(),
const ShadowNodeCloneFunction &cloneFunction = nullptr
);
ViewShadowNode(
const SharedViewShadowNode &shadowNode,
const SharedViewProps &props = nullptr,
const SharedShadowNodeSharedList &children = nullptr
);
using ConcreteViewShadowNode::ConcreteViewShadowNode;
ComponentName getComponentName() const override;
void appendChild(const SharedShadowNode &child);
#pragma mark - Equality
bool operator==(const ShadowNode& rhs) const override;
#pragma mark - DebugStringConvertible
SharedDebugStringConvertibleList getDebugProps() const override;
private:
#pragma mark - LayoutableShadowNode
SharedLayoutableShadowNodeList getLayoutableChildNodes() const override;
SharedLayoutableShadowNode cloneAndReplaceChild(const SharedLayoutableShadowNode &child) override;
};
} // namespace react