mirror of
https://github.com/status-im/react-native.git
synced 2025-02-04 13:44:04 +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 <UIKit/UIKit.h>
|
||||||
|
|
||||||
#import <fabric/uimanager/TreeMutationInstruction.h>
|
#import <fabric/uimanager/ShadowView.h>
|
||||||
|
#import <fabric/uimanager/ShadowViewMutation.h>
|
||||||
#import <React/RCTPrimitives.h>
|
#import <React/RCTPrimitives.h>
|
||||||
#import <React/RCTMountingManagerDelegate.h>
|
#import <React/RCTMountingManagerDelegate.h>
|
||||||
|
|
||||||
@ -28,7 +29,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
* The order of mutation tnstructions matters.
|
* The order of mutation tnstructions matters.
|
||||||
* Can be called from any thread.
|
* Can be called from any thread.
|
||||||
*/
|
*/
|
||||||
- (void)mutateComponentViewTreeWithMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions
|
- (void)performTransactionWithMutations:(facebook::react::ShadowViewMutationList)mutations
|
||||||
rootTag:(ReactTag)rootTag;
|
rootTag:(ReactTag)rootTag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,124 +38,113 @@ using namespace facebook::react;
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mutateComponentViewTreeWithMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions
|
- (void)performTransactionWithMutations:(facebook::react::ShadowViewMutationList)mutations
|
||||||
rootTag:(ReactTag)rootTag
|
rootTag:(ReactTag)rootTag
|
||||||
{
|
{
|
||||||
NSMutableArray<RCTMountItemProtocol> *mountItems =
|
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) {
|
for (const auto &mutation : mutations) {
|
||||||
switch (instruction.getType()) {
|
switch (mutation.type) {
|
||||||
case TreeMutationInstruction::Creation: {
|
case ShadowViewMutation::Create: {
|
||||||
NSString *componentName = RCTNSStringFromString(instruction.getNewChildNode()->getComponentName(), NSASCIIStringEncoding);
|
NSString *componentName = RCTNSStringFromString(mutation.newChildShadowView.componentName, NSASCIIStringEncoding);
|
||||||
RCTCreateMountItem *mountItem =
|
RCTCreateMountItem *mountItem =
|
||||||
[[RCTCreateMountItem alloc] initWithComponentName:componentName
|
[[RCTCreateMountItem alloc] initWithComponentName:componentName
|
||||||
tag:instruction.getNewChildNode()->getTag()];
|
tag:mutation.newChildShadowView.tag];
|
||||||
[mountItems addObject:mountItem];
|
[mountItems addObject:mountItem];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TreeMutationInstruction::Deletion: {
|
case ShadowViewMutation::Delete: {
|
||||||
NSString *componentName = RCTNSStringFromString(instruction.getOldChildNode()->getComponentName(), NSASCIIStringEncoding);
|
NSString *componentName = RCTNSStringFromString(mutation.oldChildShadowView.componentName, NSASCIIStringEncoding);
|
||||||
RCTDeleteMountItem *mountItem =
|
RCTDeleteMountItem *mountItem =
|
||||||
[[RCTDeleteMountItem alloc] initWithComponentName:componentName
|
[[RCTDeleteMountItem alloc] initWithComponentName:componentName
|
||||||
tag:instruction.getOldChildNode()->getTag()];
|
tag:mutation.oldChildShadowView.tag];
|
||||||
[mountItems addObject:mountItem];
|
[mountItems addObject:mountItem];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TreeMutationInstruction::Insertion: {
|
case ShadowViewMutation::Insert: {
|
||||||
// Props
|
// Props
|
||||||
[mountItems addObject:[[RCTUpdatePropsMountItem alloc] initWithTag:instruction.getNewChildNode()->getTag()
|
[mountItems addObject:[[RCTUpdatePropsMountItem alloc] initWithTag:mutation.newChildShadowView.tag
|
||||||
oldProps:nullptr
|
oldProps:nullptr
|
||||||
newProps:instruction.getNewChildNode()->getProps()]];
|
newProps:mutation.newChildShadowView.props]];
|
||||||
|
|
||||||
// EventEmitter
|
// EventEmitter
|
||||||
[mountItems addObject:[[RCTUpdateEventEmitterMountItem alloc] initWithTag:instruction.getNewChildNode()->getTag()
|
[mountItems addObject:[[RCTUpdateEventEmitterMountItem alloc] initWithTag:mutation.newChildShadowView.tag
|
||||||
eventEmitter:instruction.getNewChildNode()->getEventEmitter()]];
|
eventEmitter:mutation.newChildShadowView.eventEmitter]];
|
||||||
|
|
||||||
// LocalData
|
// LocalData
|
||||||
if (instruction.getNewChildNode()->getLocalData()) {
|
if (mutation.newChildShadowView.localData) {
|
||||||
[mountItems addObject:[[RCTUpdateLocalDataMountItem alloc] initWithTag:instruction.getNewChildNode()->getTag()
|
[mountItems addObject:[[RCTUpdateLocalDataMountItem alloc] initWithTag:mutation.newChildShadowView.tag
|
||||||
oldLocalData:nullptr
|
oldLocalData:nullptr
|
||||||
newLocalData:instruction.getNewChildNode()->getLocalData()]];
|
newLocalData:mutation.newChildShadowView.localData]];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Layout
|
// Layout
|
||||||
auto layoutableNewShadowNode =
|
if (mutation.newChildShadowView.layoutMetrics != EmptyLayoutMetrics) {
|
||||||
std::dynamic_pointer_cast<const LayoutableShadowNode>(instruction.getNewChildNode());
|
[mountItems addObject:[[RCTUpdateLayoutMetricsMountItem alloc] initWithTag:mutation.newChildShadowView.tag
|
||||||
|
|
||||||
if (layoutableNewShadowNode) {
|
|
||||||
[mountItems addObject:[[RCTUpdateLayoutMetricsMountItem alloc] initWithTag:instruction.getNewChildNode()->getTag()
|
|
||||||
oldLayoutMetrics:{}
|
oldLayoutMetrics:{}
|
||||||
newLayoutMetrics:layoutableNewShadowNode->getLayoutMetrics()]];
|
newLayoutMetrics:mutation.newChildShadowView.layoutMetrics]];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insertion
|
// Insertion
|
||||||
RCTInsertMountItem *mountItem =
|
RCTInsertMountItem *mountItem =
|
||||||
[[RCTInsertMountItem alloc] initWithChildTag:instruction.getNewChildNode()->getTag()
|
[[RCTInsertMountItem alloc] initWithChildTag:mutation.newChildShadowView.tag
|
||||||
parentTag:instruction.getParentNode()->getTag()
|
parentTag:mutation.parentShadowView.tag
|
||||||
index:instruction.getIndex()];
|
index:mutation.index];
|
||||||
[mountItems addObject:mountItem];
|
[mountItems addObject:mountItem];
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TreeMutationInstruction::Removal: {
|
case ShadowViewMutation::Remove: {
|
||||||
RCTRemoveMountItem *mountItem =
|
RCTRemoveMountItem *mountItem =
|
||||||
[[RCTRemoveMountItem alloc] initWithChildTag:instruction.getOldChildNode()->getTag()
|
[[RCTRemoveMountItem alloc] initWithChildTag:mutation.oldChildShadowView.tag
|
||||||
parentTag:instruction.getParentNode()->getTag()
|
parentTag:mutation.parentShadowView.tag
|
||||||
index:instruction.getIndex()];
|
index:mutation.index];
|
||||||
[mountItems addObject:mountItem];
|
[mountItems addObject:mountItem];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TreeMutationInstruction::Replacement: {
|
case ShadowViewMutation::Update: {
|
||||||
SharedShadowNode oldShadowNode = instruction.getOldChildNode();
|
auto oldChildShadowView = mutation.oldChildShadowView;
|
||||||
SharedShadowNode newShadowNode = instruction.getNewChildNode();
|
auto newChildShadowView = mutation.newChildShadowView;
|
||||||
|
|
||||||
// Props
|
// Props
|
||||||
if (oldShadowNode->getProps() != newShadowNode->getProps()) {
|
if (oldChildShadowView.props != newChildShadowView.props) {
|
||||||
RCTUpdatePropsMountItem *mountItem =
|
RCTUpdatePropsMountItem *mountItem =
|
||||||
[[RCTUpdatePropsMountItem alloc] initWithTag:instruction.getOldChildNode()->getTag()
|
[[RCTUpdatePropsMountItem alloc] initWithTag:mutation.oldChildShadowView.tag
|
||||||
oldProps:instruction.getOldChildNode()->getProps()
|
oldProps:mutation.oldChildShadowView.props
|
||||||
newProps:instruction.getNewChildNode()->getProps()];
|
newProps:mutation.newChildShadowView.props];
|
||||||
[mountItems addObject:mountItem];
|
[mountItems addObject:mountItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
// EventEmitter
|
// EventEmitter
|
||||||
if (oldShadowNode->getEventEmitter() != newShadowNode->getEventEmitter()) {
|
if (oldChildShadowView.eventEmitter != newChildShadowView.eventEmitter) {
|
||||||
RCTUpdateEventEmitterMountItem *mountItem =
|
RCTUpdateEventEmitterMountItem *mountItem =
|
||||||
[[RCTUpdateEventEmitterMountItem alloc] initWithTag:instruction.getOldChildNode()->getTag()
|
[[RCTUpdateEventEmitterMountItem alloc] initWithTag:mutation.oldChildShadowView.tag
|
||||||
eventEmitter:instruction.getOldChildNode()->getEventEmitter()];
|
eventEmitter:mutation.oldChildShadowView.eventEmitter];
|
||||||
[mountItems addObject:mountItem];
|
[mountItems addObject:mountItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalData
|
// LocalData
|
||||||
if (oldShadowNode->getLocalData() != newShadowNode->getLocalData()) {
|
if (oldChildShadowView.localData != newChildShadowView.localData) {
|
||||||
RCTUpdateLocalDataMountItem *mountItem =
|
RCTUpdateLocalDataMountItem *mountItem =
|
||||||
[[RCTUpdateLocalDataMountItem alloc] initWithTag:newShadowNode->getTag()
|
[[RCTUpdateLocalDataMountItem alloc] initWithTag:newChildShadowView.tag
|
||||||
oldLocalData:oldShadowNode->getLocalData()
|
oldLocalData:oldChildShadowView.localData
|
||||||
newLocalData:newShadowNode->getLocalData()];
|
newLocalData:newChildShadowView.localData];
|
||||||
[mountItems addObject:mountItem];
|
[mountItems addObject:mountItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Layout
|
// Layout
|
||||||
auto layoutableOldShadowNode =
|
if (oldChildShadowView.layoutMetrics != newChildShadowView.layoutMetrics) {
|
||||||
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 *mountItem =
|
||||||
[[RCTUpdateLayoutMetricsMountItem alloc] initWithTag:instruction.getOldChildNode()->getTag()
|
[[RCTUpdateLayoutMetricsMountItem alloc] initWithTag:mutation.oldChildShadowView.tag
|
||||||
oldLayoutMetrics:layoutableOldShadowNode->getLayoutMetrics()
|
oldLayoutMetrics:oldChildShadowView.layoutMetrics
|
||||||
newLayoutMetrics:layoutableNewShadowNode->getLayoutMetrics()];
|
newLayoutMetrics:newChildShadowView.layoutMetrics];
|
||||||
[mountItems addObject:mountItem];
|
[mountItems addObject:mountItem];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#import <fabric/core/LayoutConstraints.h>
|
#import <fabric/core/LayoutConstraints.h>
|
||||||
#import <fabric/core/LayoutContext.h>
|
#import <fabric/core/LayoutContext.h>
|
||||||
#import <fabric/uimanager/FabricUIManager.h>
|
#import <fabric/uimanager/FabricUIManager.h>
|
||||||
#import <fabric/uimanager/TreeMutationInstruction.h>
|
#import <fabric/uimanager/ShadowViewMutation.h>
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@ -23,7 +23,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
@protocol RCTSchedulerDelegate
|
@protocol RCTSchedulerDelegate
|
||||||
|
|
||||||
- (void)schedulerDidComputeMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions rootTag:(ReactTag)rootTag;
|
- (void)schedulerDidFinishTransaction:(facebook::react::ShadowViewMutationList)mutations
|
||||||
|
rootTag:(ReactTag)rootTag;
|
||||||
|
|
||||||
- (void)schedulerDidRequestPreliminaryViewAllocationWithComponentName:(NSString *)componentName;
|
- (void)schedulerDidRequestPreliminaryViewAllocationWithComponentName:(NSString *)componentName;
|
||||||
|
|
||||||
|
@ -30,9 +30,9 @@ class SchedulerDelegateProxy: public SchedulerDelegate {
|
|||||||
public:
|
public:
|
||||||
SchedulerDelegateProxy(void *scheduler): scheduler_(scheduler) {}
|
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_;
|
RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_;
|
||||||
[scheduler.delegate schedulerDidComputeMutationInstructions:instructions rootTag:rootTag];
|
[scheduler.delegate schedulerDidFinishTransaction:mutations rootTag:rootTag];
|
||||||
}
|
}
|
||||||
|
|
||||||
void schedulerDidRequestPreliminaryViewAllocation(ComponentName componentName) override {
|
void schedulerDidRequestPreliminaryViewAllocation(ComponentName componentName) override {
|
||||||
|
@ -69,10 +69,10 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
#pragma mark - RCTSchedulerDelegate
|
#pragma mark - RCTSchedulerDelegate
|
||||||
|
|
||||||
- (void)schedulerDidComputeMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions
|
- (void)schedulerDidFinishTransaction:(facebook::react::ShadowViewMutationList)mutations
|
||||||
rootTag:(ReactTag)rootTag
|
rootTag:(ReactTag)rootTag
|
||||||
{
|
{
|
||||||
[_mountingManager mutateComponentViewTreeWithMutationInstructions:instructions
|
[_mountingManager performTransactionWithMutations:mutations
|
||||||
rootTag:rootTag];
|
rootTag:rootTag];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ using namespace facebook::react;
|
|||||||
[_scheduler registerRootTag:surface.rootTag];
|
[_scheduler registerRootTag:surface.rootTag];
|
||||||
[self runSurface:surface];
|
[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];
|
[_mountingManager.componentViewRegistry dequeueComponentViewWithName:@"Root" tag:surface.rootTag];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ public:
|
|||||||
/*
|
/*
|
||||||
* Equality operators.
|
* Equality operators.
|
||||||
* Use this to compare `ShadowNode`s values for equality (and non-equality).
|
* 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.
|
* during tree diffing process.
|
||||||
* Child nodes are not considered as part of the value.
|
* Child nodes are not considered as part of the value.
|
||||||
*/
|
*/
|
||||||
|
@ -5,202 +5,217 @@
|
|||||||
|
|
||||||
#include "Differentiator.h"
|
#include "Differentiator.h"
|
||||||
|
|
||||||
|
#include "ShadowView.h"
|
||||||
|
#include <fabric/core/LayoutableShadowNode.h>
|
||||||
|
|
||||||
namespace facebook {
|
namespace facebook {
|
||||||
namespace react {
|
namespace react {
|
||||||
|
|
||||||
static void calculateMutationInstructions(
|
static ShadowViewNodePairList sliceChildShadowNodeViewPairs(const ShadowNode &shadowNode) {
|
||||||
TreeMutationInstructionList &instructions,
|
ShadowViewNodePairList pairList;
|
||||||
SharedShadowNode parentNode,
|
|
||||||
const SharedShadowNodeList &oldChildNodes,
|
for (const auto &childShadowNode : shadowNode.getChildren()) {
|
||||||
const SharedShadowNodeList &newChildNodes
|
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,
|
// 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
|
if (oldChildPairs == newChildPairs) {
|
||||||
// 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) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldChildNodes.size() == 0 && newChildNodes.size() == 0) {
|
if (oldChildPairs.size() == 0 && newChildPairs.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<Tag, SharedShadowNode> insertedNodes;
|
std::unordered_map<Tag, ShadowViewNodePair> insertedPaires;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
TreeMutationInstructionList createInstructions = {};
|
ShadowViewMutationList createMutations = {};
|
||||||
TreeMutationInstructionList deleteInstructions = {};
|
ShadowViewMutationList deleteMutations = {};
|
||||||
TreeMutationInstructionList insertInstructions = {};
|
ShadowViewMutationList insertMutations = {};
|
||||||
TreeMutationInstructionList removeInstructions = {};
|
ShadowViewMutationList removeMutations = {};
|
||||||
TreeMutationInstructionList replaceInstructions = {};
|
ShadowViewMutationList updateMutations = {};
|
||||||
TreeMutationInstructionList downwardInstructions = {};
|
ShadowViewMutationList downwardMutations = {};
|
||||||
TreeMutationInstructionList destructionDownwardInstructions = {};
|
ShadowViewMutationList destructiveDownwardMutations = {};
|
||||||
|
|
||||||
// Stage 1: Collectings Updates
|
// Stage 1: Collecting `Update` mutations
|
||||||
for (index = 0; index < oldChildNodes.size() && index < newChildNodes.size(); index++) {
|
for (index = 0; index < oldChildPairs.size() && index < newChildPairs.size(); index++) {
|
||||||
const auto &oldChildNode = oldChildNodes.at(index);
|
const auto &oldChildPair = oldChildPairs[index];
|
||||||
const auto &newChildNode = newChildNodes.at(index);
|
const auto &newChildPair = newChildPairs[index];
|
||||||
|
|
||||||
if (oldChildNode->getTag() != newChildNode->getTag()) {
|
if (oldChildPair.shadowView.tag != newChildPair.shadowView.tag) {
|
||||||
// Totally different nodes, updating is impossible.
|
// Totally different nodes, updating is impossible.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*oldChildNode != *newChildNode) {
|
if (oldChildPair.shadowView != newChildPair.shadowView) {
|
||||||
replaceInstructions.push_back(
|
updateMutations.push_back(
|
||||||
TreeMutationInstruction::Replace(
|
ShadowViewMutation::UpdateMutation(
|
||||||
parentNode,
|
parentShadowView,
|
||||||
oldChildNode,
|
oldChildPair.shadowView,
|
||||||
newChildNode,
|
newChildPair.shadowView,
|
||||||
index
|
index
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateMutationInstructions(
|
const auto oldGrandChildPairs = sliceChildShadowNodeViewPairs(oldChildPair.shadowNode);
|
||||||
*(newChildNode->getChildren().size() ? &downwardInstructions : &destructionDownwardInstructions),
|
const auto newGrandChildPairs = sliceChildShadowNodeViewPairs(newChildPair.shadowNode);
|
||||||
oldChildNode,
|
calculateShadowViewMutations(
|
||||||
oldChildNode->getChildren(),
|
*(newGrandChildPairs.size() ? &downwardMutations : &destructiveDownwardMutations),
|
||||||
newChildNode->getChildren()
|
oldChildPair.shadowView,
|
||||||
|
oldGrandChildPairs,
|
||||||
|
newGrandChildPairs
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
int lastIndexAfterFirstStage = index;
|
int lastIndexAfterFirstStage = index;
|
||||||
|
|
||||||
// Stage 2: Collectings Insertions
|
// Stage 2: Collecting `Insert` mutations
|
||||||
for (; index < newChildNodes.size(); index++) {
|
for (; index < newChildPairs.size(); index++) {
|
||||||
const auto &newChildNode = newChildNodes.at(index);
|
const auto &newChildPair = newChildPairs[index];
|
||||||
|
|
||||||
insertInstructions.push_back(
|
insertMutations.push_back(
|
||||||
TreeMutationInstruction::Insert(
|
ShadowViewMutation::InsertMutation(
|
||||||
parentNode,
|
parentShadowView,
|
||||||
newChildNode,
|
newChildPair.shadowView,
|
||||||
index
|
index
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
insertedNodes.insert({newChildNode->getTag(), newChildNode});
|
insertedPaires.insert({newChildPair.shadowView.tag, newChildPair});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stage 3: Collectings Deletions and Removals
|
// Stage 3: Collecting `Delete` and `Remove` mutations
|
||||||
for (index = lastIndexAfterFirstStage; index < oldChildNodes.size(); index++) {
|
for (index = lastIndexAfterFirstStage; index < oldChildPairs.size(); index++) {
|
||||||
const auto &oldChildNode = oldChildNodes.at(index);
|
const auto &oldChildPair = oldChildPairs[index];
|
||||||
|
|
||||||
// Even if the old node was (re)inserted, we have to generate `remove`
|
// Even if the old view was (re)inserted, we have to generate `remove`
|
||||||
// instruction.
|
// mutation.
|
||||||
removeInstructions.push_back(
|
removeMutations.push_back(
|
||||||
TreeMutationInstruction::Remove(
|
ShadowViewMutation::RemoveMutation(
|
||||||
parentNode,
|
parentShadowView,
|
||||||
oldChildNode,
|
oldChildPair.shadowView,
|
||||||
index
|
index
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const auto &it = insertedNodes.find(oldChildNode->getTag());
|
const auto &it = insertedPaires.find(oldChildPair.shadowView.tag);
|
||||||
|
|
||||||
if (it == insertedNodes.end()) {
|
if (it == insertedPaires.end()) {
|
||||||
// The old node was *not* (re)inserted.
|
// The old view was *not* (re)inserted.
|
||||||
// We have to generate `delete` instruction and apply the algorithm
|
// We have to generate `delete` mutation and apply the algorithm
|
||||||
// recursively.
|
// recursively.
|
||||||
deleteInstructions.push_back(
|
deleteMutations.push_back(
|
||||||
TreeMutationInstruction::Delete(
|
ShadowViewMutation::DeleteMutation(
|
||||||
oldChildNode
|
oldChildPair.shadowView
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// We also have to call the algorithm recursively to clean up the entire
|
// We also have to call the algorithm recursively to clean up the entire
|
||||||
// subtree starting from the removed node.
|
// subtree starting from the removed view.
|
||||||
calculateMutationInstructions(
|
calculateShadowViewMutations(
|
||||||
destructionDownwardInstructions,
|
destructiveDownwardMutations,
|
||||||
oldChildNode,
|
oldChildPair.shadowView,
|
||||||
oldChildNode->getChildren(),
|
sliceChildShadowNodeViewPairs(oldChildPair.shadowNode),
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// The old node *was* (re)inserted.
|
// The old view *was* (re)inserted.
|
||||||
// We have to call the algorithm recursively if the inserted node
|
// We have to call the algorithm recursively if the inserted view
|
||||||
// is *not* the same as removed one.
|
// is *not* the same as removed one.
|
||||||
const auto &newChildNode = it->second;
|
const auto &newChildPair = it->second;
|
||||||
if (newChildNode != oldChildNode) {
|
if (newChildPair.shadowView != oldChildPair.shadowView) {
|
||||||
calculateMutationInstructions(
|
const auto oldGrandChildPairs = sliceChildShadowNodeViewPairs(oldChildPair.shadowNode);
|
||||||
*(newChildNode->getChildren().size() ? &downwardInstructions : &destructionDownwardInstructions),
|
const auto newGrandChildPairs = sliceChildShadowNodeViewPairs(newChildPair.shadowNode);
|
||||||
newChildNode,
|
calculateShadowViewMutations(
|
||||||
oldChildNode->getChildren(),
|
*(newGrandChildPairs.size() ? &downwardMutations : &destructiveDownwardMutations),
|
||||||
newChildNode->getChildren()
|
newChildPair.shadowView,
|
||||||
|
oldGrandChildPairs,
|
||||||
|
newGrandChildPairs
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// In any case we have to remove the node from `insertedNodes` as
|
// In any case we have to remove the view from `insertedPaires` as
|
||||||
// indication that the node was actually removed (which means that
|
// indication that the view was actually removed (which means that
|
||||||
// the node existed before), hence we don't have to generate
|
// the view existed before), hence we don't have to generate
|
||||||
// `create` instruction.
|
// `create` mutation.
|
||||||
insertedNodes.erase(it);
|
insertedPaires.erase(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stage 4: Collectings Creations
|
// Stage 4: Collecting `Create` mutations
|
||||||
for (index = lastIndexAfterFirstStage; index < newChildNodes.size(); index++) {
|
for (index = lastIndexAfterFirstStage; index < newChildPairs.size(); index++) {
|
||||||
const auto &newChildNode = newChildNodes.at(index);
|
const auto &newChildPair = newChildPairs[index];
|
||||||
|
|
||||||
if (insertedNodes.find(newChildNode->getTag()) == insertedNodes.end()) {
|
if (insertedPaires.find(newChildPair.shadowView.tag) == insertedPaires.end()) {
|
||||||
// The new node was (re)inserted, so there is no need to create it.
|
// The new view was (re)inserted, so there is no need to create it.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
createInstructions.push_back(
|
createMutations.push_back(
|
||||||
TreeMutationInstruction::Create(
|
ShadowViewMutation::CreateMutation(
|
||||||
newChildNode
|
newChildPair.shadowView
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
calculateMutationInstructions(
|
calculateShadowViewMutations(
|
||||||
downwardInstructions,
|
downwardMutations,
|
||||||
newChildNode,
|
newChildPair.shadowView,
|
||||||
{},
|
{},
|
||||||
newChildNode->getChildren()
|
sliceChildShadowNodeViewPairs(newChildPair.shadowNode)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// All instructions in an optimal order:
|
// All mutations in an optimal order:
|
||||||
instructions.insert(instructions.end(), destructionDownwardInstructions.begin(), destructionDownwardInstructions.end());
|
mutations.insert(mutations.end(), destructiveDownwardMutations.begin(), destructiveDownwardMutations.end());
|
||||||
instructions.insert(instructions.end(), replaceInstructions.begin(), replaceInstructions.end());
|
mutations.insert(mutations.end(), updateMutations.begin(), updateMutations.end());
|
||||||
instructions.insert(instructions.end(), removeInstructions.rbegin(), removeInstructions.rend());
|
mutations.insert(mutations.end(), removeMutations.rbegin(), removeMutations.rend());
|
||||||
instructions.insert(instructions.end(), createInstructions.begin(), createInstructions.end());
|
mutations.insert(mutations.end(), deleteMutations.begin(), deleteMutations.end());
|
||||||
instructions.insert(instructions.end(), downwardInstructions.begin(), downwardInstructions.end());
|
mutations.insert(mutations.end(), createMutations.begin(), createMutations.end());
|
||||||
instructions.insert(instructions.end(), insertInstructions.begin(), insertInstructions.end());
|
mutations.insert(mutations.end(), insertMutations.begin(), insertMutations.end());
|
||||||
instructions.insert(instructions.end(), deleteInstructions.begin(), deleteInstructions.end());
|
mutations.insert(mutations.end(), downwardMutations.begin(), downwardMutations.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void calculateMutationInstructions(
|
ShadowViewMutationList calculateShadowViewMutations(
|
||||||
TreeMutationInstructionList &instructions,
|
const ShadowNode &oldRootShadowNode,
|
||||||
const SharedShadowNode &oldRootShadowNode,
|
const ShadowNode &newRootShadowNode
|
||||||
const SharedShadowNode &newRootShadowNode
|
|
||||||
) {
|
) {
|
||||||
// Root shadow nodes must have same tag.
|
// Root shadow nodes must have same tag.
|
||||||
assert(oldRootShadowNode->getTag() == newRootShadowNode->getTag());
|
assert(oldRootShadowNode.getTag() == newRootShadowNode.getTag());
|
||||||
|
|
||||||
if (*oldRootShadowNode != *newRootShadowNode) {
|
ShadowViewMutationList mutations;
|
||||||
instructions.push_back(
|
|
||||||
TreeMutationInstruction::Replace(
|
if (oldRootShadowNode != newRootShadowNode) {
|
||||||
nullptr,
|
mutations.push_back(
|
||||||
oldRootShadowNode,
|
ShadowViewMutation::UpdateMutation(
|
||||||
newRootShadowNode,
|
ShadowView(),
|
||||||
|
ShadowView(oldRootShadowNode),
|
||||||
|
ShadowView(newRootShadowNode),
|
||||||
-1
|
-1
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateMutationInstructions(
|
calculateShadowViewMutations(
|
||||||
instructions,
|
mutations,
|
||||||
oldRootShadowNode,
|
ShadowView(oldRootShadowNode),
|
||||||
oldRootShadowNode->getChildren(),
|
sliceChildShadowNodeViewPairs(oldRootShadowNode),
|
||||||
newRootShadowNode->getChildren()
|
sliceChildShadowNodeViewPairs(newRootShadowNode)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return mutations;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace react
|
} // namespace react
|
||||||
|
@ -6,20 +6,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <fabric/core/ShadowNode.h>
|
#include <fabric/core/ShadowNode.h>
|
||||||
#include <fabric/uimanager/TreeMutationInstruction.h>
|
#include <fabric/uimanager/ShadowViewMutation.h>
|
||||||
|
|
||||||
namespace facebook {
|
namespace facebook {
|
||||||
namespace react {
|
namespace react {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculates set of mutation instuctions which describe how the old
|
* Calculates a list of view mutations which describes how the old
|
||||||
* ShadowNode tree can be transformed to the new ShadowNode tree.
|
* `ShadowTree` can be transformed to the new one.
|
||||||
* The set of instuctions might be and might not be optimal.
|
* The list of mutations might be and might not be optimal.
|
||||||
*/
|
*/
|
||||||
void calculateMutationInstructions(
|
ShadowViewMutationList calculateShadowViewMutations(
|
||||||
TreeMutationInstructionList &instructions,
|
const ShadowNode &oldRootShadowNode,
|
||||||
const SharedShadowNode &oldNode,
|
const ShadowNode &newRootShadowNode
|
||||||
const SharedShadowNode &newNode
|
|
||||||
);
|
);
|
||||||
|
|
||||||
} // namespace react
|
} // namespace react
|
||||||
|
@ -82,9 +82,9 @@ SchedulerDelegate *Scheduler::getDelegate() const {
|
|||||||
|
|
||||||
#pragma mark - ShadowTreeDelegate
|
#pragma mark - ShadowTreeDelegate
|
||||||
|
|
||||||
void Scheduler::shadowTreeDidCommit(const SharedShadowTree &shadowTree, const TreeMutationInstructionList &instructions) {
|
void Scheduler::shadowTreeDidCommit(const SharedShadowTree &shadowTree, const ShadowViewMutationList &mutations) {
|
||||||
if (delegate_) {
|
if (delegate_) {
|
||||||
delegate_->schedulerDidComputeMutationInstructions(shadowTree->getRootTag(), instructions);
|
delegate_->schedulerDidFinishTransaction(shadowTree->getRootTag(), mutations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ public:
|
|||||||
|
|
||||||
#pragma mark - ShadowTreeDelegate
|
#pragma mark - ShadowTreeDelegate
|
||||||
|
|
||||||
void shadowTreeDidCommit(const SharedShadowTree &shadowTree, const TreeMutationInstructionList &instructions) override;
|
void shadowTreeDidCommit(const SharedShadowTree &shadowTree, const ShadowViewMutationList &mutations) override;
|
||||||
|
|
||||||
#pragma mark - Deprecated
|
#pragma mark - Deprecated
|
||||||
|
|
||||||
@ -67,7 +67,6 @@ public:
|
|||||||
std::shared_ptr<FabricUIManager> getUIManager_DO_NOT_USE();
|
std::shared_ptr<FabricUIManager> getUIManager_DO_NOT_USE();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
SchedulerDelegate *delegate_;
|
SchedulerDelegate *delegate_;
|
||||||
std::shared_ptr<FabricUIManager> uiManager_;
|
std::shared_ptr<FabricUIManager> uiManager_;
|
||||||
std::unordered_map<Tag, SharedShadowTree> shadowTreeRegistry_;
|
std::unordered_map<Tag, SharedShadowTree> shadowTreeRegistry_;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#include <fabric/core/ReactPrimitives.h>
|
#include <fabric/core/ReactPrimitives.h>
|
||||||
#include <fabric/core/ShadowNode.h>
|
#include <fabric/core/ShadowNode.h>
|
||||||
#include <fabric/uimanager/TreeMutationInstruction.h>
|
#include <fabric/uimanager/ShadowViewMutation.h>
|
||||||
|
|
||||||
namespace facebook {
|
namespace facebook {
|
||||||
namespace react {
|
namespace react {
|
||||||
@ -24,10 +24,10 @@ public:
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Called right after Scheduler computed (and laid out) a new updated version
|
* Called right after Scheduler computed (and laid out) a new updated version
|
||||||
* of the tree and calculated a set of mutation instructions which are
|
* of the tree and calculated a set of mutations which are suffisient
|
||||||
* suffisient to construct a new one.
|
* 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.
|
* Called right after a new ShadowNode was created.
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#include "ShadowTreeDelegate.h"
|
#include "ShadowTreeDelegate.h"
|
||||||
#include "Differentiator.h"
|
#include "Differentiator.h"
|
||||||
#include "TreeMutationInstruction.h"
|
#include "ShadowViewMutation.h"
|
||||||
|
|
||||||
namespace facebook {
|
namespace facebook {
|
||||||
namespace react {
|
namespace react {
|
||||||
@ -78,19 +78,16 @@ void ShadowTree::complete(UnsharedRootShadowNode newRootShadowNode) {
|
|||||||
|
|
||||||
newRootShadowNode->sealRecursive();
|
newRootShadowNode->sealRecursive();
|
||||||
|
|
||||||
TreeMutationInstructionList instructions = TreeMutationInstructionList();
|
auto mutations = calculateShadowViewMutations(
|
||||||
|
*oldRootShadowNode,
|
||||||
calculateMutationInstructions(
|
*newRootShadowNode
|
||||||
instructions,
|
|
||||||
oldRootShadowNode,
|
|
||||||
newRootShadowNode
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (commit(oldRootShadowNode, newRootShadowNode, instructions)) {
|
if (commit(oldRootShadowNode, newRootShadowNode, mutations)) {
|
||||||
emitLayoutEvents(instructions);
|
emitLayoutEvents(mutations);
|
||||||
|
|
||||||
if (delegate_) {
|
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(
|
bool ShadowTree::commit(
|
||||||
const SharedRootShadowNode &oldRootShadowNode,
|
const SharedRootShadowNode &oldRootShadowNode,
|
||||||
const SharedRootShadowNode &newRootShadowNode,
|
const SharedRootShadowNode &newRootShadowNode,
|
||||||
const TreeMutationInstructionList &mutationInstructions
|
const ShadowViewMutationList &mutations
|
||||||
) {
|
) {
|
||||||
std::lock_guard<std::mutex> lock(commitMutex_);
|
std::lock_guard<std::mutex> lock(commitMutex_);
|
||||||
|
|
||||||
@ -108,69 +105,57 @@ bool ShadowTree::commit(
|
|||||||
|
|
||||||
rootShadowNode_ = newRootShadowNode;
|
rootShadowNode_ = newRootShadowNode;
|
||||||
|
|
||||||
toggleEventEmitters(mutationInstructions);
|
toggleEventEmitters(mutations);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShadowTree::emitLayoutEvents(const TreeMutationInstructionList &instructions) {
|
void ShadowTree::emitLayoutEvents(const ShadowViewMutationList &mutations) {
|
||||||
for (const auto &instruction : instructions) {
|
for (const auto &mutation : mutations) {
|
||||||
const auto &type = instruction.getType();
|
// Only `Insert` and `Update` mutations can affect layout metrics.
|
||||||
|
|
||||||
// Only `Insertion` and `Replacement` instructions can affect layout metrics.
|
|
||||||
if (
|
if (
|
||||||
type == TreeMutationInstruction::Insertion ||
|
mutation.type != ShadowViewMutation::Insert &&
|
||||||
type == TreeMutationInstruction::Replacement
|
mutation.type != ShadowViewMutation::Update
|
||||||
) {
|
) {
|
||||||
const auto &newShadowNode = instruction.getNewChildNode();
|
continue;
|
||||||
const auto &eventEmitter = newShadowNode->getEventEmitter();
|
}
|
||||||
const auto &viewEventEmitter = std::dynamic_pointer_cast<const ViewEventEmitter>(eventEmitter);
|
|
||||||
|
const auto viewEventEmitter = std::dynamic_pointer_cast<const ViewEventEmitter>(mutation.newChildShadowView.eventEmitter);
|
||||||
|
|
||||||
// Checking if particular shadow node supports `onLayout` event (part of `ViewEventEmitter`).
|
// Checking if particular shadow node supports `onLayout` event (part of `ViewEventEmitter`).
|
||||||
if (viewEventEmitter) {
|
if (!viewEventEmitter) {
|
||||||
// Now we know that both (old and new) shadow nodes must be `LayoutableShadowNode` subclasses.
|
continue;
|
||||||
assert(std::dynamic_pointer_cast<const LayoutableShadowNode>(newShadowNode));
|
}
|
||||||
|
|
||||||
// Checking if the `onLayout` event was requested for the particular Shadow Node.
|
// Checking if the `onLayout` event was requested for the particular Shadow Node.
|
||||||
const auto &viewProps = std::dynamic_pointer_cast<const ViewProps>(newShadowNode->getProps());
|
const auto viewProps = std::dynamic_pointer_cast<const ViewProps>(mutation.newChildShadowView.props);
|
||||||
if (viewProps && !viewProps->onLayout) {
|
if (viewProps && !viewProps->onLayout) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(T29661055): Consider using `std::reinterpret_pointer_cast`.
|
// In case if we have `oldChildShadowView`, checking that layout metrics have changed.
|
||||||
const auto &newLayoutableShadowNode =
|
if (
|
||||||
std::dynamic_pointer_cast<const LayoutableShadowNode>(newShadowNode);
|
mutation.type != ShadowViewMutation::Update &&
|
||||||
|
mutation.oldChildShadowView.layoutMetrics == mutation.newChildShadowView.layoutMetrics
|
||||||
// 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;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
viewEventEmitter->onLayout(newLayoutableShadowNode->getLayoutMetrics());
|
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());
|
std::lock_guard<std::recursive_mutex> lock(EventEmitter::DispatchMutex());
|
||||||
|
|
||||||
for (const auto &instruction : instructions) {
|
for (const auto &mutation : mutations) {
|
||||||
if (instruction.getType() == TreeMutationInstruction::Deletion) {
|
if (mutation.type == ShadowViewMutation::Delete) {
|
||||||
instruction.getOldChildNode()->getEventEmitter()->setEnabled(false);
|
mutation.oldChildShadowView.eventEmitter->setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &instruction : instructions) {
|
for (const auto &mutation : mutations) {
|
||||||
if (instruction.getType() == TreeMutationInstruction::Creation) {
|
if (mutation.type == ShadowViewMutation::Create) {
|
||||||
instruction.getNewChildNode()->getEventEmitter()->setEnabled(true);
|
mutation.newChildShadowView.eventEmitter->setEnabled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include <fabric/core/ReactPrimitives.h>
|
#include <fabric/core/ReactPrimitives.h>
|
||||||
#include <fabric/core/ShadowNode.h>
|
#include <fabric/core/ShadowNode.h>
|
||||||
#include <fabric/uimanager/ShadowTreeDelegate.h>
|
#include <fabric/uimanager/ShadowTreeDelegate.h>
|
||||||
|
#include <fabric/uimanager/ShadowViewMutation.h>
|
||||||
|
|
||||||
namespace facebook {
|
namespace facebook {
|
||||||
namespace react {
|
namespace react {
|
||||||
@ -80,10 +81,10 @@ private:
|
|||||||
bool commit(
|
bool commit(
|
||||||
const SharedRootShadowNode &oldRootShadowNode,
|
const SharedRootShadowNode &oldRootShadowNode,
|
||||||
const SharedRootShadowNode &newRootShadowNode,
|
const SharedRootShadowNode &newRootShadowNode,
|
||||||
const TreeMutationInstructionList &mutationInstructions
|
const ShadowViewMutationList &mutations
|
||||||
);
|
);
|
||||||
void toggleEventEmitters(const TreeMutationInstructionList &instructions);
|
void toggleEventEmitters(const ShadowViewMutationList &mutations);
|
||||||
void emitLayoutEvents(const TreeMutationInstructionList &instructions);
|
void emitLayoutEvents(const ShadowViewMutationList &mutations);
|
||||||
|
|
||||||
const Tag rootTag_;
|
const Tag rootTag_;
|
||||||
SharedRootShadowNode rootShadowNode_;
|
SharedRootShadowNode rootShadowNode_;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <fabric/uimanager/TreeMutationInstruction.h>
|
#include <fabric/uimanager/ShadowViewMutation.h>
|
||||||
|
|
||||||
namespace facebook {
|
namespace facebook {
|
||||||
namespace react {
|
namespace react {
|
||||||
@ -21,7 +21,7 @@ public:
|
|||||||
/*
|
/*
|
||||||
* Called right after Shadow Tree commit a new state of the the tree.
|
* 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
|
} // namespace react
|
||||||
|
@ -15,7 +15,7 @@ namespace facebook {
|
|||||||
namespace react {
|
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
|
* pointers to an old shadow view, a new shadow view, a parent shadow view and
|
||||||
* final index of inserted or updated view.
|
* final index of inserted or updated view.
|
||||||
* Use static methods to instantiate mutations of different types.
|
* Use static methods to instantiate mutations of different types.
|
||||||
@ -25,21 +25,21 @@ struct ShadowViewMutation final {
|
|||||||
#pragma mark - Designated Initializers
|
#pragma mark - Designated Initializers
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates and returns an `Create` mutation instruction.
|
* Creates and returns an `Create` mutation.
|
||||||
*/
|
*/
|
||||||
static ShadowViewMutation CreateMutation(
|
static ShadowViewMutation CreateMutation(
|
||||||
ShadowView shadowView
|
ShadowView shadowView
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates and returns an `Delete` mutation instruction.
|
* Creates and returns an `Delete` mutation.
|
||||||
*/
|
*/
|
||||||
static ShadowViewMutation DeleteMutation(
|
static ShadowViewMutation DeleteMutation(
|
||||||
ShadowView shadowView
|
ShadowView shadowView
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates and returns an `Insert` mutation instruction.
|
* Creates and returns an `Insert` mutation.
|
||||||
*/
|
*/
|
||||||
static ShadowViewMutation InsertMutation(
|
static ShadowViewMutation InsertMutation(
|
||||||
ShadowView parentShadowView,
|
ShadowView parentShadowView,
|
||||||
@ -48,7 +48,7 @@ struct ShadowViewMutation final {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates and returns a `Remove` mutation instruction.
|
* Creates and returns a `Remove` mutation.
|
||||||
*/
|
*/
|
||||||
static ShadowViewMutation RemoveMutation(
|
static ShadowViewMutation RemoveMutation(
|
||||||
ShadowView parentShadowView,
|
ShadowView parentShadowView,
|
||||||
@ -57,7 +57,7 @@ struct ShadowViewMutation final {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates and returns an `Update` mutation instruction.
|
* Creates and returns an `Update` mutation.
|
||||||
*/
|
*/
|
||||||
static ShadowViewMutation UpdateMutation(
|
static ShadowViewMutation UpdateMutation(
|
||||||
ShadowView parentShadowView,
|
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