From 352f592767b148747da2d5822f0f4de17eb7b9c2 Mon Sep 17 00:00:00 2001 From: Emil Sjolander Date: Thu, 29 Dec 2016 04:52:20 -0800 Subject: [PATCH] Allow decimal measurements on java Summary: Preserve floating point values when passing them across the JNI bridge. Differential Revision: D4366605 fbshipit-source-id: 0b94ee87a03a6ed918360dd9998930e780fc865d --- java/com/facebook/yoga/YogaMeasureOutput.java | 14 ++--- java/jni/YGJNI.cpp | 9 ++-- .../tests/com/facebook/yoga/YogaNodeTest.java | 54 +++++++++++++++++++ 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/java/com/facebook/yoga/YogaMeasureOutput.java b/java/com/facebook/yoga/YogaMeasureOutput.java index 7bb845a0..d276fbac 100644 --- a/java/com/facebook/yoga/YogaMeasureOutput.java +++ b/java/com/facebook/yoga/YogaMeasureOutput.java @@ -15,18 +15,20 @@ package com.facebook.yoga; public class YogaMeasureOutput { public static long make(float width, float height) { - return make((int) width, (int) height); + final int wBits = Float.floatToRawIntBits(width); + final int hBits = Float.floatToRawIntBits(height); + return ((long) wBits) << 32 | ((long) hBits); } public static long make(int width, int height) { - return ((long) width) << 32 | ((long) height); + return make((float) width, (float) height); } - public static int getWidth(long measureOutput) { - return (int) (0xFFFFFFFF & (measureOutput >> 32)); + public static float getWidth(long measureOutput) { + return Float.intBitsToFloat((int) (0xFFFFFFFF & (measureOutput >> 32))); } - public static int getHeight(long measureOutput) { - return (int) (0xFFFFFFFF & measureOutput); + public static float getHeight(long measureOutput) { + return Float.intBitsToFloat((int) (0xFFFFFFFF & measureOutput)); } } diff --git a/java/jni/YGJNI.cpp b/java/jni/YGJNI.cpp index 09236b88..d0c2a804 100644 --- a/java/jni/YGJNI.cpp +++ b/java/jni/YGJNI.cpp @@ -67,10 +67,13 @@ static YGSize YGJNIMeasureFunc(YGNodeRef node, static_assert(sizeof(measureResult) == 8, "Expected measureResult to be 8 bytes, or two 32 bit ints"); - const float measuredWidth = static_cast(0xFFFFFFFF & (measureResult >> 32)); - const float measuredHeight = static_cast(0xFFFFFFFF & measureResult); + int32_t wBits = 0xFFFFFFFF & (measureResult >> 32); + int32_t hBits = 0xFFFFFFFF & measureResult; - return YGSize{measuredWidth, measuredHeight}; + const float *measuredWidth = reinterpret_cast(&wBits); + const float *measuredHeight = reinterpret_cast(&hBits); + + return YGSize{*measuredWidth, *measuredHeight}; } else { YGLog(YGLogLevelError, "Java YGNode was GCed during layout calculation\n"); return YGSize{ diff --git a/java/tests/com/facebook/yoga/YogaNodeTest.java b/java/tests/com/facebook/yoga/YogaNodeTest.java index d7c759ea..cfa0dcd5 100644 --- a/java/tests/com/facebook/yoga/YogaNodeTest.java +++ b/java/tests/com/facebook/yoga/YogaNodeTest.java @@ -41,6 +41,60 @@ public class YogaNodeTest { assertEquals(100, (int) node.getLayoutHeight()); } + @Test + public void testMeasureFloat() { + final YogaNode node = new YogaNode(); + node.setMeasureFunction(new YogaMeasureFunction() { + public long measure( + YogaNodeAPI node, + float width, + YogaMeasureMode widthMode, + float height, + YogaMeasureMode heightMode) { + return YogaMeasureOutput.make(100.5f, 100.5f); + } + }); + node.calculateLayout(); + assertEquals(100.5f, node.getLayoutWidth(), 0.0f); + assertEquals(100.5f, node.getLayoutHeight(), 0.0f); + } + + @Test + public void testMeasureFloatMin() { + final YogaNode node = new YogaNode(); + node.setMeasureFunction(new YogaMeasureFunction() { + public long measure( + YogaNodeAPI node, + float width, + YogaMeasureMode widthMode, + float height, + YogaMeasureMode heightMode) { + return YogaMeasureOutput.make(Float.MIN_VALUE, Float.MIN_VALUE); + } + }); + node.calculateLayout(); + assertEquals(Float.MIN_VALUE, node.getLayoutWidth(), 0.0f); + assertEquals(Float.MIN_VALUE, node.getLayoutHeight(), 0.0f); + } + + @Test + public void testMeasureFloatMax() { + final YogaNode node = new YogaNode(); + node.setMeasureFunction(new YogaMeasureFunction() { + public long measure( + YogaNodeAPI node, + float width, + YogaMeasureMode widthMode, + float height, + YogaMeasureMode heightMode) { + return YogaMeasureOutput.make(Float.MAX_VALUE, Float.MAX_VALUE); + } + }); + node.calculateLayout(); + assertEquals(Float.MAX_VALUE, node.getLayoutWidth(), 0.0f); + assertEquals(Float.MAX_VALUE, node.getLayoutHeight(), 0.0f); + } + private YogaLogLevel mLogLevel; private String mLogMessage;