Commit dd54b7e0 authored by Ian Kilpatrick's avatar Ian Kilpatrick Committed by Commit Bot

[FlexNG] Add support for OOF-positioned static-positions within FlexNG.

This builds on previous changes to (finally!) add the correct
static-positions within the NGFlexLayoutAlgorithm.

This takes into account the main-axis, and cross-axis
alignment/justification - and converts it to the correct
inline/block axis.

As we may not know the final block-size when we encounter an
OOF-positioned node, we "adjust" this within the fragment builder once
known.

This is important for block-end/block-center aligned OOF-positioned
nodes.

Bug: 845235
Change-Id: I45c89ae1f676ec06d742b86e4b744cfc3dbe6f75
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1841245
Commit-Queue: Ian Kilpatrick <ikilpatrick@chromium.org>
Reviewed-by: default avatarMorten Stenshorne <mstensho@chromium.org>
Reviewed-by: default avatarDavid Grogan <dgrogan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#723411}
parent 4a039b0e
......@@ -197,8 +197,17 @@ void NGContainerFragmentBuilder::AddOutOfFlowChildCandidate(
NGLogicalStaticPosition::BlockEdge block_edge) {
DCHECK(child);
// If an OOF-positioned candidate has a static-position which uses a
// non-block-start edge, we need to adjust its static-position when the final
// block-size is known.
bool needs_block_offset_adjustment =
block_edge != NGLogicalStaticPosition::BlockEdge::kBlockStart;
has_oof_candidate_that_needs_block_offset_adjustment_ |=
needs_block_offset_adjustment;
oof_positioned_candidates_.emplace_back(
child, NGLogicalStaticPosition{child_offset, inline_edge, block_edge});
child, NGLogicalStaticPosition{child_offset, inline_edge, block_edge},
/* inline_container */ nullptr, needs_block_offset_adjustment);
}
void NGContainerFragmentBuilder::AddOutOfFlowInlineChildCandidate(
......@@ -226,6 +235,27 @@ void NGContainerFragmentBuilder::SwapOutOfFlowPositionedCandidates(
Vector<NGLogicalOutOfFlowPositionedNode>* candidates) {
DCHECK(candidates->IsEmpty());
std::swap(oof_positioned_candidates_, *candidates);
if (!has_oof_candidate_that_needs_block_offset_adjustment_)
return;
using BlockEdge = NGLogicalStaticPosition::BlockEdge;
// We might have an OOF-positioned candidate whose static-position depends on
// the final block-size of this fragment.
DCHECK_NE(BlockSize(), kIndefiniteSize);
for (auto& candidate : *candidates) {
if (!candidate.needs_block_offset_adjustment)
continue;
if (candidate.static_position.block_edge == BlockEdge::kBlockCenter)
candidate.static_position.offset.block_offset += BlockSize() / 2;
else if (candidate.static_position.block_edge == BlockEdge::kBlockEnd)
candidate.static_position.offset.block_offset += BlockSize();
candidate.needs_block_offset_adjustment = false;
}
has_oof_candidate_that_needs_block_offset_adjustment_ = false;
}
void NGContainerFragmentBuilder::
......
......@@ -240,6 +240,8 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
bool has_block_fragmentation_ = false;
bool is_fragmentation_context_root_ = false;
bool may_have_descendant_above_block_start_ = false;
bool has_oof_candidate_that_needs_block_offset_adjustment_ = false;
};
} // namespace blink
......
......@@ -50,16 +50,90 @@ LayoutUnit NGFlexLayoutAlgorithm::MainAxisContentExtent(
return content_box_size_.inline_size;
}
namespace {
enum AxisEdge { kStart, kCenter, kEnd };
// Maps the resolved justify-content value to a static-position edge.
AxisEdge MainAxisStaticPositionEdge(const ComputedStyle& style,
bool is_column) {
const StyleContentAlignmentData justify =
FlexLayoutAlgorithm::ResolvedJustifyContent(style);
const ContentPosition content_position = justify.GetPosition();
bool is_reverse_flex = is_column
? style.ResolvedIsColumnReverseFlexDirection()
: style.ResolvedIsRowReverseFlexDirection();
if (content_position == ContentPosition::kFlexEnd)
return is_reverse_flex ? AxisEdge::kStart : AxisEdge::kEnd;
if (content_position == ContentPosition::kCenter ||
justify.Distribution() == ContentDistributionType::kSpaceAround ||
justify.Distribution() == ContentDistributionType::kSpaceEvenly)
return AxisEdge::kCenter;
return is_reverse_flex ? AxisEdge::kEnd : AxisEdge::kStart;
}
// Maps the resolved alignment value to a static-position edge.
AxisEdge CrossAxisStaticPositionEdge(const ComputedStyle& style,
const ComputedStyle& child_style) {
ItemPosition alignment =
FlexLayoutAlgorithm::AlignmentForChild(style, child_style);
bool is_wrap_reverse = style.FlexWrap() == EFlexWrap::kWrapReverse;
if (alignment == ItemPosition::kFlexEnd)
return is_wrap_reverse ? AxisEdge::kStart : AxisEdge::kEnd;
if (alignment == ItemPosition::kCenter)
return AxisEdge::kCenter;
return is_wrap_reverse ? AxisEdge::kEnd : AxisEdge::kStart;
}
} // namespace
void NGFlexLayoutAlgorithm::HandleOutOfFlowPositioned(NGBlockNode child) {
// TODO(dgrogan): There's stuff from
// https://www.w3.org/TR/css-flexbox-1/#abspos-items that isn't done here.
// Specifically, neither rtl nor alignment is handled here, at least.
// Look at LayoutFlexibleBox::PrepareChildForPositionedLayout and
// SetStaticPositionForPositionedLayout to see how to statically position
// this.
container_builder_.AddOutOfFlowChildCandidate(
child, {border_scrollbar_padding_.inline_start,
border_scrollbar_padding_.block_start});
AxisEdge main_axis_edge = MainAxisStaticPositionEdge(Style(), is_column_);
AxisEdge cross_axis_edge =
CrossAxisStaticPositionEdge(Style(), child.Style());
AxisEdge inline_axis_edge = is_column_ ? cross_axis_edge : main_axis_edge;
AxisEdge block_axis_edge = is_column_ ? main_axis_edge : cross_axis_edge;
using InlineEdge = NGLogicalStaticPosition::InlineEdge;
using BlockEdge = NGLogicalStaticPosition::BlockEdge;
InlineEdge inline_edge;
BlockEdge block_edge;
LogicalOffset offset(border_scrollbar_padding_.inline_start,
border_scrollbar_padding_.block_start);
// Determine the static-position based off the axis-edge.
if (inline_axis_edge == AxisEdge::kStart) {
inline_edge = InlineEdge::kInlineStart;
} else if (inline_axis_edge == AxisEdge::kCenter) {
inline_edge = InlineEdge::kInlineCenter;
offset.inline_offset += content_box_size_.inline_size / 2;
} else {
inline_edge = InlineEdge::kInlineEnd;
offset.inline_offset += content_box_size_.inline_size;
}
// We may not know the final block-size of the fragment yet. This will be
// adjusted within the |NGContainerFragmentBuilder| once set.
if (block_axis_edge == AxisEdge::kStart) {
block_edge = BlockEdge::kBlockStart;
} else if (block_axis_edge == AxisEdge::kCenter) {
block_edge = BlockEdge::kBlockCenter;
offset.block_offset -= border_scrollbar_padding_.BlockSum() / 2;
} else {
block_edge = BlockEdge::kBlockEnd;
offset.block_offset -= border_scrollbar_padding_.BlockSum();
}
container_builder_.AddOutOfFlowChildCandidate(child, offset, inline_edge,
block_edge);
}
bool NGFlexLayoutAlgorithm::IsColumnContainerMainSizeDefinite() const {
......
......@@ -237,10 +237,8 @@ bool NGOutOfFlowLayoutPart::SweepLegacyCandidates(
// size first.
// We perform a pre-layout to correctly determine the static position.
// Copied from LayoutBlock::LayoutPositionedObject
// TODO(layout-dev): Remove this once LayoutFlexibleBox is removed.
LayoutBox* layout_box = ToLayoutBox(legacy_object);
// TODO(dgrogan): The NG flexbox implementation doesn't have an
// analogous method yet, so abspos children of NG flexboxes that have a
// legacy containing block will not be positioned correctly.
if (layout_box->Parent()->IsFlexibleBox()) {
LayoutFlexibleBox* parent = ToLayoutFlexibleBox(layout_box->Parent());
if (parent->SetStaticPositionForPositionedLayout(*layout_box)) {
......
......@@ -54,14 +54,17 @@ struct NGLogicalOutOfFlowPositionedNode {
NGLogicalStaticPosition static_position;
// Continuation root of the optional inline container.
const LayoutInline* inline_container;
bool needs_block_offset_adjustment;
NGLogicalOutOfFlowPositionedNode(
NGBlockNode node,
NGLogicalStaticPosition static_position,
const LayoutInline* inline_container = nullptr)
const LayoutInline* inline_container = nullptr,
bool needs_block_offset_adjustment = false)
: node(node),
static_position(static_position),
inline_container(inline_container) {
inline_container(inline_container),
needs_block_offset_adjustment(needs_block_offset_adjustment) {
DCHECK(!inline_container ||
inline_container == inline_container->ContinuationRoot());
}
......
......@@ -442,6 +442,8 @@ crbug.com/417223 external/wpt/css/css-position/position-relative-table-tr-left-a
crbug.com/417223 external/wpt/css/css-position/position-relative-table-tr-left.html [ Failure ]
crbug.com/417223 external/wpt/css/css-position/position-relative-table-tr-top-absolute-child.html [ Failure ]
crbug.com/417223 external/wpt/css/css-position/position-relative-table-tr-top.html [ Failure ]
crbug.com/845235 external/wpt/css/css-position/position-absolute-center-001.tentative.html [ Failure ]
crbug.com/845235 external/wpt/css/css-position/position-absolute-center-002.tentative.html [ Failure ]
crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-color-001.xht [ Failure ]
crbug.com/949909 external/wpt/css/css-text-decor/text-emphasis-position-above-left-001.xht [ Failure ]
......@@ -1343,7 +1345,6 @@ crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/negative-overflow.html
crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/order-painting.html [ Failure ]
crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/overflow-auto-resizes-correctly.html [ Failure ]
crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/percentage-height-replaced-element.html [ Failure ]
crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/position-absolute-child.html [ Failure ]
crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/relpos-with-percentage-top.html [ Failure ]
crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/style-change.html [ Failure ]
......@@ -1379,8 +1380,6 @@ crbug.com/591099 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/order_v
crbug.com/591099 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/overflow-top-left.html [ Failure ]
crbug.com/591099 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/percentage-heights-007.html [ Failure ]
crbug.com/591099 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/percentage-heights-quirks-node.html [ Failure ]
crbug.com/591099 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/position-absolute-001.html [ Failure ]
crbug.com/591099 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/position-absolute-002.html [ Failure ]
crbug.com/591099 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/quirks-auto-block-size-with-percentage-item.html [ Pass Failure ]
crbug.com/591099 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/scrollbars-auto.html [ Failure ]
crbug.com/591099 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/scrollbars.html [ Failure ]
......
<!DOCTYPE html>
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/1432">
<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
<style>
#containing-block {
position: relative;
width: 100px;
height: 100px;
background: red;
display: flex;
}
#containing-block > div {
flex-grow: 1;
}
#inner-flex {
display: flex;
justify-content: center;
}
span {
display: inline-block;
inline-size: 50px;
block-size: 10px;
}
</style>
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<div id="containing-block" style="flex-direction: row;">
<div id="inner-flex" style="margin: 10px; height: 100px;">
<div style="position: absolute; top: 0; height: 100px; background: green;">
<span></span>
<span></span>
</div>
</div>
<div style="height: 100px; background: green;"></div>
</div>
<!DOCTYPE html>
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/1432">
<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
<style>
#containing-block {
position: relative;
width: 100px;
height: 100px;
background: red;
display: flex;
}
#containing-block > div {
flex-grow: 1;
}
#inner-flex {
display: flex;
align-items: center;
}
span {
display: inline-block;
inline-size: 50px;
block-size: 10px;
}
</style>
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<div id="containing-block" style="flex-direction: column;">
<div id="inner-flex" style="margin: 10px; width: 100px;">
<div style="position: absolute; left: 0; width: 100px; background: green; writing-mode: vertical-rl;">
<span></span>
<span></span>
</div>
</div>
<div style="width: 100px; background: green;"></div>
</div>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment