Skip to content

Commit

Permalink
Add YogaNodeProperties implementation based on ByteBuffer
Browse files Browse the repository at this point in the history
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
  • Loading branch information
davidaurelio authored and facebook-github-bot committed Jul 30, 2018
1 parent 930bf16 commit 0c97e75
Show file tree
Hide file tree
Showing 7 changed files with 749 additions and 19 deletions.
41 changes: 26 additions & 15 deletions ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@
public class YogaNode implements Cloneable {

static {
SoLoader.loadLibrary("yoga");
SoLoader.loadLibrary("yoga");
}

/**
* Get native instance count. Useful for testing only.
*/
/** Get native instance count. Useful for testing only. */
static native int jni_YGNodeGetInstanceCount();

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

public YogaNode(boolean unsafeClownyUseByteBufferValueDoesNotMatter) {
mDelegate = new YogaNodePropertiesByteBuffer(this);
}

public YogaNode(boolean unsafeClownyUseByteBufferValueDoesNotMatter, YogaConfig config) {
mDelegate = new YogaNodePropertiesByteBuffer(this, config);
}

public long getNativePointer() {
return mDelegate.getNativePointer();
}
Expand Down Expand Up @@ -69,6 +75,7 @@ public YogaNode getChildAt(int i) {
}

private native void jni_YGNodeInsertChild(long nativePointer, long childPointer, int index);

public void addChildAt(YogaNode child, int i) {
if (child.mOwner != null) {
throw new IllegalStateException("Child already has a parent, it must be removed first.");
Expand Down Expand Up @@ -144,6 +151,7 @@ private void clearChildren() {
}

private native void jni_YGNodeRemoveChild(long nativePointer, long childPointer);

public YogaNode removeChildAt(int i) {
if (mChildren == null) {
throw new IllegalStateException(
Expand All @@ -156,12 +164,10 @@ public YogaNode removeChildAt(int i) {
}

/**
* @returns the {@link YogaNode} that owns this {@link YogaNode}.
* The owner is used to identify the YogaTree that a {@link YogaNode} belongs
* to.
* This method will return the parent of the {@link YogaNode} when the
* {@link YogaNode} only belongs to one YogaTree or null when the
* {@link YogaNode} is shared between two or more YogaTrees.
* @returns the {@link YogaNode} that owns this {@link YogaNode}. The owner is used to identify
* the YogaTree that a {@link YogaNode} belongs to. This method will return the parent of the
* {@link YogaNode} when the {@link YogaNode} only belongs to one YogaTree or null when the
* {@link YogaNode} is shared between two or more YogaTrees.
*/
@Nullable
public YogaNode getOwner() {
Expand All @@ -179,17 +185,19 @@ public int indexOf(YogaNode child) {
return mChildren == null ? -1 : mChildren.indexOf(child);
}

private native void jni_YGNodeCalculateLayout(long nativePointer, float width, float height);
private native boolean jni_YGNodeCalculateLayout(long nativePointer, float width, float height);

public void calculateLayout(float width, float height) {
jni_YGNodeCalculateLayout(getNativePointer(), width, height);
mDelegate.onAfterCalculateLayout();
boolean hasNewLayout = jni_YGNodeCalculateLayout(getNativePointer(), width, height);
mDelegate.onAfterCalculateLayout(hasNewLayout);
}

public boolean hasNewLayout() {
return mDelegate.hasNewLayout();
}

private native void jni_YGNodeMarkDirty(long nativePointer);

public void dirty() {
jni_YGNodeMarkDirty(getNativePointer());
}
Expand All @@ -205,6 +213,7 @@ public boolean isDirty() {
}

private native void jni_YGNodeCopyStyle(long dstNativePointer, long srcNativePointer);

public void copyStyle(YogaNode srcNode) {
jni_YGNodeCopyStyle(getNativePointer(), srcNode.getNativePointer());
}
Expand Down Expand Up @@ -498,6 +507,7 @@ public YogaDirection getLayoutDirection() {
}

private native void jni_YGNodeSetHasMeasureFunc(long nativePointer, boolean hasMeasureFunc);

public void setMeasureFunction(YogaMeasureFunction measureFunction) {
mMeasureFunction = measureFunction;
jni_YGNodeSetHasMeasureFunc(getNativePointer(), measureFunction != null);
Expand All @@ -523,6 +533,7 @@ public final long measure(float width, int widthMode, float height, int heightMo
}

private native void jni_YGNodeSetHasBaselineFunc(long nativePointer, boolean hasMeasureFunc);

public void setBaselineFunction(YogaBaselineFunction baselineFunction) {
mBaselineFunction = baselineFunction;
jni_YGNodeSetHasBaselineFunc(getNativePointer(), baselineFunction != null);
Expand All @@ -548,8 +559,8 @@ public Object getData() {
private native void jni_YGNodePrint(long nativePointer);

/**
* Use the set logger (defaults to adb log) to print out the styles, children, and computed
* layout of the tree rooted at this node.
* Use the set logger (defaults to adb log) to print out the styles, children, and computed layout
* of the tree rooted at this node.
*/
public void print() {
jni_YGNodePrint(getNativePointer());
Expand Down
151 changes: 151 additions & 0 deletions ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeMemoryLayout.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*
*/

package com.facebook.yoga;

import com.facebook.proguard.annotations.DoNotStrip;
import java.nio.ByteBuffer;

@DoNotStrip
/* package */ final class YogaNodeMemoryLayout {

private static final int FLOAT_SIZE = 4;
private static final int INT_SIZE = 4;
private static final int VALUE_SIZE = FLOAT_SIZE + INT_SIZE;
private static final byte FALSE = 0;
private static final byte TRUE = 1;
private static final int AUTO = YogaUnit.AUTO.intValue();
private static final int POINT = YogaUnit.POINT.intValue();
private static final int PERCENT = YogaUnit.PERCENT.intValue();
private static final int UNDEFINED = YogaUnit.UNDEFINED.intValue();

// TODO(davidaurelio) code-gen these values
static final int styleDirection = 0;
static final int styleFlexDirection = 4;
static final int styleJustifyContent = 8;
static final int styleAlignContent = 12;
static final int styleAlignItems = 16;
static final int styleAlignSelf = 20;
static final int stylePositionType = 24;
static final int styleFlexWrap = 28;
static final int styleOverflow = 32;
static final int styleDisplay = 36;
static final int styleFlex = 40;
static final int styleFlexGrow = 48;
static final int styleFlexShrink = 56;
static final int styleFlexBasis = 64;
static final int styleMargin = 72;
static final int stylePosition = 144;
static final int stylePadding = 216;
static final int styleBorder = 288;
static final int styleDimensions = 360;
static final int styleMinDimensions = 376;
static final int styleMaxDimensions = 392;
static final int styleAspectRatio = 408;

static final int styleWidth = styleDimensions;
static final int styleHeight = styleDimensions + VALUE_SIZE;
static final int styleMinWidth = styleMinDimensions;
static final int styleMinHeight = styleMinDimensions + VALUE_SIZE;
static final int styleMaxWidth = styleMaxDimensions;
static final int styleMaxHeight = styleMaxDimensions + VALUE_SIZE;

static final int layoutPosition = 0;
static final int layoutDimensions = 16;
static final int layoutMargin = 24;
static final int layoutBorder = 48;
static final int layoutPadding = 72;
static final int layoutDirection = 96;
static final int layoutComputedFlexBasisGeneration = 100;
static final int layoutComputedFlexBasis = 104;
static final int layoutHadOverflow = 112;
static final int layoutGenerationCount = 116;
static final int layoutLastOwnerDirection = 120;
static final int layoutNextCachedMeasurementsIndex = 124;
static final int layoutCachedMeasurements = 128;
static final int layoutMeasuredDimensions = 512;
static final int layoutCachedLayout = 520;
static final int layoutDidUseLegacyFlag = 544;
static final int layoutDoesLegacyStretchFlagAffectsLayout = 545;

static final int layoutX = layoutPosition;
static final int layoutY = layoutPosition + FLOAT_SIZE;
static final int layoutWidth = layoutDimensions;
static final int layoutHeight = layoutDimensions + FLOAT_SIZE;

static int stylePositionOffset(YogaEdge edge) {
return stylePosition + edge.intValue() * VALUE_SIZE;
}

static int styleMarginOffset(YogaEdge edge) {
return styleMargin + edge.intValue() * VALUE_SIZE;
}

static int layoutMarginOffset(YogaEdge edge) {
return layoutMargin + edge.intValue() * FLOAT_SIZE;
}

static int stylePaddingOffset(YogaEdge edge) {
return stylePadding + edge.intValue() * VALUE_SIZE;
}

static int layoutPaddingOffset(YogaEdge edge) {
return layoutPadding + edge.intValue() * FLOAT_SIZE;
}

static int styleBorderOffset(YogaEdge edge) {
return styleBorder + edge.intValue() * VALUE_SIZE;
}

static int layoutBorderOffset(YogaEdge edge) {
return layoutBorder + edge.intValue() * FLOAT_SIZE;
}

static void putOptional(ByteBuffer buffer, int offset, float value) {
buffer.putFloat(offset, value);
buffer.put(
offset + FLOAT_SIZE, YogaConstants.isUndefined(value) ? TRUE : FALSE); // bool isUndefined_
}

static float getOptional(ByteBuffer buffer, int offset) {
return getBoolean(buffer, offset + FLOAT_SIZE)
? YogaConstants.UNDEFINED
: buffer.getFloat(offset);
}

private static void putValue(ByteBuffer buffer, int offset, float value, int unit) {
if (YogaConstants.isUndefined(value)) {
value = YogaConstants.UNDEFINED;
unit = UNDEFINED;
}
buffer.putFloat(offset, value);
buffer.putInt(offset + FLOAT_SIZE, unit);
}

static void putAutoValue(ByteBuffer buffer, int offset) {
putValue(buffer, offset, 0, AUTO);
}

static void putPointValue(ByteBuffer buffer, int offset, float value) {
putValue(buffer, offset, value, POINT);
}

static void putPercentValue(ByteBuffer buffer, int offset, float value) {
putValue(buffer, offset, value, PERCENT);
}

static YogaValue getValue(ByteBuffer buffer, int offset) {
float value = buffer.getFloat(offset);
int unit = buffer.getInt(offset + FLOAT_SIZE);
return new YogaValue(value, YogaUnit.fromInt(unit));
}

static boolean getBoolean(ByteBuffer buffer, int offset) {
return buffer.get(offset) != 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public interface YogaNodeProperties {

long getNativePointer();

void onAfterCalculateLayout();
void onAfterCalculateLayout(boolean hasNewLayout);

void reset();

Expand Down
Loading

0 comments on commit 0c97e75

Please sign in to comment.