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
This commit is contained in:
Valentin Shergin 2018-09-03 22:53:15 -07:00 committed by Facebook Github Bot
parent 2a942b7ae8
commit 5c83855c75
5 changed files with 278 additions and 0 deletions

View File

@ -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

View File

@ -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 <fabric/core/LayoutableShadowNode.h>
namespace facebook {
namespace react {
static LayoutMetrics layoutMetricsFromShadowNode(const ShadowNode &shadowNode) {
auto layoutableShadowNode = dynamic_cast<const LayoutableShadowNode *>(&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

View File

@ -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 <fabric/core/LayoutMetrics.h>
#include <fabric/core/LocalData.h>
#include <fabric/core/Props.h>
#include <fabric/core/ReactPrimitives.h>
#include <fabric/core/ShadowNode.h>
#include <fabric/events/EventEmitter.h>
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<ShadowViewNodePair>;
} // namespace react
} // namespace facebook

View File

@ -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

View File

@ -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 <vector>
#include <fabric/uimanager/ShadowView.h>
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<ShadowViewMutation>;
} // namespace react
} // namespace facebook