From 0df65bb7d4fcb935b3dea589f3cb7b73a5d52483 Mon Sep 17 00:00:00 2001 From: Andy Street Date: Mon, 14 Nov 2016 04:34:57 -0800 Subject: [PATCH] BREAKING [react_native/css_layout] Update RN shadow nodes to hold CSSNode instead of extending CSSNode Summary: This diff makes it so ReactShadowNode holds a CSSNode instead of extending one. This will enable us to pool and re-use CSSNodes and will allow us to keep from breaking the CSSNode api assumption that nodes that have measure functions don't have children (right now, text nodes have measure functions, but they also have raw text children). BREAKING This diff makes ReactShadowNode no longer extend CSSNodeDEPRECATED. If you have code that depended on that, e.g. via instanceof checks, that will no longer work as expected. Subclasses that override getChildAt/addChildAt/etc will need to update your method signatures. There should be no runtime behavior changes. Reviewed By: emilsjolander Differential Revision: D4153818 fbshipit-source-id: 2836434dd925d8e4651b9bb94b602c235e1e7665 --- .../react/uimanager/LayoutShadowNode.java | 18 +- .../react/uimanager/ReactShadowNode.java | 330 ++++++++++++++---- .../react/uimanager/UIImplementation.java | 2 +- .../views/modal/ModalHostShadowNode.java | 4 +- .../react/views/text/ReactTextShadowNode.java | 73 ++-- 5 files changed, 305 insertions(+), 122 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java index ae5828323..e8d043136 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java @@ -29,27 +29,32 @@ public class LayoutShadowNode extends ReactShadowNode { @ReactProp(name = ViewProps.MIN_WIDTH, defaultFloat = CSSConstants.UNDEFINED) public void setMinWidth(float minWidth) { - setStyleMinWidth(CSSConstants.isUndefined(minWidth) ? minWidth : PixelUtil.toPixelFromDIP(minWidth)); + setStyleMinWidth( + CSSConstants.isUndefined(minWidth) ? minWidth : PixelUtil.toPixelFromDIP(minWidth)); } @ReactProp(name = ViewProps.MAX_WIDTH, defaultFloat = CSSConstants.UNDEFINED) public void setMaxWidth(float maxWidth) { - setStyleMaxWidth(CSSConstants.isUndefined(maxWidth) ? maxWidth : PixelUtil.toPixelFromDIP(maxWidth)); + setStyleMaxWidth( + CSSConstants.isUndefined(maxWidth) ? maxWidth : PixelUtil.toPixelFromDIP(maxWidth)); } @ReactProp(name = ViewProps.HEIGHT, defaultFloat = CSSConstants.UNDEFINED) public void setHeight(float height) { - setStyleHeight(CSSConstants.isUndefined(height) ? height : PixelUtil.toPixelFromDIP(height)); + setStyleHeight( + CSSConstants.isUndefined(height) ? height : PixelUtil.toPixelFromDIP(height)); } @ReactProp(name = ViewProps.MIN_HEIGHT, defaultFloat = CSSConstants.UNDEFINED) public void setMinHeight(float minHeight) { - setStyleMinHeight(CSSConstants.isUndefined(minHeight) ? minHeight : PixelUtil.toPixelFromDIP(minHeight)); + setStyleMinHeight( + CSSConstants.isUndefined(minHeight) ? minHeight : PixelUtil.toPixelFromDIP(minHeight)); } @ReactProp(name = ViewProps.MAX_HEIGHT, defaultFloat = CSSConstants.UNDEFINED) public void setMaxHeight(float maxHeight) { - setStyleMaxHeight(CSSConstants.isUndefined(maxHeight) ? maxHeight : PixelUtil.toPixelFromDIP(maxHeight)); + setStyleMaxHeight( + CSSConstants.isUndefined(maxHeight) ? maxHeight : PixelUtil.toPixelFromDIP(maxHeight)); } @ReactProp(name = ViewProps.FLEX, defaultFloat = 0f) @@ -81,7 +86,8 @@ public class LayoutShadowNode extends ReactShadowNode { @ReactProp(name = ViewProps.FLEX_WRAP) public void setFlexWrap(@Nullable String flexWrap) { - setWrap(flexWrap == null ? CSSWrap.NOWRAP : CSSWrap.valueOf(flexWrap.toUpperCase(Locale.US))); + setFlexWrap( + flexWrap == null ? CSSWrap.NOWRAP : CSSWrap.valueOf(flexWrap.toUpperCase(Locale.US))); } @ReactProp(name = ViewProps.ALIGN_SELF) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java index 520ced417..581182060 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java @@ -13,8 +13,17 @@ import javax.annotation.Nullable; import java.util.ArrayList; +import com.facebook.csslayout.CSSAlign; import com.facebook.csslayout.CSSConstants; +import com.facebook.csslayout.CSSDirection; +import com.facebook.csslayout.CSSFlexDirection; +import com.facebook.csslayout.CSSJustify; +import com.facebook.csslayout.CSSLayoutContext; +import com.facebook.csslayout.CSSNodeAPI; import com.facebook.csslayout.CSSNodeDEPRECATED; +import com.facebook.csslayout.CSSOverflow; +import com.facebook.csslayout.CSSPositionType; +import com.facebook.csslayout.CSSWrap; import com.facebook.csslayout.Spacing; import com.facebook.infer.annotation.Assertions; import com.facebook.react.uimanager.annotations.ReactPropertyHolder; @@ -43,7 +52,7 @@ import com.facebook.react.uimanager.annotations.ReactPropertyHolder; * information. */ @ReactPropertyHolder -public class ReactShadowNode extends CSSNodeDEPRECATED { +public class ReactShadowNode { private int mReactTag; private @Nullable String mViewClassName; @@ -51,6 +60,8 @@ public class ReactShadowNode extends CSSNodeDEPRECATED { private @Nullable ThemedReactContext mThemedContext; private boolean mShouldNotifyOnLayout; private boolean mNodeUpdated = true; + private @Nullable ArrayList mChildren; + private @Nullable ReactShadowNode mParent; // layout-only nodes private boolean mIsLayoutOnly; @@ -63,6 +74,7 @@ public class ReactShadowNode extends CSSNodeDEPRECATED { private float mAbsoluteBottom; private final Spacing mDefaultPadding = new Spacing(0); private final Spacing mPadding = new Spacing(CSSConstants.UNDEFINED); + private final CSSNodeDEPRECATED mCSSNode = new CSSNodeDEPRECATED(); /** * Nodes that return {@code true} will be treated as "virtual" nodes. That is, nodes that are not @@ -88,7 +100,7 @@ public class ReactShadowNode extends CSSNodeDEPRECATED { } public final boolean hasUpdates() { - return mNodeUpdated || hasNewLayout() || isDirty(); + return mNodeUpdated || hasNewLayout() || mCSSNode.isDirty(); } public final void markUpdateSeen() { @@ -109,74 +121,45 @@ public class ReactShadowNode extends CSSNodeDEPRECATED { } } - public boolean hasUnseenUpdates() { + public final boolean hasUnseenUpdates() { return mNodeUpdated; } - @Override public void dirty() { if (!isVirtual()) { - super.dirty(); + mCSSNode.dirty(); } } - public void setDefaultPadding(int spacingType, float padding) { - mDefaultPadding.set(spacingType, padding); - updatePadding(); - } - - @Override - public void setPadding(int spacingType, float padding) { - mPadding.set(spacingType, padding); - updatePadding(); - } - - private void updatePadding() { - for (int spacingType = Spacing.LEFT; spacingType <= Spacing.ALL; spacingType++) { - if (spacingType == Spacing.LEFT || - spacingType == Spacing.RIGHT || - spacingType == Spacing.START || - spacingType == Spacing.END) { - if (CSSConstants.isUndefined(mPadding.getRaw(spacingType)) && - CSSConstants.isUndefined(mPadding.getRaw(Spacing.HORIZONTAL)) && - CSSConstants.isUndefined(mPadding.getRaw(Spacing.ALL))) { - super.setPadding(spacingType, mDefaultPadding.getRaw(spacingType)); - } else { - super.setPadding(spacingType, mPadding.getRaw(spacingType)); - } - } else if (spacingType == Spacing.TOP || spacingType == Spacing.BOTTOM) { - if (CSSConstants.isUndefined(mPadding.getRaw(spacingType)) && - CSSConstants.isUndefined(mPadding.getRaw(Spacing.VERTICAL)) && - CSSConstants.isUndefined(mPadding.getRaw(Spacing.ALL))) { - super.setPadding(spacingType, mDefaultPadding.getRaw(spacingType)); - } else { - super.setPadding(spacingType, mPadding.getRaw(spacingType)); - } - } else { - if (CSSConstants.isUndefined(mPadding.getRaw(spacingType))) { - super.setPadding(spacingType, mDefaultPadding.getRaw(spacingType)); - } else { - super.setPadding(spacingType, mPadding.getRaw(spacingType)); - } - } + public void addChildAt(ReactShadowNode child, int i) { + if (child.mParent != null) { + throw new IllegalViewOperationException( + "Tried to add child that already has a parent! Remove it from its parent first."); } - } + if (mChildren == null) { + mChildren = new ArrayList(4); + } + mChildren.add(i, child); + child.mParent = this; - @Override - public void addChildAt(CSSNodeDEPRECATED child, int i) { - super.addChildAt(child, i); + mCSSNode.addChildAt(child.mCSSNode, i); markUpdated(); - ReactShadowNode node = (ReactShadowNode) child; - int increase = node.mIsLayoutOnly ? node.mTotalNativeChildren : 1; + int increase = child.mIsLayoutOnly ? child.mTotalNativeChildren : 1; mTotalNativeChildren += increase; updateNativeChildrenCountInParent(increase); } - @Override public ReactShadowNode removeChildAt(int i) { - ReactShadowNode removed = (ReactShadowNode) super.removeChildAt(i); + if (mChildren == null) { + throw new ArrayIndexOutOfBoundsException( + "Index " + i + " out of bounds: node has no children"); + } + ReactShadowNode removed = mChildren.remove(i); + removed.mParent = null; + + mCSSNode.removeChildAt(i); markUpdated(); int decrease = removed.mIsLayoutOnly ? removed.mTotalNativeChildren : 1; @@ -185,12 +168,35 @@ public class ReactShadowNode extends CSSNodeDEPRECATED { return removed; } + public final int getChildCount() { + return mChildren == null ? 0 : mChildren.size(); + } + + public final ReactShadowNode getChildAt(int i) { + if (mChildren == null) { + throw new ArrayIndexOutOfBoundsException( + "Index " + i + " out of bounds: node has no children"); + } + return mChildren.get(i); + } + + public final int indexOf(ReactShadowNode child) { + return mChildren == null ? -1 : mChildren.indexOf(child); + } + public void removeAllChildren() { + if (getChildCount() == 0) { + return; + } + int decrease = 0; for (int i = getChildCount() - 1; i >= 0; i--) { - ReactShadowNode removed = (ReactShadowNode) super.removeChildAt(i); - decrease += removed.mIsLayoutOnly ? removed.mTotalNativeChildren : 1; + mCSSNode.removeChildAt(i); + ReactShadowNode toRemove = getChildAt(i); + toRemove.mParent = null; + decrease += toRemove.mIsLayoutOnly ? toRemove.mTotalNativeChildren : 1; } + Assertions.assertNotNull(mChildren).clear(); markUpdated(); mTotalNativeChildren -= decrease; @@ -294,14 +300,8 @@ public class ReactShadowNode extends CSSNodeDEPRECATED { mViewClassName = viewClassName; } - @Override - public final ReactShadowNode getChildAt(int i) { - return (ReactShadowNode) super.getChildAt(i); - } - - @Override public final @Nullable ReactShadowNode getParent() { - return (ReactShadowNode) super.getParent(); + return mParent; } /** @@ -309,7 +309,7 @@ public class ReactShadowNode extends CSSNodeDEPRECATED { * never change during the lifetime of a {@link ReactShadowNode} instance, but different instances * can have different contexts; don't cache any calculations based on theme values globally. */ - public ThemedReactContext getThemedContext() { + public final ThemedReactContext getThemedContext() { return Assertions.assertNotNull(mThemedContext); } @@ -317,19 +317,27 @@ public class ReactShadowNode extends CSSNodeDEPRECATED { mThemedContext = themedContext; } - public void setShouldNotifyOnLayout(boolean shouldNotifyOnLayout) { - mShouldNotifyOnLayout = shouldNotifyOnLayout; + public final boolean shouldNotifyOnLayout() { + return mShouldNotifyOnLayout; } - public boolean shouldNotifyOnLayout() { - return mShouldNotifyOnLayout; + public void calculateLayout(CSSLayoutContext layoutContext) { + mCSSNode.calculateLayout(layoutContext); + } + + public final boolean hasNewLayout() { + return mCSSNode.hasNewLayout(); + } + + public final void markLayoutSeen() { + mCSSNode.markLayoutSeen(); } /** * Adds a child that the native view hierarchy will have at this index in the native view * corresponding to this node. */ - public void addNativeChildAt(ReactShadowNode child, int nativeIndex) { + public final void addNativeChildAt(ReactShadowNode child, int nativeIndex) { Assertions.assertCondition(!mIsLayoutOnly); Assertions.assertCondition(!child.mIsLayoutOnly); @@ -341,14 +349,14 @@ public class ReactShadowNode extends CSSNodeDEPRECATED { child.mNativeParent = this; } - public ReactShadowNode removeNativeChildAt(int i) { + public final ReactShadowNode removeNativeChildAt(int i) { Assertions.assertNotNull(mNativeChildren); ReactShadowNode removed = mNativeChildren.remove(i); removed.mNativeParent = null; return removed; } - public void removeAllNativeChildren() { + public final void removeAllNativeChildren() { if (mNativeChildren != null) { for (int i = mNativeChildren.size() - 1; i >= 0; i--) { mNativeChildren.get(i).mNativeParent = null; @@ -357,16 +365,16 @@ public class ReactShadowNode extends CSSNodeDEPRECATED { } } - public int getNativeChildCount() { + public final int getNativeChildCount() { return mNativeChildren == null ? 0 : mNativeChildren.size(); } - public int indexOfNativeChild(ReactShadowNode nativeChild) { + public final int indexOfNativeChild(ReactShadowNode nativeChild) { Assertions.assertNotNull(mNativeChildren); return mNativeChildren.indexOf(nativeChild); } - public @Nullable ReactShadowNode getNativeParent() { + public final @Nullable ReactShadowNode getNativeParent() { return mNativeParent; } @@ -374,18 +382,18 @@ public class ReactShadowNode extends CSSNodeDEPRECATED { * Sets whether this node only contributes to the layout of its children without doing any * drawing or functionality itself. */ - public void setIsLayoutOnly(boolean isLayoutOnly) { + public final void setIsLayoutOnly(boolean isLayoutOnly) { Assertions.assertCondition(getParent() == null, "Must remove from no opt parent first"); Assertions.assertCondition(mNativeParent == null, "Must remove from native parent first"); Assertions.assertCondition(getNativeChildCount() == 0, "Must remove all native children first"); mIsLayoutOnly = isLayoutOnly; } - public boolean isLayoutOnly() { + public final boolean isLayoutOnly() { return mIsLayoutOnly; } - public int getTotalNativeChildren() { + public final int getTotalNativeChildren() { return mTotalNativeChildren; } @@ -418,7 +426,7 @@ public class ReactShadowNode extends CSSNodeDEPRECATED { * getNativeOffsetForChild(Node 3) => 4 * getNativeOffsetForChild(Node 4) => 6 */ - public int getNativeOffsetForChild(ReactShadowNode child) { + public final int getNativeOffsetForChild(ReactShadowNode child) { int index = 0; boolean found = false; for (int i = 0; i < getChildCount(); i++) { @@ -435,6 +443,22 @@ public class ReactShadowNode extends CSSNodeDEPRECATED { return index; } + public final float getLayoutX() { + return mCSSNode.getLayoutX(); + } + + public final float getLayoutY() { + return mCSSNode.getLayoutY(); + } + + public final float getLayoutWidth() { + return mCSSNode.getLayoutWidth(); + } + + public final float getLayoutHeight() { + return mCSSNode.getLayoutHeight(); + } + /** * @return the x position of the corresponding view on the screen, rounded to pixels */ @@ -462,4 +486,158 @@ public class ReactShadowNode extends CSSNodeDEPRECATED { public int getScreenHeight() { return Math.round(mAbsoluteBottom - mAbsoluteTop); } + + public final CSSDirection getLayoutDirection() { + return mCSSNode.getLayoutDirection(); + } + + public void setLayoutDirection(CSSDirection direction) { + mCSSNode.setDirection(direction); + } + + public final float getStyleWidth() { + return mCSSNode.getStyleWidth(); + } + + public void setStyleWidth(float widthPx) { + mCSSNode.setStyleWidth(widthPx); + } + + public void setStyleMinWidth(float widthPx) { + mCSSNode.setStyleMinWidth(widthPx); + } + + public void setStyleMaxWidth(float widthPx) { + mCSSNode.setStyleMaxWidth(widthPx); + } + + public final float getStyleHeight() { + return mCSSNode.getStyleHeight(); + } + + public void setStyleHeight(float heightPx) { + mCSSNode.setStyleHeight(heightPx); + } + + public void setStyleMinHeight(float widthPx) { + mCSSNode.setStyleMinHeight(widthPx); + } + + public void setStyleMaxHeight(float widthPx) { + mCSSNode.setStyleMaxHeight(widthPx); + } + + public void setFlex(float flex) { + mCSSNode.setFlex(flex); + } + + public void setFlexGrow(float flexGrow) { + mCSSNode.setFlexGrow(flexGrow); + } + + public void setFlexShrink(float flexShrink) { + mCSSNode.setFlexShrink(flexShrink); + } + + public void setFlexBasis(float flexBasis) { + mCSSNode.setFlexBasis(flexBasis); + } + + public void setFlexDirection(CSSFlexDirection flexDirection) { + mCSSNode.setFlexDirection(flexDirection); + } + + public void setFlexWrap(CSSWrap wrap) { + mCSSNode.setWrap(wrap); + } + + public void setAlignSelf(CSSAlign alignSelf) { + mCSSNode.setAlignSelf(alignSelf); + } + + public void setAlignItems(CSSAlign alignItems) { + mCSSNode.setAlignItems(alignItems); + } + + public void setJustifyContent(CSSJustify justifyContent) { + mCSSNode.setJustifyContent(justifyContent); + } + + public void setOverflow(CSSOverflow overflow) { + mCSSNode.setOverflow(overflow); + } + + public void setMargin(int spacingType, float margin) { + mCSSNode.setMargin(spacingType, margin); + } + + public final float getPadding(int spacingType) { + return mCSSNode.getPadding(spacingType); + } + + public void setDefaultPadding(int spacingType, float padding) { + mDefaultPadding.set(spacingType, padding); + updatePadding(); + } + + public void setPadding(int spacingType, float padding) { + mPadding.set(spacingType, padding); + updatePadding(); + } + + private void updatePadding() { + for (int spacingType = Spacing.LEFT; spacingType <= Spacing.ALL; spacingType++) { + if (spacingType == Spacing.LEFT || + spacingType == Spacing.RIGHT || + spacingType == Spacing.START || + spacingType == Spacing.END) { + if (CSSConstants.isUndefined(mPadding.getRaw(spacingType)) && + CSSConstants.isUndefined(mPadding.getRaw(Spacing.HORIZONTAL)) && + CSSConstants.isUndefined(mPadding.getRaw(Spacing.ALL))) { + mCSSNode.setPadding(spacingType, mDefaultPadding.getRaw(spacingType)); + } else { + mCSSNode.setPadding(spacingType, mPadding.getRaw(spacingType)); + } + } else if (spacingType == Spacing.TOP || spacingType == Spacing.BOTTOM) { + if (CSSConstants.isUndefined(mPadding.getRaw(spacingType)) && + CSSConstants.isUndefined(mPadding.getRaw(Spacing.VERTICAL)) && + CSSConstants.isUndefined(mPadding.getRaw(Spacing.ALL))) { + mCSSNode.setPadding(spacingType, mDefaultPadding.getRaw(spacingType)); + } else { + mCSSNode.setPadding(spacingType, mPadding.getRaw(spacingType)); + } + } else { + if (CSSConstants.isUndefined(mPadding.getRaw(spacingType))) { + mCSSNode.setPadding(spacingType, mDefaultPadding.getRaw(spacingType)); + } else { + mCSSNode.setPadding(spacingType, mPadding.getRaw(spacingType)); + } + } + } + } + + public void setBorder(int spacingType, float borderWidth) { + mCSSNode.setBorder(spacingType, borderWidth); + } + + public void setPosition(int spacingType, float position) { + mCSSNode.setPosition(spacingType, position); + } + + public void setPositionType(CSSPositionType positionType) { + mCSSNode.setPositionType(positionType); + } + + public void setShouldNotifyOnLayout(boolean shouldNotifyOnLayout) { + mShouldNotifyOnLayout = shouldNotifyOnLayout; + } + + public void setMeasureFunction(CSSNodeAPI.MeasureFunction measureFunction) { + mCSSNode.setMeasureFunction(measureFunction); + } + + @Override + public String toString() { + return mCSSNode.toString(); + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java index d43391eed..aa0089069 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java @@ -86,7 +86,7 @@ public class UIImplementation { ReactShadowNode rootCSSNode = new ReactShadowNode(); I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance(); if (sharedI18nUtilInstance.isRTL(mReactContext)) { - rootCSSNode.setDirection(CSSDirection.RTL); + rootCSSNode.setLayoutDirection(CSSDirection.RTL); } rootCSSNode.setViewClassName("Root"); return rootCSSNode; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostShadowNode.java index b6b310c48..52f3c2251 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostShadowNode.java @@ -11,8 +11,8 @@ package com.facebook.react.views.modal; import android.graphics.Point; -import com.facebook.csslayout.CSSNodeDEPRECATED; import com.facebook.react.uimanager.LayoutShadowNode; +import com.facebook.react.uimanager.ReactShadowNode; /** * We implement the Modal by using an Android Dialog. That will fill the entire window of the @@ -29,7 +29,7 @@ class ModalHostShadowNode extends LayoutShadowNode { * within the in Modal.js. This needs to fill the entire window. */ @Override - public void addChildAt(CSSNodeDEPRECATED child, int i) { + public void addChildAt(ReactShadowNode child, int i) { super.addChildAt(child, i); Point modalSize = ModalHostHelper.getModalHostSize(getThemedContext()); child.setStyleWidth(modalSize.x); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java index 47809ea45..95b19e815 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java @@ -33,7 +33,6 @@ import android.widget.TextView; import com.facebook.csslayout.CSSDirection; import com.facebook.csslayout.CSSConstants; import com.facebook.csslayout.CSSMeasureMode; -import com.facebook.csslayout.CSSNodeDEPRECATED; import com.facebook.csslayout.CSSNodeAPI; import com.facebook.csslayout.MeasureOutput; import com.facebook.csslayout.Spacing; @@ -43,6 +42,7 @@ import com.facebook.react.bridge.ReadableMap; import com.facebook.react.common.annotations.VisibleForTesting; import com.facebook.react.uimanager.IllegalViewOperationException; import com.facebook.react.uimanager.LayoutShadowNode; +import com.facebook.react.uimanager.ReactShadowNode; import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.ReactShadowNode; import com.facebook.react.uimanager.UIViewOperationQueue; @@ -105,15 +105,15 @@ public class ReactTextShadowNode extends LayoutShadowNode { } private static void buildSpannedFromTextCSSNode( - ReactTextShadowNode textCSSNode, + ReactTextShadowNode textShadowNode, SpannableStringBuilder sb, List ops) { int start = sb.length(); - if (textCSSNode.mText != null) { - sb.append(textCSSNode.mText); + if (textShadowNode.mText != null) { + sb.append(textShadowNode.mText); } - for (int i = 0, length = textCSSNode.getChildCount(); i < length; i++) { - CSSNodeDEPRECATED child = textCSSNode.getChildAt(i); + for (int i = 0, length = textShadowNode.getChildCount(); i < length; i++) { + ReactShadowNode child = textShadowNode.getChildAt(i); if (child instanceof ReactTextShadowNode) { buildSpannedFromTextCSSNode((ReactTextShadowNode) child, sb, ops); } else if (child instanceof ReactTextInlineImageShadowNode) { @@ -129,57 +129,57 @@ public class ReactTextShadowNode extends LayoutShadowNode { throw new IllegalViewOperationException("Unexpected view type nested under text node: " + child.getClass()); } - ((ReactShadowNode) child).markUpdateSeen(); + child.markUpdateSeen(); } int end = sb.length(); if (end >= start) { - if (textCSSNode.mIsColorSet) { - ops.add(new SetSpanOperation(start, end, new ForegroundColorSpan(textCSSNode.mColor))); + if (textShadowNode.mIsColorSet) { + ops.add(new SetSpanOperation(start, end, new ForegroundColorSpan(textShadowNode.mColor))); } - if (textCSSNode.mIsBackgroundColorSet) { + if (textShadowNode.mIsBackgroundColorSet) { ops.add(new SetSpanOperation( start, end, - new BackgroundColorSpan(textCSSNode.mBackgroundColor))); + new BackgroundColorSpan(textShadowNode.mBackgroundColor))); } - if (textCSSNode.mFontSize != UNSET) { - ops.add(new SetSpanOperation(start, end, new AbsoluteSizeSpan(textCSSNode.mFontSize))); + if (textShadowNode.mFontSize != UNSET) { + ops.add(new SetSpanOperation(start, end, new AbsoluteSizeSpan(textShadowNode.mFontSize))); } - if (textCSSNode.mFontStyle != UNSET || - textCSSNode.mFontWeight != UNSET || - textCSSNode.mFontFamily != null) { + if (textShadowNode.mFontStyle != UNSET || + textShadowNode.mFontWeight != UNSET || + textShadowNode.mFontFamily != null) { ops.add(new SetSpanOperation( start, end, new CustomStyleSpan( - textCSSNode.mFontStyle, - textCSSNode.mFontWeight, - textCSSNode.mFontFamily, - textCSSNode.getThemedContext().getAssets()))); + textShadowNode.mFontStyle, + textShadowNode.mFontWeight, + textShadowNode.mFontFamily, + textShadowNode.getThemedContext().getAssets()))); } - if (textCSSNode.mIsUnderlineTextDecorationSet) { + if (textShadowNode.mIsUnderlineTextDecorationSet) { ops.add(new SetSpanOperation(start, end, new UnderlineSpan())); } - if (textCSSNode.mIsLineThroughTextDecorationSet) { + if (textShadowNode.mIsLineThroughTextDecorationSet) { ops.add(new SetSpanOperation(start, end, new StrikethroughSpan())); } - if (textCSSNode.mTextShadowOffsetDx != 0 || textCSSNode.mTextShadowOffsetDy != 0) { + if (textShadowNode.mTextShadowOffsetDx != 0 || textShadowNode.mTextShadowOffsetDy != 0) { ops.add(new SetSpanOperation( start, end, new ShadowStyleSpan( - textCSSNode.mTextShadowOffsetDx, - textCSSNode.mTextShadowOffsetDy, - textCSSNode.mTextShadowRadius, - textCSSNode.mTextShadowColor))); + textShadowNode.mTextShadowOffsetDx, + textShadowNode.mTextShadowOffsetDy, + textShadowNode.mTextShadowRadius, + textShadowNode.mTextShadowColor))); } - if (!Float.isNaN(textCSSNode.getEffectiveLineHeight())) { + if (!Float.isNaN(textShadowNode.getEffectiveLineHeight())) { ops.add(new SetSpanOperation( start, end, - new CustomLineHeightSpan(textCSSNode.getEffectiveLineHeight()))); + new CustomLineHeightSpan(textShadowNode.getEffectiveLineHeight()))); } - ops.add(new SetSpanOperation(start, end, new ReactTagSpan(textCSSNode.getReactTag()))); + ops.add(new SetSpanOperation(start, end, new ReactTagSpan(textShadowNode.getReactTag()))); } } @@ -218,7 +218,7 @@ public class ReactTextShadowNode extends LayoutShadowNode { return sb; } - private static final CSSNodeAPI.MeasureFunction TEXT_MEASURE_FUNCTION = + private final CSSNodeAPI.MeasureFunction mTextMeasureFunction = new CSSNodeAPI.MeasureFunction() { @Override public long measure( @@ -228,11 +228,10 @@ public class ReactTextShadowNode extends LayoutShadowNode { float height, CSSMeasureMode heightMode) { // TODO(5578671): Handle text direction (see View#getTextDirectionHeuristic) - ReactTextShadowNode reactCSSNode = (ReactTextShadowNode) node; TextPaint textPaint = sTextPaintInstance; Layout layout; Spanned text = Assertions.assertNotNull( - reactCSSNode.mPreparedSpannableText, + mPreparedSpannableText, "Spannable element has not been prepared in onBeforeLayout"); BoringLayout.Metrics boring = BoringLayout.isBoring(text, textPaint); float desiredWidth = boring == null ? @@ -278,11 +277,11 @@ public class ReactTextShadowNode extends LayoutShadowNode { true); } - if (reactCSSNode.mNumberOfLines != UNSET && - reactCSSNode.mNumberOfLines < layout.getLineCount()) { + if (mNumberOfLines != UNSET && + mNumberOfLines < layout.getLineCount()) { return MeasureOutput.make( layout.getWidth(), - layout.getLineBottom(reactCSSNode.mNumberOfLines - 1)); + layout.getLineBottom(mNumberOfLines - 1)); } else { return MeasureOutput.make(layout.getWidth(), layout.getHeight()); } @@ -356,7 +355,7 @@ public class ReactTextShadowNode extends LayoutShadowNode { public ReactTextShadowNode(boolean isVirtual) { mIsVirtual = isVirtual; if (!isVirtual) { - setMeasureFunction(TEXT_MEASURE_FUNCTION); + setMeasureFunction(mTextMeasureFunction); } }