mirror of
https://github.com/status-im/react-native.git
synced 2025-01-12 02:24:23 +00:00
Fabric: Using ShadowView instead of ShadowNode in Mutations
Summary: @public This is quite a big diff but the actual meaningful change is simple: now we use ShadowView class instead of ShadowNode in mutation instructions. Note: * In some places (especially during diffing) we have to operate with ShadowNodeViewPair objects (which represents a pair of ShadowNode and ShadowView). The reason for that is that we cannot construct child ShadowViews from parent ShadowViews because they don't have any information about children. * `ShadowTree::emitLayoutEvents` is now much simpler because ShadowView better represents the specifics of this kind of object. * The code in RCTMountingManager also became simpler. This change will allow us to implement more cool tricks soon. Reviewed By: mdvacca Differential Revision: D9403564 fbshipit-source-id: dbc7c61af250144d6c7335a01dc30df0005559a2
This commit is contained in:
parent
5c83855c75
commit
0792fba63f
@ -7,7 +7,8 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <fabric/uimanager/TreeMutationInstruction.h>
|
||||
#import <fabric/uimanager/ShadowView.h>
|
||||
#import <fabric/uimanager/ShadowViewMutation.h>
|
||||
#import <React/RCTPrimitives.h>
|
||||
#import <React/RCTMountingManagerDelegate.h>
|
||||
|
||||
@ -28,8 +29,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
* The order of mutation tnstructions matters.
|
||||
* Can be called from any thread.
|
||||
*/
|
||||
- (void)mutateComponentViewTreeWithMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions
|
||||
rootTag:(ReactTag)rootTag;
|
||||
- (void)performTransactionWithMutations:(facebook::react::ShadowViewMutationList)mutations
|
||||
rootTag:(ReactTag)rootTag;
|
||||
|
||||
/**
|
||||
* Suggests preliminary creation of a component view of given type.
|
||||
|
@ -38,123 +38,112 @@ using namespace facebook::react;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)mutateComponentViewTreeWithMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions
|
||||
rootTag:(ReactTag)rootTag
|
||||
- (void)performTransactionWithMutations:(facebook::react::ShadowViewMutationList)mutations
|
||||
rootTag:(ReactTag)rootTag
|
||||
{
|
||||
NSMutableArray<RCTMountItemProtocol> *mountItems =
|
||||
[[NSMutableArray<RCTMountItemProtocol> alloc] initWithCapacity:instructions.size() * 2 /* ~ the worst case */];
|
||||
[[NSMutableArray<RCTMountItemProtocol> alloc] initWithCapacity:mutations.size() * 2 /* ~ the worst case */];
|
||||
|
||||
for (auto instruction : instructions) {
|
||||
switch (instruction.getType()) {
|
||||
case TreeMutationInstruction::Creation: {
|
||||
NSString *componentName = RCTNSStringFromString(instruction.getNewChildNode()->getComponentName(), NSASCIIStringEncoding);
|
||||
for (const auto &mutation : mutations) {
|
||||
switch (mutation.type) {
|
||||
case ShadowViewMutation::Create: {
|
||||
NSString *componentName = RCTNSStringFromString(mutation.newChildShadowView.componentName, NSASCIIStringEncoding);
|
||||
RCTCreateMountItem *mountItem =
|
||||
[[RCTCreateMountItem alloc] initWithComponentName:componentName
|
||||
tag:instruction.getNewChildNode()->getTag()];
|
||||
tag:mutation.newChildShadowView.tag];
|
||||
[mountItems addObject:mountItem];
|
||||
break;
|
||||
}
|
||||
|
||||
case TreeMutationInstruction::Deletion: {
|
||||
NSString *componentName = RCTNSStringFromString(instruction.getOldChildNode()->getComponentName(), NSASCIIStringEncoding);
|
||||
case ShadowViewMutation::Delete: {
|
||||
NSString *componentName = RCTNSStringFromString(mutation.oldChildShadowView.componentName, NSASCIIStringEncoding);
|
||||
RCTDeleteMountItem *mountItem =
|
||||
[[RCTDeleteMountItem alloc] initWithComponentName:componentName
|
||||
tag:instruction.getOldChildNode()->getTag()];
|
||||
tag:mutation.oldChildShadowView.tag];
|
||||
[mountItems addObject:mountItem];
|
||||
break;
|
||||
}
|
||||
|
||||
case TreeMutationInstruction::Insertion: {
|
||||
case ShadowViewMutation::Insert: {
|
||||
// Props
|
||||
[mountItems addObject:[[RCTUpdatePropsMountItem alloc] initWithTag:instruction.getNewChildNode()->getTag()
|
||||
[mountItems addObject:[[RCTUpdatePropsMountItem alloc] initWithTag:mutation.newChildShadowView.tag
|
||||
oldProps:nullptr
|
||||
newProps:instruction.getNewChildNode()->getProps()]];
|
||||
newProps:mutation.newChildShadowView.props]];
|
||||
|
||||
// EventEmitter
|
||||
[mountItems addObject:[[RCTUpdateEventEmitterMountItem alloc] initWithTag:instruction.getNewChildNode()->getTag()
|
||||
eventEmitter:instruction.getNewChildNode()->getEventEmitter()]];
|
||||
[mountItems addObject:[[RCTUpdateEventEmitterMountItem alloc] initWithTag:mutation.newChildShadowView.tag
|
||||
eventEmitter:mutation.newChildShadowView.eventEmitter]];
|
||||
|
||||
// LocalData
|
||||
if (instruction.getNewChildNode()->getLocalData()) {
|
||||
[mountItems addObject:[[RCTUpdateLocalDataMountItem alloc] initWithTag:instruction.getNewChildNode()->getTag()
|
||||
if (mutation.newChildShadowView.localData) {
|
||||
[mountItems addObject:[[RCTUpdateLocalDataMountItem alloc] initWithTag:mutation.newChildShadowView.tag
|
||||
oldLocalData:nullptr
|
||||
newLocalData:instruction.getNewChildNode()->getLocalData()]];
|
||||
newLocalData:mutation.newChildShadowView.localData]];
|
||||
}
|
||||
|
||||
// Layout
|
||||
auto layoutableNewShadowNode =
|
||||
std::dynamic_pointer_cast<const LayoutableShadowNode>(instruction.getNewChildNode());
|
||||
|
||||
if (layoutableNewShadowNode) {
|
||||
[mountItems addObject:[[RCTUpdateLayoutMetricsMountItem alloc] initWithTag:instruction.getNewChildNode()->getTag()
|
||||
if (mutation.newChildShadowView.layoutMetrics != EmptyLayoutMetrics) {
|
||||
[mountItems addObject:[[RCTUpdateLayoutMetricsMountItem alloc] initWithTag:mutation.newChildShadowView.tag
|
||||
oldLayoutMetrics:{}
|
||||
newLayoutMetrics:layoutableNewShadowNode->getLayoutMetrics()]];
|
||||
newLayoutMetrics:mutation.newChildShadowView.layoutMetrics]];
|
||||
}
|
||||
|
||||
// Insertion
|
||||
RCTInsertMountItem *mountItem =
|
||||
[[RCTInsertMountItem alloc] initWithChildTag:instruction.getNewChildNode()->getTag()
|
||||
parentTag:instruction.getParentNode()->getTag()
|
||||
index:instruction.getIndex()];
|
||||
[[RCTInsertMountItem alloc] initWithChildTag:mutation.newChildShadowView.tag
|
||||
parentTag:mutation.parentShadowView.tag
|
||||
index:mutation.index];
|
||||
[mountItems addObject:mountItem];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TreeMutationInstruction::Removal: {
|
||||
case ShadowViewMutation::Remove: {
|
||||
RCTRemoveMountItem *mountItem =
|
||||
[[RCTRemoveMountItem alloc] initWithChildTag:instruction.getOldChildNode()->getTag()
|
||||
parentTag:instruction.getParentNode()->getTag()
|
||||
index:instruction.getIndex()];
|
||||
[[RCTRemoveMountItem alloc] initWithChildTag:mutation.oldChildShadowView.tag
|
||||
parentTag:mutation.parentShadowView.tag
|
||||
index:mutation.index];
|
||||
[mountItems addObject:mountItem];
|
||||
break;
|
||||
}
|
||||
|
||||
case TreeMutationInstruction::Replacement: {
|
||||
SharedShadowNode oldShadowNode = instruction.getOldChildNode();
|
||||
SharedShadowNode newShadowNode = instruction.getNewChildNode();
|
||||
case ShadowViewMutation::Update: {
|
||||
auto oldChildShadowView = mutation.oldChildShadowView;
|
||||
auto newChildShadowView = mutation.newChildShadowView;
|
||||
|
||||
// Props
|
||||
if (oldShadowNode->getProps() != newShadowNode->getProps()) {
|
||||
if (oldChildShadowView.props != newChildShadowView.props) {
|
||||
RCTUpdatePropsMountItem *mountItem =
|
||||
[[RCTUpdatePropsMountItem alloc] initWithTag:instruction.getOldChildNode()->getTag()
|
||||
oldProps:instruction.getOldChildNode()->getProps()
|
||||
newProps:instruction.getNewChildNode()->getProps()];
|
||||
[[RCTUpdatePropsMountItem alloc] initWithTag:mutation.oldChildShadowView.tag
|
||||
oldProps:mutation.oldChildShadowView.props
|
||||
newProps:mutation.newChildShadowView.props];
|
||||
[mountItems addObject:mountItem];
|
||||
}
|
||||
|
||||
// EventEmitter
|
||||
if (oldShadowNode->getEventEmitter() != newShadowNode->getEventEmitter()) {
|
||||
if (oldChildShadowView.eventEmitter != newChildShadowView.eventEmitter) {
|
||||
RCTUpdateEventEmitterMountItem *mountItem =
|
||||
[[RCTUpdateEventEmitterMountItem alloc] initWithTag:instruction.getOldChildNode()->getTag()
|
||||
eventEmitter:instruction.getOldChildNode()->getEventEmitter()];
|
||||
[[RCTUpdateEventEmitterMountItem alloc] initWithTag:mutation.oldChildShadowView.tag
|
||||
eventEmitter:mutation.oldChildShadowView.eventEmitter];
|
||||
[mountItems addObject:mountItem];
|
||||
}
|
||||
|
||||
// LocalData
|
||||
if (oldShadowNode->getLocalData() != newShadowNode->getLocalData()) {
|
||||
if (oldChildShadowView.localData != newChildShadowView.localData) {
|
||||
RCTUpdateLocalDataMountItem *mountItem =
|
||||
[[RCTUpdateLocalDataMountItem alloc] initWithTag:newShadowNode->getTag()
|
||||
oldLocalData:oldShadowNode->getLocalData()
|
||||
newLocalData:newShadowNode->getLocalData()];
|
||||
[[RCTUpdateLocalDataMountItem alloc] initWithTag:newChildShadowView.tag
|
||||
oldLocalData:oldChildShadowView.localData
|
||||
newLocalData:newChildShadowView.localData];
|
||||
[mountItems addObject:mountItem];
|
||||
}
|
||||
|
||||
// Layout
|
||||
auto layoutableOldShadowNode =
|
||||
std::dynamic_pointer_cast<const LayoutableShadowNode>(oldShadowNode);
|
||||
|
||||
if (layoutableOldShadowNode) {
|
||||
auto layoutableNewShadowNode =
|
||||
std::dynamic_pointer_cast<const LayoutableShadowNode>(newShadowNode);
|
||||
|
||||
if (layoutableOldShadowNode->getLayoutMetrics() != layoutableNewShadowNode->getLayoutMetrics()) {
|
||||
RCTUpdateLayoutMetricsMountItem *mountItem =
|
||||
[[RCTUpdateLayoutMetricsMountItem alloc] initWithTag:instruction.getOldChildNode()->getTag()
|
||||
oldLayoutMetrics:layoutableOldShadowNode->getLayoutMetrics()
|
||||
newLayoutMetrics:layoutableNewShadowNode->getLayoutMetrics()];
|
||||
[mountItems addObject:mountItem];
|
||||
}
|
||||
if (oldChildShadowView.layoutMetrics != newChildShadowView.layoutMetrics) {
|
||||
RCTUpdateLayoutMetricsMountItem *mountItem =
|
||||
[[RCTUpdateLayoutMetricsMountItem alloc] initWithTag:mutation.oldChildShadowView.tag
|
||||
oldLayoutMetrics:oldChildShadowView.layoutMetrics
|
||||
newLayoutMetrics:newChildShadowView.layoutMetrics];
|
||||
[mountItems addObject:mountItem];
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -12,7 +12,7 @@
|
||||
#import <fabric/core/LayoutConstraints.h>
|
||||
#import <fabric/core/LayoutContext.h>
|
||||
#import <fabric/uimanager/FabricUIManager.h>
|
||||
#import <fabric/uimanager/TreeMutationInstruction.h>
|
||||
#import <fabric/uimanager/ShadowViewMutation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@ -23,7 +23,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
@protocol RCTSchedulerDelegate
|
||||
|
||||
- (void)schedulerDidComputeMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions rootTag:(ReactTag)rootTag;
|
||||
- (void)schedulerDidFinishTransaction:(facebook::react::ShadowViewMutationList)mutations
|
||||
rootTag:(ReactTag)rootTag;
|
||||
|
||||
- (void)schedulerDidRequestPreliminaryViewAllocationWithComponentName:(NSString *)componentName;
|
||||
|
||||
|
@ -30,9 +30,9 @@ class SchedulerDelegateProxy: public SchedulerDelegate {
|
||||
public:
|
||||
SchedulerDelegateProxy(void *scheduler): scheduler_(scheduler) {}
|
||||
|
||||
void schedulerDidComputeMutationInstructions(Tag rootTag, const TreeMutationInstructionList &instructions) override {
|
||||
void schedulerDidFinishTransaction(Tag rootTag, const ShadowViewMutationList &mutations) override {
|
||||
RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_;
|
||||
[scheduler.delegate schedulerDidComputeMutationInstructions:instructions rootTag:rootTag];
|
||||
[scheduler.delegate schedulerDidFinishTransaction:mutations rootTag:rootTag];
|
||||
}
|
||||
|
||||
void schedulerDidRequestPreliminaryViewAllocation(ComponentName componentName) override {
|
||||
|
@ -69,11 +69,11 @@ using namespace facebook::react;
|
||||
|
||||
#pragma mark - RCTSchedulerDelegate
|
||||
|
||||
- (void)schedulerDidComputeMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions
|
||||
- (void)schedulerDidFinishTransaction:(facebook::react::ShadowViewMutationList)mutations
|
||||
rootTag:(ReactTag)rootTag
|
||||
{
|
||||
[_mountingManager mutateComponentViewTreeWithMutationInstructions:instructions
|
||||
rootTag:rootTag];
|
||||
[_mountingManager performTransactionWithMutations:mutations
|
||||
rootTag:rootTag];
|
||||
}
|
||||
|
||||
- (void)schedulerDidRequestPreliminaryViewAllocationWithComponentName:(NSString *)componentName
|
||||
@ -89,7 +89,7 @@ using namespace facebook::react;
|
||||
[_scheduler registerRootTag:surface.rootTag];
|
||||
[self runSurface:surface];
|
||||
|
||||
// FIXME: Mutation instruction MUST produce instruction for root node.
|
||||
// FIXME: mutation MUST produce instruction for root node.
|
||||
[_mountingManager.componentViewRegistry dequeueComponentViewWithName:@"Root" tag:surface.rootTag];
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ public:
|
||||
/*
|
||||
* Equality operators.
|
||||
* Use this to compare `ShadowNode`s values for equality (and non-equality).
|
||||
* Same values indicates that nodes must not produce mutation instructions
|
||||
* Same values indicates that nodes must not produce mutations
|
||||
* during tree diffing process.
|
||||
* Child nodes are not considered as part of the value.
|
||||
*/
|
||||
|
@ -5,202 +5,217 @@
|
||||
|
||||
#include "Differentiator.h"
|
||||
|
||||
#include "ShadowView.h"
|
||||
#include <fabric/core/LayoutableShadowNode.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
static void calculateMutationInstructions(
|
||||
TreeMutationInstructionList &instructions,
|
||||
SharedShadowNode parentNode,
|
||||
const SharedShadowNodeList &oldChildNodes,
|
||||
const SharedShadowNodeList &newChildNodes
|
||||
static ShadowViewNodePairList sliceChildShadowNodeViewPairs(const ShadowNode &shadowNode) {
|
||||
ShadowViewNodePairList pairList;
|
||||
|
||||
for (const auto &childShadowNode : shadowNode.getChildren()) {
|
||||
pairList.push_back({ShadowView(*childShadowNode), *childShadowNode});
|
||||
}
|
||||
|
||||
return pairList;
|
||||
}
|
||||
|
||||
static void calculateShadowViewMutations(
|
||||
ShadowViewMutationList &mutations,
|
||||
const ShadowView &parentShadowView,
|
||||
const ShadowViewNodePairList &oldChildPairs,
|
||||
const ShadowViewNodePairList &newChildPairs
|
||||
) {
|
||||
// The current version of the algorithm is otimized for simplicity,
|
||||
// not for performance of optimal result.
|
||||
// not for performance or optimal result.
|
||||
|
||||
// TODO(shergin): Consider to use Minimal Edit Distance algorithm to produce
|
||||
// optimal set of instructions and improve mounting performance.
|
||||
// https://en.wikipedia.org/wiki/Edit_distance
|
||||
// https://www.geeksforgeeks.org/dynamic-programming-set-5-edit-distance/
|
||||
|
||||
if (oldChildNodes == newChildNodes) {
|
||||
if (oldChildPairs == newChildPairs) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldChildNodes.size() == 0 && newChildNodes.size() == 0) {
|
||||
if (oldChildPairs.size() == 0 && newChildPairs.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::unordered_map<Tag, SharedShadowNode> insertedNodes;
|
||||
std::unordered_map<Tag, ShadowViewNodePair> insertedPaires;
|
||||
int index = 0;
|
||||
|
||||
TreeMutationInstructionList createInstructions = {};
|
||||
TreeMutationInstructionList deleteInstructions = {};
|
||||
TreeMutationInstructionList insertInstructions = {};
|
||||
TreeMutationInstructionList removeInstructions = {};
|
||||
TreeMutationInstructionList replaceInstructions = {};
|
||||
TreeMutationInstructionList downwardInstructions = {};
|
||||
TreeMutationInstructionList destructionDownwardInstructions = {};
|
||||
ShadowViewMutationList createMutations = {};
|
||||
ShadowViewMutationList deleteMutations = {};
|
||||
ShadowViewMutationList insertMutations = {};
|
||||
ShadowViewMutationList removeMutations = {};
|
||||
ShadowViewMutationList updateMutations = {};
|
||||
ShadowViewMutationList downwardMutations = {};
|
||||
ShadowViewMutationList destructiveDownwardMutations = {};
|
||||
|
||||
// Stage 1: Collectings Updates
|
||||
for (index = 0; index < oldChildNodes.size() && index < newChildNodes.size(); index++) {
|
||||
const auto &oldChildNode = oldChildNodes.at(index);
|
||||
const auto &newChildNode = newChildNodes.at(index);
|
||||
// Stage 1: Collecting `Update` mutations
|
||||
for (index = 0; index < oldChildPairs.size() && index < newChildPairs.size(); index++) {
|
||||
const auto &oldChildPair = oldChildPairs[index];
|
||||
const auto &newChildPair = newChildPairs[index];
|
||||
|
||||
if (oldChildNode->getTag() != newChildNode->getTag()) {
|
||||
if (oldChildPair.shadowView.tag != newChildPair.shadowView.tag) {
|
||||
// Totally different nodes, updating is impossible.
|
||||
break;
|
||||
}
|
||||
|
||||
if (*oldChildNode != *newChildNode) {
|
||||
replaceInstructions.push_back(
|
||||
TreeMutationInstruction::Replace(
|
||||
parentNode,
|
||||
oldChildNode,
|
||||
newChildNode,
|
||||
if (oldChildPair.shadowView != newChildPair.shadowView) {
|
||||
updateMutations.push_back(
|
||||
ShadowViewMutation::UpdateMutation(
|
||||
parentShadowView,
|
||||
oldChildPair.shadowView,
|
||||
newChildPair.shadowView,
|
||||
index
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
calculateMutationInstructions(
|
||||
*(newChildNode->getChildren().size() ? &downwardInstructions : &destructionDownwardInstructions),
|
||||
oldChildNode,
|
||||
oldChildNode->getChildren(),
|
||||
newChildNode->getChildren()
|
||||
const auto oldGrandChildPairs = sliceChildShadowNodeViewPairs(oldChildPair.shadowNode);
|
||||
const auto newGrandChildPairs = sliceChildShadowNodeViewPairs(newChildPair.shadowNode);
|
||||
calculateShadowViewMutations(
|
||||
*(newGrandChildPairs.size() ? &downwardMutations : &destructiveDownwardMutations),
|
||||
oldChildPair.shadowView,
|
||||
oldGrandChildPairs,
|
||||
newGrandChildPairs
|
||||
);
|
||||
}
|
||||
|
||||
int lastIndexAfterFirstStage = index;
|
||||
|
||||
// Stage 2: Collectings Insertions
|
||||
for (; index < newChildNodes.size(); index++) {
|
||||
const auto &newChildNode = newChildNodes.at(index);
|
||||
// Stage 2: Collecting `Insert` mutations
|
||||
for (; index < newChildPairs.size(); index++) {
|
||||
const auto &newChildPair = newChildPairs[index];
|
||||
|
||||
insertInstructions.push_back(
|
||||
TreeMutationInstruction::Insert(
|
||||
parentNode,
|
||||
newChildNode,
|
||||
insertMutations.push_back(
|
||||
ShadowViewMutation::InsertMutation(
|
||||
parentShadowView,
|
||||
newChildPair.shadowView,
|
||||
index
|
||||
)
|
||||
);
|
||||
|
||||
insertedNodes.insert({newChildNode->getTag(), newChildNode});
|
||||
insertedPaires.insert({newChildPair.shadowView.tag, newChildPair});
|
||||
}
|
||||
|
||||
// Stage 3: Collectings Deletions and Removals
|
||||
for (index = lastIndexAfterFirstStage; index < oldChildNodes.size(); index++) {
|
||||
const auto &oldChildNode = oldChildNodes.at(index);
|
||||
// Stage 3: Collecting `Delete` and `Remove` mutations
|
||||
for (index = lastIndexAfterFirstStage; index < oldChildPairs.size(); index++) {
|
||||
const auto &oldChildPair = oldChildPairs[index];
|
||||
|
||||
// Even if the old node was (re)inserted, we have to generate `remove`
|
||||
// instruction.
|
||||
removeInstructions.push_back(
|
||||
TreeMutationInstruction::Remove(
|
||||
parentNode,
|
||||
oldChildNode,
|
||||
// Even if the old view was (re)inserted, we have to generate `remove`
|
||||
// mutation.
|
||||
removeMutations.push_back(
|
||||
ShadowViewMutation::RemoveMutation(
|
||||
parentShadowView,
|
||||
oldChildPair.shadowView,
|
||||
index
|
||||
)
|
||||
);
|
||||
|
||||
const auto &it = insertedNodes.find(oldChildNode->getTag());
|
||||
const auto &it = insertedPaires.find(oldChildPair.shadowView.tag);
|
||||
|
||||
if (it == insertedNodes.end()) {
|
||||
// The old node was *not* (re)inserted.
|
||||
// We have to generate `delete` instruction and apply the algorithm
|
||||
if (it == insertedPaires.end()) {
|
||||
// The old view was *not* (re)inserted.
|
||||
// We have to generate `delete` mutation and apply the algorithm
|
||||
// recursively.
|
||||
deleteInstructions.push_back(
|
||||
TreeMutationInstruction::Delete(
|
||||
oldChildNode
|
||||
deleteMutations.push_back(
|
||||
ShadowViewMutation::DeleteMutation(
|
||||
oldChildPair.shadowView
|
||||
)
|
||||
);
|
||||
|
||||
// We also have to call the algorithm recursively to clean up the entire
|
||||
// subtree starting from the removed node.
|
||||
calculateMutationInstructions(
|
||||
destructionDownwardInstructions,
|
||||
oldChildNode,
|
||||
oldChildNode->getChildren(),
|
||||
// subtree starting from the removed view.
|
||||
calculateShadowViewMutations(
|
||||
destructiveDownwardMutations,
|
||||
oldChildPair.shadowView,
|
||||
sliceChildShadowNodeViewPairs(oldChildPair.shadowNode),
|
||||
{}
|
||||
);
|
||||
} else {
|
||||
// The old node *was* (re)inserted.
|
||||
// We have to call the algorithm recursively if the inserted node
|
||||
// The old view *was* (re)inserted.
|
||||
// We have to call the algorithm recursively if the inserted view
|
||||
// is *not* the same as removed one.
|
||||
const auto &newChildNode = it->second;
|
||||
if (newChildNode != oldChildNode) {
|
||||
calculateMutationInstructions(
|
||||
*(newChildNode->getChildren().size() ? &downwardInstructions : &destructionDownwardInstructions),
|
||||
newChildNode,
|
||||
oldChildNode->getChildren(),
|
||||
newChildNode->getChildren()
|
||||
const auto &newChildPair = it->second;
|
||||
if (newChildPair.shadowView != oldChildPair.shadowView) {
|
||||
const auto oldGrandChildPairs = sliceChildShadowNodeViewPairs(oldChildPair.shadowNode);
|
||||
const auto newGrandChildPairs = sliceChildShadowNodeViewPairs(newChildPair.shadowNode);
|
||||
calculateShadowViewMutations(
|
||||
*(newGrandChildPairs.size() ? &downwardMutations : &destructiveDownwardMutations),
|
||||
newChildPair.shadowView,
|
||||
oldGrandChildPairs,
|
||||
newGrandChildPairs
|
||||
);
|
||||
}
|
||||
|
||||
// In any case we have to remove the node from `insertedNodes` as
|
||||
// indication that the node was actually removed (which means that
|
||||
// the node existed before), hence we don't have to generate
|
||||
// `create` instruction.
|
||||
insertedNodes.erase(it);
|
||||
// In any case we have to remove the view from `insertedPaires` as
|
||||
// indication that the view was actually removed (which means that
|
||||
// the view existed before), hence we don't have to generate
|
||||
// `create` mutation.
|
||||
insertedPaires.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
// Stage 4: Collectings Creations
|
||||
for (index = lastIndexAfterFirstStage; index < newChildNodes.size(); index++) {
|
||||
const auto &newChildNode = newChildNodes.at(index);
|
||||
// Stage 4: Collecting `Create` mutations
|
||||
for (index = lastIndexAfterFirstStage; index < newChildPairs.size(); index++) {
|
||||
const auto &newChildPair = newChildPairs[index];
|
||||
|
||||
if (insertedNodes.find(newChildNode->getTag()) == insertedNodes.end()) {
|
||||
// The new node was (re)inserted, so there is no need to create it.
|
||||
if (insertedPaires.find(newChildPair.shadowView.tag) == insertedPaires.end()) {
|
||||
// The new view was (re)inserted, so there is no need to create it.
|
||||
continue;
|
||||
}
|
||||
|
||||
createInstructions.push_back(
|
||||
TreeMutationInstruction::Create(
|
||||
newChildNode
|
||||
createMutations.push_back(
|
||||
ShadowViewMutation::CreateMutation(
|
||||
newChildPair.shadowView
|
||||
)
|
||||
);
|
||||
|
||||
calculateMutationInstructions(
|
||||
downwardInstructions,
|
||||
newChildNode,
|
||||
calculateShadowViewMutations(
|
||||
downwardMutations,
|
||||
newChildPair.shadowView,
|
||||
{},
|
||||
newChildNode->getChildren()
|
||||
sliceChildShadowNodeViewPairs(newChildPair.shadowNode)
|
||||
);
|
||||
}
|
||||
|
||||
// All instructions in an optimal order:
|
||||
instructions.insert(instructions.end(), destructionDownwardInstructions.begin(), destructionDownwardInstructions.end());
|
||||
instructions.insert(instructions.end(), replaceInstructions.begin(), replaceInstructions.end());
|
||||
instructions.insert(instructions.end(), removeInstructions.rbegin(), removeInstructions.rend());
|
||||
instructions.insert(instructions.end(), createInstructions.begin(), createInstructions.end());
|
||||
instructions.insert(instructions.end(), downwardInstructions.begin(), downwardInstructions.end());
|
||||
instructions.insert(instructions.end(), insertInstructions.begin(), insertInstructions.end());
|
||||
instructions.insert(instructions.end(), deleteInstructions.begin(), deleteInstructions.end());
|
||||
// All mutations in an optimal order:
|
||||
mutations.insert(mutations.end(), destructiveDownwardMutations.begin(), destructiveDownwardMutations.end());
|
||||
mutations.insert(mutations.end(), updateMutations.begin(), updateMutations.end());
|
||||
mutations.insert(mutations.end(), removeMutations.rbegin(), removeMutations.rend());
|
||||
mutations.insert(mutations.end(), deleteMutations.begin(), deleteMutations.end());
|
||||
mutations.insert(mutations.end(), createMutations.begin(), createMutations.end());
|
||||
mutations.insert(mutations.end(), insertMutations.begin(), insertMutations.end());
|
||||
mutations.insert(mutations.end(), downwardMutations.begin(), downwardMutations.end());
|
||||
}
|
||||
|
||||
void calculateMutationInstructions(
|
||||
TreeMutationInstructionList &instructions,
|
||||
const SharedShadowNode &oldRootShadowNode,
|
||||
const SharedShadowNode &newRootShadowNode
|
||||
ShadowViewMutationList calculateShadowViewMutations(
|
||||
const ShadowNode &oldRootShadowNode,
|
||||
const ShadowNode &newRootShadowNode
|
||||
) {
|
||||
// Root shadow nodes must have same tag.
|
||||
assert(oldRootShadowNode->getTag() == newRootShadowNode->getTag());
|
||||
assert(oldRootShadowNode.getTag() == newRootShadowNode.getTag());
|
||||
|
||||
if (*oldRootShadowNode != *newRootShadowNode) {
|
||||
instructions.push_back(
|
||||
TreeMutationInstruction::Replace(
|
||||
nullptr,
|
||||
oldRootShadowNode,
|
||||
newRootShadowNode,
|
||||
ShadowViewMutationList mutations;
|
||||
|
||||
if (oldRootShadowNode != newRootShadowNode) {
|
||||
mutations.push_back(
|
||||
ShadowViewMutation::UpdateMutation(
|
||||
ShadowView(),
|
||||
ShadowView(oldRootShadowNode),
|
||||
ShadowView(newRootShadowNode),
|
||||
-1
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
calculateMutationInstructions(
|
||||
instructions,
|
||||
oldRootShadowNode,
|
||||
oldRootShadowNode->getChildren(),
|
||||
newRootShadowNode->getChildren()
|
||||
calculateShadowViewMutations(
|
||||
mutations,
|
||||
ShadowView(oldRootShadowNode),
|
||||
sliceChildShadowNodeViewPairs(oldRootShadowNode),
|
||||
sliceChildShadowNodeViewPairs(newRootShadowNode)
|
||||
);
|
||||
|
||||
return mutations;
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
|
@ -6,20 +6,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <fabric/core/ShadowNode.h>
|
||||
#include <fabric/uimanager/TreeMutationInstruction.h>
|
||||
#include <fabric/uimanager/ShadowViewMutation.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
/*
|
||||
* Calculates set of mutation instuctions which describe how the old
|
||||
* ShadowNode tree can be transformed to the new ShadowNode tree.
|
||||
* The set of instuctions might be and might not be optimal.
|
||||
* Calculates a list of view mutations which describes how the old
|
||||
* `ShadowTree` can be transformed to the new one.
|
||||
* The list of mutations might be and might not be optimal.
|
||||
*/
|
||||
void calculateMutationInstructions(
|
||||
TreeMutationInstructionList &instructions,
|
||||
const SharedShadowNode &oldNode,
|
||||
const SharedShadowNode &newNode
|
||||
ShadowViewMutationList calculateShadowViewMutations(
|
||||
const ShadowNode &oldRootShadowNode,
|
||||
const ShadowNode &newRootShadowNode
|
||||
);
|
||||
|
||||
} // namespace react
|
||||
|
@ -82,9 +82,9 @@ SchedulerDelegate *Scheduler::getDelegate() const {
|
||||
|
||||
#pragma mark - ShadowTreeDelegate
|
||||
|
||||
void Scheduler::shadowTreeDidCommit(const SharedShadowTree &shadowTree, const TreeMutationInstructionList &instructions) {
|
||||
void Scheduler::shadowTreeDidCommit(const SharedShadowTree &shadowTree, const ShadowViewMutationList &mutations) {
|
||||
if (delegate_) {
|
||||
delegate_->schedulerDidComputeMutationInstructions(shadowTree->getRootTag(), instructions);
|
||||
delegate_->schedulerDidFinishTransaction(shadowTree->getRootTag(), mutations);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ public:
|
||||
|
||||
#pragma mark - ShadowTreeDelegate
|
||||
|
||||
void shadowTreeDidCommit(const SharedShadowTree &shadowTree, const TreeMutationInstructionList &instructions) override;
|
||||
void shadowTreeDidCommit(const SharedShadowTree &shadowTree, const ShadowViewMutationList &mutations) override;
|
||||
|
||||
#pragma mark - Deprecated
|
||||
|
||||
@ -67,7 +67,6 @@ public:
|
||||
std::shared_ptr<FabricUIManager> getUIManager_DO_NOT_USE();
|
||||
|
||||
private:
|
||||
|
||||
SchedulerDelegate *delegate_;
|
||||
std::shared_ptr<FabricUIManager> uiManager_;
|
||||
std::unordered_map<Tag, SharedShadowTree> shadowTreeRegistry_;
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#include <fabric/core/ReactPrimitives.h>
|
||||
#include <fabric/core/ShadowNode.h>
|
||||
#include <fabric/uimanager/TreeMutationInstruction.h>
|
||||
#include <fabric/uimanager/ShadowViewMutation.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
@ -24,10 +24,10 @@ public:
|
||||
|
||||
/*
|
||||
* Called right after Scheduler computed (and laid out) a new updated version
|
||||
* of the tree and calculated a set of mutation instructions which are
|
||||
* suffisient to construct a new one.
|
||||
* of the tree and calculated a set of mutations which are suffisient
|
||||
* to construct a new one.
|
||||
*/
|
||||
virtual void schedulerDidComputeMutationInstructions(Tag rootTag, const TreeMutationInstructionList &instructions) = 0;
|
||||
virtual void schedulerDidFinishTransaction(Tag rootTag, const ShadowViewMutationList &mutations) = 0;
|
||||
|
||||
/*
|
||||
* Called right after a new ShadowNode was created.
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include "ShadowTreeDelegate.h"
|
||||
#include "Differentiator.h"
|
||||
#include "TreeMutationInstruction.h"
|
||||
#include "ShadowViewMutation.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
@ -78,19 +78,16 @@ void ShadowTree::complete(UnsharedRootShadowNode newRootShadowNode) {
|
||||
|
||||
newRootShadowNode->sealRecursive();
|
||||
|
||||
TreeMutationInstructionList instructions = TreeMutationInstructionList();
|
||||
|
||||
calculateMutationInstructions(
|
||||
instructions,
|
||||
oldRootShadowNode,
|
||||
newRootShadowNode
|
||||
auto mutations = calculateShadowViewMutations(
|
||||
*oldRootShadowNode,
|
||||
*newRootShadowNode
|
||||
);
|
||||
|
||||
if (commit(oldRootShadowNode, newRootShadowNode, instructions)) {
|
||||
emitLayoutEvents(instructions);
|
||||
if (commit(oldRootShadowNode, newRootShadowNode, mutations)) {
|
||||
emitLayoutEvents(mutations);
|
||||
|
||||
if (delegate_) {
|
||||
delegate_->shadowTreeDidCommit(shared_from_this(), instructions);
|
||||
delegate_->shadowTreeDidCommit(shared_from_this(), mutations);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -98,7 +95,7 @@ void ShadowTree::complete(UnsharedRootShadowNode newRootShadowNode) {
|
||||
bool ShadowTree::commit(
|
||||
const SharedRootShadowNode &oldRootShadowNode,
|
||||
const SharedRootShadowNode &newRootShadowNode,
|
||||
const TreeMutationInstructionList &mutationInstructions
|
||||
const ShadowViewMutationList &mutations
|
||||
) {
|
||||
std::lock_guard<std::mutex> lock(commitMutex_);
|
||||
|
||||
@ -108,69 +105,57 @@ bool ShadowTree::commit(
|
||||
|
||||
rootShadowNode_ = newRootShadowNode;
|
||||
|
||||
toggleEventEmitters(mutationInstructions);
|
||||
toggleEventEmitters(mutations);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShadowTree::emitLayoutEvents(const TreeMutationInstructionList &instructions) {
|
||||
for (const auto &instruction : instructions) {
|
||||
const auto &type = instruction.getType();
|
||||
|
||||
// Only `Insertion` and `Replacement` instructions can affect layout metrics.
|
||||
void ShadowTree::emitLayoutEvents(const ShadowViewMutationList &mutations) {
|
||||
for (const auto &mutation : mutations) {
|
||||
// Only `Insert` and `Update` mutations can affect layout metrics.
|
||||
if (
|
||||
type == TreeMutationInstruction::Insertion ||
|
||||
type == TreeMutationInstruction::Replacement
|
||||
mutation.type != ShadowViewMutation::Insert &&
|
||||
mutation.type != ShadowViewMutation::Update
|
||||
) {
|
||||
const auto &newShadowNode = instruction.getNewChildNode();
|
||||
const auto &eventEmitter = newShadowNode->getEventEmitter();
|
||||
const auto &viewEventEmitter = std::dynamic_pointer_cast<const ViewEventEmitter>(eventEmitter);
|
||||
|
||||
// Checking if particular shadow node supports `onLayout` event (part of `ViewEventEmitter`).
|
||||
if (viewEventEmitter) {
|
||||
// Now we know that both (old and new) shadow nodes must be `LayoutableShadowNode` subclasses.
|
||||
assert(std::dynamic_pointer_cast<const LayoutableShadowNode>(newShadowNode));
|
||||
|
||||
// Checking if the `onLayout` event was requested for the particular Shadow Node.
|
||||
const auto &viewProps = std::dynamic_pointer_cast<const ViewProps>(newShadowNode->getProps());
|
||||
if (viewProps && !viewProps->onLayout) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO(T29661055): Consider using `std::reinterpret_pointer_cast`.
|
||||
const auto &newLayoutableShadowNode =
|
||||
std::dynamic_pointer_cast<const LayoutableShadowNode>(newShadowNode);
|
||||
|
||||
// In case if we have `oldShadowNode`, we have to check that layout metrics have changed.
|
||||
if (type == TreeMutationInstruction::Replacement) {
|
||||
const auto &oldShadowNode = instruction.getOldChildNode();
|
||||
assert(std::dynamic_pointer_cast<const LayoutableShadowNode>(oldShadowNode));
|
||||
// TODO(T29661055): Consider using `std::reinterpret_pointer_cast`.
|
||||
const auto &oldLayoutableShadowNode =
|
||||
std::dynamic_pointer_cast<const LayoutableShadowNode>(oldShadowNode);
|
||||
|
||||
if (oldLayoutableShadowNode->getLayoutMetrics() == newLayoutableShadowNode->getLayoutMetrics()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
viewEventEmitter->onLayout(newLayoutableShadowNode->getLayoutMetrics());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto viewEventEmitter = std::dynamic_pointer_cast<const ViewEventEmitter>(mutation.newChildShadowView.eventEmitter);
|
||||
|
||||
// Checking if particular shadow node supports `onLayout` event (part of `ViewEventEmitter`).
|
||||
if (!viewEventEmitter) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Checking if the `onLayout` event was requested for the particular Shadow Node.
|
||||
const auto viewProps = std::dynamic_pointer_cast<const ViewProps>(mutation.newChildShadowView.props);
|
||||
if (viewProps && !viewProps->onLayout) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// In case if we have `oldChildShadowView`, checking that layout metrics have changed.
|
||||
if (
|
||||
mutation.type != ShadowViewMutation::Update &&
|
||||
mutation.oldChildShadowView.layoutMetrics == mutation.newChildShadowView.layoutMetrics
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
viewEventEmitter->onLayout(mutation.newChildShadowView.layoutMetrics);
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowTree::toggleEventEmitters(const TreeMutationInstructionList &instructions) {
|
||||
void ShadowTree::toggleEventEmitters(const ShadowViewMutationList &mutations) {
|
||||
std::lock_guard<std::recursive_mutex> lock(EventEmitter::DispatchMutex());
|
||||
|
||||
for (const auto &instruction : instructions) {
|
||||
if (instruction.getType() == TreeMutationInstruction::Deletion) {
|
||||
instruction.getOldChildNode()->getEventEmitter()->setEnabled(false);
|
||||
for (const auto &mutation : mutations) {
|
||||
if (mutation.type == ShadowViewMutation::Delete) {
|
||||
mutation.oldChildShadowView.eventEmitter->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &instruction : instructions) {
|
||||
if (instruction.getType() == TreeMutationInstruction::Creation) {
|
||||
instruction.getNewChildNode()->getEventEmitter()->setEnabled(true);
|
||||
for (const auto &mutation : mutations) {
|
||||
if (mutation.type == ShadowViewMutation::Create) {
|
||||
mutation.newChildShadowView.eventEmitter->setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <fabric/core/ReactPrimitives.h>
|
||||
#include <fabric/core/ShadowNode.h>
|
||||
#include <fabric/uimanager/ShadowTreeDelegate.h>
|
||||
#include <fabric/uimanager/ShadowViewMutation.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
@ -80,10 +81,10 @@ private:
|
||||
bool commit(
|
||||
const SharedRootShadowNode &oldRootShadowNode,
|
||||
const SharedRootShadowNode &newRootShadowNode,
|
||||
const TreeMutationInstructionList &mutationInstructions
|
||||
const ShadowViewMutationList &mutations
|
||||
);
|
||||
void toggleEventEmitters(const TreeMutationInstructionList &instructions);
|
||||
void emitLayoutEvents(const TreeMutationInstructionList &instructions);
|
||||
void toggleEventEmitters(const ShadowViewMutationList &mutations);
|
||||
void emitLayoutEvents(const ShadowViewMutationList &mutations);
|
||||
|
||||
const Tag rootTag_;
|
||||
SharedRootShadowNode rootShadowNode_;
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fabric/uimanager/TreeMutationInstruction.h>
|
||||
#include <fabric/uimanager/ShadowViewMutation.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
@ -21,7 +21,7 @@ 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;
|
||||
virtual void shadowTreeDidCommit(const std::shared_ptr<ShadowTree> &shadowTree, const ShadowViewMutationList &mutations) = 0;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
|
@ -15,7 +15,7 @@ namespace facebook {
|
||||
namespace react {
|
||||
|
||||
/*
|
||||
* Describes a single native view tree mutation instruction which may contain
|
||||
* Describes a single native view tree mutation 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.
|
||||
@ -25,21 +25,21 @@ struct ShadowViewMutation final {
|
||||
#pragma mark - Designated Initializers
|
||||
|
||||
/*
|
||||
* Creates and returns an `Create` mutation instruction.
|
||||
* Creates and returns an `Create` mutation.
|
||||
*/
|
||||
static ShadowViewMutation CreateMutation(
|
||||
ShadowView shadowView
|
||||
);
|
||||
|
||||
/*
|
||||
* Creates and returns an `Delete` mutation instruction.
|
||||
* Creates and returns an `Delete` mutation.
|
||||
*/
|
||||
static ShadowViewMutation DeleteMutation(
|
||||
ShadowView shadowView
|
||||
);
|
||||
|
||||
/*
|
||||
* Creates and returns an `Insert` mutation instruction.
|
||||
* Creates and returns an `Insert` mutation.
|
||||
*/
|
||||
static ShadowViewMutation InsertMutation(
|
||||
ShadowView parentShadowView,
|
||||
@ -48,16 +48,16 @@ struct ShadowViewMutation final {
|
||||
);
|
||||
|
||||
/*
|
||||
* Creates and returns a `Remove` mutation instruction.
|
||||
* Creates and returns a `Remove` mutation.
|
||||
*/
|
||||
static ShadowViewMutation RemoveMutation(
|
||||
ShadowView parentShadowView,
|
||||
ShadowView childShadowView,
|
||||
int index
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Creates and returns an `Update` mutation instruction.
|
||||
* Creates and returns an `Update` mutation.
|
||||
*/
|
||||
static ShadowViewMutation UpdateMutation(
|
||||
ShadowView parentShadowView,
|
||||
|
@ -1,203 +0,0 @@
|
||||
/**
|
||||
* 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 "TreeMutationInstruction.h"
|
||||
|
||||
#include <fabric/debug/DebugStringConvertibleItem.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
const TreeMutationInstruction TreeMutationInstruction::Create(
|
||||
SharedShadowNode node
|
||||
) {
|
||||
assert(node);
|
||||
|
||||
return TreeMutationInstruction(
|
||||
Creation,
|
||||
nullptr,
|
||||
nullptr,
|
||||
node,
|
||||
-1
|
||||
);
|
||||
}
|
||||
|
||||
const TreeMutationInstruction TreeMutationInstruction::Delete(
|
||||
SharedShadowNode node
|
||||
) {
|
||||
assert(node);
|
||||
|
||||
return TreeMutationInstruction(
|
||||
Deletion,
|
||||
nullptr,
|
||||
node,
|
||||
nullptr,
|
||||
-1
|
||||
);
|
||||
}
|
||||
|
||||
const TreeMutationInstruction TreeMutationInstruction::Insert(
|
||||
SharedShadowNode parentNode,
|
||||
SharedShadowNode childNode,
|
||||
int index
|
||||
) {
|
||||
assert(parentNode);
|
||||
assert(childNode);
|
||||
assert(index != -1);
|
||||
|
||||
return TreeMutationInstruction(
|
||||
Insertion,
|
||||
parentNode,
|
||||
nullptr,
|
||||
childNode,
|
||||
index
|
||||
);
|
||||
}
|
||||
|
||||
const TreeMutationInstruction TreeMutationInstruction::Remove(
|
||||
SharedShadowNode parentNode,
|
||||
SharedShadowNode childNode,
|
||||
int index
|
||||
) {
|
||||
assert(parentNode);
|
||||
assert(childNode);
|
||||
assert(index != -1);
|
||||
|
||||
return TreeMutationInstruction(
|
||||
Removal,
|
||||
parentNode,
|
||||
childNode,
|
||||
nullptr,
|
||||
index
|
||||
);
|
||||
}
|
||||
|
||||
const TreeMutationInstruction TreeMutationInstruction::Replace(
|
||||
SharedShadowNode parentNode,
|
||||
SharedShadowNode oldChildNode,
|
||||
SharedShadowNode newChildNode,
|
||||
int index
|
||||
) {
|
||||
assert(oldChildNode);
|
||||
assert(newChildNode);
|
||||
|
||||
return TreeMutationInstruction(
|
||||
Replacement,
|
||||
parentNode,
|
||||
oldChildNode,
|
||||
newChildNode,
|
||||
index
|
||||
);
|
||||
}
|
||||
|
||||
TreeMutationInstruction::TreeMutationInstruction(
|
||||
Type type,
|
||||
SharedShadowNode parentNode,
|
||||
SharedShadowNode oldChildNode,
|
||||
SharedShadowNode newChildNode,
|
||||
int index
|
||||
):
|
||||
type_(type),
|
||||
parentNode_(parentNode),
|
||||
oldChildNode_(oldChildNode),
|
||||
newChildNode_(newChildNode),
|
||||
index_(index) {};
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
TreeMutationInstruction::Type TreeMutationInstruction::getType() const {
|
||||
return type_;
|
||||
}
|
||||
|
||||
SharedShadowNode TreeMutationInstruction::getParentNode() const {
|
||||
assert(parentNode_);
|
||||
return parentNode_;
|
||||
}
|
||||
|
||||
SharedShadowNode TreeMutationInstruction::getOldChildNode() const {
|
||||
assert(oldChildNode_);
|
||||
return oldChildNode_;
|
||||
}
|
||||
|
||||
SharedShadowNode TreeMutationInstruction::getNewChildNode() const {
|
||||
assert(newChildNode_);
|
||||
return newChildNode_;
|
||||
}
|
||||
|
||||
int TreeMutationInstruction::getIndex() const {
|
||||
assert(index_ != -1);
|
||||
return index_;
|
||||
}
|
||||
|
||||
#pragma mark - DebugStringConvertible
|
||||
|
||||
std::string TreeMutationInstruction::getDebugName() const {
|
||||
switch (type_) {
|
||||
case Creation:
|
||||
return "Create";
|
||||
case Deletion:
|
||||
return "Delete";
|
||||
case Insertion:
|
||||
return "Insert";
|
||||
case Removal:
|
||||
return "Remove";
|
||||
case Replacement:
|
||||
return "Replace";
|
||||
}
|
||||
};
|
||||
|
||||
std::string TreeMutationInstruction::getDebugValue() const {
|
||||
switch (type_) {
|
||||
case Creation:
|
||||
return "[*" + folly::to<std::string>(newChildNode_->getTag()) + "]";
|
||||
case Deletion:
|
||||
return "[~" + folly::to<std::string>(oldChildNode_->getTag()) + "]";
|
||||
case Insertion:
|
||||
return "[" + folly::to<std::string>(newChildNode_->getTag()) + "->" + folly::to<std::string>(parentNode_->getTag()) + "]";
|
||||
case Removal:
|
||||
return "[" + folly::to<std::string>(oldChildNode_->getTag()) + "<~" + folly::to<std::string>(parentNode_->getTag()) + "]";
|
||||
case Replacement:
|
||||
return "[=" + folly::to<std::string>(oldChildNode_->getTag()) + "]";
|
||||
}
|
||||
};
|
||||
|
||||
SharedDebugStringConvertibleList TreeMutationInstruction::getDebugProps() const {
|
||||
DebugStringConvertibleOptions options = {.maximumDepth = 1, .format = false};
|
||||
|
||||
switch (type_) {
|
||||
case Creation:
|
||||
return SharedDebugStringConvertibleList {
|
||||
std::make_shared<DebugStringConvertibleItem>("node", newChildNode_->getDebugDescription(options)),
|
||||
};
|
||||
case Deletion:
|
||||
return SharedDebugStringConvertibleList {
|
||||
std::make_shared<DebugStringConvertibleItem>("node", oldChildNode_->getDebugDescription(options)),
|
||||
};
|
||||
case Insertion:
|
||||
return SharedDebugStringConvertibleList {
|
||||
std::make_shared<DebugStringConvertibleItem>("parentNode", parentNode_->getDebugDescription(options)),
|
||||
std::make_shared<DebugStringConvertibleItem>("childNode", newChildNode_->getDebugDescription(options)),
|
||||
std::make_shared<DebugStringConvertibleItem>("index", folly::to<std::string>(index_))
|
||||
};
|
||||
case Removal:
|
||||
return SharedDebugStringConvertibleList {
|
||||
std::make_shared<DebugStringConvertibleItem>("parentNode", parentNode_->getDebugDescription(options)),
|
||||
std::make_shared<DebugStringConvertibleItem>("childNode", oldChildNode_->getDebugDescription(options)),
|
||||
std::make_shared<DebugStringConvertibleItem>("index", folly::to<std::string>(index_))
|
||||
};
|
||||
case Replacement:
|
||||
return SharedDebugStringConvertibleList {
|
||||
std::make_shared<DebugStringConvertibleItem>("parentNode", parentNode_ ? parentNode_->getDebugDescription(options) : "nullptr"),
|
||||
std::make_shared<DebugStringConvertibleItem>("oldChildNode", oldChildNode_->getDebugDescription(options)),
|
||||
std::make_shared<DebugStringConvertibleItem>("newChildNode", newChildNode_->getDebugDescription(options)),
|
||||
std::make_shared<DebugStringConvertibleItem>("index", folly::to<std::string>(index_))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
@ -1,119 +0,0 @@
|
||||
/**
|
||||
* 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/core/ShadowNode.h>
|
||||
#include <fabric/debug/DebugStringConvertible.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class TreeMutationInstruction;
|
||||
|
||||
using TreeMutationInstructionList = std::vector<TreeMutationInstruction>;
|
||||
|
||||
/*
|
||||
* Describes single native views tree mutation instruction which may contain
|
||||
* pointers to an old shadow node, a new shadow node, a parent shadow node and
|
||||
* final index of inserted or updated node.
|
||||
* The relationship between native view instances and shadow node instances is
|
||||
* defined by `tag` value.
|
||||
* Use static methods to instantiate mutation instructions of different types.
|
||||
*/
|
||||
class TreeMutationInstruction:
|
||||
public DebugStringConvertible {
|
||||
public:
|
||||
|
||||
#pragma mark - Designated Initializers
|
||||
|
||||
/*
|
||||
* Creates and returns an *Creation* instruction.
|
||||
*/
|
||||
static const TreeMutationInstruction Create(
|
||||
SharedShadowNode node
|
||||
);
|
||||
|
||||
/*
|
||||
* Creates and returns an *Deletion* instruction.
|
||||
*/
|
||||
static const TreeMutationInstruction Delete(
|
||||
SharedShadowNode node
|
||||
);
|
||||
|
||||
/*
|
||||
* Creates and returns an *Insertion* instruction.
|
||||
*/
|
||||
static const TreeMutationInstruction Insert(
|
||||
SharedShadowNode parentNode,
|
||||
SharedShadowNode childNode,
|
||||
int index
|
||||
);
|
||||
|
||||
/*
|
||||
* Creates and returns a *Removal* instruction.
|
||||
*/
|
||||
static const TreeMutationInstruction Remove(
|
||||
SharedShadowNode parentNode,
|
||||
SharedShadowNode childNode,
|
||||
int index
|
||||
);
|
||||
|
||||
/*
|
||||
* Creates and returns an *Replacement* instruction.
|
||||
*/
|
||||
static const TreeMutationInstruction Replace(
|
||||
SharedShadowNode parentNode,
|
||||
SharedShadowNode oldChildNode,
|
||||
SharedShadowNode newChildNode,
|
||||
int index
|
||||
);
|
||||
|
||||
#pragma mark - Type
|
||||
|
||||
enum Type {
|
||||
Creation,
|
||||
Deletion,
|
||||
Insertion,
|
||||
Removal,
|
||||
Replacement
|
||||
};
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
Type getType() const;
|
||||
SharedShadowNode getParentNode() const;
|
||||
SharedShadowNode getOldChildNode() const;
|
||||
SharedShadowNode getNewChildNode() const;
|
||||
int getIndex() const;
|
||||
|
||||
#pragma mark - DebugStringConvertible
|
||||
|
||||
std::string getDebugName() const override;
|
||||
std::string getDebugValue() const override;
|
||||
SharedDebugStringConvertibleList getDebugProps() const override;
|
||||
|
||||
private:
|
||||
TreeMutationInstruction(
|
||||
Type type,
|
||||
SharedShadowNode parentNode,
|
||||
SharedShadowNode oldChildNode,
|
||||
SharedShadowNode newChildNode,
|
||||
int index
|
||||
);
|
||||
|
||||
Type type_ {Creation};
|
||||
SharedShadowNode parentNode_ {nullptr};
|
||||
SharedShadowNode oldChildNode_ {nullptr};
|
||||
SharedShadowNode newChildNode_ {nullptr};
|
||||
int index_ {-1};
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
Loading…
x
Reference in New Issue
Block a user