Added implementation for YogaNodeJNIBatching and logic for passing array from c++ to java

Summary: This diff adds the logic to transfer layout outputs using a float array

Reviewed By: davidaurelio

Differential Revision: D14368120

fbshipit-source-id: d1f22283bcea051d15657f42c15b90edaa0a8a7a
This commit is contained in:
Sidharth Guglani
2019-04-01 06:11:51 -07:00
committed by Facebook Github Bot
parent 5fad8008ab
commit c11faf2d56
2 changed files with 320 additions and 66 deletions

View File

@@ -0,0 +1,177 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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 javax.annotation.Nullable;
import com.facebook.proguard.annotations.DoNotStrip;
@DoNotStrip
public class YogaNodeJNIBatching extends YogaNodeJNIBase {
/* Those flags needs be in sync with YGJNI.cpp */
private static final byte MARGIN = 1;
private static final byte PADDING = 2;
private static final byte BORDER = 4;
private static final byte DOES_LEGACY_STRETCH_BEHAVIOUR = 8;
private static final byte HAS_NEW_LAYOUT = 16;
private static final byte LAYOUT_EDGE_SET_FLAG_INDEX = 0;
private static final byte LAYOUT_WIDTH_INDEX = 1;
private static final byte LAYOUT_HEIGHT_INDEX = 2;
private static final byte LAYOUT_LEFT_INDEX = 3;
private static final byte LAYOUT_TOP_INDEX = 4;
private static final byte LAYOUT_DIRECTION_INDEX = 5;
private static final byte LAYOUT_MARGIN_START_INDEX = 6;
private static final byte LAYOUT_PADDING_START_INDEX = 10;
private static final byte LAYOUT_BORDER_START_INDEX = 14;
@DoNotStrip
private @Nullable float[] arr = null;
@DoNotStrip
private int mLayoutDirection = 0;
private boolean mHasNewLayout = true;
public YogaNodeJNIBatching() {
super();
}
public YogaNodeJNIBatching(YogaConfig config) {
super(config);
}
@Override
public void reset() {
super.reset();
arr = null;
mHasNewLayout = true;
mLayoutDirection = 0;
}
@Override
public float getLayoutX() {
return arr != null ? arr[LAYOUT_LEFT_INDEX] : 0;
}
@Override
public float getLayoutY() {
return arr != null ? arr[LAYOUT_TOP_INDEX] : 0;
}
@Override
public float getLayoutWidth() {
return arr != null ? arr[LAYOUT_WIDTH_INDEX] : 0;
}
@Override
public float getLayoutHeight() {
return arr != null ? arr[LAYOUT_HEIGHT_INDEX] : 0;
}
@Override
public boolean getDoesLegacyStretchFlagAffectsLayout() {
return arr != null && (((int) arr[LAYOUT_EDGE_SET_FLAG_INDEX] & DOES_LEGACY_STRETCH_BEHAVIOUR) == DOES_LEGACY_STRETCH_BEHAVIOUR);
}
@Override
public float getLayoutMargin(YogaEdge edge) {
if (arr != null && ((int) arr[LAYOUT_EDGE_SET_FLAG_INDEX] & MARGIN) == MARGIN) {
switch (edge) {
case LEFT:
return arr[LAYOUT_MARGIN_START_INDEX];
case TOP:
return arr[LAYOUT_MARGIN_START_INDEX + 1];
case RIGHT:
return arr[LAYOUT_MARGIN_START_INDEX + 2];
case BOTTOM:
return arr[LAYOUT_MARGIN_START_INDEX + 3];
case START:
return getLayoutDirection() == YogaDirection.RTL ? arr[LAYOUT_MARGIN_START_INDEX + 2] : arr[LAYOUT_MARGIN_START_INDEX];
case END:
return getLayoutDirection() == YogaDirection.RTL ? arr[LAYOUT_MARGIN_START_INDEX] : arr[LAYOUT_MARGIN_START_INDEX + 2];
default:
throw new IllegalArgumentException("Cannot get layout margins of multi-edge shorthands");
}
} else {
return 0;
}
}
@Override
public float getLayoutPadding(YogaEdge edge) {
if (arr != null && ((int) arr[LAYOUT_EDGE_SET_FLAG_INDEX] & PADDING) == PADDING) {
int paddingStartIndex = LAYOUT_PADDING_START_INDEX - ((((int)arr[LAYOUT_EDGE_SET_FLAG_INDEX] & MARGIN) == MARGIN) ? 0 : 4);
switch (edge) {
case LEFT:
return arr[paddingStartIndex];
case TOP:
return arr[paddingStartIndex + 1];
case RIGHT:
return arr[paddingStartIndex + 2];
case BOTTOM:
return arr[paddingStartIndex + 3];
case START:
return getLayoutDirection() == YogaDirection.RTL ? arr[paddingStartIndex + 2] : arr[paddingStartIndex];
case END:
return getLayoutDirection() == YogaDirection.RTL ? arr[paddingStartIndex] : arr[paddingStartIndex + 2];
default:
throw new IllegalArgumentException("Cannot get layout paddings of multi-edge shorthands");
}
} else {
return 0;
}
}
@Override
public float getLayoutBorder(YogaEdge edge) {
if (arr != null && ((int) arr[LAYOUT_EDGE_SET_FLAG_INDEX] & BORDER) == BORDER) {
int borderStartIndex = LAYOUT_BORDER_START_INDEX - ((((int) arr[LAYOUT_EDGE_SET_FLAG_INDEX] & MARGIN) == MARGIN) ? 0 : 4) - ((((int) arr[LAYOUT_EDGE_SET_FLAG_INDEX] & PADDING) == PADDING) ? 0 : 4);
switch (edge) {
case LEFT:
return arr[borderStartIndex];
case TOP:
return arr[borderStartIndex + 1];
case RIGHT:
return arr[borderStartIndex + 2];
case BOTTOM:
return arr[borderStartIndex + 3];
case START:
return getLayoutDirection() == YogaDirection.RTL ? arr[borderStartIndex + 2] : arr[borderStartIndex];
case END:
return getLayoutDirection() == YogaDirection.RTL ? arr[borderStartIndex] : arr[borderStartIndex + 2];
default:
throw new IllegalArgumentException("Cannot get layout border of multi-edge shorthands");
}
} else {
return 0;
}
}
@Override
public YogaDirection getLayoutDirection() {
return YogaDirection.fromInt(arr != null ? (int) arr[LAYOUT_DIRECTION_INDEX] : mLayoutDirection);
}
@Override
public boolean hasNewLayout() {
if (arr != null) {
return (((int) arr[LAYOUT_EDGE_SET_FLAG_INDEX]) & HAS_NEW_LAYOUT) == HAS_NEW_LAYOUT;
} else {
return mHasNewLayout;
}
}
@Override
public void markLayoutSeen() {
if (arr != null) {
arr[LAYOUT_EDGE_SET_FLAG_INDEX] = ((int) arr[LAYOUT_EDGE_SET_FLAG_INDEX]) & ~(HAS_NEW_LAYOUT);
}
mHasNewLayout = false;
}
}

View File

@@ -62,6 +62,16 @@ enum YGStyleInput {
IsReferenceBaseline, IsReferenceBaseline,
}; };
const short int LAYOUT_EDGE_SET_FLAG_INDEX = 0;
const short int LAYOUT_WIDTH_INDEX = 1;
const short int LAYOUT_HEIGHT_INDEX = 2;
const short int LAYOUT_LEFT_INDEX = 3;
const short int LAYOUT_TOP_INDEX = 4;
const short int LAYOUT_DIRECTION_INDEX = 5;
const short int LAYOUT_MARGIN_START_INDEX = 6;
const short int LAYOUT_PADDING_START_INDEX = 10;
const short int LAYOUT_BORDER_START_INDEX = 14;
class PtrJNodeMap { class PtrJNodeMap {
using JNodeArray = JArrayClass<JYogaNode::javaobject>; using JNodeArray = JArrayClass<JYogaNode::javaobject>;
std::map<YGNodeRef, size_t> ptrsToIdxs_; std::map<YGNodeRef, size_t> ptrsToIdxs_;
@@ -97,6 +107,9 @@ union YGNodeContext {
void* asVoidPtr; void* asVoidPtr;
}; };
const int DOES_LEGACY_STRETCH_BEHAVIOUR = 8;
const int HAS_NEW_LAYOUT = 16;
class YGNodeEdges { class YGNodeEdges {
uintptr_t edges_; uintptr_t edges_;
@@ -127,6 +140,10 @@ public:
edges_ |= edge; edges_ |= edge;
return *this; return *this;
} }
int get() {
return edges_;
}
}; };
struct YogaValue { struct YogaValue {
@@ -177,80 +194,140 @@ static void YGTransferLayoutOutputsRecursive(
auto edgesSet = YGNodeEdges{root}; auto edgesSet = YGNodeEdges{root};
static auto widthField = obj->getClass()->getField<jfloat>("mWidth"); if (false) {
static auto heightField = obj->getClass()->getField<jfloat>("mHeight"); bool marginFieldSet = edgesSet.has(YGNodeEdges::MARGIN);
static auto leftField = obj->getClass()->getField<jfloat>("mLeft"); bool paddingFieldSet = edgesSet.has(YGNodeEdges::PADDING);
static auto topField = obj->getClass()->getField<jfloat>("mTop"); bool borderFieldSet = edgesSet.has(YGNodeEdges::BORDER);
static auto marginLeftField = int fieldFlags = edgesSet.get();
obj->getClass()->getField<jfloat>("mMarginLeft"); fieldFlags |= HAS_NEW_LAYOUT;
static auto marginTopField = obj->getClass()->getField<jfloat>("mMarginTop"); if (YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(root)) {
static auto marginRightField = fieldFlags |= DOES_LEGACY_STRETCH_BEHAVIOUR;
obj->getClass()->getField<jfloat>("mMarginRight"); }
static auto marginBottomField =
obj->getClass()->getField<jfloat>("mMarginBottom");
static auto paddingLeftField = const int arrSize = 6 + (marginFieldSet ? 4 : 0) +
obj->getClass()->getField<jfloat>("mPaddingLeft"); (paddingFieldSet ? 4 : 0) + (borderFieldSet ? 4 : 0);
static auto paddingTopField = float arr[18];
obj->getClass()->getField<jfloat>("mPaddingTop"); arr[LAYOUT_EDGE_SET_FLAG_INDEX] = fieldFlags;
static auto paddingRightField = arr[LAYOUT_WIDTH_INDEX] = YGNodeLayoutGetWidth(root);
obj->getClass()->getField<jfloat>("mPaddingRight"); arr[LAYOUT_HEIGHT_INDEX] = YGNodeLayoutGetHeight(root);
static auto paddingBottomField = arr[LAYOUT_LEFT_INDEX] = YGNodeLayoutGetLeft(root);
obj->getClass()->getField<jfloat>("mPaddingBottom"); arr[LAYOUT_TOP_INDEX] = YGNodeLayoutGetTop(root);
arr[LAYOUT_DIRECTION_INDEX] =
static_cast<jint>(YGNodeLayoutGetDirection(root));
if (marginFieldSet) {
arr[LAYOUT_MARGIN_START_INDEX] = YGNodeLayoutGetMargin(root, YGEdgeLeft);
arr[LAYOUT_MARGIN_START_INDEX + 1] =
YGNodeLayoutGetMargin(root, YGEdgeTop);
arr[LAYOUT_MARGIN_START_INDEX + 2] =
YGNodeLayoutGetMargin(root, YGEdgeRight);
arr[LAYOUT_MARGIN_START_INDEX + 3] =
YGNodeLayoutGetMargin(root, YGEdgeBottom);
}
if (paddingFieldSet) {
int paddingStartIndex =
LAYOUT_PADDING_START_INDEX - (marginFieldSet ? 0 : 4);
arr[paddingStartIndex] = YGNodeLayoutGetPadding(root, YGEdgeLeft);
arr[paddingStartIndex + 1] = YGNodeLayoutGetPadding(root, YGEdgeTop);
arr[paddingStartIndex + 2] = YGNodeLayoutGetPadding(root, YGEdgeRight);
arr[paddingStartIndex + 3] = YGNodeLayoutGetPadding(root, YGEdgeBottom);
}
static auto borderLeftField = if (borderFieldSet) {
obj->getClass()->getField<jfloat>("mBorderLeft"); int borderStartIndex = LAYOUT_BORDER_START_INDEX -
static auto borderTopField = obj->getClass()->getField<jfloat>("mBorderTop"); (marginFieldSet ? 0 : 4) - (paddingFieldSet ? 0 : 4);
static auto borderRightField = arr[borderStartIndex] = YGNodeLayoutGetBorder(root, YGEdgeLeft);
obj->getClass()->getField<jfloat>("mBorderRight"); arr[borderStartIndex + 1] = YGNodeLayoutGetBorder(root, YGEdgeTop);
static auto borderBottomField = arr[borderStartIndex + 2] = YGNodeLayoutGetBorder(root, YGEdgeRight);
obj->getClass()->getField<jfloat>("mBorderBottom"); arr[borderStartIndex + 3] = YGNodeLayoutGetBorder(root, YGEdgeBottom);
}
static auto hasNewLayoutField = static auto arrField = obj->getClass()->getField<jfloatArray>("arr");
obj->getClass()->getField<jboolean>("mHasNewLayout"); local_ref<jfloatArray> arrFinal = make_float_array(arrSize);
static auto doesLegacyStretchBehaviour = obj->getClass()->getField<jboolean>( arrFinal->setRegion(0, arrSize, arr);
"mDoesLegacyStretchFlagAffectsLayout"); obj->setFieldValue<jfloatArray>(arrField, arrFinal.get());
obj->setFieldValue(widthField, YGNodeLayoutGetWidth(root)); } else {
obj->setFieldValue(heightField, YGNodeLayoutGetHeight(root)); static auto widthField = obj->getClass()->getField<jfloat>("mWidth");
obj->setFieldValue(leftField, YGNodeLayoutGetLeft(root)); static auto heightField = obj->getClass()->getField<jfloat>("mHeight");
obj->setFieldValue(topField, YGNodeLayoutGetTop(root)); static auto leftField = obj->getClass()->getField<jfloat>("mLeft");
obj->setFieldValue<jboolean>( static auto topField = obj->getClass()->getField<jfloat>("mTop");
doesLegacyStretchBehaviour,
YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(root));
obj->setFieldValue<jboolean>(hasNewLayoutField, true);
YGTransferLayoutDirection(root, obj);
if (edgesSet.has(YGNodeEdges::MARGIN)) { static auto marginLeftField =
obj->setFieldValue( obj->getClass()->getField<jfloat>("mMarginLeft");
marginLeftField, YGNodeLayoutGetMargin(root, YGEdgeLeft)); static auto marginTopField =
obj->setFieldValue(marginTopField, YGNodeLayoutGetMargin(root, YGEdgeTop)); obj->getClass()->getField<jfloat>("mMarginTop");
obj->setFieldValue( static auto marginRightField =
marginRightField, YGNodeLayoutGetMargin(root, YGEdgeRight)); obj->getClass()->getField<jfloat>("mMarginRight");
obj->setFieldValue( static auto marginBottomField =
marginBottomField, YGNodeLayoutGetMargin(root, YGEdgeBottom)); obj->getClass()->getField<jfloat>("mMarginBottom");
}
if (edgesSet.has(YGNodeEdges::PADDING)) { static auto paddingLeftField =
obj->setFieldValue( obj->getClass()->getField<jfloat>("mPaddingLeft");
paddingLeftField, YGNodeLayoutGetPadding(root, YGEdgeLeft)); static auto paddingTopField =
obj->setFieldValue( obj->getClass()->getField<jfloat>("mPaddingTop");
paddingTopField, YGNodeLayoutGetPadding(root, YGEdgeTop)); static auto paddingRightField =
obj->setFieldValue( obj->getClass()->getField<jfloat>("mPaddingRight");
paddingRightField, YGNodeLayoutGetPadding(root, YGEdgeRight)); static auto paddingBottomField =
obj->setFieldValue( obj->getClass()->getField<jfloat>("mPaddingBottom");
paddingBottomField, YGNodeLayoutGetPadding(root, YGEdgeBottom));
}
if (edgesSet.has(YGNodeEdges::BORDER)) { static auto borderLeftField =
obj->setFieldValue( obj->getClass()->getField<jfloat>("mBorderLeft");
borderLeftField, YGNodeLayoutGetBorder(root, YGEdgeLeft)); static auto borderTopField =
obj->setFieldValue(borderTopField, YGNodeLayoutGetBorder(root, YGEdgeTop)); obj->getClass()->getField<jfloat>("mBorderTop");
obj->setFieldValue( static auto borderRightField =
borderRightField, YGNodeLayoutGetBorder(root, YGEdgeRight)); obj->getClass()->getField<jfloat>("mBorderRight");
obj->setFieldValue( static auto borderBottomField =
borderBottomField, YGNodeLayoutGetBorder(root, YGEdgeBottom)); obj->getClass()->getField<jfloat>("mBorderBottom");
static auto hasNewLayoutField =
obj->getClass()->getField<jboolean>("mHasNewLayout");
static auto doesLegacyStretchBehaviour =
obj->getClass()->getField<jboolean>(
"mDoesLegacyStretchFlagAffectsLayout");
obj->setFieldValue(widthField, YGNodeLayoutGetWidth(root));
obj->setFieldValue(heightField, YGNodeLayoutGetHeight(root));
obj->setFieldValue(leftField, YGNodeLayoutGetLeft(root));
obj->setFieldValue(topField, YGNodeLayoutGetTop(root));
obj->setFieldValue<jboolean>(
doesLegacyStretchBehaviour,
YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(root));
obj->setFieldValue<jboolean>(hasNewLayoutField, true);
YGTransferLayoutDirection(root, obj);
if (edgesSet.has(YGNodeEdges::MARGIN)) {
obj->setFieldValue(
marginLeftField, YGNodeLayoutGetMargin(root, YGEdgeLeft));
obj->setFieldValue(
marginTopField, YGNodeLayoutGetMargin(root, YGEdgeTop));
obj->setFieldValue(
marginRightField, YGNodeLayoutGetMargin(root, YGEdgeRight));
obj->setFieldValue(
marginBottomField, YGNodeLayoutGetMargin(root, YGEdgeBottom));
}
if (edgesSet.has(YGNodeEdges::PADDING)) {
obj->setFieldValue(
paddingLeftField, YGNodeLayoutGetPadding(root, YGEdgeLeft));
obj->setFieldValue(
paddingTopField, YGNodeLayoutGetPadding(root, YGEdgeTop));
obj->setFieldValue(
paddingRightField, YGNodeLayoutGetPadding(root, YGEdgeRight));
obj->setFieldValue(
paddingBottomField, YGNodeLayoutGetPadding(root, YGEdgeBottom));
}
if (edgesSet.has(YGNodeEdges::BORDER)) {
obj->setFieldValue(
borderLeftField, YGNodeLayoutGetBorder(root, YGEdgeLeft));
obj->setFieldValue(
borderTopField, YGNodeLayoutGetBorder(root, YGEdgeTop));
obj->setFieldValue(
borderRightField, YGNodeLayoutGetBorder(root, YGEdgeRight));
obj->setFieldValue(
borderBottomField, YGNodeLayoutGetBorder(root, YGEdgeBottom));
}
} }
root->setHasNewLayout(false); root->setHasNewLayout(false);