diff --git a/java/com/facebook/yoga/YogaBaselineFunction.java b/java/com/facebook/yoga/YogaBaselineFunction.java new file mode 100644 index 00000000..1bfb52a7 --- /dev/null +++ b/java/com/facebook/yoga/YogaBaselineFunction.java @@ -0,0 +1,22 @@ +/** + * 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 com.facebook.proguard.annotations.DoNotStrip; + +@DoNotStrip +public interface YogaBaselineFunction { + /** + * Return the baseline of the node in pixels. When no baseline function is set the baseline + * default to the computed height of the node. + */ + @DoNotStrip + float baseline(YogaNodeAPI node, float width, float height); +} diff --git a/java/com/facebook/yoga/YogaNode.java b/java/com/facebook/yoga/YogaNode.java index 87b22985..432c2040 100644 --- a/java/com/facebook/yoga/YogaNode.java +++ b/java/com/facebook/yoga/YogaNode.java @@ -52,6 +52,7 @@ public class YogaNode implements YogaNodeAPI { private YogaNode mParent; private List mChildren; private YogaMeasureFunction mMeasureFunction; + private YogaBaselineFunction mBaselineFunction; private long mNativePointer; private Object mData; @@ -623,6 +624,18 @@ public class YogaNode implements YogaNodeAPI { YogaMeasureMode.values()[heightMode]); } + private native void jni_YGNodeSetHasBaselineFunc(long nativePointer, boolean hasMeasureFunc); + @Override + public void setBaselineFunction(YogaBaselineFunction baselineFunction) { + mBaselineFunction = baselineFunction; + jni_YGNodeSetHasBaselineFunc(mNativePointer, baselineFunction != null); + } + + @DoNotStrip + public final float baseline(float width, float height) { + return mBaselineFunction.baseline(this, width, height); + } + @Override public boolean isMeasureDefined() { return mMeasureFunction != null; diff --git a/java/com/facebook/yoga/YogaNodeAPI.java b/java/com/facebook/yoga/YogaNodeAPI.java index 98742d34..6d782c45 100644 --- a/java/com/facebook/yoga/YogaNodeAPI.java +++ b/java/com/facebook/yoga/YogaNodeAPI.java @@ -18,6 +18,7 @@ public interface YogaNodeAPI { YogaNodeType getParent(); int indexOf(YogaNodeType child); void setMeasureFunction(YogaMeasureFunction measureFunction); + void setBaselineFunction(YogaBaselineFunction measureFunction); boolean isMeasureDefined(); void calculateLayout(); boolean isDirty(); diff --git a/java/jni/YGJNI.cpp b/java/jni/YGJNI.cpp index 46aaecfb..54610dba 100644 --- a/java/jni/YGJNI.cpp +++ b/java/jni/YGJNI.cpp @@ -63,6 +63,14 @@ static void YGPrint(YGNodeRef node) { } } +static float YGJNIBaselineFunc(YGNodeRef node, float width, float height) { + if (auto obj = YGNodeJobject(node)->lockLocal()) { + return findClassLocal("com/facebook/yoga/YogaNode")->getMethod("baseline")(obj, width, height); + } else { + return height; + } +} + static YGSize YGJNIMeasureFunc(YGNodeRef node, float width, YGMeasureMode widthMode, @@ -203,6 +211,10 @@ void jni_YGNodeSetHasMeasureFunc(alias_ref, jlong nativePointer, jboole YGNodeSetMeasureFunc(_jlong2YGNodeRef(nativePointer), hasMeasureFunc ? YGJNIMeasureFunc : NULL); } +void jni_YGNodeSetHasBaselineFunc(alias_ref, jlong nativePointer, jboolean hasBaselineFunc) { + YGNodeSetBaselineFunc(_jlong2YGNodeRef(nativePointer), hasBaselineFunc ? YGJNIBaselineFunc : NULL); +} + jboolean jni_YGNodeHasNewLayout(alias_ref, jlong nativePointer) { return (jboolean) YGNodeGetHasNewLayout(_jlong2YGNodeRef(nativePointer)); } @@ -332,6 +344,7 @@ jint JNI_OnLoad(JavaVM *vm, void *) { YGMakeNativeMethod(jni_YGNodeIsDirty), YGMakeNativeMethod(jni_YGNodeMarkLayoutSeen), YGMakeNativeMethod(jni_YGNodeSetHasMeasureFunc), + YGMakeNativeMethod(jni_YGNodeSetHasBaselineFunc), YGMakeNativeMethod(jni_YGNodeCopyStyle), YGMakeNativeMethod(jni_YGNodeStyleGetDirection), YGMakeNativeMethod(jni_YGNodeStyleSetDirection), diff --git a/java/tests/com/facebook/yoga/YogaNodeTest.java b/java/tests/com/facebook/yoga/YogaNodeTest.java index ddec8cff..53104dfb 100644 --- a/java/tests/com/facebook/yoga/YogaNodeTest.java +++ b/java/tests/com/facebook/yoga/YogaNodeTest.java @@ -23,6 +23,35 @@ public class YogaNodeTest { assertEquals(refCount + 1, YogaNode.jni_YGNodeGetInstanceCount()); } + @Test + public void testBaseline() { + final YogaNode root = new YogaNode(); + root.setFlexDirection(YogaFlexDirection.ROW); + root.setAlignItems(YogaAlign.BASELINE); + root.setWidth(100); + root.setHeight(100); + + final YogaNode child1 = new YogaNode(); + child1.setWidth(40); + child1.setHeight(40); + root.addChildAt(child1, 0); + + final YogaNode child2 = new YogaNode(); + child2.setWidth(40); + child2.setHeight(40); + child2.setBaselineFunction(new YogaBaselineFunction() { + public float baseline(YogaNodeAPI node, float width, float height) { + return 0; + } + }); + root.addChildAt(child2, 1); + + root.calculateLayout(); + + assertEquals(0, (int) child1.getLayoutY()); + assertEquals(40, (int) child2.getLayoutY()); + } + @Test public void testMeasure() { final YogaNode node = new YogaNode();