Skip to content

Commit

Permalink
Revert "Android: Enable views to be nested within <Text> (facebook#23195
Browse files Browse the repository at this point in the history
)"
  • Loading branch information
dulmandakh committed Apr 3, 2019
1 parent d9711e2 commit f651990
Show file tree
Hide file tree
Showing 19 changed files with 135 additions and 672 deletions.
15 changes: 14 additions & 1 deletion Libraries/Components/View/View.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
'use strict';

const React = require('React');
const TextAncestor = require('TextAncestor');
const ViewNativeComponent = require('ViewNativeComponent');

const invariant = require('invariant');

import type {ViewProps} from 'ViewPropTypes';

export type Props = ViewProps;
Expand All @@ -32,7 +35,17 @@ if (__DEV__) {
props: Props,
forwardedRef: React.Ref<typeof ViewNativeComponent>,
) => {
return <ViewNativeComponent {...props} ref={forwardedRef} />;
return (
<TextAncestor.Consumer>
{hasTextAncestor => {
invariant(
!hasTextAncestor,
'Nesting of <View> within <Text> is not currently supported.',
);
return <ViewNativeComponent {...props} ref={forwardedRef} />;
}}
</TextAncestor.Consumer>
);
};
ViewToExport = React.forwardRef(View);
ViewToExport.displayName = 'View';
Expand Down
4 changes: 0 additions & 4 deletions Libraries/Text/Text.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,12 @@ const viewConfig = {
minimumFontScale: true,
textBreakStrategy: true,
onTextLayout: true,
onInlineViewLayout: true,
dataDetectorType: true,
},
directEventTypes: {
topTextLayout: {
registrationName: 'onTextLayout',
},
topInlineViewLayout: {
registrationName: 'onInlineViewLayout',
},
},
uiViewClassName: 'RCTText',
};
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -195,16 +195,16 @@ public synchronized void updateLayout(
// Check if the parent of the view has to layout the view, or the child has to lay itself out.
if (!mRootTags.get(parentTag)) {
ViewManager parentViewManager = mTagsToViewManagers.get(parentTag);
IViewManagerWithChildren parentViewManagerWithChildren;
if (parentViewManager instanceof IViewManagerWithChildren) {
parentViewManagerWithChildren = (IViewManagerWithChildren) parentViewManager;
ViewGroupManager parentViewGroupManager;
if (parentViewManager instanceof ViewGroupManager) {
parentViewGroupManager = (ViewGroupManager) parentViewManager;
} else {
throw new IllegalViewOperationException(
"Trying to use view with tag " + parentTag +
" as a parent, but its Manager doesn't implement IViewManagerWithChildren");
" as a parent, but its Manager doesn't extends ViewGroupManager");
}
if (parentViewManagerWithChildren != null
&& !parentViewManagerWithChildren.needsCustomLayoutForChildren()) {
if (parentViewGroupManager != null
&& !parentViewGroupManager.needsCustomLayoutForChildren()) {
updateLayout(viewToUpdate, x, y, width, height);
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,6 @@ private static class NodeIndexPair {
private final ShadowNodeRegistry mShadowNodeRegistry;
private final SparseBooleanArray mTagsWithLayoutVisited = new SparseBooleanArray();

public static void assertNodeSupportedWithoutOptimizer(ReactShadowNode node) {
// NativeKind.LEAF nodes require the optimizer. They are not ViewGroups so they cannot host
// their native children themselves. Their native children need to be hoisted by the optimizer
// to an ancestor which is a ViewGroup.
Assertions.assertCondition(
node.getNativeKind() != NativeKind.LEAF,
"Nodes with NativeKind.LEAF are not supported when the optimizer is disabled");
}

public NativeViewHierarchyOptimizer(
UIViewOperationQueue uiViewOperationQueue,
ShadowNodeRegistry shadowNodeRegistry) {
Expand All @@ -88,7 +79,6 @@ public void handleCreateView(
ThemedReactContext themedContext,
@Nullable ReactStylesDiffMap initialProps) {
if (!ENABLED) {
assertNodeSupportedWithoutOptimizer(node);
int tag = node.getReactTag();
mUIViewOperationQueue.enqueueCreateView(
themedContext,
Expand All @@ -102,7 +92,7 @@ public void handleCreateView(
isLayoutOnlyAndCollapsable(initialProps);
node.setIsLayoutOnly(isLayoutOnly);

if (node.getNativeKind() != NativeKind.NONE) {
if (!isLayoutOnly) {
mUIViewOperationQueue.enqueueCreateView(
themedContext,
node.getReactTag(),
Expand All @@ -128,7 +118,6 @@ public void handleUpdateView(
String className,
ReactStylesDiffMap props) {
if (!ENABLED) {
assertNodeSupportedWithoutOptimizer(node);
mUIViewOperationQueue.enqueueUpdateProperties(node.getReactTag(), className, props);
return;
}
Expand Down Expand Up @@ -159,7 +148,6 @@ public void handleManageChildren(
int[] tagsToDelete,
int[] indicesToDelete) {
if (!ENABLED) {
assertNodeSupportedWithoutOptimizer(nodeToManage);
mUIViewOperationQueue.enqueueManageChildren(
nodeToManage.getReactTag(),
indicesToRemove,
Expand Down Expand Up @@ -201,7 +189,6 @@ public void handleSetChildren(
ReadableArray childrenTags
) {
if (!ENABLED) {
assertNodeSupportedWithoutOptimizer(nodeToManage);
mUIViewOperationQueue.enqueueSetChildren(
nodeToManage.getReactTag(),
childrenTags);
Expand All @@ -221,9 +208,8 @@ public void handleSetChildren(
*/
public void handleUpdateLayout(ReactShadowNode node) {
if (!ENABLED) {
assertNodeSupportedWithoutOptimizer(node);
mUIViewOperationQueue.enqueueUpdateLayout(
Assertions.assertNotNull(node.getLayoutParent()).getReactTag(),
Assertions.assertNotNull(node.getParent()).getReactTag(),
node.getReactTag(),
node.getScreenX(),
node.getScreenY(),
Expand All @@ -235,12 +221,6 @@ public void handleUpdateLayout(ReactShadowNode node) {
applyLayoutBase(node);
}

public void handleForceViewToBeNonLayoutOnly(ReactShadowNode node) {
if (node.isLayoutOnly()) {
transitionLayoutOnlyViewToNativeView(node, null);
}
}

/**
* Processes the shadow hierarchy to dispatch all necessary updateLayout calls to the native
* hierarchy. Should be called after all updateLayout calls for a batch have been handled.
Expand All @@ -249,18 +229,16 @@ public void onBatchComplete() {
mTagsWithLayoutVisited.clear();
}

private NodeIndexPair walkUpUntilNativeKindIsParent(
private NodeIndexPair walkUpUntilNonLayoutOnly(
ReactShadowNode node,
int indexInNativeChildren) {
while (node.getNativeKind() != NativeKind.PARENT) {
while (node.isLayoutOnly()) {
ReactShadowNode parent = node.getParent();
if (parent == null) {
return null;
}

indexInNativeChildren = indexInNativeChildren +
(node.getNativeKind() == NativeKind.LEAF ? 1 : 0) +
parent.getNativeOffsetForChild(node);
indexInNativeChildren = indexInNativeChildren + parent.getNativeOffsetForChild(node);
node = parent;
}

Expand All @@ -269,8 +247,8 @@ private NodeIndexPair walkUpUntilNativeKindIsParent(

private void addNodeToNode(ReactShadowNode parent, ReactShadowNode child, int index) {
int indexInNativeChildren = parent.getNativeOffsetForChild(parent.getChildAt(index));
if (parent.getNativeKind() != NativeKind.PARENT) {
NodeIndexPair result = walkUpUntilNativeKindIsParent(parent, indexInNativeChildren);
if (parent.isLayoutOnly()) {
NodeIndexPair result = walkUpUntilNonLayoutOnly(parent, indexInNativeChildren);
if (result == null) {
// If the parent hasn't been attached to its native parent yet, don't issue commands to the
// native hierarchy. We'll do that when the parent node actually gets attached somewhere.
Expand All @@ -280,26 +258,20 @@ private void addNodeToNode(ReactShadowNode parent, ReactShadowNode child, int in
indexInNativeChildren = result.index;
}

if (child.getNativeKind() != NativeKind.NONE) {
addNativeChild(parent, child, indexInNativeChildren);
if (!child.isLayoutOnly()) {
addNonLayoutNode(parent, child, indexInNativeChildren);
} else {
addNonNativeChild(parent, child, indexInNativeChildren);
addLayoutOnlyNode(parent, child, indexInNativeChildren);
}
}

/**
* For handling node removal from manageChildren. In the case of removing a node which isn't
* hosting its own children (e.g. layout-only or NativeKind.LEAF), we need to recursively remove
* all its children from their native parents.
* For handling node removal from manageChildren. In the case of removing a layout-only node, we
* need to instead recursively remove all its children from their native parents.
*/
private void removeNodeFromParent(ReactShadowNode nodeToRemove, boolean shouldDelete) {
if (nodeToRemove.getNativeKind() != NativeKind.PARENT) {
for (int i = nodeToRemove.getChildCount() - 1; i >= 0; i--) {
removeNodeFromParent(nodeToRemove.getChildAt(i), shouldDelete);
}
}

ReactShadowNode nativeNodeToRemoveFrom = nodeToRemove.getNativeParent();

if (nativeNodeToRemoveFrom != null) {
int index = nativeNodeToRemoveFrom.indexOfNativeChild(nodeToRemove);
nativeNodeToRemoveFrom.removeNativeChildAt(index);
Expand All @@ -310,17 +282,21 @@ private void removeNodeFromParent(ReactShadowNode nodeToRemove, boolean shouldDe
null,
shouldDelete ? new int[] {nodeToRemove.getReactTag()} : null,
shouldDelete ? new int[] {index} : null);
} else {
for (int i = nodeToRemove.getChildCount() - 1; i >= 0; i--) {
removeNodeFromParent(nodeToRemove.getChildAt(i), shouldDelete);
}
}
}

private void addNonNativeChild(
ReactShadowNode nativeParent,
ReactShadowNode nonNativeChild,
private void addLayoutOnlyNode(
ReactShadowNode nonLayoutOnlyNode,
ReactShadowNode layoutOnlyNode,
int index) {
addGrandchildren(nativeParent, nonNativeChild, index);
addGrandchildren(nonLayoutOnlyNode, layoutOnlyNode, index);
}

private void addNativeChild(
private void addNonLayoutNode(
ReactShadowNode parent,
ReactShadowNode child,
int index) {
Expand All @@ -331,33 +307,30 @@ private void addNativeChild(
new ViewAtIndex[] {new ViewAtIndex(child.getReactTag(), index)},
null,
null);

if (child.getNativeKind() != NativeKind.PARENT) {
addGrandchildren(parent, child, index + 1);
}
}

private void addGrandchildren(
ReactShadowNode nativeParent,
ReactShadowNode child,
int index) {
Assertions.assertCondition(child.getNativeKind() != NativeKind.PARENT);
Assertions.assertCondition(!nativeParent.isLayoutOnly());

// `child` can't hold native children. Add all of `child`'s children to `parent`.
int currentIndex = index;
for (int i = 0; i < child.getChildCount(); i++) {
ReactShadowNode grandchild = child.getChildAt(i);
Assertions.assertCondition(grandchild.getNativeParent() == null);

// Adding this child could result in adding multiple native views
int grandchildCountBefore = nativeParent.getNativeChildCount();
if (grandchild.getNativeKind() == NativeKind.NONE) {
addNonNativeChild(nativeParent, grandchild, currentIndex);
if (grandchild.isLayoutOnly()) {
// Adding this child could result in adding multiple native views
int grandchildCountBefore = nativeParent.getNativeChildCount();
addLayoutOnlyNode(nativeParent, grandchild, currentIndex);
int grandchildCountAfter = nativeParent.getNativeChildCount();
currentIndex += grandchildCountAfter - grandchildCountBefore;
} else {
addNativeChild(nativeParent, grandchild, currentIndex);
addNonLayoutNode(nativeParent, grandchild, currentIndex);
currentIndex++;
}
int grandchildCountAfter = nativeParent.getNativeChildCount();
currentIndex += grandchildCountAfter - grandchildCountBefore;
}
}

Expand All @@ -376,16 +349,10 @@ private void applyLayoutBase(ReactShadowNode node) {
int x = node.getScreenX();
int y = node.getScreenY();

while (parent != null && parent.getNativeKind() != NativeKind.PARENT) {
if (!parent.isVirtual()) {
// Skip these additions for virtual nodes. This has the same effect as `getLayout*`
// returning `0`. Virtual nodes aren't in the Yoga tree so we can't call `getLayout*` on
// them.

// TODO(7854667): handle and test proper clipping
x += Math.round(parent.getLayoutX());
y += Math.round(parent.getLayoutY());
}
while (parent != null && parent.isLayoutOnly()) {
// TODO(7854667): handle and test proper clipping
x += Math.round(parent.getLayoutX());
y += Math.round(parent.getLayoutY());

parent = parent.getParent();
}
Expand All @@ -394,10 +361,10 @@ private void applyLayoutBase(ReactShadowNode node) {
}

private void applyLayoutRecursive(ReactShadowNode toUpdate, int x, int y) {
if (toUpdate.getNativeKind() != NativeKind.NONE && toUpdate.getNativeParent() != null) {
if (!toUpdate.isLayoutOnly() && toUpdate.getNativeParent() != null) {
int tag = toUpdate.getReactTag();
mUIViewOperationQueue.enqueueUpdateLayout(
toUpdate.getLayoutParent().getReactTag(),
toUpdate.getNativeParent().getReactTag(),
tag,
x,
y,
Expand Down
Loading

0 comments on commit f651990

Please sign in to comment.