Move configuration to new YGConfig and pass them down to CalculateLayout

Summary:
Move configuration to new ```YGConfig``` and pass them down to CalculateLayout. See #418 .

Adds ```YGConfigNew()``` + ```YGConfigFree```, and changed ```YGSetExperimentalFeatureEnabled``` to use the config.

New function for calculation is ```YGNodeCalculateLayoutWithConfig```.
Closes https://github.com/facebook/yoga/pull/432

Reviewed By: astreet

Differential Revision: D4611359

Pulled By: emilsjolander

fbshipit-source-id: a1332f0e1b21cec02129dd021ee57408449e10b0
This commit is contained in:
Lukas Wöhrl 2017-03-01 09:19:55 -08:00 committed by Facebook Github Bot
parent 4d69f4b2d1
commit bdd9aed909
5 changed files with 177 additions and 57 deletions

View File

@ -0,0 +1,49 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.yoga;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.soloader.SoLoader;
@DoNotStrip
public class YogaConfig {
static {
SoLoader.loadLibrary("yoga");
}
long mNativePointer;
private native long jni_YGConfigNew();
public YogaConfig() {
mNativePointer = jni_YGConfigNew();
if (mNativePointer == 0) {
throw new IllegalStateException("Failed to allocate native memory");
}
}
private native void jni_YGConfigFree(long nativePointer);
@Override
protected void finalize() throws Throwable {
try {
jni_YGConfigFree(mNativePointer);
} finally {
super.finalize();
}
}
private native void jni_YGConfigSetExperimentalFeatureEnabled(
long nativePointer,
int feature,
boolean enabled);
public void setExperimentalFeatureEnabled(YogaExperimentalFeature feature, boolean enabled) {
jni_YGConfigSetExperimentalFeatureEnabled(mNativePointer, feature.intValue(), enabled);
}
}

View File

@ -35,20 +35,6 @@ public class YogaNode implements YogaNodeAPI<YogaNode> {
jni_YGSetLogger(logger);
}
private static native void jni_YGSetExperimentalFeatureEnabled(
int feature,
boolean enabled);
public static void setExperimentalFeatureEnabled(
YogaExperimentalFeature feature,
boolean enabled) {
jni_YGSetExperimentalFeatureEnabled(feature.intValue(), enabled);
}
private static native boolean jni_YGIsExperimentalFeatureEnabled(int feature);
public static boolean isExperimentalFeatureEnabled(YogaExperimentalFeature feature) {
return jni_YGIsExperimentalFeatureEnabled(feature.intValue());
}
private YogaNode mParent;
private List<YogaNode> mChildren;
private YogaMeasureFunction mMeasureFunction;
@ -104,6 +90,14 @@ public class YogaNode implements YogaNodeAPI<YogaNode> {
}
}
private native long jni_YGNodeNewWithConfig(long configPointer);
public YogaNode(YogaConfig config) {
mNativePointer = jni_YGNodeNewWithConfig(config.mNativePointer);
if (mNativePointer == 0) {
throw new IllegalStateException("Failed to allocate native memory");
}
}
private native void jni_YGNodeFree(long nativePointer);
@Override
protected void finalize() throws Throwable {

View File

@ -150,6 +150,10 @@ static inline YGNodeRef _jlong2YGNodeRef(jlong addr) {
return reinterpret_cast<YGNodeRef>(static_cast<intptr_t>(addr));
}
static inline YGConfigRef _jlong2YGConfigRef(jlong addr) {
return reinterpret_cast<YGConfigRef>(static_cast<intptr_t>(addr));
}
void jni_YGSetLogger(alias_ref<jclass> clazz, alias_ref<jobject> logger) {
if (jLogger) {
jLogger->releaseAlias();
@ -171,18 +175,6 @@ void jni_YGLog(alias_ref<jclass> clazz, jint level, jstring message) {
Environment::current()->ReleaseStringUTFChars(message, nMessage);
}
void jni_YGSetExperimentalFeatureEnabled(alias_ref<jclass> clazz, jint feature, jboolean enabled) {
YGSetExperimentalFeatureEnabled(static_cast<YGExperimentalFeature>(feature), enabled);
}
jboolean jni_YGIsExperimentalFeatureEnabled(alias_ref<jclass> clazz, jint feature) {
return YGIsExperimentalFeatureEnabled(static_cast<YGExperimentalFeature>(feature));
}
jint jni_YGNodeGetInstanceCount(alias_ref<jclass> clazz) {
return YGNodeGetInstanceCount();
}
jlong jni_YGNodeNew(alias_ref<jobject> thiz) {
const YGNodeRef node = YGNodeNew();
YGNodeSetContext(node, new weak_ref<jobject>(make_weak(thiz)));
@ -190,6 +182,13 @@ jlong jni_YGNodeNew(alias_ref<jobject> thiz) {
return reinterpret_cast<jlong>(node);
}
jlong jni_YGNodeNewWithConfig(alias_ref<jobject> thiz, jlong configPointer) {
const YGNodeRef node = YGNodeNewWithConfig(_jlong2YGConfigRef(configPointer));
YGNodeSetContext(node, new weak_ref<jobject>(make_weak(thiz)));
YGNodeSetPrintFunc(node, YGPrint);
return reinterpret_cast<jlong>(node);
}
void jni_YGNodeFree(alias_ref<jobject> thiz, jlong nativePointer) {
const YGNodeRef node = _jlong2YGNodeRef(nativePointer);
delete YGNodeJobject(node);
@ -368,6 +367,24 @@ YG_NODE_JNI_STYLE_UNIT_PROP(MaxHeight);
// Yoga specific properties, not compatible with flexbox specification
YG_NODE_JNI_STYLE_PROP(jfloat, float, AspectRatio);
jlong jni_YGConfigNew(alias_ref<jobject>) {
return reinterpret_cast<jlong>(YGConfigNew());
}
void jni_YGConfigFree(alias_ref<jobject>, jlong nativePointer) {
const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
YGConfigFree(config);
}
void jni_YGConfigSetExperimentalFeatureEnabled(alias_ref<jobject>, jlong nativePointer, jint feature, jboolean enabled) {
const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
YGConfigSetExperimentalFeatureEnabled(config, static_cast<YGExperimentalFeature>(feature), enabled);
}
jint jni_YGNodeGetInstanceCount(alias_ref<jclass> clazz) {
return YGNodeGetInstanceCount();
}
#define YGMakeNativeMethod(name) makeNativeMethod(#name, name)
jint JNI_OnLoad(JavaVM *vm, void *) {
@ -375,6 +392,7 @@ jint JNI_OnLoad(JavaVM *vm, void *) {
registerNatives("com/facebook/yoga/YogaNode",
{
YGMakeNativeMethod(jni_YGNodeNew),
YGMakeNativeMethod(jni_YGNodeNewWithConfig),
YGMakeNativeMethod(jni_YGNodeFree),
YGMakeNativeMethod(jni_YGNodeReset),
YGMakeNativeMethod(jni_YGNodeInsertChild),
@ -452,8 +470,12 @@ jint JNI_OnLoad(JavaVM *vm, void *) {
YGMakeNativeMethod(jni_YGNodeGetInstanceCount),
YGMakeNativeMethod(jni_YGSetLogger),
YGMakeNativeMethod(jni_YGLog),
YGMakeNativeMethod(jni_YGSetExperimentalFeatureEnabled),
YGMakeNativeMethod(jni_YGIsExperimentalFeatureEnabled),
});
registerNatives("com/facebook/yoga/YogaConfig",
{
YGMakeNativeMethod(jni_YGConfigNew),
YGMakeNativeMethod(jni_YGConfigFree),
YGMakeNativeMethod(jni_YGConfigSetExperimentalFeatureEnabled),
});
});
}

View File

@ -94,6 +94,8 @@ typedef struct YGStyle {
float aspectRatio;
} YGStyle;
typedef struct YGConfig { bool experimentalFeatures[YGExperimentalFeatureCount + 1]; } YGConfig;
typedef struct YGNode {
YGStyle style;
YGLayout layout;
@ -107,6 +109,7 @@ typedef struct YGNode {
YGMeasureFunc measure;
YGBaselineFunc baseline;
YGPrintFunc print;
YGConfigRef config;
void *context;
bool isDirty;
@ -191,6 +194,14 @@ static YGNode gYGNodeDefaults = {
},
};
static YGConfig gYGConfigDefaults = {
.experimentalFeatures =
{
[YGExperimentalFeatureRounding] = false,
[YGExperimentalFeatureWebFlexBasis] = false,
},
};
static void YGNodeMarkDirtyInternal(const YGNodeRef node);
YGMalloc gYGMalloc = &malloc;
@ -290,15 +301,21 @@ static inline float YGValueResolveMargin(const YGValue *const value, const float
int32_t gNodeInstanceCount = 0;
YGNodeRef YGNodeNew(void) {
WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) {
const YGNodeRef node = gYGMalloc(sizeof(YGNode));
YG_ASSERT(node, "Could not allocate memory for node");
gNodeInstanceCount++;
memcpy(node, &gYGNodeDefaults, sizeof(YGNode));
node->config = config;
return node;
}
YGNodeRef YGNodeNew(void) {
return YGNodeNewWithConfig(&gYGConfigDefaults);
}
void YGNodeFree(const YGNodeRef node) {
if (node->parent) {
YGNodeListDelete(node->parent->children, node);
@ -331,13 +348,27 @@ void YGNodeReset(const YGNodeRef node) {
YG_ASSERT(node->parent == NULL, "Cannot reset a node still attached to a parent");
YGNodeListFree(node->children);
const YGConfigRef config = node->config;
memcpy(node, &gYGNodeDefaults, sizeof(YGNode));
node->config = config;
}
int32_t YGNodeGetInstanceCount(void) {
return gNodeInstanceCount;
}
YGConfigRef YGConfigNew(void) {
const YGConfigRef config = gYGMalloc(sizeof(YGConfig));
YG_ASSERT(config, "Could not allocate memory for config");
memcpy(config, &gYGConfigDefaults, sizeof(YGConfig));
return config;
}
void YGConfigFree(const YGConfigRef config) {
gYGFree(config);
}
static void YGNodeMarkDirtyInternal(const YGNodeRef node) {
if (!node->isDirty) {
node->isDirty = true;
@ -678,7 +709,8 @@ bool YGLayoutNodeInternal(const YGNodeRef node,
const float parentWidth,
const float parentHeight,
const bool performLayout,
const char *reason);
const char *reason,
const YGConfigRef config);
inline bool YGFloatIsUndefined(const float value) {
return isnan(value);
@ -1335,7 +1367,8 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node,
const float parentWidth,
const float parentHeight,
const YGMeasureMode heightMode,
const YGDirection direction) {
const YGDirection direction,
const YGConfigRef config) {
const YGFlexDirection mainAxis = YGFlexDirectionResolve(node->style.flexDirection, direction);
const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
const float mainAxisSize = isMainAxisRow ? width : height;
@ -1354,7 +1387,7 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node,
if (!YGFloatIsUndefined(resolvedFlexBasis) && !YGFloatIsUndefined(mainAxisSize)) {
if (YGFloatIsUndefined(child->layout.computedFlexBasis) ||
(YGIsExperimentalFeatureEnabled(YGExperimentalFeatureWebFlexBasis) &&
(YGConfigIsExperimentalFeatureEnabled(config, YGExperimentalFeatureWebFlexBasis) &&
child->layout.computedFlexBasisGeneration != gCurrentGenerationCount)) {
child->layout.computedFlexBasis =
fmaxf(resolvedFlexBasis, YGNodePaddingAndBorderForAxis(child, mainAxis, parentWidth));
@ -1456,7 +1489,8 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node,
parentWidth,
parentHeight,
false,
"measure");
"measure",
config);
child->layout.computedFlexBasis =
fmaxf(child->layout.measuredDimensions[dim[mainAxis]],
@ -1471,7 +1505,8 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node,
const float width,
const YGMeasureMode widthMode,
const float height,
const YGDirection direction) {
const YGDirection direction,
const YGConfigRef config) {
const YGFlexDirection mainAxis = YGFlexDirectionResolve(node->style.flexDirection, direction);
const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction);
const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
@ -1560,7 +1595,8 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node,
childWidth,
childHeight,
false,
"abs-measure");
"abs-measure",
config);
childWidth = child->layout.measuredDimensions[YGDimensionWidth] +
YGNodeMarginForAxis(child, YGFlexDirectionRow, width);
childHeight = child->layout.measuredDimensions[YGDimensionHeight] +
@ -1576,7 +1612,8 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node,
childWidth,
childHeight,
true,
"abs-layout");
"abs-layout",
config);
if (YGNodeIsTrailingPosDefined(child, mainAxis) && !YGNodeIsLeadingPosDefined(child, mainAxis)) {
child->layout.position[leading[mainAxis]] = node->layout.measuredDimensions[dim[mainAxis]] -
@ -1854,7 +1891,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
const YGMeasureMode heightMeasureMode,
const float parentWidth,
const float parentHeight,
const bool performLayout) {
const bool performLayout,
const YGConfigRef config) {
YG_ASSERT(YGFloatIsUndefined(availableWidth) ? widthMeasureMode == YGMeasureModeUndefined : true,
"availableWidth is indefinite so widthMeasureMode must be "
"YGMeasureModeUndefined");
@ -2056,7 +2094,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
availableInnerWidth,
availableInnerHeight,
heightMeasureMode,
direction);
direction,
config);
}
}
@ -2173,7 +2212,7 @@ static void YGNodelayoutImpl(const YGNodeRef node,
availableInnerMainDim = minInnerMainDim;
} else if (!YGFloatIsUndefined(maxInnerMainDim) && sizeConsumedOnCurrentLine > maxInnerMainDim) {
availableInnerMainDim = maxInnerMainDim;
} else if (YGIsExperimentalFeatureEnabled(YGExperimentalFeatureMinFlexFix)) {
} else if (YGConfigIsExperimentalFeatureEnabled(config, YGExperimentalFeatureMinFlexFix)) {
// TODO: this needs to be moved out of experimental feature, as this is legitimate fix
// If the measurement isn't exact, we want to use as little space as possible
availableInnerMainDim = sizeConsumedOnCurrentLine;
@ -2422,7 +2461,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
availableInnerWidth,
availableInnerHeight,
performLayout && !requiresStretchLayout,
"flex");
"flex",
config);
currentRelativeChild = currentRelativeChild->nextChild;
}
@ -2660,7 +2700,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
availableInnerWidth,
availableInnerHeight,
true,
"stretch");
"stretch",
config);
}
} else {
const float remainingCrossDim =
@ -2827,7 +2868,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
availableInnerWidth,
availableInnerHeight,
true,
"stretch");
"stretch",
config);
}
}
break;
@ -2915,7 +2957,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
availableInnerWidth,
isMainAxisRow ? measureModeMainDim : measureModeCrossDim,
availableInnerHeight,
direction);
direction,
config);
}
// STEP 11: SETTING TRAILING POSITIONS FOR CHILDREN
@ -3057,7 +3100,8 @@ bool YGLayoutNodeInternal(const YGNodeRef node,
const float parentWidth,
const float parentHeight,
const bool performLayout,
const char *reason) {
const char *reason,
const YGConfigRef config) {
YGLayout *layout = &node->layout;
gDepth++;
@ -3186,7 +3230,8 @@ bool YGLayoutNodeInternal(const YGNodeRef node,
heightMeasureMode,
parentWidth,
parentHeight,
performLayout);
performLayout,
config);
if (gPrintChanges) {
printf("%s%d.}%s", YGSpacer(gDepth), gDepth, needToVisitNode ? "*" : "");
@ -3352,11 +3397,11 @@ void YGNodeCalculateLayout(const YGNodeRef node,
parentWidth,
parentHeight,
true,
"initia"
"l")) {
YGNodeSetPosition(node, node->layout.direction, node->layout.dimensions[YGDimensionWidth], node->layout.dimensions[YGDimensionHeight], parentWidth);
"initial",
node->config)) {
YGNodeSetPosition(node, node->layout.direction, parentWidth, parentHeight, parentWidth);
if (YGIsExperimentalFeatureEnabled(YGExperimentalFeatureRounding)) {
if (YGConfigIsExperimentalFeatureEnabled(node->config, YGExperimentalFeatureRounding)) {
YGRoundToPixelGrid(node);
}
@ -3377,14 +3422,15 @@ void YGLog(YGLogLevel level, const char *format, ...) {
va_end(args);
}
static bool experimentalFeatures[YGExperimentalFeatureCount + 1];
void YGSetExperimentalFeatureEnabled(YGExperimentalFeature feature, bool enabled) {
experimentalFeatures[feature] = enabled;
void YGConfigSetExperimentalFeatureEnabled(const YGConfigRef config,
const YGExperimentalFeature feature,
const bool enabled) {
config->experimentalFeatures[feature] = enabled;
}
inline bool YGIsExperimentalFeatureEnabled(YGExperimentalFeature feature) {
return experimentalFeatures[feature];
inline bool YGConfigIsExperimentalFeatureEnabled(const YGConfigRef config,
const YGExperimentalFeature feature) {
return config->experimentalFeatures[feature];
}
void YGSetMemoryFuncs(YGMalloc ygmalloc, YGCalloc yccalloc, YGRealloc ygrealloc, YGFree ygfree) {

View File

@ -46,6 +46,7 @@ typedef struct YGValue {
static const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined};
static const YGValue YGValueAuto = {YGUndefined, YGUnitAuto};
typedef struct YGConfig *YGConfigRef;
typedef struct YGNode *YGNodeRef;
typedef YGSize (*YGMeasureFunc)(YGNodeRef node,
float width,
@ -63,6 +64,7 @@ typedef void (*YGFree)(void *ptr);
// YGNode
WIN_EXPORT YGNodeRef YGNodeNew(void);
WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config);
WIN_EXPORT void YGNodeFree(const YGNodeRef node);
WIN_EXPORT void YGNodeFreeRecursive(const YGNodeRef node);
WIN_EXPORT void YGNodeReset(const YGNodeRef node);
@ -223,8 +225,15 @@ WIN_EXPORT void YGLog(YGLogLevel level, const char *message, ...);
// If you want to avoid rounding - set PointScaleFactor to 0
WIN_EXPORT void YGSetPointScaleFactor(float pixelsInPoint);
WIN_EXPORT void YGSetExperimentalFeatureEnabled(YGExperimentalFeature feature, bool enabled);
WIN_EXPORT bool YGIsExperimentalFeatureEnabled(YGExperimentalFeature feature);
// YGConfig
WIN_EXPORT YGConfigRef YGConfigNew(void);
WIN_EXPORT void YGConfigFree(const YGConfigRef config);
WIN_EXPORT void YGConfigSetExperimentalFeatureEnabled(const YGConfigRef config,
const YGExperimentalFeature feature,
const bool enabled);
WIN_EXPORT bool YGConfigIsExperimentalFeatureEnabled(const YGConfigRef config,
const YGExperimentalFeature feature);
WIN_EXPORT void
YGSetMemoryFuncs(YGMalloc ygmalloc, YGCalloc yccalloc, YGRealloc ygrealloc, YGFree ygfree);