Make Java YogaNode cloneable
Summary: This diff exposes the YogaNode clone operation to JNI in order to be able to clone Java YogaNode objects. The clone method performs a shallow copy of the java YogaNode. I made YogaNode to implement Cloneable, I know that this might not be a good idea but in this case it simplifies the cloning mechanism. I am open to suggestions. IMPORTANT NOTES: - The current implementation IS NOT making a deep copy of the mData instance variable. - The mParent Java instance variable will reference the parent of the original Java YogaNode, is that ok sebmarkbage? Reviewed By: priteshrnandgaonkar Differential Revision: D6935971 fbshipit-source-id: a2008f1eb849b5074585b48699b7de56d5ac90d4
This commit is contained in:
committed by
Facebook Github Bot
parent
43fda26275
commit
747c2a4208
@@ -16,7 +16,7 @@ import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@DoNotStrip
|
||||
public class YogaNode {
|
||||
public class YogaNode implements Cloneable {
|
||||
|
||||
static {
|
||||
SoLoader.loadLibrary("yoga");
|
||||
@@ -31,7 +31,7 @@ public class YogaNode {
|
||||
private List<YogaNode> mChildren;
|
||||
private YogaMeasureFunction mMeasureFunction;
|
||||
private YogaBaselineFunction mBaselineFunction;
|
||||
private final long mNativePointer;
|
||||
private long mNativePointer;
|
||||
private Object mData;
|
||||
|
||||
/* Those flags needs be in sync with YGJNI.cpp */
|
||||
@@ -160,6 +160,18 @@ public class YogaNode {
|
||||
jni_YGNodeInsertChild(mNativePointer, child.mNativePointer, i);
|
||||
}
|
||||
|
||||
private native long jni_YGNodeClone(long nativePointer, Object newNode);
|
||||
|
||||
@Override
|
||||
public YogaNode clone() throws CloneNotSupportedException {
|
||||
YogaNode clonedYogaNode = (YogaNode) super.clone();
|
||||
long clonedNativePointer = jni_YGNodeClone(mNativePointer, clonedYogaNode);
|
||||
clonedYogaNode.mNativePointer = clonedNativePointer;
|
||||
clonedYogaNode.mChildren =
|
||||
mChildren != null ? (List<YogaNode>) ((ArrayList) mChildren).clone() : null;
|
||||
return clonedYogaNode;
|
||||
}
|
||||
|
||||
private native void jni_YGNodeRemoveChild(long nativePointer, long childPointer);
|
||||
public YogaNode removeChildAt(int i) {
|
||||
|
||||
|
@@ -250,6 +250,16 @@ jlong jni_YGNodeNewWithConfig(alias_ref<jobject> thiz, jlong configPointer) {
|
||||
return reinterpret_cast<jlong>(node);
|
||||
}
|
||||
|
||||
jlong jni_YGNodeClone(
|
||||
alias_ref<jobject> thiz,
|
||||
jlong nativePointer,
|
||||
alias_ref<jobject> clonedJavaObject) {
|
||||
const YGNodeRef clonedYogaNode = YGNodeClone(_jlong2YGNodeRef(nativePointer));
|
||||
clonedYogaNode->setContext(
|
||||
new weak_ref<jobject>(make_weak(clonedJavaObject)));
|
||||
return reinterpret_cast<jlong>(clonedYogaNode);
|
||||
}
|
||||
|
||||
void jni_YGNodeFree(alias_ref<jobject> thiz, jlong nativePointer) {
|
||||
const YGNodeRef node = _jlong2YGNodeRef(nativePointer);
|
||||
delete YGNodeJobject(node);
|
||||
@@ -612,6 +622,7 @@ jint JNI_OnLoad(JavaVM *vm, void *) {
|
||||
YGMakeNativeMethod(jni_YGNodeStyleSetAspectRatio),
|
||||
YGMakeNativeMethod(jni_YGNodeGetInstanceCount),
|
||||
YGMakeNativeMethod(jni_YGNodePrint),
|
||||
YGMakeNativeMethod(jni_YGNodeClone),
|
||||
});
|
||||
registerNatives("com/facebook/yoga/YogaConfig",
|
||||
{
|
||||
|
@@ -10,9 +10,12 @@
|
||||
package com.facebook.yoga;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import org.junit.Test;
|
||||
|
||||
public class YogaNodeTest {
|
||||
@@ -221,7 +224,61 @@ public class YogaNodeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNodeClonedLeak() throws Exception {
|
||||
public void testCloneNode() throws Exception {
|
||||
YogaConfig config = new YogaConfig();
|
||||
YogaNode root = new YogaNode(config);
|
||||
YogaNode child = new YogaNode(config);
|
||||
YogaNode grandChild = new YogaNode(config);
|
||||
root.addChildAt(child, 0);
|
||||
child.addChildAt(grandChild, 0);
|
||||
child.setFlexDirection(YogaFlexDirection.ROW);
|
||||
|
||||
YogaNode clonedChild = child.clone();
|
||||
|
||||
assertNotSame(clonedChild, child);
|
||||
|
||||
assertEquals(YogaFlexDirection.ROW, child.getFlexDirection());
|
||||
assertEquals(child.getFlexDirection(), clonedChild.getFlexDirection());
|
||||
|
||||
// Verify the cloning is shallow on the List of children
|
||||
assertEquals(1, child.getChildCount());
|
||||
assertEquals(child.getChildCount(), clonedChild.getChildCount());
|
||||
assertEquals(child.getChildAt(0), clonedChild.getChildAt(0));
|
||||
|
||||
child.removeChildAt(0);
|
||||
assertEquals(0, child.getChildCount());
|
||||
assertEquals(1, clonedChild.getChildCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloneNodeListener() throws Exception {
|
||||
final AtomicBoolean onNodeClonedExecuted = new AtomicBoolean(false);
|
||||
YogaConfig config = new YogaConfig();
|
||||
config.setOnNodeCloned(
|
||||
new YogaNodeClonedFunction() {
|
||||
@Override
|
||||
public void onNodeCloned(
|
||||
YogaNode oldNode, YogaNode newNode, YogaNode parent, int childIndex) {
|
||||
onNodeClonedExecuted.set(true);
|
||||
}
|
||||
});
|
||||
YogaNode root = new YogaNode(config);
|
||||
root.setWidth(100f);
|
||||
root.setHeight(100f);
|
||||
YogaNode child0 = new YogaNode(config);
|
||||
root.addChildAt(child0, 0);
|
||||
root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED);
|
||||
|
||||
// Force a clone to happen.
|
||||
final YogaNode root2 = root.clone();
|
||||
root2.setWidth(200f);
|
||||
root2.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED);
|
||||
|
||||
assertTrue(onNodeClonedExecuted.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnNodeClonedLeak() throws Exception {
|
||||
YogaConfig config = new YogaConfig();
|
||||
config.setOnNodeCloned(
|
||||
new YogaNodeClonedFunction() {
|
||||
@@ -232,7 +289,7 @@ public class YogaNodeTest {
|
||||
}
|
||||
});
|
||||
config.setOnNodeCloned(null);
|
||||
java.lang.ref.WeakReference<Object> ref = new java.lang.ref.WeakReference<Object>(config);
|
||||
WeakReference<Object> ref = new WeakReference<Object>(config);
|
||||
// noinspection UnusedAssignment
|
||||
config = null;
|
||||
// try and free for the next 5 seconds, usually it works after the
|
||||
|
Reference in New Issue
Block a user