/** * Copyright (c) 2014-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.yoga; import javax.annotation.Nullable; import java.util.List; import java.util.ArrayList; import com.facebook.proguard.annotations.DoNotStrip; import com.facebook.soloader.SoLoader; @DoNotStrip public class YogaNode implements YogaNodeAPI<YogaNode> { static { SoLoader.loadLibrary("yoga"); } /** * Get native instance count. Useful for testing only. */ static native int jni_YGNodeGetInstanceCount(); static native void jni_YGLog(int level, String message); private static native void jni_YGSetLogger(Object logger); public static void setLogger(YogaLogger logger) { jni_YGSetLogger(logger); } private static native void jni_YGSetExperimentalFeatureEnabled( int feature, boolean enabled); public static void setExperimentalFeatureEnabled( YogaExperimentalFeature feature, boolean enabled) { jni_YGSetExperimentalFeatureEnabled(feature.intValue(), enabled); } private static native boolean jni_YGIsExperimentalFeatureEnabled(int feature); public static boolean isExperimentalFeatureEnabled(YogaExperimentalFeature feature) { return jni_YGIsExperimentalFeatureEnabled(feature.intValue()); } private YogaNode mParent; private List<YogaNode> mChildren; private YogaMeasureFunction mMeasureFunction; private long mNativePointer; private Object mData; private boolean mHasSetPadding = false; private boolean mHasSetMargin = false; private boolean mHasSetBorder = false; private boolean mHasSetPosition = false; @DoNotStrip private float mWidth = YogaConstants.UNDEFINED; @DoNotStrip private float mHeight = YogaConstants.UNDEFINED; @DoNotStrip private float mTop = YogaConstants.UNDEFINED; @DoNotStrip private float mLeft = YogaConstants.UNDEFINED; @DoNotStrip private int mLayoutDirection = 0; private native long jni_YGNodeNew(); public YogaNode() { mNativePointer = jni_YGNodeNew(); if (mNativePointer == 0) { throw new IllegalStateException("Failed to allocate native memory"); } } private native void jni_YGNodeFree(long nativePointer); @Override protected void finalize() throws Throwable { try { jni_YGNodeFree(mNativePointer); } finally { super.finalize(); } } private native void jni_YGNodeReset(long nativePointer); @Override public void reset() { mHasSetPadding = false; mHasSetMargin = false; mHasSetBorder = false; mHasSetPosition = false; mWidth = YogaConstants.UNDEFINED; mHeight = YogaConstants.UNDEFINED; mTop = YogaConstants.UNDEFINED; mLeft = YogaConstants.UNDEFINED; mLayoutDirection = 0; mMeasureFunction = null; mData = null; jni_YGNodeReset(mNativePointer); } @Override public int getChildCount() { return mChildren == null ? 0 : mChildren.size(); } @Override public YogaNode getChildAt(int i) { return mChildren.get(i); } private native void jni_YGNodeInsertChild(long nativePointer, long childPointer, int index); @Override public void addChildAt(YogaNode child, int i) { if (child.mParent != null) { throw new IllegalStateException("Child already has a parent, it must be removed first."); } if (mChildren == null) { mChildren = new ArrayList<>(4); } mChildren.add(i, child); child.mParent = this; jni_YGNodeInsertChild(mNativePointer, child.mNativePointer, i); } private native void jni_YGNodeRemoveChild(long nativePointer, long childPointer); @Override public YogaNode removeChildAt(int i) { final YogaNode child = mChildren.remove(i); child.mParent = null; jni_YGNodeRemoveChild(mNativePointer, child.mNativePointer); return child; } @Override public @Nullable YogaNode getParent() { return mParent; } @Override public int indexOf(YogaNode child) { return mChildren == null ? -1 : mChildren.indexOf(child); } private native void jni_YGNodeCalculateLayout(long nativePointer); @Override public void calculateLayout() { jni_YGNodeCalculateLayout(mNativePointer); } private native boolean jni_YGNodeHasNewLayout(long nativePointer); @Override public boolean hasNewLayout() { return jni_YGNodeHasNewLayout(mNativePointer); } private native void jni_YGNodeMarkDirty(long nativePointer); @Override public void dirty() { jni_YGNodeMarkDirty(mNativePointer); } private native boolean jni_YGNodeIsDirty(long nativePointer); @Override public boolean isDirty() { return jni_YGNodeIsDirty(mNativePointer); } private native void jni_YGNodeMarkLayoutSeen(long nativePointer); @Override public void markLayoutSeen() { jni_YGNodeMarkLayoutSeen(mNativePointer); } private native void jni_YGNodeCopyStyle(long dstNativePointer, long srcNativePointer); @Override public void copyStyle(YogaNode srcNode) { jni_YGNodeCopyStyle(mNativePointer, srcNode.mNativePointer); } private native int jni_YGNodeStyleGetDirection(long nativePointer); @Override public YogaDirection getStyleDirection() { return YogaDirection.values()[jni_YGNodeStyleGetDirection(mNativePointer)]; } private native void jni_YGNodeStyleSetDirection(long nativePointer, int direction); @Override public void setDirection(YogaDirection direction) { jni_YGNodeStyleSetDirection(mNativePointer, direction.intValue()); } private native int jni_YGNodeStyleGetFlexDirection(long nativePointer); @Override public YogaFlexDirection getFlexDirection() { return YogaFlexDirection.values()[jni_YGNodeStyleGetFlexDirection(mNativePointer)]; } private native void jni_YGNodeStyleSetFlexDirection(long nativePointer, int flexDirection); @Override public void setFlexDirection(YogaFlexDirection flexDirection) { jni_YGNodeStyleSetFlexDirection(mNativePointer, flexDirection.intValue()); } private native int jni_YGNodeStyleGetJustifyContent(long nativePointer); @Override public YogaJustify getJustifyContent() { return YogaJustify.values()[jni_YGNodeStyleGetJustifyContent(mNativePointer)]; } private native void jni_YGNodeStyleSetJustifyContent(long nativePointer, int justifyContent); @Override public void setJustifyContent(YogaJustify justifyContent) { jni_YGNodeStyleSetJustifyContent(mNativePointer, justifyContent.intValue()); } private native int jni_YGNodeStyleGetAlignItems(long nativePointer); @Override public YogaAlign getAlignItems() { return YogaAlign.values()[jni_YGNodeStyleGetAlignItems(mNativePointer)]; } private native void jni_YGNodeStyleSetAlignItems(long nativePointer, int alignItems); @Override public void setAlignItems(YogaAlign alignItems) { jni_YGNodeStyleSetAlignItems(mNativePointer, alignItems.intValue()); } private native int jni_YGNodeStyleGetAlignSelf(long nativePointer); @Override public YogaAlign getAlignSelf() { return YogaAlign.values()[jni_YGNodeStyleGetAlignSelf(mNativePointer)]; } private native void jni_YGNodeStyleSetAlignSelf(long nativePointer, int alignSelf); @Override public void setAlignSelf(YogaAlign alignSelf) { jni_YGNodeStyleSetAlignSelf(mNativePointer, alignSelf.intValue()); } private native int jni_YGNodeStyleGetAlignContent(long nativePointer); @Override public YogaAlign getAlignContent() { return YogaAlign.values()[jni_YGNodeStyleGetAlignContent(mNativePointer)]; } private native void jni_YGNodeStyleSetAlignContent(long nativePointer, int alignContent); @Override public void setAlignContent(YogaAlign alignContent) { jni_YGNodeStyleSetAlignContent(mNativePointer, alignContent.intValue()); } private native int jni_YGNodeStyleGetPositionType(long nativePointer); @Override public YogaPositionType getPositionType() { return YogaPositionType.values()[jni_YGNodeStyleGetPositionType(mNativePointer)]; } private native void jni_YGNodeStyleSetPositionType(long nativePointer, int positionType); @Override public void setPositionType(YogaPositionType positionType) { jni_YGNodeStyleSetPositionType(mNativePointer, positionType.intValue()); } private native void jni_YGNodeStyleSetFlexWrap(long nativePointer, int wrapType); @Override public void setWrap(YogaWrap flexWrap) { jni_YGNodeStyleSetFlexWrap(mNativePointer, flexWrap.intValue()); } private native int jni_YGNodeStyleGetOverflow(long nativePointer); @Override public YogaOverflow getOverflow() { return YogaOverflow.values()[jni_YGNodeStyleGetOverflow(mNativePointer)]; } private native void jni_YGNodeStyleSetOverflow(long nativePointer, int overflow); @Override public void setOverflow(YogaOverflow overflow) { jni_YGNodeStyleSetOverflow(mNativePointer, overflow.intValue()); } private native void jni_YGNodeStyleSetFlex(long nativePointer, float flex); @Override public void setFlex(float flex) { jni_YGNodeStyleSetFlex(mNativePointer, flex); } private native float jni_YGNodeStyleGetFlexGrow(long nativePointer); @Override public float getFlexGrow() { return jni_YGNodeStyleGetFlexGrow(mNativePointer); } private native void jni_YGNodeStyleSetFlexGrow(long nativePointer, float flexGrow); @Override public void setFlexGrow(float flexGrow) { jni_YGNodeStyleSetFlexGrow(mNativePointer, flexGrow); } private native float jni_YGNodeStyleGetFlexShrink(long nativePointer); @Override public float getFlexShrink() { return jni_YGNodeStyleGetFlexShrink(mNativePointer); } private native void jni_YGNodeStyleSetFlexShrink(long nativePointer, float flexShrink); @Override public void setFlexShrink(float flexShrink) { jni_YGNodeStyleSetFlexShrink(mNativePointer, flexShrink); } private native Object jni_YGNodeStyleGetFlexBasis(long nativePointer); @Override public YogaValue getFlexBasis() { return (YogaValue) jni_YGNodeStyleGetFlexBasis(mNativePointer); } private native void jni_YGNodeStyleSetFlexBasis(long nativePointer, float flexBasis); @Override public void setFlexBasis(float flexBasis) { jni_YGNodeStyleSetFlexBasis(mNativePointer, flexBasis); } private native void jni_YGNodeStyleSetFlexBasisPercent(long nativePointer, float percent); @Override public void setFlexBasisPercent(float percent) { jni_YGNodeStyleSetFlexBasisPercent(mNativePointer, percent); } private native Object jni_YGNodeStyleGetMargin(long nativePointer, int edge); @Override public YogaValue getMargin(YogaEdge edge) { if (!mHasSetMargin) { return edge.intValue() < YogaEdge.START.intValue() ? YogaValue.ZERO : YogaValue.UNDEFINED; } return (YogaValue) jni_YGNodeStyleGetMargin(mNativePointer, edge.intValue()); } private native void jni_YGNodeStyleSetMargin(long nativePointer, int edge, float margin); @Override public void setMargin(YogaEdge edge, float margin) { mHasSetMargin = true; jni_YGNodeStyleSetMargin(mNativePointer, edge.intValue(), margin); } private native void jni_YGNodeStyleSetMarginPercent(long nativePointer, int edge, float percent); @Override public void setMarginPercent(YogaEdge edge, float percent) { mHasSetMargin = true; jni_YGNodeStyleSetMarginPercent(mNativePointer, edge.intValue(), percent); } private native Object jni_YGNodeStyleGetPadding(long nativePointer, int edge); @Override public YogaValue getPadding(YogaEdge edge) { if (!mHasSetPadding) { return edge.intValue() < YogaEdge.START.intValue() ? YogaValue.ZERO : YogaValue.UNDEFINED; } return (YogaValue) jni_YGNodeStyleGetPadding(mNativePointer, edge.intValue()); } private native void jni_YGNodeStyleSetPadding(long nativePointer, int edge, float padding); @Override public void setPadding(YogaEdge edge, float padding) { mHasSetPadding = true; jni_YGNodeStyleSetPadding(mNativePointer, edge.intValue(), padding); } private native void jni_YGNodeStyleSetPaddingPercent(long nativePointer, int edge, float percent); @Override public void setPaddingPercent(YogaEdge edge, float percent) { mHasSetPadding = true; jni_YGNodeStyleSetPaddingPercent(mNativePointer, edge.intValue(), percent); } private native float jni_YGNodeStyleGetBorder(long nativePointer, int edge); @Override public float getBorder(YogaEdge edge) { if (!mHasSetBorder) { return edge.intValue() < YogaEdge.START.intValue() ? 0 : YogaConstants.UNDEFINED; } return jni_YGNodeStyleGetBorder(mNativePointer, edge.intValue()); } private native void jni_YGNodeStyleSetBorder(long nativePointer, int edge, float border); @Override public void setBorder(YogaEdge edge, float border) { mHasSetBorder = true; jni_YGNodeStyleSetBorder(mNativePointer, edge.intValue(), border); } private native Object jni_YGNodeStyleGetPosition(long nativePointer, int edge); @Override public YogaValue getPosition(YogaEdge edge) { if (!mHasSetPosition) { return YogaValue.UNDEFINED; } return (YogaValue) jni_YGNodeStyleGetPosition(mNativePointer, edge.intValue()); } private native void jni_YGNodeStyleSetPosition(long nativePointer, int edge, float position); @Override public void setPosition(YogaEdge edge, float position) { mHasSetPosition = true; jni_YGNodeStyleSetPosition(mNativePointer, edge.intValue(), position); } private native void jni_YGNodeStyleSetPositionPercent(long nativePointer, int edge, float percent); @Override public void setPositionPercent(YogaEdge edge, float percent) { mHasSetPosition = true; jni_YGNodeStyleSetPositionPercent(mNativePointer, edge.intValue(), percent); } private native Object jni_YGNodeStyleGetWidth(long nativePointer); @Override public YogaValue getWidth() { return (YogaValue) jni_YGNodeStyleGetWidth(mNativePointer); } private native void jni_YGNodeStyleSetWidth(long nativePointer, float width); @Override public void setWidth(float width) { jni_YGNodeStyleSetWidth(mNativePointer, width); } private native void jni_YGNodeStyleSetWidthPercent(long nativePointer, float percent); @Override public void setWidthPercent(float percent) { jni_YGNodeStyleSetWidthPercent(mNativePointer, percent); } private native Object jni_YGNodeStyleGetHeight(long nativePointer); @Override public YogaValue getHeight() { return (YogaValue) jni_YGNodeStyleGetHeight(mNativePointer); } private native void jni_YGNodeStyleSetHeight(long nativePointer, float height); @Override public void setHeight(float height) { jni_YGNodeStyleSetHeight(mNativePointer, height); } private native void jni_YGNodeStyleSetHeightPercent(long nativePointer, float percent); @Override public void setHeightPercent(float percent) { jni_YGNodeStyleSetHeightPercent(mNativePointer, percent); } private native Object jni_YGNodeStyleGetMinWidth(long nativePointer); @Override public YogaValue getMinWidth() { return (YogaValue) jni_YGNodeStyleGetMinWidth(mNativePointer); } private native void jni_YGNodeStyleSetMinWidth(long nativePointer, float minWidth); @Override public void setMinWidth(float minWidth) { jni_YGNodeStyleSetMinWidth(mNativePointer, minWidth); } private native void jni_YGNodeStyleSetMinWidthPercent(long nativePointer, float percent); @Override public void setMinWidthPercent(float percent) { jni_YGNodeStyleSetMinWidthPercent(mNativePointer, percent); } private native Object jni_YGNodeStyleGetMinHeight(long nativePointer); @Override public YogaValue getMinHeight() { return (YogaValue) jni_YGNodeStyleGetMinHeight(mNativePointer); } private native void jni_YGNodeStyleSetMinHeight(long nativePointer, float minHeight); @Override public void setMinHeight(float minHeight) { jni_YGNodeStyleSetMinHeight(mNativePointer, minHeight); } private native void jni_YGNodeStyleSetMinHeightPercent(long nativePointer, float percent); @Override public void setMinHeightPercent(float percent) { jni_YGNodeStyleSetMinHeightPercent(mNativePointer, percent); } private native Object jni_YGNodeStyleGetMaxWidth(long nativePointer); @Override public YogaValue getMaxWidth() { return (YogaValue) jni_YGNodeStyleGetMaxWidth(mNativePointer); } private native void jni_YGNodeStyleSetMaxWidth(long nativePointer, float maxWidth); @Override public void setMaxWidth(float maxWidth) { jni_YGNodeStyleSetMaxWidth(mNativePointer, maxWidth); } private native void jni_YGNodeStyleSetMaxWidthPercent(long nativePointer, float percent); @Override public void setMaxWidthPercent(float percent) { jni_YGNodeStyleSetMaxWidthPercent(mNativePointer, percent); } private native Object jni_YGNodeStyleGetMaxHeight(long nativePointer); @Override public YogaValue getMaxHeight() { return (YogaValue) jni_YGNodeStyleGetMaxHeight(mNativePointer); } private native void jni_YGNodeStyleSetMaxHeight(long nativePointer, float maxheight); @Override public void setMaxHeight(float maxheight) { jni_YGNodeStyleSetMaxHeight(mNativePointer, maxheight); } private native void jni_YGNodeStyleSetMaxHeightPercent(long nativePointer, float percent); @Override public void setMaxHeightPercent(float percent) { jni_YGNodeStyleSetMaxHeightPercent(mNativePointer, percent); } private native float jni_YGNodeStyleGetAspectRatio(long nativePointer); public float getAspectRatio() { return jni_YGNodeStyleGetAspectRatio(mNativePointer); } private native void jni_YGNodeStyleSetAspectRatio(long nativePointer, float aspectRatio); public void setAspectRatio(float aspectRatio) { jni_YGNodeStyleSetAspectRatio(mNativePointer, aspectRatio); } @Override public float getLayoutX() { return mLeft; } @Override public float getLayoutY() { return mTop; } @Override public float getLayoutWidth() { return mWidth; } @Override public float getLayoutHeight() { return mHeight; } @Override public YogaDirection getLayoutDirection() { return YogaDirection.values()[mLayoutDirection]; } private native void jni_YGNodeSetHasMeasureFunc(long nativePointer, boolean hasMeasureFunc); @Override public void setMeasureFunction(YogaMeasureFunction measureFunction) { mMeasureFunction = measureFunction; jni_YGNodeSetHasMeasureFunc(mNativePointer, measureFunction != null); } // Implementation Note: Why this method needs to stay final // // We cache the jmethodid for this method in Yoga code. This means that even if a subclass // were to override measure, we'd still call this implementation from layout code since the // overriding method will have a different jmethodid. This is final to prevent that mistake. @DoNotStrip public final long measure(float width, int widthMode, float height, int heightMode) { if (!isMeasureDefined()) { throw new RuntimeException("Measure function isn't defined!"); } return mMeasureFunction.measure( this, width, YogaMeasureMode.values()[widthMode], height, YogaMeasureMode.values()[heightMode]); } @Override public boolean isMeasureDefined() { return mMeasureFunction != null; } @Override public void setData(Object data) { mData = data; } @Override public Object getData() { return mData; } }