Remove legacy absolute positioning path (#1725)
Summary: X-link: https://github.com/facebook/react-native/pull/46984 Pull Request resolved: https://github.com/facebook/yoga/pull/1725 The legacy (wrong) absolute positioning path positions in two places, including work that is definitely always overwritten in the new absolute layout path. This came up before for position: static, but we didn't clean this up at the time. This code is also now leading display: contents impl being more annoying. This diff tries to converge to the more spec correct implementation of positioning here, that also only happens in one place. Previous path would potentially also incorrectly justify when `justify-content` was non-default, but not handled in the previous few cases? We don't have access to the flexLine at this point later, and apart from the existing tests now passing I reused the new correct logic for justification (spec says we should position child as if its the only child in the container https://www.w3.org/TR/css-flexbox-1/#abspos-items). I added a new, more scoped errata `AbsolutePositionWithoutInsetsExcludesPadding` to preserve some of the legacy behavior that showed as very breaking. I also did not try removing `AbsolutePercentAgainstInnerSize` which I suspect would be more breaking than this change. Changelog: [General][Breaking] - More spec compliant absolute positioning Reviewed By: joevilches Differential Revision: D64244949 fbshipit-source-id: ca97570e0de82e8f0424a0912adfd0b05254559e
This commit is contained in:
committed by
Facebook GitHub Bot
parent
43be5888c4
commit
568718242d
7
enums.py
7
enums.py
@@ -61,9 +61,10 @@ ENUMS = {
|
|||||||
# Allows main-axis flex basis to be stretched without flexGrow being
|
# Allows main-axis flex basis to be stretched without flexGrow being
|
||||||
# set (previously referred to as "UseLegacyStretchBehaviour")
|
# set (previously referred to as "UseLegacyStretchBehaviour")
|
||||||
("StretchFlexBasis", 1 << 0),
|
("StretchFlexBasis", 1 << 0),
|
||||||
# Positioning of absolute nodes will have various bugs related to
|
# Absolute position in a given axis will be relative to the padding
|
||||||
# justification, alignment, and insets
|
# edge of the parent container instead of the content edge when a
|
||||||
("AbsolutePositioningIncorrect", 1 << 1),
|
# specific inset (top/bottom/left/right) is not set.
|
||||||
|
("AbsolutePositionWithoutInsetsExcludesPadding", 1 << 1),
|
||||||
# Absolute nodes will resolve percentages against the inner size of
|
# Absolute nodes will resolve percentages against the inner size of
|
||||||
# their containing node, not the padding box
|
# their containing node, not the padding box
|
||||||
("AbsolutePercentAgainstInnerSize", 1 << 2),
|
("AbsolutePercentAgainstInnerSize", 1 << 2),
|
||||||
|
@@ -12,7 +12,7 @@ package com.facebook.yoga;
|
|||||||
public enum YogaErrata {
|
public enum YogaErrata {
|
||||||
NONE(0),
|
NONE(0),
|
||||||
STRETCH_FLEX_BASIS(1),
|
STRETCH_FLEX_BASIS(1),
|
||||||
ABSOLUTE_POSITIONING_INCORRECT(2),
|
ABSOLUTE_POSITION_WITHOUT_INSETS_EXCLUDES_PADDING(2),
|
||||||
ABSOLUTE_PERCENT_AGAINST_INNER_SIZE(4),
|
ABSOLUTE_PERCENT_AGAINST_INNER_SIZE(4),
|
||||||
ALL(2147483647),
|
ALL(2147483647),
|
||||||
CLASSIC(2147483646);
|
CLASSIC(2147483646);
|
||||||
@@ -31,7 +31,7 @@ public enum YogaErrata {
|
|||||||
switch (value) {
|
switch (value) {
|
||||||
case 0: return NONE;
|
case 0: return NONE;
|
||||||
case 1: return STRETCH_FLEX_BASIS;
|
case 1: return STRETCH_FLEX_BASIS;
|
||||||
case 2: return ABSOLUTE_POSITIONING_INCORRECT;
|
case 2: return ABSOLUTE_POSITION_WITHOUT_INSETS_EXCLUDES_PADDING;
|
||||||
case 4: return ABSOLUTE_PERCENT_AGAINST_INNER_SIZE;
|
case 4: return ABSOLUTE_PERCENT_AGAINST_INNER_SIZE;
|
||||||
case 2147483647: return ALL;
|
case 2147483647: return ALL;
|
||||||
case 2147483646: return CLASSIC;
|
case 2147483646: return CLASSIC;
|
||||||
|
@@ -55,7 +55,7 @@ export enum Edge {
|
|||||||
export enum Errata {
|
export enum Errata {
|
||||||
None = 0,
|
None = 0,
|
||||||
StretchFlexBasis = 1,
|
StretchFlexBasis = 1,
|
||||||
AbsolutePositioningIncorrect = 2,
|
AbsolutePositionWithoutInsetsExcludesPadding = 2,
|
||||||
AbsolutePercentAgainstInnerSize = 4,
|
AbsolutePercentAgainstInnerSize = 4,
|
||||||
All = 2147483647,
|
All = 2147483647,
|
||||||
Classic = 2147483646,
|
Classic = 2147483646,
|
||||||
@@ -162,7 +162,7 @@ const constants = {
|
|||||||
EDGE_ALL: Edge.All,
|
EDGE_ALL: Edge.All,
|
||||||
ERRATA_NONE: Errata.None,
|
ERRATA_NONE: Errata.None,
|
||||||
ERRATA_STRETCH_FLEX_BASIS: Errata.StretchFlexBasis,
|
ERRATA_STRETCH_FLEX_BASIS: Errata.StretchFlexBasis,
|
||||||
ERRATA_ABSOLUTE_POSITIONING_INCORRECT: Errata.AbsolutePositioningIncorrect,
|
ERRATA_ABSOLUTE_POSITION_WITHOUT_INSETS_EXCLUDES_PADDING: Errata.AbsolutePositionWithoutInsetsExcludesPadding,
|
||||||
ERRATA_ABSOLUTE_PERCENT_AGAINST_INNER_SIZE: Errata.AbsolutePercentAgainstInnerSize,
|
ERRATA_ABSOLUTE_PERCENT_AGAINST_INNER_SIZE: Errata.AbsolutePercentAgainstInnerSize,
|
||||||
ERRATA_ALL: Errata.All,
|
ERRATA_ALL: Errata.All,
|
||||||
ERRATA_CLASSIC: Errata.Classic,
|
ERRATA_CLASSIC: Errata.Classic,
|
||||||
|
@@ -105,8 +105,8 @@ const char* YGErrataToString(const YGErrata value) {
|
|||||||
return "none";
|
return "none";
|
||||||
case YGErrataStretchFlexBasis:
|
case YGErrataStretchFlexBasis:
|
||||||
return "stretch-flex-basis";
|
return "stretch-flex-basis";
|
||||||
case YGErrataAbsolutePositioningIncorrect:
|
case YGErrataAbsolutePositionWithoutInsetsExcludesPadding:
|
||||||
return "absolute-positioning-incorrect";
|
return "absolute-position-without-insets-excludes-padding";
|
||||||
case YGErrataAbsolutePercentAgainstInnerSize:
|
case YGErrataAbsolutePercentAgainstInnerSize:
|
||||||
return "absolute-percent-against-inner-size";
|
return "absolute-percent-against-inner-size";
|
||||||
case YGErrataAll:
|
case YGErrataAll:
|
||||||
|
@@ -61,7 +61,7 @@ YG_ENUM_DECL(
|
|||||||
YGErrata,
|
YGErrata,
|
||||||
YGErrataNone = 0,
|
YGErrataNone = 0,
|
||||||
YGErrataStretchFlexBasis = 1,
|
YGErrataStretchFlexBasis = 1,
|
||||||
YGErrataAbsolutePositioningIncorrect = 2,
|
YGErrataAbsolutePositionWithoutInsetsExcludesPadding = 2,
|
||||||
YGErrataAbsolutePercentAgainstInnerSize = 4,
|
YGErrataAbsolutePercentAgainstInnerSize = 4,
|
||||||
YGErrataAll = 2147483647,
|
YGErrataAll = 2147483647,
|
||||||
YGErrataClassic = 2147483646)
|
YGErrataClassic = 2147483646)
|
||||||
|
@@ -19,12 +19,15 @@ static inline void setFlexStartLayoutPosition(
|
|||||||
const Direction direction,
|
const Direction direction,
|
||||||
const FlexDirection axis,
|
const FlexDirection axis,
|
||||||
const float containingBlockWidth) {
|
const float containingBlockWidth) {
|
||||||
child->setLayoutPosition(
|
float position = child->style().computeFlexStartMargin(
|
||||||
child->style().computeFlexStartMargin(
|
axis, direction, containingBlockWidth) +
|
||||||
axis, direction, containingBlockWidth) +
|
parent->getLayout().border(flexStartEdge(axis));
|
||||||
parent->getLayout().border(flexStartEdge(axis)) +
|
|
||||||
parent->getLayout().padding(flexStartEdge(axis)),
|
if (!child->hasErrata(Errata::AbsolutePositionWithoutInsetsExcludesPadding)) {
|
||||||
flexStartEdge(axis));
|
position += parent->getLayout().padding(flexStartEdge(axis));
|
||||||
|
}
|
||||||
|
|
||||||
|
child->setLayoutPosition(position, flexStartEdge(axis));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void setFlexEndLayoutPosition(
|
static inline void setFlexEndLayoutPosition(
|
||||||
@@ -33,15 +36,16 @@ static inline void setFlexEndLayoutPosition(
|
|||||||
const Direction direction,
|
const Direction direction,
|
||||||
const FlexDirection axis,
|
const FlexDirection axis,
|
||||||
const float containingBlockWidth) {
|
const float containingBlockWidth) {
|
||||||
|
float flexEndPosition = parent->getLayout().border(flexEndEdge(axis)) +
|
||||||
|
child->style().computeFlexEndMargin(
|
||||||
|
axis, direction, containingBlockWidth);
|
||||||
|
|
||||||
|
if (!child->hasErrata(Errata::AbsolutePositionWithoutInsetsExcludesPadding)) {
|
||||||
|
flexEndPosition += parent->getLayout().padding(flexEndEdge(axis));
|
||||||
|
}
|
||||||
|
|
||||||
child->setLayoutPosition(
|
child->setLayoutPosition(
|
||||||
getPositionOfOppositeEdge(
|
getPositionOfOppositeEdge(flexEndPosition, axis, parent, child),
|
||||||
parent->getLayout().border(flexEndEdge(axis)) +
|
|
||||||
parent->getLayout().padding(flexEndEdge(axis)) +
|
|
||||||
child->style().computeFlexEndMargin(
|
|
||||||
axis, direction, containingBlockWidth),
|
|
||||||
axis,
|
|
||||||
parent,
|
|
||||||
child),
|
|
||||||
flexStartEdge(axis));
|
flexStartEdge(axis));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,22 +55,30 @@ static inline void setCenterLayoutPosition(
|
|||||||
const Direction direction,
|
const Direction direction,
|
||||||
const FlexDirection axis,
|
const FlexDirection axis,
|
||||||
const float containingBlockWidth) {
|
const float containingBlockWidth) {
|
||||||
const float parentContentBoxSize =
|
float parentContentBoxSize =
|
||||||
parent->getLayout().measuredDimension(dimension(axis)) -
|
parent->getLayout().measuredDimension(dimension(axis)) -
|
||||||
parent->getLayout().border(flexStartEdge(axis)) -
|
parent->getLayout().border(flexStartEdge(axis)) -
|
||||||
parent->getLayout().border(flexEndEdge(axis)) -
|
parent->getLayout().border(flexEndEdge(axis));
|
||||||
parent->getLayout().padding(flexStartEdge(axis)) -
|
|
||||||
parent->getLayout().padding(flexEndEdge(axis));
|
if (!child->hasErrata(Errata::AbsolutePositionWithoutInsetsExcludesPadding)) {
|
||||||
|
parentContentBoxSize -= parent->getLayout().padding(flexStartEdge(axis));
|
||||||
|
parentContentBoxSize -= parent->getLayout().padding(flexEndEdge(axis));
|
||||||
|
}
|
||||||
|
|
||||||
const float childOuterSize =
|
const float childOuterSize =
|
||||||
child->getLayout().measuredDimension(dimension(axis)) +
|
child->getLayout().measuredDimension(dimension(axis)) +
|
||||||
child->style().computeMarginForAxis(axis, containingBlockWidth);
|
child->style().computeMarginForAxis(axis, containingBlockWidth);
|
||||||
child->setLayoutPosition(
|
|
||||||
(parentContentBoxSize - childOuterSize) / 2.0f +
|
float position = (parentContentBoxSize - childOuterSize) / 2.0f +
|
||||||
parent->getLayout().border(flexStartEdge(axis)) +
|
parent->getLayout().border(flexStartEdge(axis)) +
|
||||||
parent->getLayout().padding(flexStartEdge(axis)) +
|
child->style().computeFlexStartMargin(
|
||||||
child->style().computeFlexStartMargin(
|
axis, direction, containingBlockWidth);
|
||||||
axis, direction, containingBlockWidth),
|
|
||||||
flexStartEdge(axis));
|
if (!child->hasErrata(Errata::AbsolutePositionWithoutInsetsExcludesPadding)) {
|
||||||
|
position += parent->getLayout().padding(flexStartEdge(axis));
|
||||||
|
}
|
||||||
|
|
||||||
|
child->setLayoutPosition(position, flexStartEdge(axis));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void justifyAbsoluteChild(
|
static void justifyAbsoluteChild(
|
||||||
@@ -133,62 +145,6 @@ static void alignAbsoluteChild(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// To ensure no breaking changes, we preserve the legacy way of positioning
|
|
||||||
// absolute children and determine if we should use it using an errata.
|
|
||||||
static void positionAbsoluteChildLegacy(
|
|
||||||
const yoga::Node* const containingNode,
|
|
||||||
const yoga::Node* const parent,
|
|
||||||
yoga::Node* child,
|
|
||||||
const Direction direction,
|
|
||||||
const FlexDirection axis,
|
|
||||||
const bool isMainAxis,
|
|
||||||
const float containingBlockWidth,
|
|
||||||
const float containingBlockHeight) {
|
|
||||||
const bool isAxisRow = isRow(axis);
|
|
||||||
const bool shouldCenter = isMainAxis
|
|
||||||
? parent->style().justifyContent() == Justify::Center
|
|
||||||
: resolveChildAlignment(parent, child) == Align::Center;
|
|
||||||
const bool shouldFlexEnd = isMainAxis
|
|
||||||
? parent->style().justifyContent() == Justify::FlexEnd
|
|
||||||
: ((resolveChildAlignment(parent, child) == Align::FlexEnd) ^
|
|
||||||
(parent->style().flexWrap() == Wrap::WrapReverse));
|
|
||||||
|
|
||||||
if (child->style().isFlexEndPositionDefined(axis, direction) &&
|
|
||||||
(!child->style().isFlexStartPositionDefined(axis, direction) ||
|
|
||||||
child->style().isFlexStartPositionAuto(axis, direction))) {
|
|
||||||
child->setLayoutPosition(
|
|
||||||
containingNode->getLayout().measuredDimension(dimension(axis)) -
|
|
||||||
child->getLayout().measuredDimension(dimension(axis)) -
|
|
||||||
containingNode->style().computeFlexEndBorder(axis, direction) -
|
|
||||||
child->style().computeFlexEndMargin(
|
|
||||||
axis,
|
|
||||||
direction,
|
|
||||||
isAxisRow ? containingBlockWidth : containingBlockHeight) -
|
|
||||||
child->style().computeFlexEndPosition(
|
|
||||||
axis,
|
|
||||||
direction,
|
|
||||||
isAxisRow ? containingBlockWidth : containingBlockHeight),
|
|
||||||
flexStartEdge(axis));
|
|
||||||
} else if (
|
|
||||||
(!child->style().isFlexStartPositionDefined(axis, direction) ||
|
|
||||||
child->style().isFlexStartPositionAuto(axis, direction)) &&
|
|
||||||
shouldCenter) {
|
|
||||||
child->setLayoutPosition(
|
|
||||||
(parent->getLayout().measuredDimension(dimension(axis)) -
|
|
||||||
child->getLayout().measuredDimension(dimension(axis))) /
|
|
||||||
2.0f,
|
|
||||||
flexStartEdge(axis));
|
|
||||||
} else if (
|
|
||||||
(!child->style().isFlexStartPositionDefined(axis, direction) ||
|
|
||||||
child->style().isFlexStartPositionAuto(axis, direction)) &&
|
|
||||||
shouldFlexEnd) {
|
|
||||||
child->setLayoutPosition(
|
|
||||||
(parent->getLayout().measuredDimension(dimension(axis)) -
|
|
||||||
child->getLayout().measuredDimension(dimension(axis))),
|
|
||||||
flexStartEdge(axis));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Absolutely positioned nodes do not participate in flex layout and thus their
|
* Absolutely positioned nodes do not participate in flex layout and thus their
|
||||||
* positions can be determined independently from the rest of their siblings.
|
* positions can be determined independently from the rest of their siblings.
|
||||||
@@ -205,7 +161,7 @@ static void positionAbsoluteChildLegacy(
|
|||||||
* This function does that positioning for the given axis. The spec has more
|
* This function does that positioning for the given axis. The spec has more
|
||||||
* information on this topic: https://www.w3.org/TR/css-flexbox-1/#abspos-items
|
* information on this topic: https://www.w3.org/TR/css-flexbox-1/#abspos-items
|
||||||
*/
|
*/
|
||||||
static void positionAbsoluteChildImpl(
|
static void positionAbsoluteChild(
|
||||||
const yoga::Node* const containingNode,
|
const yoga::Node* const containingNode,
|
||||||
const yoga::Node* const parent,
|
const yoga::Node* const parent,
|
||||||
yoga::Node* child,
|
yoga::Node* child,
|
||||||
@@ -267,36 +223,6 @@ static void positionAbsoluteChildImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void positionAbsoluteChild(
|
|
||||||
const yoga::Node* const containingNode,
|
|
||||||
const yoga::Node* const parent,
|
|
||||||
yoga::Node* child,
|
|
||||||
const Direction direction,
|
|
||||||
const FlexDirection axis,
|
|
||||||
const bool isMainAxis,
|
|
||||||
const float containingBlockWidth,
|
|
||||||
const float containingBlockHeight) {
|
|
||||||
child->hasErrata(Errata::AbsolutePositioningIncorrect)
|
|
||||||
? positionAbsoluteChildLegacy(
|
|
||||||
containingNode,
|
|
||||||
parent,
|
|
||||||
child,
|
|
||||||
direction,
|
|
||||||
axis,
|
|
||||||
isMainAxis,
|
|
||||||
containingBlockWidth,
|
|
||||||
containingBlockHeight)
|
|
||||||
: positionAbsoluteChildImpl(
|
|
||||||
containingNode,
|
|
||||||
parent,
|
|
||||||
child,
|
|
||||||
direction,
|
|
||||||
axis,
|
|
||||||
isMainAxis,
|
|
||||||
containingBlockWidth,
|
|
||||||
containingBlockHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
void layoutAbsoluteChild(
|
void layoutAbsoluteChild(
|
||||||
const yoga::Node* const containingNode,
|
const yoga::Node* const containingNode,
|
||||||
const yoga::Node* const node,
|
const yoga::Node* const node,
|
||||||
|
@@ -981,7 +981,6 @@ static void resolveFlexibleLength(
|
|||||||
static void justifyMainAxis(
|
static void justifyMainAxis(
|
||||||
yoga::Node* const node,
|
yoga::Node* const node,
|
||||||
FlexLine& flexLine,
|
FlexLine& flexLine,
|
||||||
const size_t startOfLineIndex,
|
|
||||||
const FlexDirection mainAxis,
|
const FlexDirection mainAxis,
|
||||||
const FlexDirection crossAxis,
|
const FlexDirection crossAxis,
|
||||||
const Direction direction,
|
const Direction direction,
|
||||||
@@ -1081,102 +1080,69 @@ static void justifyMainAxis(
|
|||||||
float maxAscentForCurrentLine = 0;
|
float maxAscentForCurrentLine = 0;
|
||||||
float maxDescentForCurrentLine = 0;
|
float maxDescentForCurrentLine = 0;
|
||||||
bool isNodeBaselineLayout = isBaselineLayout(node);
|
bool isNodeBaselineLayout = isBaselineLayout(node);
|
||||||
for (size_t i = startOfLineIndex; i < flexLine.endOfLineIndex; i++) {
|
for (auto child : flexLine.itemsInFlow) {
|
||||||
const auto child = node->getChild(i);
|
|
||||||
const Style& childStyle = child->style();
|
|
||||||
const LayoutResults& childLayout = child->getLayout();
|
const LayoutResults& childLayout = child->getLayout();
|
||||||
if (childStyle.display() == Display::None) {
|
if (child->style().flexStartMarginIsAuto(mainAxis, direction) &&
|
||||||
continue;
|
flexLine.layout.remainingFreeSpace > 0.0f) {
|
||||||
|
flexLine.layout.mainDim += flexLine.layout.remainingFreeSpace /
|
||||||
|
static_cast<float>(flexLine.numberOfAutoMargins);
|
||||||
}
|
}
|
||||||
if (childStyle.positionType() == PositionType::Absolute &&
|
|
||||||
child->style().isFlexStartPositionDefined(mainAxis, direction) &&
|
if (performLayout) {
|
||||||
!child->style().isFlexStartPositionAuto(mainAxis, direction)) {
|
child->setLayoutPosition(
|
||||||
if (performLayout) {
|
childLayout.position(flexStartEdge(mainAxis)) +
|
||||||
// In case the child is position absolute and has left/top being
|
flexLine.layout.mainDim,
|
||||||
// defined, we override the position to whatever the user said (and
|
flexStartEdge(mainAxis));
|
||||||
// margin/border).
|
}
|
||||||
child->setLayoutPosition(
|
|
||||||
child->style().computeFlexStartPosition(
|
if (child != flexLine.itemsInFlow.back()) {
|
||||||
mainAxis, direction, availableInnerMainDim) +
|
flexLine.layout.mainDim += betweenMainDim;
|
||||||
node->style().computeFlexStartBorder(mainAxis, direction) +
|
}
|
||||||
child->style().computeFlexStartMargin(
|
|
||||||
mainAxis, direction, availableInnerWidth),
|
if (child->style().flexEndMarginIsAuto(mainAxis, direction) &&
|
||||||
flexStartEdge(mainAxis));
|
flexLine.layout.remainingFreeSpace > 0.0f) {
|
||||||
}
|
flexLine.layout.mainDim += flexLine.layout.remainingFreeSpace /
|
||||||
|
static_cast<float>(flexLine.numberOfAutoMargins);
|
||||||
|
}
|
||||||
|
bool canSkipFlex =
|
||||||
|
!performLayout && sizingModeCrossDim == SizingMode::StretchFit;
|
||||||
|
if (canSkipFlex) {
|
||||||
|
// If we skipped the flex step, then we can't rely on the measuredDims
|
||||||
|
// because they weren't computed. This means we can't call
|
||||||
|
// dimensionWithMargin.
|
||||||
|
flexLine.layout.mainDim +=
|
||||||
|
child->style().computeMarginForAxis(mainAxis, availableInnerWidth) +
|
||||||
|
childLayout.computedFlexBasis.unwrap();
|
||||||
|
flexLine.layout.crossDim = availableInnerCrossDim;
|
||||||
} else {
|
} else {
|
||||||
// Now that we placed the element, we need to update the variables.
|
// The main dimension is the sum of all the elements dimension plus
|
||||||
// We need to do that only for relative elements. Absolute elements do not
|
// the spacing.
|
||||||
// take part in that phase.
|
flexLine.layout.mainDim +=
|
||||||
if (childStyle.positionType() != PositionType::Absolute) {
|
child->dimensionWithMargin(mainAxis, availableInnerWidth);
|
||||||
if (child->style().flexStartMarginIsAuto(mainAxis, direction) &&
|
|
||||||
flexLine.layout.remainingFreeSpace > 0.0f) {
|
|
||||||
flexLine.layout.mainDim += flexLine.layout.remainingFreeSpace /
|
|
||||||
static_cast<float>(flexLine.numberOfAutoMargins);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (performLayout) {
|
if (isNodeBaselineLayout) {
|
||||||
child->setLayoutPosition(
|
// If the child is baseline aligned then the cross dimension is
|
||||||
childLayout.position(flexStartEdge(mainAxis)) +
|
// calculated by adding maxAscent and maxDescent from the baseline.
|
||||||
flexLine.layout.mainDim,
|
const float ascent = calculateBaseline(child) +
|
||||||
flexStartEdge(mainAxis));
|
child->style().computeFlexStartMargin(
|
||||||
}
|
FlexDirection::Column, direction, availableInnerWidth);
|
||||||
|
const float descent =
|
||||||
|
child->getLayout().measuredDimension(Dimension::Height) +
|
||||||
|
child->style().computeMarginForAxis(
|
||||||
|
FlexDirection::Column, availableInnerWidth) -
|
||||||
|
ascent;
|
||||||
|
|
||||||
if (child != flexLine.itemsInFlow.back()) {
|
maxAscentForCurrentLine =
|
||||||
flexLine.layout.mainDim += betweenMainDim;
|
yoga::maxOrDefined(maxAscentForCurrentLine, ascent);
|
||||||
}
|
maxDescentForCurrentLine =
|
||||||
|
yoga::maxOrDefined(maxDescentForCurrentLine, descent);
|
||||||
if (child->style().flexEndMarginIsAuto(mainAxis, direction) &&
|
} else {
|
||||||
flexLine.layout.remainingFreeSpace > 0.0f) {
|
// The cross dimension is the max of the elements dimension since
|
||||||
flexLine.layout.mainDim += flexLine.layout.remainingFreeSpace /
|
// there can only be one element in that cross dimension in the case
|
||||||
static_cast<float>(flexLine.numberOfAutoMargins);
|
// when the items are not baseline aligned
|
||||||
}
|
flexLine.layout.crossDim = yoga::maxOrDefined(
|
||||||
bool canSkipFlex =
|
flexLine.layout.crossDim,
|
||||||
!performLayout && sizingModeCrossDim == SizingMode::StretchFit;
|
child->dimensionWithMargin(crossAxis, availableInnerWidth));
|
||||||
if (canSkipFlex) {
|
|
||||||
// If we skipped the flex step, then we can't rely on the measuredDims
|
|
||||||
// because they weren't computed. This means we can't call
|
|
||||||
// dimensionWithMargin.
|
|
||||||
flexLine.layout.mainDim += child->style().computeMarginForAxis(
|
|
||||||
mainAxis, availableInnerWidth) +
|
|
||||||
childLayout.computedFlexBasis.unwrap();
|
|
||||||
flexLine.layout.crossDim = availableInnerCrossDim;
|
|
||||||
} else {
|
|
||||||
// The main dimension is the sum of all the elements dimension plus
|
|
||||||
// the spacing.
|
|
||||||
flexLine.layout.mainDim +=
|
|
||||||
child->dimensionWithMargin(mainAxis, availableInnerWidth);
|
|
||||||
|
|
||||||
if (isNodeBaselineLayout) {
|
|
||||||
// If the child is baseline aligned then the cross dimension is
|
|
||||||
// calculated by adding maxAscent and maxDescent from the baseline.
|
|
||||||
const float ascent = calculateBaseline(child) +
|
|
||||||
child->style().computeFlexStartMargin(
|
|
||||||
FlexDirection::Column, direction, availableInnerWidth);
|
|
||||||
const float descent =
|
|
||||||
child->getLayout().measuredDimension(Dimension::Height) +
|
|
||||||
child->style().computeMarginForAxis(
|
|
||||||
FlexDirection::Column, availableInnerWidth) -
|
|
||||||
ascent;
|
|
||||||
|
|
||||||
maxAscentForCurrentLine =
|
|
||||||
yoga::maxOrDefined(maxAscentForCurrentLine, ascent);
|
|
||||||
maxDescentForCurrentLine =
|
|
||||||
yoga::maxOrDefined(maxDescentForCurrentLine, descent);
|
|
||||||
} else {
|
|
||||||
// The cross dimension is the max of the elements dimension since
|
|
||||||
// there can only be one element in that cross dimension in the case
|
|
||||||
// when the items are not baseline aligned
|
|
||||||
flexLine.layout.crossDim = yoga::maxOrDefined(
|
|
||||||
flexLine.layout.crossDim,
|
|
||||||
child->dimensionWithMargin(crossAxis, availableInnerWidth));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (performLayout) {
|
|
||||||
child->setLayoutPosition(
|
|
||||||
childLayout.position(flexStartEdge(mainAxis)) +
|
|
||||||
node->style().computeFlexStartBorder(mainAxis, direction) +
|
|
||||||
leadingMainDim,
|
|
||||||
flexStartEdge(mainAxis));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1616,7 +1582,6 @@ static void calculateLayoutImpl(
|
|||||||
justifyMainAxis(
|
justifyMainAxis(
|
||||||
node,
|
node,
|
||||||
flexLine,
|
flexLine,
|
||||||
startOfLineIndex,
|
|
||||||
mainAxis,
|
mainAxis,
|
||||||
crossAxis,
|
crossAxis,
|
||||||
direction,
|
direction,
|
||||||
@@ -1668,151 +1633,116 @@ static void calculateLayoutImpl(
|
|||||||
// STEP 7: CROSS-AXIS ALIGNMENT
|
// STEP 7: CROSS-AXIS ALIGNMENT
|
||||||
// We can skip child alignment if we're just measuring the container.
|
// We can skip child alignment if we're just measuring the container.
|
||||||
if (performLayout) {
|
if (performLayout) {
|
||||||
for (size_t i = startOfLineIndex; i < endOfLineIndex; i++) {
|
for (auto child : flexLine.itemsInFlow) {
|
||||||
const auto child = node->getChild(i);
|
float leadingCrossDim = leadingPaddingAndBorderCross;
|
||||||
if (child->style().display() == Display::None) {
|
|
||||||
continue;
|
// For a relative children, we're either using alignItems (owner) or
|
||||||
}
|
// alignSelf (child) in order to determine the position in the cross
|
||||||
if (child->style().positionType() == PositionType::Absolute) {
|
// axis
|
||||||
// If the child is absolutely positioned and has a
|
const Align alignItem = resolveChildAlignment(node, child);
|
||||||
// top/left/bottom/right set, override all the previously computed
|
|
||||||
// positions to set it correctly.
|
// If the child uses align stretch, we need to lay it out one more
|
||||||
const bool isChildLeadingPosDefined =
|
// time, this time forcing the cross-axis size to be the computed
|
||||||
child->style().isFlexStartPositionDefined(crossAxis, direction) &&
|
// cross size for the current line.
|
||||||
!child->style().isFlexStartPositionAuto(crossAxis, direction);
|
if (alignItem == Align::Stretch &&
|
||||||
if (isChildLeadingPosDefined) {
|
!child->style().flexStartMarginIsAuto(crossAxis, direction) &&
|
||||||
child->setLayoutPosition(
|
!child->style().flexEndMarginIsAuto(crossAxis, direction)) {
|
||||||
child->style().computeFlexStartPosition(
|
// If the child defines a definite size for its cross axis, there's
|
||||||
crossAxis, direction, availableInnerCrossDim) +
|
// no need to stretch.
|
||||||
node->style().computeFlexStartBorder(crossAxis, direction) +
|
if (!child->hasDefiniteLength(
|
||||||
child->style().computeFlexStartMargin(
|
dimension(crossAxis), availableInnerCrossDim)) {
|
||||||
crossAxis, direction, availableInnerWidth),
|
float childMainSize =
|
||||||
flexStartEdge(crossAxis));
|
child->getLayout().measuredDimension(dimension(mainAxis));
|
||||||
}
|
const auto& childStyle = child->style();
|
||||||
// If leading position is not defined or calculations result in Nan,
|
float childCrossSize = childStyle.aspectRatio().isDefined()
|
||||||
// default to border + margin
|
? child->style().computeMarginForAxis(
|
||||||
if (!isChildLeadingPosDefined ||
|
crossAxis, availableInnerWidth) +
|
||||||
yoga::isUndefined(
|
(isMainAxisRow
|
||||||
child->getLayout().position(flexStartEdge(crossAxis)))) {
|
? childMainSize / childStyle.aspectRatio().unwrap()
|
||||||
child->setLayoutPosition(
|
: childMainSize * childStyle.aspectRatio().unwrap())
|
||||||
node->style().computeFlexStartBorder(crossAxis, direction) +
|
: flexLine.layout.crossDim;
|
||||||
child->style().computeFlexStartMargin(
|
|
||||||
crossAxis, direction, availableInnerWidth),
|
childMainSize += child->style().computeMarginForAxis(
|
||||||
flexStartEdge(crossAxis));
|
mainAxis, availableInnerWidth);
|
||||||
|
|
||||||
|
SizingMode childMainSizingMode = SizingMode::StretchFit;
|
||||||
|
SizingMode childCrossSizingMode = SizingMode::StretchFit;
|
||||||
|
constrainMaxSizeForMode(
|
||||||
|
child,
|
||||||
|
direction,
|
||||||
|
mainAxis,
|
||||||
|
availableInnerMainDim,
|
||||||
|
availableInnerWidth,
|
||||||
|
&childMainSizingMode,
|
||||||
|
&childMainSize);
|
||||||
|
constrainMaxSizeForMode(
|
||||||
|
child,
|
||||||
|
direction,
|
||||||
|
crossAxis,
|
||||||
|
availableInnerCrossDim,
|
||||||
|
availableInnerWidth,
|
||||||
|
&childCrossSizingMode,
|
||||||
|
&childCrossSize);
|
||||||
|
|
||||||
|
const float childWidth =
|
||||||
|
isMainAxisRow ? childMainSize : childCrossSize;
|
||||||
|
const float childHeight =
|
||||||
|
!isMainAxisRow ? childMainSize : childCrossSize;
|
||||||
|
|
||||||
|
auto alignContent = node->style().alignContent();
|
||||||
|
auto crossAxisDoesNotGrow =
|
||||||
|
alignContent != Align::Stretch && isNodeFlexWrap;
|
||||||
|
const SizingMode childWidthSizingMode =
|
||||||
|
yoga::isUndefined(childWidth) ||
|
||||||
|
(!isMainAxisRow && crossAxisDoesNotGrow)
|
||||||
|
? SizingMode::MaxContent
|
||||||
|
: SizingMode::StretchFit;
|
||||||
|
const SizingMode childHeightSizingMode =
|
||||||
|
yoga::isUndefined(childHeight) ||
|
||||||
|
(isMainAxisRow && crossAxisDoesNotGrow)
|
||||||
|
? SizingMode::MaxContent
|
||||||
|
: SizingMode::StretchFit;
|
||||||
|
|
||||||
|
calculateLayoutInternal(
|
||||||
|
child,
|
||||||
|
childWidth,
|
||||||
|
childHeight,
|
||||||
|
direction,
|
||||||
|
childWidthSizingMode,
|
||||||
|
childHeightSizingMode,
|
||||||
|
availableInnerWidth,
|
||||||
|
availableInnerHeight,
|
||||||
|
true,
|
||||||
|
LayoutPassReason::kStretch,
|
||||||
|
layoutMarkerData,
|
||||||
|
depth,
|
||||||
|
generationCount);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
float leadingCrossDim = leadingPaddingAndBorderCross;
|
const float remainingCrossDim = containerCrossAxis -
|
||||||
|
child->dimensionWithMargin(crossAxis, availableInnerWidth);
|
||||||
|
|
||||||
// For a relative children, we're either using alignItems (owner) or
|
if (child->style().flexStartMarginIsAuto(crossAxis, direction) &&
|
||||||
// alignSelf (child) in order to determine the position in the cross
|
child->style().flexEndMarginIsAuto(crossAxis, direction)) {
|
||||||
// axis
|
leadingCrossDim += yoga::maxOrDefined(0.0f, remainingCrossDim / 2);
|
||||||
const Align alignItem = resolveChildAlignment(node, child);
|
} else if (child->style().flexEndMarginIsAuto(crossAxis, direction)) {
|
||||||
|
// No-Op
|
||||||
// If the child uses align stretch, we need to lay it out one more
|
} else if (child->style().flexStartMarginIsAuto(
|
||||||
// time, this time forcing the cross-axis size to be the computed
|
crossAxis, direction)) {
|
||||||
// cross size for the current line.
|
leadingCrossDim += yoga::maxOrDefined(0.0f, remainingCrossDim);
|
||||||
if (alignItem == Align::Stretch &&
|
} else if (alignItem == Align::FlexStart) {
|
||||||
!child->style().flexStartMarginIsAuto(crossAxis, direction) &&
|
// No-Op
|
||||||
!child->style().flexEndMarginIsAuto(crossAxis, direction)) {
|
} else if (alignItem == Align::Center) {
|
||||||
// If the child defines a definite size for its cross axis, there's
|
leadingCrossDim += remainingCrossDim / 2;
|
||||||
// no need to stretch.
|
|
||||||
if (!child->hasDefiniteLength(
|
|
||||||
dimension(crossAxis), availableInnerCrossDim)) {
|
|
||||||
float childMainSize =
|
|
||||||
child->getLayout().measuredDimension(dimension(mainAxis));
|
|
||||||
const auto& childStyle = child->style();
|
|
||||||
float childCrossSize = childStyle.aspectRatio().isDefined()
|
|
||||||
? child->style().computeMarginForAxis(
|
|
||||||
crossAxis, availableInnerWidth) +
|
|
||||||
(isMainAxisRow
|
|
||||||
? childMainSize / childStyle.aspectRatio().unwrap()
|
|
||||||
: childMainSize * childStyle.aspectRatio().unwrap())
|
|
||||||
: flexLine.layout.crossDim;
|
|
||||||
|
|
||||||
childMainSize += child->style().computeMarginForAxis(
|
|
||||||
mainAxis, availableInnerWidth);
|
|
||||||
|
|
||||||
SizingMode childMainSizingMode = SizingMode::StretchFit;
|
|
||||||
SizingMode childCrossSizingMode = SizingMode::StretchFit;
|
|
||||||
constrainMaxSizeForMode(
|
|
||||||
child,
|
|
||||||
direction,
|
|
||||||
mainAxis,
|
|
||||||
availableInnerMainDim,
|
|
||||||
availableInnerWidth,
|
|
||||||
&childMainSizingMode,
|
|
||||||
&childMainSize);
|
|
||||||
constrainMaxSizeForMode(
|
|
||||||
child,
|
|
||||||
direction,
|
|
||||||
crossAxis,
|
|
||||||
availableInnerCrossDim,
|
|
||||||
availableInnerWidth,
|
|
||||||
&childCrossSizingMode,
|
|
||||||
&childCrossSize);
|
|
||||||
|
|
||||||
const float childWidth =
|
|
||||||
isMainAxisRow ? childMainSize : childCrossSize;
|
|
||||||
const float childHeight =
|
|
||||||
!isMainAxisRow ? childMainSize : childCrossSize;
|
|
||||||
|
|
||||||
auto alignContent = node->style().alignContent();
|
|
||||||
auto crossAxisDoesNotGrow =
|
|
||||||
alignContent != Align::Stretch && isNodeFlexWrap;
|
|
||||||
const SizingMode childWidthSizingMode =
|
|
||||||
yoga::isUndefined(childWidth) ||
|
|
||||||
(!isMainAxisRow && crossAxisDoesNotGrow)
|
|
||||||
? SizingMode::MaxContent
|
|
||||||
: SizingMode::StretchFit;
|
|
||||||
const SizingMode childHeightSizingMode =
|
|
||||||
yoga::isUndefined(childHeight) ||
|
|
||||||
(isMainAxisRow && crossAxisDoesNotGrow)
|
|
||||||
? SizingMode::MaxContent
|
|
||||||
: SizingMode::StretchFit;
|
|
||||||
|
|
||||||
calculateLayoutInternal(
|
|
||||||
child,
|
|
||||||
childWidth,
|
|
||||||
childHeight,
|
|
||||||
direction,
|
|
||||||
childWidthSizingMode,
|
|
||||||
childHeightSizingMode,
|
|
||||||
availableInnerWidth,
|
|
||||||
availableInnerHeight,
|
|
||||||
true,
|
|
||||||
LayoutPassReason::kStretch,
|
|
||||||
layoutMarkerData,
|
|
||||||
depth,
|
|
||||||
generationCount);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const float remainingCrossDim = containerCrossAxis -
|
leadingCrossDim += remainingCrossDim;
|
||||||
child->dimensionWithMargin(crossAxis, availableInnerWidth);
|
|
||||||
|
|
||||||
if (child->style().flexStartMarginIsAuto(crossAxis, direction) &&
|
|
||||||
child->style().flexEndMarginIsAuto(crossAxis, direction)) {
|
|
||||||
leadingCrossDim +=
|
|
||||||
yoga::maxOrDefined(0.0f, remainingCrossDim / 2);
|
|
||||||
} else if (child->style().flexEndMarginIsAuto(
|
|
||||||
crossAxis, direction)) {
|
|
||||||
// No-Op
|
|
||||||
} else if (child->style().flexStartMarginIsAuto(
|
|
||||||
crossAxis, direction)) {
|
|
||||||
leadingCrossDim += yoga::maxOrDefined(0.0f, remainingCrossDim);
|
|
||||||
} else if (alignItem == Align::FlexStart) {
|
|
||||||
// No-Op
|
|
||||||
} else if (alignItem == Align::Center) {
|
|
||||||
leadingCrossDim += remainingCrossDim / 2;
|
|
||||||
} else {
|
|
||||||
leadingCrossDim += remainingCrossDim;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// And we apply the position
|
|
||||||
child->setLayoutPosition(
|
|
||||||
child->getLayout().position(flexStartEdge(crossAxis)) +
|
|
||||||
totalLineCrossDim + leadingCrossDim,
|
|
||||||
flexStartEdge(crossAxis));
|
|
||||||
}
|
}
|
||||||
|
// And we apply the position
|
||||||
|
child->setLayoutPosition(
|
||||||
|
child->getLayout().position(flexStartEdge(crossAxis)) +
|
||||||
|
totalLineCrossDim + leadingCrossDim,
|
||||||
|
flexStartEdge(crossAxis));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,7 +18,7 @@ namespace facebook::yoga {
|
|||||||
enum class Errata : uint32_t {
|
enum class Errata : uint32_t {
|
||||||
None = YGErrataNone,
|
None = YGErrataNone,
|
||||||
StretchFlexBasis = YGErrataStretchFlexBasis,
|
StretchFlexBasis = YGErrataStretchFlexBasis,
|
||||||
AbsolutePositioningIncorrect = YGErrataAbsolutePositioningIncorrect,
|
AbsolutePositionWithoutInsetsExcludesPadding = YGErrataAbsolutePositionWithoutInsetsExcludesPadding,
|
||||||
AbsolutePercentAgainstInnerSize = YGErrataAbsolutePercentAgainstInnerSize,
|
AbsolutePercentAgainstInnerSize = YGErrataAbsolutePercentAgainstInnerSize,
|
||||||
All = YGErrataAll,
|
All = YGErrataAll,
|
||||||
Classic = YGErrataClassic,
|
Classic = YGErrataClassic,
|
||||||
|
Reference in New Issue
Block a user