Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use containing block to adjust absolute child position #41490

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ static void setChildTrailingPosition(
flexEndEdge(axis));
}

static bool needsTrailingPosition(const FlexDirection axis) {
return axis == FlexDirection::RowReverse ||
axis == FlexDirection::ColumnReverse;
}

static void constrainMaxSizeForMode(
const yoga::Node* const node,
const enum FlexDirection axis,
Expand Down Expand Up @@ -314,11 +319,12 @@ static void computeFlexBasisForChild(
}

static void layoutAbsoluteChild(
const yoga::Node* const containingNode,
const yoga::Node* const node,
yoga::Node* const child,
const float width,
const float containingBlockWidth,
const float containingBlockHeight,
const SizingMode widthMode,
const float height,
const Direction direction,
LayoutData& layoutMarkerData,
const uint32_t depth,
Expand All @@ -333,48 +339,65 @@ static void layoutAbsoluteChild(
SizingMode childWidthSizingMode = SizingMode::MaxContent;
SizingMode childHeightSizingMode = SizingMode::MaxContent;

auto marginRow = child->getMarginForAxis(FlexDirection::Row, width);
auto marginColumn = child->getMarginForAxis(FlexDirection::Column, width);
auto marginRow =
child->getMarginForAxis(FlexDirection::Row, containingBlockWidth);
auto marginColumn =
child->getMarginForAxis(FlexDirection::Column, containingBlockWidth);

if (styleDefinesDimension(child, FlexDirection::Row, width)) {
if (styleDefinesDimension(child, FlexDirection::Row, containingBlockWidth)) {
childWidth =
yoga::resolveValue(child->getResolvedDimension(Dimension::Width), width)
yoga::resolveValue(
child->getResolvedDimension(Dimension::Width), containingBlockWidth)
.unwrap() +
marginRow;
} else {
// If the child doesn't have a specified width, compute the width based on
// the left/right offsets if they're defined.
if (child->isInlineStartPositionDefined(FlexDirection::Row, direction) &&
child->isInlineEndPositionDefined(FlexDirection::Row, direction)) {
childWidth = node->getLayout().measuredDimension(Dimension::Width) -
(node->getInlineStartBorder(FlexDirection::Row, direction) +
node->getInlineEndBorder(FlexDirection::Row, direction)) -
(child->getInlineStartPosition(FlexDirection::Row, direction, width) +
child->getInlineEndPosition(FlexDirection::Row, direction, width));
if (child->isFlexStartPositionDefined(FlexDirection::Row) &&
child->isFlexEndPositionDefined(FlexDirection::Row)) {
childWidth =
boundAxis(child, FlexDirection::Row, childWidth, width, width);
containingNode->getLayout().measuredDimension(Dimension::Width) -
(containingNode->getFlexStartBorder(FlexDirection::Row, direction) +
containingNode->getFlexEndBorder(FlexDirection::Row, direction)) -
(child->getFlexStartPosition(
FlexDirection::Row, containingBlockWidth) +
child->getFlexEndPosition(FlexDirection::Row, containingBlockWidth));
childWidth = boundAxis(
child,
FlexDirection::Row,
childWidth,
containingBlockWidth,
containingBlockWidth);
}
}

if (styleDefinesDimension(child, FlexDirection::Column, height)) {
if (styleDefinesDimension(
child, FlexDirection::Column, containingBlockHeight)) {
childHeight = yoga::resolveValue(
child->getResolvedDimension(Dimension::Height), height)
child->getResolvedDimension(Dimension::Height),
containingBlockHeight)
.unwrap() +
marginColumn;
} else {
// If the child doesn't have a specified height, compute the height based on
// the top/bottom offsets if they're defined.
if (child->isInlineStartPositionDefined(FlexDirection::Column, direction) &&
child->isInlineEndPositionDefined(FlexDirection::Column, direction)) {
childHeight = node->getLayout().measuredDimension(Dimension::Height) -
(node->getInlineStartBorder(FlexDirection::Column, direction) +
node->getInlineEndBorder(FlexDirection::Column, direction)) -
(child->getInlineStartPosition(
FlexDirection::Column, direction, height) +
child->getInlineEndPosition(
FlexDirection::Column, direction, height));
if (child->isFlexStartPositionDefined(FlexDirection::Column) &&
child->isFlexEndPositionDefined(FlexDirection::Column)) {
childHeight =
boundAxis(child, FlexDirection::Column, childHeight, height, width);
containingNode->getLayout().measuredDimension(Dimension::Height) -
(containingNode->getFlexStartBorder(
FlexDirection::Column, direction) +
containingNode->getFlexEndBorder(FlexDirection::Column, direction)) -
(child->getFlexStartPosition(
FlexDirection::Column, containingBlockHeight) +
child->getFlexEndPosition(
FlexDirection::Column, containingBlockHeight));
childHeight = boundAxis(
child,
FlexDirection::Column,
childHeight,
containingBlockHeight,
containingBlockWidth);
}
}

Expand Down Expand Up @@ -408,9 +431,9 @@ static void layoutAbsoluteChild(
// wrap to the size of its owner. This is the same behavior as many browsers
// implement.
if (!isMainAxisRow && yoga::isUndefined(childWidth) &&
widthMode != SizingMode::MaxContent && yoga::isDefined(width) &&
width > 0) {
childWidth = width;
widthMode != SizingMode::MaxContent &&
yoga::isDefined(containingBlockWidth) && containingBlockWidth > 0) {
childWidth = containingBlockWidth;
childWidthSizingMode = SizingMode::FitContent;
}

Expand All @@ -429,9 +452,9 @@ static void layoutAbsoluteChild(
depth,
generationCount);
childWidth = child->getLayout().measuredDimension(Dimension::Width) +
child->getMarginForAxis(FlexDirection::Row, width);
child->getMarginForAxis(FlexDirection::Row, containingBlockWidth);
childHeight = child->getLayout().measuredDimension(Dimension::Height) +
child->getMarginForAxis(FlexDirection::Column, width);
child->getMarginForAxis(FlexDirection::Column, containingBlockWidth);
}

calculateLayoutInternal(
Expand All @@ -452,11 +475,15 @@ static void layoutAbsoluteChild(
if (child->isFlexEndPositionDefined(mainAxis) &&
!child->isFlexStartPositionDefined(mainAxis)) {
child->setLayoutPosition(
node->getLayout().measuredDimension(dimension(mainAxis)) -
containingNode->getLayout().measuredDimension(dimension(mainAxis)) -
child->getLayout().measuredDimension(dimension(mainAxis)) -
node->getFlexEndBorder(mainAxis, direction) -
child->getFlexEndMargin(mainAxis, isMainAxisRow ? width : height) -
child->getFlexEndPosition(mainAxis, isMainAxisRow ? width : height),
containingNode->getFlexEndBorder(mainAxis, direction) -
child->getFlexEndMargin(
mainAxis,
isMainAxisRow ? containingBlockWidth : containingBlockHeight) -
child->getFlexEndPosition(
mainAxis,
isMainAxisRow ? containingBlockWidth : containingBlockHeight),
flexStartEdge(mainAxis));
} else if (
!child->isFlexStartPositionDefined(mainAxis) &&
Expand All @@ -480,25 +507,28 @@ static void layoutAbsoluteChild(
child->setLayoutPosition(
child->getFlexStartPosition(
mainAxis,
node->getLayout().measuredDimension(dimension(mainAxis))) +
node->getFlexStartBorder(mainAxis, direction) +
containingNode->getLayout().measuredDimension(
dimension(mainAxis))) +
containingNode->getFlexStartBorder(mainAxis, direction) +
child->getFlexStartMargin(
mainAxis,
node->getLayout().measuredDimension(dimension(mainAxis))),
isMainAxisRow ? containingBlockWidth : containingBlockHeight),
flexStartEdge(mainAxis));
}

if (child->isFlexEndPositionDefined(crossAxis) &&
!child->isFlexStartPositionDefined(crossAxis)) {
child->setLayoutPosition(
node->getLayout().measuredDimension(dimension(crossAxis)) -
containingNode->getLayout().measuredDimension(dimension(crossAxis)) -
child->getLayout().measuredDimension(dimension(crossAxis)) -
node->getFlexEndBorder(crossAxis, direction) -
child->getFlexEndMargin(crossAxis, isMainAxisRow ? height : width) -
containingNode->getFlexEndBorder(crossAxis, direction) -
child->getFlexEndMargin(
crossAxis,
isMainAxisRow ? containingBlockHeight : containingBlockWidth) -
child->getFlexEndPosition(
crossAxis, isMainAxisRow ? height : width),
crossAxis,
isMainAxisRow ? containingBlockHeight : containingBlockWidth),
flexStartEdge(crossAxis));

} else if (
!child->isFlexStartPositionDefined(crossAxis) &&
resolveChildAlignment(node, child) == Align::Center) {
Expand All @@ -516,21 +546,104 @@ static void layoutAbsoluteChild(
child->getLayout().measuredDimension(dimension(crossAxis))),
flexStartEdge(crossAxis));
} else if (
node->getConfig()->isExperimentalFeatureEnabled(
containingNode->getConfig()->isExperimentalFeatureEnabled(
ExperimentalFeature::AbsolutePercentageAgainstPaddingEdge) &&
child->isFlexStartPositionDefined(crossAxis)) {
child->setLayoutPosition(
child->getFlexStartPosition(
crossAxis,
node->getLayout().measuredDimension(dimension(crossAxis))) +
node->getFlexStartBorder(crossAxis, direction) +
containingNode->getLayout().measuredDimension(
dimension(crossAxis))) +
containingNode->getFlexStartBorder(crossAxis, direction) +
child->getFlexStartMargin(
crossAxis,
node->getLayout().measuredDimension(dimension(crossAxis))),
isMainAxisRow ? containingBlockHeight : containingBlockWidth),
flexStartEdge(crossAxis));
}
}

static void layoutAbsoluteDescendants(
yoga::Node* containingNode,
yoga::Node* currentNode,
SizingMode widthSizingMode,
Direction currentNodeDirection,
LayoutData& layoutMarkerData,
uint32_t currentDepth,
uint32_t generationCount,
float currentNodeMainOffsetFromContainingBlock,
float currentNodeCrossOffsetFromContainingBlock) {
const FlexDirection mainAxis = resolveDirection(
currentNode->getStyle().flexDirection(), currentNodeDirection);
const FlexDirection crossAxis =
resolveCrossDirection(mainAxis, currentNodeDirection);
for (auto child : currentNode->getChildren()) {
if (child->getStyle().display() == Display::None) {
continue;
} else if (child->getStyle().positionType() == PositionType::Absolute) {
layoutAbsoluteChild(
containingNode,
currentNode,
child,
containingNode->getLayout().measuredDimension(Dimension::Width),
containingNode->getLayout().measuredDimension(Dimension::Height),
widthSizingMode,
currentNodeDirection,
layoutMarkerData,
currentDepth,
generationCount);

const bool isMainAxisRow = isRow(mainAxis);
const bool mainInsetsDefined = isMainAxisRow
? child->getStyle().horizontalInsetsDefined()
: child->getStyle().verticalInsetsDefined();
const bool crossInsetsDefined = isMainAxisRow
? child->getStyle().verticalInsetsDefined()
: child->getStyle().horizontalInsetsDefined();

const float childMainOffsetFromParent = mainInsetsDefined
? (child->getLayout().position(flexStartEdge(mainAxis)) -
currentNodeMainOffsetFromContainingBlock)
: child->getLayout().position(flexStartEdge(mainAxis));
const float childCrossOffsetFromParent = crossInsetsDefined
? (child->getLayout().position(flexStartEdge(crossAxis)) -
currentNodeCrossOffsetFromContainingBlock)
: child->getLayout().position(flexStartEdge(crossAxis));

child->setLayoutPosition(
childMainOffsetFromParent, flexStartEdge(mainAxis));
child->setLayoutPosition(
childCrossOffsetFromParent, flexStartEdge(crossAxis));

if (needsTrailingPosition(mainAxis)) {
setChildTrailingPosition(currentNode, child, mainAxis);
}
if (needsTrailingPosition(crossAxis)) {
setChildTrailingPosition(currentNode, child, crossAxis);
}
} else if (child->getStyle().positionType() == PositionType::Static) {
const Direction childDirection =
child->resolveDirection(currentNodeDirection);
const float childMainOffsetFromContainingBlock =
currentNodeMainOffsetFromContainingBlock +
child->getLayout().position(flexStartEdge(mainAxis));
const float childCrossOffsetFromContainingBlock =
currentNodeCrossOffsetFromContainingBlock +
child->getLayout().position(flexStartEdge(crossAxis));

layoutAbsoluteDescendants(
containingNode,
child,
widthSizingMode,
childDirection,
layoutMarkerData,
currentDepth + 1,
generationCount,
childMainOffsetFromContainingBlock,
childCrossOffsetFromContainingBlock);
}
}
}

static void measureNodeWithMeasureFunc(
yoga::Node* const node,
float availableWidth,
Expand Down Expand Up @@ -2304,42 +2417,63 @@ static void calculateLayoutImpl(

if (performLayout) {
// STEP 10: SIZING AND POSITIONING ABSOLUTE CHILDREN
for (auto child : node->getChildren()) {
if (child->getStyle().display() == Display::None ||
child->getStyle().positionType() != PositionType::Absolute) {
continue;
if (!node->hasErrata(Errata::PositionStaticBehavesLikeRelative)) {
// Let the containing block layout its absolute descendants. By definition
// the containing block will not be static unless we are at the root.
if (node->getStyle().positionType() != PositionType::Static ||
depth == 1) {
layoutAbsoluteDescendants(
node,
node,
isMainAxisRow ? sizingModeMainDim : sizingModeCrossDim,
direction,
layoutMarkerData,
depth,
generationCount,
0.0f,
0.0f);
}
const bool absolutePercentageAgainstPaddingEdge =
node->getConfig()->isExperimentalFeatureEnabled(
ExperimentalFeature::AbsolutePercentageAgainstPaddingEdge);
} else {
for (auto child : node->getChildren()) {
if (child->getStyle().display() == Display::None ||
child->getStyle().positionType() != PositionType::Absolute) {
continue;
}
const bool absolutePercentageAgainstPaddingEdge =
node->getConfig()->isExperimentalFeatureEnabled(
ExperimentalFeature::AbsolutePercentageAgainstPaddingEdge);

layoutAbsoluteChild(
node,
child,
absolutePercentageAgainstPaddingEdge
? node->getLayout().measuredDimension(Dimension::Width)
: availableInnerWidth,
isMainAxisRow ? sizingModeMainDim : sizingModeCrossDim,
absolutePercentageAgainstPaddingEdge
? node->getLayout().measuredDimension(Dimension::Height)
: availableInnerHeight,
direction,
layoutMarkerData,
depth,
generationCount);
layoutAbsoluteChild(
node,
node,
child,
absolutePercentageAgainstPaddingEdge
? node->getLayout().measuredDimension(Dimension::Width)
: availableInnerWidth,
absolutePercentageAgainstPaddingEdge
? node->getLayout().measuredDimension(Dimension::Height)
: availableInnerHeight,
isMainAxisRow ? sizingModeMainDim : sizingModeCrossDim,
direction,
layoutMarkerData,
depth,
generationCount);
}
}

// STEP 11: SETTING TRAILING POSITIONS FOR CHILDREN
const bool needsMainTrailingPos = mainAxis == FlexDirection::RowReverse ||
mainAxis == FlexDirection::ColumnReverse;
const bool needsCrossTrailingPos = crossAxis == FlexDirection::RowReverse ||
crossAxis == FlexDirection::ColumnReverse;
const bool needsMainTrailingPos = needsTrailingPosition(mainAxis);
const bool needsCrossTrailingPos = needsTrailingPosition(crossAxis);

// Set trailing position if necessary.
if (needsMainTrailingPos || needsCrossTrailingPos) {
for (size_t i = 0; i < childCount; i++) {
const auto child = node->getChild(i);
if (child->getStyle().display() == Display::None) {
// Absolute children will be handled by their containing block since we
// cannot guarantee that their positions are set when their parents are
// done with layout.
if (child->getStyle().display() == Display::None ||
(!node->hasErrata(Errata::PositionStaticBehavesLikeRelative) &&
child->getStyle().positionType() == PositionType::Absolute)) {
continue;
}
if (needsMainTrailingPos) {
Expand Down
Loading
Loading