Introduce "Sealing" of ReactShadowNodes

Summary: This diff introduces the concept of "Seal" ReactShadowNodes. This new field will be used to guarantee immutability of commited ReactShodow Nodes.

Reviewed By: fkgozali

Differential Revision: D8552709

fbshipit-source-id: dfd95730f10341af0dd762f8a8aa186563cf33e9
This commit is contained in:
David Vacca 2018-06-22 11:29:07 -07:00 committed by Facebook Github Bot
parent f19c36116c
commit 001e217f33
4 changed files with 45 additions and 6 deletions

View File

@ -10,7 +10,6 @@ package com.facebook.react.fabric;
import static android.view.View.MeasureSpec.AT_MOST;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.UNSPECIFIED;
import static com.facebook.react.uimanager.common.UIManagerType.DEFAULT;
import static com.facebook.react.uimanager.common.UIManagerType.FABRIC;
import android.os.SystemClock;
@ -22,7 +21,6 @@ import com.facebook.infer.annotation.Assertions;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.JavaScriptContextHolder;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableNativeMap;
@ -41,13 +39,11 @@ import com.facebook.react.uimanager.ReactShadowNode;
import com.facebook.react.uimanager.ReactShadowNodeImpl;
import com.facebook.react.uimanager.ReactStylesDiffMap;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.UIManagerHelper;
import com.facebook.react.uimanager.UIViewOperationQueue;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.uimanager.ViewManagerRegistry;
import com.facebook.react.uimanager.common.MeasureSpecProvider;
import com.facebook.react.uimanager.common.SizeMonitoringFrameLayout;
import com.facebook.react.uimanager.common.ViewUtil;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.systrace.Systrace;
import com.facebook.systrace.SystraceMessage;
@ -295,10 +291,10 @@ public class FabricUIManager implements UIManager, JSHandler {
"FabricUIManager.appendChild")
.flush();
try {
// If the child to append is shared with another tree (child.getParent() != null),
// If the child to append was already committed (child.isSealed()),
// then we add a mutation of it. In the future this will be performed by FabricJS / Fiber.
//TODO: T27926878 avoid cloning shared child
if (child.getParent() != null) {
if (child.isSealed()) {
child = child.mutableCopy(child.getInstanceHandle());
}
parent.addChildAt(child, parent.getChildCount());
@ -474,6 +470,7 @@ public class FabricUIManager implements UIManager, JSHandler {
// and we do not need to hold references to the previous tree anymore
node.setOriginalReactShadowNode(null);
node.markUpdateSeen();
node.markAsSealed();
}
@Override

View File

@ -377,4 +377,16 @@ public interface ReactShadowNode<T extends ReactShadowNode> {
long getInstanceHandle();
void setInstanceHandle(long instanceHandle);
/**
* Mark this {@link ReactShadowNode} as sealed. This means that the node was already committed
* and it should not be updated anymore.
*/
void markAsSealed();
/**
* @return a {@link boolean} that represents if the {@link ReactShadowNode} is sealed.
*/
boolean isSealed();
}

View File

@ -128,6 +128,7 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
private @Nullable ReactStylesDiffMap mNewProps;
private long mInstanceHandle;
private boolean mIsSealed = false;
public ReactShadowNodeImpl() {
mDefaultPadding = new Spacing(0);
@ -164,6 +165,7 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
mNewProps = null;
mParent = null;
mOriginalReactShadowNode = original;
mIsSealed = false;
}
private void replaceChild(ReactShadowNodeImpl newNode, int childIndex) {
@ -1147,4 +1149,14 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
public void setInstanceHandle(long instanceHandle) {
mInstanceHandle = instanceHandle;
}
@Override
public void markAsSealed() {
mIsSealed = true;
}
@Override
public boolean isSealed() {
return mIsSealed;
}
}

View File

@ -233,6 +233,24 @@ public class FabricUIManagerTest {
mFabricUIManager.completeRoot(rootTag, children);
}
@Test
public void testSealReactShadowNode() {
ReactRootView rootView =
new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
int rootTag = mFabricUIManager.addRootView(rootView);
String viewClass = ReactViewManager.REACT_CLASS;
ReactShadowNode container = mFabricUIManager.createNode(6, viewClass, rootTag, null, randomInstanceHandle());
List<ReactShadowNode> childSet = mFabricUIManager.createChildSet(rootTag);
mFabricUIManager.appendChildToSet(childSet, container);
assertThat(container.isSealed()).isFalse();
mFabricUIManager.completeRoot(rootTag, childSet);
assertThat(container.isSealed()).isTrue();
}
/**
* Tests that cloned text nodes will not share measure functions
*/