Skip to content

Commit 0c97e75

Browse files
davidaureliofacebook-github-bot
authored andcommitted
Add YogaNodeProperties implementation based on ByteBuffer
Summary: @public Adds an implementation of `YogaNodeProperties` that accesses style and layout properties using a `ByteBuffer` rather than JNI calls. We hope for a speed improvement. This needs further cleanup after experimenting, e.g. to codegen the offsets. Reviewed By: pasqualeanatriello Differential Revision: D8911723 fbshipit-source-id: 3c24b57eb545155878896ebb5d64d4553eb6bedc
1 parent 930bf16 commit 0c97e75

File tree

7 files changed

+749
-19
lines changed

7 files changed

+749
-19
lines changed

ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java

+26-15
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,10 @@
1818
public class YogaNode implements Cloneable {
1919

2020
static {
21-
SoLoader.loadLibrary("yoga");
21+
SoLoader.loadLibrary("yoga");
2222
}
2323

24-
/**
25-
* Get native instance count. Useful for testing only.
26-
*/
24+
/** Get native instance count. Useful for testing only. */
2725
static native int jni_YGNodeGetInstanceCount();
2826

2927
private YogaNodeProperties mDelegate;
@@ -41,6 +39,14 @@ public YogaNode(YogaConfig config) {
4139
mDelegate = new YogaNodePropertiesJNI(this, config);
4240
}
4341

42+
public YogaNode(boolean unsafeClownyUseByteBufferValueDoesNotMatter) {
43+
mDelegate = new YogaNodePropertiesByteBuffer(this);
44+
}
45+
46+
public YogaNode(boolean unsafeClownyUseByteBufferValueDoesNotMatter, YogaConfig config) {
47+
mDelegate = new YogaNodePropertiesByteBuffer(this, config);
48+
}
49+
4450
public long getNativePointer() {
4551
return mDelegate.getNativePointer();
4652
}
@@ -69,6 +75,7 @@ public YogaNode getChildAt(int i) {
6975
}
7076

7177
private native void jni_YGNodeInsertChild(long nativePointer, long childPointer, int index);
78+
7279
public void addChildAt(YogaNode child, int i) {
7380
if (child.mOwner != null) {
7481
throw new IllegalStateException("Child already has a parent, it must be removed first.");
@@ -144,6 +151,7 @@ private void clearChildren() {
144151
}
145152

146153
private native void jni_YGNodeRemoveChild(long nativePointer, long childPointer);
154+
147155
public YogaNode removeChildAt(int i) {
148156
if (mChildren == null) {
149157
throw new IllegalStateException(
@@ -156,12 +164,10 @@ public YogaNode removeChildAt(int i) {
156164
}
157165

158166
/**
159-
* @returns the {@link YogaNode} that owns this {@link YogaNode}.
160-
* The owner is used to identify the YogaTree that a {@link YogaNode} belongs
161-
* to.
162-
* This method will return the parent of the {@link YogaNode} when the
163-
* {@link YogaNode} only belongs to one YogaTree or null when the
164-
* {@link YogaNode} is shared between two or more YogaTrees.
167+
* @returns the {@link YogaNode} that owns this {@link YogaNode}. The owner is used to identify
168+
* the YogaTree that a {@link YogaNode} belongs to. This method will return the parent of the
169+
* {@link YogaNode} when the {@link YogaNode} only belongs to one YogaTree or null when the
170+
* {@link YogaNode} is shared between two or more YogaTrees.
165171
*/
166172
@Nullable
167173
public YogaNode getOwner() {
@@ -179,17 +185,19 @@ public int indexOf(YogaNode child) {
179185
return mChildren == null ? -1 : mChildren.indexOf(child);
180186
}
181187

182-
private native void jni_YGNodeCalculateLayout(long nativePointer, float width, float height);
188+
private native boolean jni_YGNodeCalculateLayout(long nativePointer, float width, float height);
189+
183190
public void calculateLayout(float width, float height) {
184-
jni_YGNodeCalculateLayout(getNativePointer(), width, height);
185-
mDelegate.onAfterCalculateLayout();
191+
boolean hasNewLayout = jni_YGNodeCalculateLayout(getNativePointer(), width, height);
192+
mDelegate.onAfterCalculateLayout(hasNewLayout);
186193
}
187194

188195
public boolean hasNewLayout() {
189196
return mDelegate.hasNewLayout();
190197
}
191198

192199
private native void jni_YGNodeMarkDirty(long nativePointer);
200+
193201
public void dirty() {
194202
jni_YGNodeMarkDirty(getNativePointer());
195203
}
@@ -205,6 +213,7 @@ public boolean isDirty() {
205213
}
206214

207215
private native void jni_YGNodeCopyStyle(long dstNativePointer, long srcNativePointer);
216+
208217
public void copyStyle(YogaNode srcNode) {
209218
jni_YGNodeCopyStyle(getNativePointer(), srcNode.getNativePointer());
210219
}
@@ -498,6 +507,7 @@ public YogaDirection getLayoutDirection() {
498507
}
499508

500509
private native void jni_YGNodeSetHasMeasureFunc(long nativePointer, boolean hasMeasureFunc);
510+
501511
public void setMeasureFunction(YogaMeasureFunction measureFunction) {
502512
mMeasureFunction = measureFunction;
503513
jni_YGNodeSetHasMeasureFunc(getNativePointer(), measureFunction != null);
@@ -523,6 +533,7 @@ public final long measure(float width, int widthMode, float height, int heightMo
523533
}
524534

525535
private native void jni_YGNodeSetHasBaselineFunc(long nativePointer, boolean hasMeasureFunc);
536+
526537
public void setBaselineFunction(YogaBaselineFunction baselineFunction) {
527538
mBaselineFunction = baselineFunction;
528539
jni_YGNodeSetHasBaselineFunc(getNativePointer(), baselineFunction != null);
@@ -548,8 +559,8 @@ public Object getData() {
548559
private native void jni_YGNodePrint(long nativePointer);
549560

550561
/**
551-
* Use the set logger (defaults to adb log) to print out the styles, children, and computed
552-
* layout of the tree rooted at this node.
562+
* Use the set logger (defaults to adb log) to print out the styles, children, and computed layout
563+
* of the tree rooted at this node.
553564
*/
554565
public void print() {
555566
jni_YGNodePrint(getNativePointer());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/*
2+
* Copyright (c) 2014-present, Facebook, Inc.
3+
*
4+
* This source code is licensed under the MIT license found in the LICENSE
5+
* file in the root directory of this source tree.
6+
*
7+
*/
8+
9+
package com.facebook.yoga;
10+
11+
import com.facebook.proguard.annotations.DoNotStrip;
12+
import java.nio.ByteBuffer;
13+
14+
@DoNotStrip
15+
/* package */ final class YogaNodeMemoryLayout {
16+
17+
private static final int FLOAT_SIZE = 4;
18+
private static final int INT_SIZE = 4;
19+
private static final int VALUE_SIZE = FLOAT_SIZE + INT_SIZE;
20+
private static final byte FALSE = 0;
21+
private static final byte TRUE = 1;
22+
private static final int AUTO = YogaUnit.AUTO.intValue();
23+
private static final int POINT = YogaUnit.POINT.intValue();
24+
private static final int PERCENT = YogaUnit.PERCENT.intValue();
25+
private static final int UNDEFINED = YogaUnit.UNDEFINED.intValue();
26+
27+
// TODO(davidaurelio) code-gen these values
28+
static final int styleDirection = 0;
29+
static final int styleFlexDirection = 4;
30+
static final int styleJustifyContent = 8;
31+
static final int styleAlignContent = 12;
32+
static final int styleAlignItems = 16;
33+
static final int styleAlignSelf = 20;
34+
static final int stylePositionType = 24;
35+
static final int styleFlexWrap = 28;
36+
static final int styleOverflow = 32;
37+
static final int styleDisplay = 36;
38+
static final int styleFlex = 40;
39+
static final int styleFlexGrow = 48;
40+
static final int styleFlexShrink = 56;
41+
static final int styleFlexBasis = 64;
42+
static final int styleMargin = 72;
43+
static final int stylePosition = 144;
44+
static final int stylePadding = 216;
45+
static final int styleBorder = 288;
46+
static final int styleDimensions = 360;
47+
static final int styleMinDimensions = 376;
48+
static final int styleMaxDimensions = 392;
49+
static final int styleAspectRatio = 408;
50+
51+
static final int styleWidth = styleDimensions;
52+
static final int styleHeight = styleDimensions + VALUE_SIZE;
53+
static final int styleMinWidth = styleMinDimensions;
54+
static final int styleMinHeight = styleMinDimensions + VALUE_SIZE;
55+
static final int styleMaxWidth = styleMaxDimensions;
56+
static final int styleMaxHeight = styleMaxDimensions + VALUE_SIZE;
57+
58+
static final int layoutPosition = 0;
59+
static final int layoutDimensions = 16;
60+
static final int layoutMargin = 24;
61+
static final int layoutBorder = 48;
62+
static final int layoutPadding = 72;
63+
static final int layoutDirection = 96;
64+
static final int layoutComputedFlexBasisGeneration = 100;
65+
static final int layoutComputedFlexBasis = 104;
66+
static final int layoutHadOverflow = 112;
67+
static final int layoutGenerationCount = 116;
68+
static final int layoutLastOwnerDirection = 120;
69+
static final int layoutNextCachedMeasurementsIndex = 124;
70+
static final int layoutCachedMeasurements = 128;
71+
static final int layoutMeasuredDimensions = 512;
72+
static final int layoutCachedLayout = 520;
73+
static final int layoutDidUseLegacyFlag = 544;
74+
static final int layoutDoesLegacyStretchFlagAffectsLayout = 545;
75+
76+
static final int layoutX = layoutPosition;
77+
static final int layoutY = layoutPosition + FLOAT_SIZE;
78+
static final int layoutWidth = layoutDimensions;
79+
static final int layoutHeight = layoutDimensions + FLOAT_SIZE;
80+
81+
static int stylePositionOffset(YogaEdge edge) {
82+
return stylePosition + edge.intValue() * VALUE_SIZE;
83+
}
84+
85+
static int styleMarginOffset(YogaEdge edge) {
86+
return styleMargin + edge.intValue() * VALUE_SIZE;
87+
}
88+
89+
static int layoutMarginOffset(YogaEdge edge) {
90+
return layoutMargin + edge.intValue() * FLOAT_SIZE;
91+
}
92+
93+
static int stylePaddingOffset(YogaEdge edge) {
94+
return stylePadding + edge.intValue() * VALUE_SIZE;
95+
}
96+
97+
static int layoutPaddingOffset(YogaEdge edge) {
98+
return layoutPadding + edge.intValue() * FLOAT_SIZE;
99+
}
100+
101+
static int styleBorderOffset(YogaEdge edge) {
102+
return styleBorder + edge.intValue() * VALUE_SIZE;
103+
}
104+
105+
static int layoutBorderOffset(YogaEdge edge) {
106+
return layoutBorder + edge.intValue() * FLOAT_SIZE;
107+
}
108+
109+
static void putOptional(ByteBuffer buffer, int offset, float value) {
110+
buffer.putFloat(offset, value);
111+
buffer.put(
112+
offset + FLOAT_SIZE, YogaConstants.isUndefined(value) ? TRUE : FALSE); // bool isUndefined_
113+
}
114+
115+
static float getOptional(ByteBuffer buffer, int offset) {
116+
return getBoolean(buffer, offset + FLOAT_SIZE)
117+
? YogaConstants.UNDEFINED
118+
: buffer.getFloat(offset);
119+
}
120+
121+
private static void putValue(ByteBuffer buffer, int offset, float value, int unit) {
122+
if (YogaConstants.isUndefined(value)) {
123+
value = YogaConstants.UNDEFINED;
124+
unit = UNDEFINED;
125+
}
126+
buffer.putFloat(offset, value);
127+
buffer.putInt(offset + FLOAT_SIZE, unit);
128+
}
129+
130+
static void putAutoValue(ByteBuffer buffer, int offset) {
131+
putValue(buffer, offset, 0, AUTO);
132+
}
133+
134+
static void putPointValue(ByteBuffer buffer, int offset, float value) {
135+
putValue(buffer, offset, value, POINT);
136+
}
137+
138+
static void putPercentValue(ByteBuffer buffer, int offset, float value) {
139+
putValue(buffer, offset, value, PERCENT);
140+
}
141+
142+
static YogaValue getValue(ByteBuffer buffer, int offset) {
143+
float value = buffer.getFloat(offset);
144+
int unit = buffer.getInt(offset + FLOAT_SIZE);
145+
return new YogaValue(value, YogaUnit.fromInt(unit));
146+
}
147+
148+
static boolean getBoolean(ByteBuffer buffer, int offset) {
149+
return buffer.get(offset) != 0;
150+
}
151+
}

ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeProperties.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public interface YogaNodeProperties {
1313

1414
long getNativePointer();
1515

16-
void onAfterCalculateLayout();
16+
void onAfterCalculateLayout(boolean hasNewLayout);
1717

1818
void reset();
1919

0 commit comments

Comments
 (0)