Initial FlatUIImplemenatation

Summary: public This patch adds an alternative UIImplementation based on an idea of creating UI hierarchy off-the-main-thread (everything but Views), flattening ReactShadowNode hierarchy and displaying it within a single View when possible. While NativeViewHierarchyOptimizer allows removing layout-only RCTViews, this allows removing RCTView, RCTText and RCTImage.

This is an initial bare-bones implementation that doesn't really draw anything, only lays out the shadow nodes. Followup diffs will add missing features.

Reviewed By: astreet

Differential Revision: D2564309

fb-gh-sync-id: 2dda4c8cfc2bac3eb39c5c15e97bd23a57550a1d
This commit is contained in:
Denis Koroskin 2015-12-01 12:07:36 -08:00 committed by facebook-github-bot-5
parent b0e39d26ae
commit b828ae4200
2 changed files with 64 additions and 23 deletions

View File

@ -41,15 +41,40 @@ public class UIImplementation {
private final int[] mMeasureBuffer = new int[4]; private final int[] mMeasureBuffer = new int[4];
public UIImplementation(ReactApplicationContext reactContext, List<ViewManager> viewManagers) { public UIImplementation(ReactApplicationContext reactContext, List<ViewManager> viewManagers) {
mViewManagers = new ViewManagerRegistry(viewManagers); this(reactContext, new ViewManagerRegistry(viewManagers));
mOperationsQueue = new UIViewOperationQueue( }
reactContext,
new NativeViewHierarchyManager(mViewManagers)); private UIImplementation(ReactApplicationContext reactContext, ViewManagerRegistry viewManagers) {
this(
viewManagers,
new UIViewOperationQueue(reactContext, new NativeViewHierarchyManager(viewManagers)));
}
protected UIImplementation(
ViewManagerRegistry viewManagers,
UIViewOperationQueue operationsQueue) {
mViewManagers = viewManagers;
mOperationsQueue = operationsQueue;
mNativeViewHierarchyOptimizer = new NativeViewHierarchyOptimizer( mNativeViewHierarchyOptimizer = new NativeViewHierarchyOptimizer(
mOperationsQueue, mOperationsQueue,
mShadowNodeRegistry); mShadowNodeRegistry);
} }
protected ReactShadowNode createRootShadowNode() {
ReactShadowNode rootCSSNode = new ReactShadowNode();
rootCSSNode.setViewClassName("Root");
return rootCSSNode;
}
protected ReactShadowNode createShadowNode(String className) {
ViewManager viewManager = mViewManagers.get(className);
return viewManager.createShadowNodeInstance();
}
protected final ReactShadowNode resolveShadowNode(int reactTag) {
return mShadowNodeRegistry.getNode(reactTag);
}
/** /**
* Registers a root node with a given tag, size and ThemedReactContext * Registers a root node with a given tag, size and ThemedReactContext
* and adds it to a node registry. * and adds it to a node registry.
@ -60,12 +85,11 @@ public class UIImplementation {
int width, int width,
int height, int height,
ThemedReactContext context) { ThemedReactContext context) {
final ReactShadowNode rootCSSNode = new ReactShadowNode(); final ReactShadowNode rootCSSNode = createRootShadowNode();
rootCSSNode.setReactTag(tag); rootCSSNode.setReactTag(tag);
rootCSSNode.setThemedContext(context); rootCSSNode.setThemedContext(context);
rootCSSNode.setStyleWidth(width); rootCSSNode.setStyleWidth(width);
rootCSSNode.setStyleHeight(height); rootCSSNode.setStyleHeight(height);
rootCSSNode.setViewClassName("Root");
mShadowNodeRegistry.addRootNode(rootCSSNode); mShadowNodeRegistry.addRootNode(rootCSSNode);
// register it within NativeViewHierarchyManager // register it within NativeViewHierarchyManager
@ -104,8 +128,7 @@ public class UIImplementation {
* Invoked by React to create a new node with a given tag, class name and properties. * Invoked by React to create a new node with a given tag, class name and properties.
*/ */
public void createView(int tag, String className, int rootViewTag, ReadableMap props) { public void createView(int tag, String className, int rootViewTag, ReadableMap props) {
ViewManager viewManager = mViewManagers.get(className); ReactShadowNode cssNode = createShadowNode(className);
ReactShadowNode cssNode = viewManager.createShadowNodeInstance();
ReactShadowNode rootNode = mShadowNodeRegistry.getNode(rootViewTag); ReactShadowNode rootNode = mShadowNodeRegistry.getNode(rootViewTag);
cssNode.setReactTag(tag); cssNode.setReactTag(tag);
cssNode.setViewClassName(className); cssNode.setViewClassName(className);
@ -120,8 +143,15 @@ public class UIImplementation {
cssNode.updateProperties(styles); cssNode.updateProperties(styles);
} }
handleCreateView(cssNode, rootViewTag, styles);
}
protected void handleCreateView(
ReactShadowNode cssNode,
int rootViewTag,
@Nullable CatalystStylesDiffMap styles) {
if (!cssNode.isVirtual()) { if (!cssNode.isVirtual()) {
mNativeViewHierarchyOptimizer.handleCreateView(cssNode, rootNode.getThemedContext(), styles); mNativeViewHierarchyOptimizer.handleCreateView(cssNode, cssNode.getThemedContext(), styles);
} }
} }
@ -141,9 +171,16 @@ public class UIImplementation {
if (props != null) { if (props != null) {
CatalystStylesDiffMap styles = new CatalystStylesDiffMap(props); CatalystStylesDiffMap styles = new CatalystStylesDiffMap(props);
cssNode.updateProperties(styles); cssNode.updateProperties(styles);
if (!cssNode.isVirtual()) { handleUpdateView(cssNode, className, styles);
mNativeViewHierarchyOptimizer.handleUpdateView(cssNode, className, styles); }
} }
protected void handleUpdateView(
ReactShadowNode cssNode,
String className,
CatalystStylesDiffMap styles) {
if (!cssNode.isVirtual()) {
mNativeViewHierarchyOptimizer.handleUpdateView(cssNode, className, styles);
} }
} }
@ -401,14 +438,7 @@ public class UIImplementation {
ReactShadowNode cssRoot = mShadowNodeRegistry.getNode(tag); ReactShadowNode cssRoot = mShadowNodeRegistry.getNode(tag);
notifyOnBeforeLayoutRecursive(cssRoot); notifyOnBeforeLayoutRecursive(cssRoot);
SystraceMessage.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "cssRoot.calculateLayout") calculateRootLayout(cssRoot);
.arg("rootTag", tag)
.flush();
try {
cssRoot.calculateLayout(mLayoutContext);
} finally {
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
}
applyUpdatesRecursive(cssRoot, 0f, 0f, eventDispatcher); applyUpdatesRecursive(cssRoot, 0f, 0f, eventDispatcher);
} }
@ -492,7 +522,7 @@ public class UIImplementation {
mOperationsQueue.setViewHierarchyUpdateDebugListener(listener); mOperationsQueue.setViewHierarchyUpdateDebugListener(listener);
} }
private void removeShadowNode(ReactShadowNode nodeToRemove) { protected final void removeShadowNode(ReactShadowNode nodeToRemove) {
mNativeViewHierarchyOptimizer.handleRemoveNode(nodeToRemove); mNativeViewHierarchyOptimizer.handleRemoveNode(nodeToRemove);
mShadowNodeRegistry.removeNode(nodeToRemove.getReactTag()); mShadowNodeRegistry.removeNode(nodeToRemove.getReactTag());
for (int i = nodeToRemove.getChildCount() - 1; i >= 0; i--) { for (int i = nodeToRemove.getChildCount() - 1; i >= 0; i--) {
@ -597,7 +627,18 @@ public class UIImplementation {
cssNode.onBeforeLayout(); cssNode.onBeforeLayout();
} }
private void applyUpdatesRecursive( protected void calculateRootLayout(ReactShadowNode cssRoot) {
SystraceMessage.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "cssRoot.calculateLayout")
.arg("rootTag", cssRoot.getReactTag())
.flush();
try {
cssRoot.calculateLayout(mLayoutContext);
} finally {
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
protected void applyUpdatesRecursive(
ReactShadowNode cssNode, ReactShadowNode cssNode,
float absoluteX, float absoluteX,
float absoluteY, float absoluteY,

View File

@ -440,7 +440,7 @@ public class UIViewOperationQueue {
private @Nullable NotThreadSafeViewHierarchyUpdateDebugListener mViewHierarchyUpdateDebugListener; private @Nullable NotThreadSafeViewHierarchyUpdateDebugListener mViewHierarchyUpdateDebugListener;
protected UIViewOperationQueue( public UIViewOperationQueue(
ReactApplicationContext reactContext, ReactApplicationContext reactContext,
NativeViewHierarchyManager nativeViewHierarchyManager) { NativeViewHierarchyManager nativeViewHierarchyManager) {
mNativeViewHierarchyManager = nativeViewHierarchyManager; mNativeViewHierarchyManager = nativeViewHierarchyManager;