Baseline support
Summary: Added baseline support (see #132) You have the ability for a custom baseline function (```float(*YGBaselineFunc)(YGNodeRef node);```) to return whatever baseline you want. Closes https://github.com/facebook/yoga/pull/317 Reviewed By: splhack Differential Revision: D4385061 Pulled By: emilsjolander fbshipit-source-id: cb8a59a09237c840fa3e21753ab68239997dab0c
This commit is contained in:
parent
5d6ce0e4ae
commit
7cfb7b8d0f
|
@ -17,7 +17,8 @@ public enum YogaAlign {
|
||||||
FLEX_START(1),
|
FLEX_START(1),
|
||||||
CENTER(2),
|
CENTER(2),
|
||||||
FLEX_END(3),
|
FLEX_END(3),
|
||||||
STRETCH(4);
|
STRETCH(4),
|
||||||
|
BASELINE(5);
|
||||||
|
|
||||||
private int mIntValue;
|
private int mIntValue;
|
||||||
|
|
||||||
|
@ -36,6 +37,7 @@ public enum YogaAlign {
|
||||||
case 2: return CENTER;
|
case 2: return CENTER;
|
||||||
case 3: return FLEX_END;
|
case 3: return FLEX_END;
|
||||||
case 4: return STRETCH;
|
case 4: return STRETCH;
|
||||||
|
case 5: return BASELINE;
|
||||||
default: throw new IllegalArgumentException("Unkown enum value: " + value);
|
default: throw new IllegalArgumentException("Unkown enum value: " + value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,13 +104,14 @@ typedef enum YGExperimentalFeature {
|
||||||
YGExperimentalFeatureWebFlexBasis,
|
YGExperimentalFeatureWebFlexBasis,
|
||||||
} YGExperimentalFeature;
|
} YGExperimentalFeature;
|
||||||
|
|
||||||
#define YGAlignCount 5
|
#define YGAlignCount 6
|
||||||
typedef enum YGAlign {
|
typedef enum YGAlign {
|
||||||
YGAlignAuto,
|
YGAlignAuto,
|
||||||
YGAlignFlexStart,
|
YGAlignFlexStart,
|
||||||
YGAlignCenter,
|
YGAlignCenter,
|
||||||
YGAlignFlexEnd,
|
YGAlignFlexEnd,
|
||||||
YGAlignStretch,
|
YGAlignStretch,
|
||||||
|
YGAlignBaseline,
|
||||||
} YGAlign;
|
} YGAlign;
|
||||||
|
|
||||||
#define YGUnitCount 3
|
#define YGUnitCount 3
|
||||||
|
|
|
@ -102,6 +102,7 @@ typedef struct YGNode {
|
||||||
struct YGNode *nextChild;
|
struct YGNode *nextChild;
|
||||||
|
|
||||||
YGMeasureFunc measure;
|
YGMeasureFunc measure;
|
||||||
|
YGBaselineFunc baseline;
|
||||||
YGPrintFunc print;
|
YGPrintFunc print;
|
||||||
void *context;
|
void *context;
|
||||||
|
|
||||||
|
@ -337,6 +338,14 @@ YGMeasureFunc YGNodeGetMeasureFunc(const YGNodeRef node) {
|
||||||
return node->measure;
|
return node->measure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void YGNodeSetBaselineFunc(const YGNodeRef node, YGBaselineFunc baselineFunc) {
|
||||||
|
node->baseline = baselineFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
YGBaselineFunc YGNodeGetBaselineFunc(const YGNodeRef node) {
|
||||||
|
return node->baseline;
|
||||||
|
}
|
||||||
|
|
||||||
void YGNodeInsertChild(const YGNodeRef node, const YGNodeRef child, const uint32_t index) {
|
void YGNodeInsertChild(const YGNodeRef node, const YGNodeRef child, const uint32_t index) {
|
||||||
YG_ASSERT(child->parent == NULL, "Child already has a parent, it must be removed first.");
|
YG_ASSERT(child->parent == NULL, "Child already has a parent, it must be removed first.");
|
||||||
YG_ASSERT(node->measure == NULL,
|
YG_ASSERT(node->measure == NULL,
|
||||||
|
@ -954,7 +963,12 @@ static inline float YGNodePaddingAndBorderForAxis(const YGNodeRef node,
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline YGAlign YGNodeAlignItem(const YGNodeRef node, const YGNodeRef child) {
|
static inline YGAlign YGNodeAlignItem(const YGNodeRef node, const YGNodeRef child) {
|
||||||
return child->style.alignSelf == YGAlignAuto ? node->style.alignItems : child->style.alignSelf;
|
const YGAlign align =
|
||||||
|
child->style.alignSelf == YGAlignAuto ? node->style.alignItems : child->style.alignSelf;
|
||||||
|
if (align == YGAlignBaseline && YGFlexDirectionIsColumn(node->style.flexDirection)) {
|
||||||
|
return YGAlignFlexStart;
|
||||||
|
}
|
||||||
|
return align;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline YGDirection YGNodeResolveDirection(const YGNodeRef node,
|
static inline YGDirection YGNodeResolveDirection(const YGNodeRef node,
|
||||||
|
@ -966,6 +980,40 @@ static inline YGDirection YGNodeResolveDirection(const YGNodeRef node,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static float YGBaseline(const YGNodeRef node) {
|
||||||
|
if (node->baseline != NULL) {
|
||||||
|
const float baseline = node->baseline(node, node->layout.measuredDimensions[YGDimensionWidth], node->layout.measuredDimensions[YGDimensionHeight]);
|
||||||
|
YG_ASSERT(!YGFloatIsUndefined(baseline), "Expect custom baseline function to not return NaN")
|
||||||
|
return baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
YGNodeRef baselineChild = NULL;
|
||||||
|
for (uint32_t i = 0; i < YGNodeGetChildCount(node); i++) {
|
||||||
|
const YGNodeRef child = YGNodeGetChild(node, i);
|
||||||
|
if (child->lineIndex > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (child->style.positionType == YGPositionTypeAbsolute) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (YGNodeAlignItem(node, child) == YGAlignBaseline) {
|
||||||
|
baselineChild = child;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baselineChild == NULL) {
|
||||||
|
baselineChild = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baselineChild == NULL) {
|
||||||
|
return node->layout.measuredDimensions[YGDimensionHeight];
|
||||||
|
}
|
||||||
|
|
||||||
|
const float baseline = YGBaseline(baselineChild);
|
||||||
|
return baseline + baselineChild->layout.position[YGEdgeTop];
|
||||||
|
}
|
||||||
|
|
||||||
static inline YGFlexDirection YGFlexDirectionResolve(const YGFlexDirection flexDirection,
|
static inline YGFlexDirection YGFlexDirectionResolve(const YGFlexDirection flexDirection,
|
||||||
const YGDirection direction) {
|
const YGDirection direction) {
|
||||||
if (direction == YGDirectionRTL) {
|
if (direction == YGDirectionRTL) {
|
||||||
|
@ -991,6 +1039,24 @@ static inline bool YGNodeIsFlex(const YGNodeRef node) {
|
||||||
(YGNodeStyleGetFlexGrow(node) != 0 || YGNodeStyleGetFlexShrink(node) != 0));
|
(YGNodeStyleGetFlexGrow(node) != 0 || YGNodeStyleGetFlexShrink(node) != 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool YGIsBaselineLayout(const YGNodeRef node) {
|
||||||
|
if (YGFlexDirectionIsColumn(node->style.flexDirection)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (node->style.alignItems == YGAlignBaseline) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (uint32_t i = 0; i < YGNodeGetChildCount(node); i++) {
|
||||||
|
const YGNodeRef child = YGNodeGetChild(node, i);
|
||||||
|
if (child->style.positionType == YGPositionTypeRelative &&
|
||||||
|
child->style.alignSelf == YGAlignBaseline) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static inline float YGNodeDimWithMargin(const YGNodeRef node,
|
static inline float YGNodeDimWithMargin(const YGNodeRef node,
|
||||||
const YGFlexDirection axis,
|
const YGFlexDirection axis,
|
||||||
const float widthSize) {
|
const float widthSize) {
|
||||||
|
@ -1583,8 +1649,6 @@ static bool YGNodeFixedSizeSetMeasuredDimensions(const YGNodeRef node,
|
||||||
// * Margins cannot be specified as 'auto'. They must be specified in terms of
|
// * Margins cannot be specified as 'auto'. They must be specified in terms of
|
||||||
// pixel
|
// pixel
|
||||||
// values, and the default value is 0.
|
// values, and the default value is 0.
|
||||||
// * The 'baseline' value is not supported for alignItems and alignSelf
|
|
||||||
// properties.
|
|
||||||
// * Values of width, maxWidth, minWidth, height, maxHeight and minHeight must
|
// * Values of width, maxWidth, minWidth, height, maxHeight and minHeight must
|
||||||
// be
|
// be
|
||||||
// specified as pixel values, not as percentages.
|
// specified as pixel values, not as percentages.
|
||||||
|
@ -1680,10 +1744,22 @@ static void YGNodelayoutImpl(const YGNodeRef node,
|
||||||
const YGDirection direction = YGNodeResolveDirection(node, parentDirection);
|
const YGDirection direction = YGNodeResolveDirection(node, parentDirection);
|
||||||
node->layout.direction = direction;
|
node->layout.direction = direction;
|
||||||
|
|
||||||
node->layout.padding[YGEdgeStart] = YGNodeLeadingPadding(node, YGFlexDirectionResolve(YGFlexDirectionRow, direction), parentWidth);
|
node->layout.padding[YGEdgeStart] =
|
||||||
node->layout.padding[YGEdgeEnd] = YGNodeTrailingPadding(node, YGFlexDirectionResolve(YGFlexDirectionRow, direction), parentWidth);
|
YGNodeLeadingPadding(node,
|
||||||
node->layout.padding[YGEdgeTop] = YGNodeLeadingPadding(node, YGFlexDirectionResolve(YGFlexDirectionColumn, direction), parentWidth);
|
YGFlexDirectionResolve(YGFlexDirectionRow, direction),
|
||||||
node->layout.padding[YGEdgeBottom] = YGNodeTrailingPadding(node, YGFlexDirectionResolve(YGFlexDirectionColumn, direction), parentWidth);
|
parentWidth);
|
||||||
|
node->layout.padding[YGEdgeEnd] =
|
||||||
|
YGNodeTrailingPadding(node,
|
||||||
|
YGFlexDirectionResolve(YGFlexDirectionRow, direction),
|
||||||
|
parentWidth);
|
||||||
|
node->layout.padding[YGEdgeTop] =
|
||||||
|
YGNodeLeadingPadding(node,
|
||||||
|
YGFlexDirectionResolve(YGFlexDirectionColumn, direction),
|
||||||
|
parentWidth);
|
||||||
|
node->layout.padding[YGEdgeBottom] =
|
||||||
|
YGNodeTrailingPadding(node,
|
||||||
|
YGFlexDirectionResolve(YGFlexDirectionColumn, direction),
|
||||||
|
parentWidth);
|
||||||
|
|
||||||
if (node->measure) {
|
if (node->measure) {
|
||||||
YGNodeWithMeasureFuncSetMeasuredDimensions(
|
YGNodeWithMeasureFuncSetMeasuredDimensions(
|
||||||
|
@ -2452,7 +2528,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 8: MULTI-LINE CONTENT ALIGNMENT
|
// STEP 8: MULTI-LINE CONTENT ALIGNMENT
|
||||||
if (lineCount > 1 && performLayout && !YGFloatIsUndefined(availableInnerCrossDim)) {
|
if (performLayout && (lineCount > 1 || YGIsBaselineLayout(node)) &&
|
||||||
|
!YGFloatIsUndefined(availableInnerCrossDim)) {
|
||||||
const float remainingAlignContentDim = availableInnerCrossDim - totalLineCrossDim;
|
const float remainingAlignContentDim = availableInnerCrossDim - totalLineCrossDim;
|
||||||
|
|
||||||
float crossDimLead = 0;
|
float crossDimLead = 0;
|
||||||
|
@ -2472,6 +2549,7 @@ static void YGNodelayoutImpl(const YGNodeRef node,
|
||||||
break;
|
break;
|
||||||
case YGAlignAuto:
|
case YGAlignAuto:
|
||||||
case YGAlignFlexStart:
|
case YGAlignFlexStart:
|
||||||
|
case YGAlignBaseline:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2482,6 +2560,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
|
||||||
|
|
||||||
// compute the line's height and find the endIndex
|
// compute the line's height and find the endIndex
|
||||||
float lineHeight = 0;
|
float lineHeight = 0;
|
||||||
|
float maxAscentForCurrentLine = 0;
|
||||||
|
float maxDescentForCurrentLine = 0;
|
||||||
for (ii = startIndex; ii < childCount; ii++) {
|
for (ii = startIndex; ii < childCount; ii++) {
|
||||||
const YGNodeRef child = YGNodeListGet(node->children, ii);
|
const YGNodeRef child = YGNodeListGet(node->children, ii);
|
||||||
|
|
||||||
|
@ -2489,12 +2569,22 @@ static void YGNodelayoutImpl(const YGNodeRef node,
|
||||||
if (child->lineIndex != i) {
|
if (child->lineIndex != i) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (YGNodeIsLayoutDimDefined(child, crossAxis)) {
|
if (YGNodeIsLayoutDimDefined(child, crossAxis)) {
|
||||||
lineHeight = fmaxf(lineHeight,
|
lineHeight = fmaxf(lineHeight,
|
||||||
child->layout.measuredDimensions[dim[crossAxis]] +
|
child->layout.measuredDimensions[dim[crossAxis]] +
|
||||||
YGNodeMarginForAxis(child, crossAxis, availableInnerWidth));
|
YGNodeMarginForAxis(child, crossAxis, availableInnerWidth));
|
||||||
}
|
}
|
||||||
|
if (YGNodeAlignItem(node, child) == YGAlignBaseline) {
|
||||||
|
const float ascent =
|
||||||
|
YGBaseline(child) +
|
||||||
|
YGNodeLeadingMargin(child, YGFlexDirectionColumn, availableInnerWidth);
|
||||||
|
const float descent =
|
||||||
|
child->layout.measuredDimensions[YGDimensionHeight] +
|
||||||
|
YGNodeMarginForAxis(child, YGFlexDirectionColumn, availableInnerWidth) - ascent;
|
||||||
|
maxAscentForCurrentLine = fmaxf(maxAscentForCurrentLine, ascent);
|
||||||
|
maxDescentForCurrentLine = fmaxf(maxDescentForCurrentLine, descent);
|
||||||
|
lineHeight = fmaxf(lineHeight, maxAscentForCurrentLine + maxDescentForCurrentLine);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
endIndex = ii;
|
endIndex = ii;
|
||||||
|
@ -2531,6 +2621,12 @@ static void YGNodelayoutImpl(const YGNodeRef node,
|
||||||
// (auto) crossAxis dimension.
|
// (auto) crossAxis dimension.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case YGAlignBaseline: {
|
||||||
|
child->layout.position[YGEdgeTop] =
|
||||||
|
currentLead + maxAscentForCurrentLine - YGBaseline(child) +
|
||||||
|
YGNodeLeadingPosition(child, YGFlexDirectionColumn, availableInnerCrossDim);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case YGAlignAuto:
|
case YGAlignAuto:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ typedef YGSize (*YGMeasureFunc)(YGNodeRef node,
|
||||||
YGMeasureMode widthMode,
|
YGMeasureMode widthMode,
|
||||||
float height,
|
float height,
|
||||||
YGMeasureMode heightMode);
|
YGMeasureMode heightMode);
|
||||||
|
typedef float (*YGBaselineFunc)(YGNodeRef node, const float width, const float height);
|
||||||
typedef void (*YGPrintFunc)(YGNodeRef node);
|
typedef void (*YGPrintFunc)(YGNodeRef node);
|
||||||
typedef int (*YGLogger)(YGLogLevel level, const char *format, va_list args);
|
typedef int (*YGLogger)(YGLogLevel level, const char *format, va_list args);
|
||||||
|
|
||||||
|
@ -138,6 +139,7 @@ WIN_EXPORT void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode
|
||||||
|
|
||||||
YG_NODE_PROPERTY(void *, Context, context);
|
YG_NODE_PROPERTY(void *, Context, context);
|
||||||
YG_NODE_PROPERTY(YGMeasureFunc, MeasureFunc, measureFunc);
|
YG_NODE_PROPERTY(YGMeasureFunc, MeasureFunc, measureFunc);
|
||||||
|
YG_NODE_PROPERTY(YGBaselineFunc, BaselineFunc, baselineFunc)
|
||||||
YG_NODE_PROPERTY(YGPrintFunc, PrintFunc, printFunc);
|
YG_NODE_PROPERTY(YGPrintFunc, PrintFunc, printFunc);
|
||||||
YG_NODE_PROPERTY(bool, HasNewLayout, hasNewLayout);
|
YG_NODE_PROPERTY(bool, HasNewLayout, hasNewLayout);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue