Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions java/com/facebook/yoga/YogaNative.kt
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,8 @@ public object YogaNative {
@JvmStatic
public external fun jni_YGNodeSetHasMeasureFuncJNI(nativePointer: Long, hasMeasureFunc: Boolean)

@JvmStatic public external fun jni_YGNodeSetNodeTypeJNI(nativePointer: Long, nodeType: Int)

@JvmStatic
public external fun jni_YGNodeSetHasMinContentMeasureFuncJNI(
nativePointer: Long,
Expand Down
11 changes: 11 additions & 0 deletions java/com/facebook/yoga/YogaNode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,17 @@ public abstract class YogaNode : YogaProps {

abstract override fun setMeasureFunction(measureFunction: YogaMeasureFunction?)

/**
* Sets the node type, which selects how layout is rounded to the pixel grid: a
* [YogaNodeType.TEXT] node's fractional size is rounded up and its position down, so its content
* is not truncated. [setMeasureFunction] sets it ([YogaNodeType.TEXT] for a function,
* [YogaNodeType.DEFAULT] for null), so call this after it.
*
* Does nothing by default, so a subclass built against an earlier [YogaNode] keeps working, with
* the rounding [setMeasureFunction] selected.
*/
public open fun setNodeType(nodeType: YogaNodeType) {}

abstract override fun setMinContentMeasureFunction(measureFunction: YogaMeasureFunction?)

abstract override fun setMinContentWidth(minContentWidth: Float)
Expand Down
4 changes: 4 additions & 0 deletions java/com/facebook/yoga/YogaNodeJNIBase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,10 @@ public abstract class YogaNodeJNIBase : YogaNode, Cloneable {
YogaNative.jni_YGNodeSetHasMeasureFuncJNI(nativePointer, measureFunction != null)
}

override fun setNodeType(nodeType: YogaNodeType) {
YogaNative.jni_YGNodeSetNodeTypeJNI(nativePointer, nodeType.intValue())
}

override fun setMinContentMeasureFunction(measureFunction: YogaMeasureFunction?) {
this.minContentMeasureFunction = measureFunction
YogaNative.jni_YGNodeSetHasMinContentMeasureFuncJNI(nativePointer, measureFunction != null)
Expand Down
10 changes: 10 additions & 0 deletions java/jni/YGJNIVanilla.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,15 @@ static void jni_YGNodeSetHasMeasureFuncJNI(
static_cast<bool>(hasMeasureFunc) ? YGJNIMeasureFunc : nullptr);
}

static void jni_YGNodeSetNodeTypeJNI(
JNIEnv* /*env*/,
jobject /*obj*/,
jlong nativePointer,
jint nodeType) {
YGNodeSetNodeType(
_jlong2YGNodeRef(nativePointer), static_cast<YGNodeType>(nodeType));
}

static YGSize YGJNIMinContentMeasureFunc(
YGNodeConstRef node,
float width,
Expand Down Expand Up @@ -1139,6 +1148,7 @@ static JNINativeMethod methods[] = {
"(JZ)V",
(void*)jni_YGNodeSetHasMeasureFuncJNI},
// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
{"jni_YGNodeSetNodeTypeJNI", "(JI)V", (void*)jni_YGNodeSetNodeTypeJNI},
{"jni_YGNodeSetHasMinContentMeasureFuncJNI",
"(JZ)V",
(void*)jni_YGNodeSetHasMinContentMeasureFuncJNI},
Expand Down
52 changes: 52 additions & 0 deletions java/tests/com/facebook/yoga/YogaNodeTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,58 @@ class YogaNodeTest {
assertNull(node.data)
}

@Test
fun testMeasuredNodeRoundsAsText() {
assertEquals(34, firstThirdWidth { it.setMeasureFunction(fillsWidth) })
}

@Test
fun testSetNodeTypeDefaultRoundsMeasuredNodeToNearest() {
assertEquals(
33,
firstThirdWidth {
it.setMeasureFunction(fillsWidth)
it.setNodeType(YogaNodeType.DEFAULT)
},
)
}

@Test
fun testSetMeasureFunctionResetsNodeTypeToText() {
assertEquals(
34,
firstThirdWidth {
it.setMeasureFunction(fillsWidth)
it.setNodeType(YogaNodeType.DEFAULT)
it.setMeasureFunction(fillsWidth)
},
)
}

/** No width of its own, so flexing gives it its third. */
private val fillsWidth = YogaMeasureFunction { _, _, _, _, _ -> YogaMeasureOutput.make(0f, 10f) }

/**
* The rounded width of the first of three nodes flexed to a third of a 100 wide row each, set up
* by [configure]: its right edge is at 33.33, which text rounding takes up to 34.
*/
private fun firstThirdWidth(configure: (YogaNode) -> Unit): Int {
val root = createNode()
root.flexDirection = YogaFlexDirection.ROW
root.setWidth(100f)
root.setHeight(10f)
for (i in 0 until 3) {
val child = createNode()
child.flexGrow = 1f
if (i == 0) {
configure(child)
}
root.addChildAt(child, i)
}
root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED)
return root.getChildAt(0).layoutWidth.toInt()
}

private fun createNode(): YogaNode = mNodeFactory.create()

private fun createNode(config: YogaConfig): YogaNode = mNodeFactory.create(config)
Expand Down
Loading