From 5c83855c757107a1b9d9a01c0f3f7c026a134a45 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 3 Sep 2018 22:53:15 -0700 Subject: [PATCH] Fabric: Introducting `ShadowView` and `ShadowViewMutation` Summary: @public We need some another object like ShadowNode (but not ShadowNode) to represent an instance of the component in the mutation instructions. This is the main motivation for introducing ShadowView. Why not use ShadowNode? ShadowNode is designed to represent a node in ShadowTree, not be a part of a mutation instruction. * ShadowNode exposes some APIs that should not be exposed to the mounting layer; * ShadowNode is an immutable data structure, so we cannot mutate it in some way which can be meaningful for mounting; * We should not add to ShadowNode any functionality which is needed only for mounting; * ShadowNode is a bit more heavy object to share that it needs to be; it's exposed (embedded into Mutation) as a `shared_ptr` which is not optimal from the performance perspective; * Retaining ShadowNode from mounting code can unnecessarily extend its lifetime which can negatively affect memory usage. Reviewed By: mdvacca Differential Revision: D9403562 fbshipit-source-id: 72ad81ed918157a62cd3d1a03261f14447649d0b --- .../fabric/core/layout/LayoutMetrics.h | 5 + ReactCommon/fabric/uimanager/ShadowView.cpp | 46 ++++++++++ ReactCommon/fabric/uimanager/ShadowView.h | 61 +++++++++++++ .../fabric/uimanager/ShadowViewMutation.cpp | 75 +++++++++++++++ .../fabric/uimanager/ShadowViewMutation.h | 91 +++++++++++++++++++ 5 files changed, 278 insertions(+) create mode 100644 ReactCommon/fabric/uimanager/ShadowView.cpp create mode 100644 ReactCommon/fabric/uimanager/ShadowView.h create mode 100644 ReactCommon/fabric/uimanager/ShadowViewMutation.cpp create mode 100644 ReactCommon/fabric/uimanager/ShadowViewMutation.h diff --git a/ReactCommon/fabric/core/layout/LayoutMetrics.h b/ReactCommon/fabric/core/layout/LayoutMetrics.h index 5c915310a..567c9177a 100644 --- a/ReactCommon/fabric/core/layout/LayoutMetrics.h +++ b/ReactCommon/fabric/core/layout/LayoutMetrics.h @@ -42,5 +42,10 @@ struct LayoutMetrics { } }; +/* + * Represents some undefined, not-yet-computed or meaningless value of `LayoutMetrics` type. + */ +static const LayoutMetrics EmptyLayoutMetrics = {.frame = { .size = {-1, -1}}}; + } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/uimanager/ShadowView.cpp b/ReactCommon/fabric/uimanager/ShadowView.cpp new file mode 100644 index 000000000..0da676a6f --- /dev/null +++ b/ReactCommon/fabric/uimanager/ShadowView.cpp @@ -0,0 +1,46 @@ +// Copyright (c) 2004-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. + +#include "ShadowView.h" + +#include + +namespace facebook { +namespace react { + +static LayoutMetrics layoutMetricsFromShadowNode(const ShadowNode &shadowNode) { + auto layoutableShadowNode = dynamic_cast(&shadowNode); + return layoutableShadowNode ? layoutableShadowNode->getLayoutMetrics() : EmptyLayoutMetrics; +} + +ShadowView::ShadowView(const ShadowNode &shadowNode): + componentName(shadowNode.getComponentName()), + componentHandle(shadowNode.getComponentHandle()), + tag(shadowNode.getTag()), + props(shadowNode.getProps()), + eventEmitter(shadowNode.getEventEmitter()), + layoutMetrics(layoutMetricsFromShadowNode(shadowNode)), + localData(shadowNode.getLocalData()) {} + +bool ShadowView::operator==(const ShadowView &rhs) const { + return + std::tie(this->tag, this->componentName, this->props, this->eventEmitter, this->layoutMetrics, this->localData) == + std::tie(rhs.tag, rhs.componentName, rhs.props, rhs.eventEmitter, rhs.layoutMetrics, rhs.localData); +} + +bool ShadowView::operator!=(const ShadowView &rhs) const { + return !(*this == rhs); +} + +bool ShadowViewNodePair::operator==(const ShadowViewNodePair &rhs) const { + return &this->shadowNode == &rhs.shadowNode; +} + +bool ShadowViewNodePair::operator!=(const ShadowViewNodePair &rhs) const { + return !(*this == rhs); +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/uimanager/ShadowView.h b/ReactCommon/fabric/uimanager/ShadowView.h new file mode 100644 index 000000000..8c737db0e --- /dev/null +++ b/ReactCommon/fabric/uimanager/ShadowView.h @@ -0,0 +1,61 @@ +// Copyright (c) 2004-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 +#include +#include +#include +#include +#include + +namespace facebook { +namespace react { + +/* + * Describes a view that can be mounted. + */ +struct ShadowView final { + ShadowView() = default; + ShadowView(const ShadowView &shadowView) = default; + + /* + * Constructs a `ShadowView` from given `ShadowNode`. + */ + explicit ShadowView(const ShadowNode &shadowNode); + + ShadowView &operator=(const ShadowView &other) = default; + + bool operator==(const ShadowView &rhs) const; + bool operator!=(const ShadowView &rhs) const; + + ComponentName componentName = ""; + ComponentHandle componentHandle = 0; + Tag tag = -1; + SharedProps props = {}; + SharedEventEmitter eventEmitter = {}; + LayoutMetrics layoutMetrics = EmptyLayoutMetrics; + SharedLocalData localData = {}; +}; + +/* + * Describes pair of a `ShadowView` and a `ShadowNode`. + */ +struct ShadowViewNodePair final { + const ShadowView shadowView; + const ShadowNode &shadowNode; + + /* + * The stored pointer to `ShadowNode` represents an indentity of the pair. + */ + bool operator==(const ShadowViewNodePair &rhs) const; + bool operator!=(const ShadowViewNodePair &rhs) const; +}; + +using ShadowViewNodePairList = std::vector; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/uimanager/ShadowViewMutation.cpp b/ReactCommon/fabric/uimanager/ShadowViewMutation.cpp new file mode 100644 index 000000000..5dd5f1cac --- /dev/null +++ b/ReactCommon/fabric/uimanager/ShadowViewMutation.cpp @@ -0,0 +1,75 @@ +/** + * 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. + */ + +#include "ShadowViewMutation.h" + +namespace facebook { +namespace react { + +ShadowViewMutation ShadowViewMutation::CreateMutation( + ShadowView shadowView +) { + return ShadowViewMutation { + .type = Create, + .newChildShadowView = shadowView, + .index = -1 + }; +} + +ShadowViewMutation ShadowViewMutation::DeleteMutation( + ShadowView shadowView +) { + return { + .type = Delete, + .oldChildShadowView = shadowView, + .index = -1 + }; +} + +ShadowViewMutation ShadowViewMutation::InsertMutation( + ShadowView parentShadowView, + ShadowView childShadowView, + int index +) { + return { + .type = Insert, + .parentShadowView = parentShadowView, + .newChildShadowView = childShadowView, + .index = index + }; +} + +ShadowViewMutation ShadowViewMutation::RemoveMutation( + ShadowView parentShadowView, + ShadowView childShadowView, + int index +) { + return { + .type = Remove, + .parentShadowView = parentShadowView, + .oldChildShadowView = childShadowView, + .index = index + }; +} + +ShadowViewMutation ShadowViewMutation::UpdateMutation( + ShadowView parentShadowView, + ShadowView oldChildShadowView, + ShadowView newChildShadowView, + int index +) { + return { + .type = Update, + .parentShadowView = parentShadowView, + .oldChildShadowView = oldChildShadowView, + .newChildShadowView = newChildShadowView, + .index = index + }; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/uimanager/ShadowViewMutation.h b/ReactCommon/fabric/uimanager/ShadowViewMutation.h new file mode 100644 index 000000000..2ba76d3f7 --- /dev/null +++ b/ReactCommon/fabric/uimanager/ShadowViewMutation.h @@ -0,0 +1,91 @@ +/** + * 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 + +#include + +namespace facebook { +namespace react { + +/* + * Describes a single native view tree mutation instruction which may contain + * pointers to an old shadow view, a new shadow view, a parent shadow view and + * final index of inserted or updated view. + * Use static methods to instantiate mutations of different types. + */ +struct ShadowViewMutation final { + +#pragma mark - Designated Initializers + + /* + * Creates and returns an `Create` mutation instruction. + */ + static ShadowViewMutation CreateMutation( + ShadowView shadowView + ); + + /* + * Creates and returns an `Delete` mutation instruction. + */ + static ShadowViewMutation DeleteMutation( + ShadowView shadowView + ); + + /* + * Creates and returns an `Insert` mutation instruction. + */ + static ShadowViewMutation InsertMutation( + ShadowView parentShadowView, + ShadowView childShadowView, + int index + ); + + /* + * Creates and returns a `Remove` mutation instruction. + */ + static ShadowViewMutation RemoveMutation( + ShadowView parentShadowView, + ShadowView childShadowView, + int index + ); + + /* + * Creates and returns an `Update` mutation instruction. + */ + static ShadowViewMutation UpdateMutation( + ShadowView parentShadowView, + ShadowView oldChildShadowView, + ShadowView newChildShadowView, + int index + ); + +#pragma mark - Type + + enum Type { + Create, + Delete, + Insert, + Remove, + Update + }; + +#pragma mark - Fields + + Type type = {Create}; + ShadowView parentShadowView = {}; + ShadowView oldChildShadowView = {}; + ShadowView newChildShadowView = {}; + int index = {}; +}; + +using ShadowViewMutationList = std::vector; + +} // namespace react +} // namespace facebook