Commit 0c953039 authored by Morten Stenshorne's avatar Morten Stenshorne Committed by Commit Bot

[LayoutNG] Handle fragmenting floats in BFC roots correctly.

This consists of two fixes:

1. The block formatting context root must not be marked as "at block
end" if there are broken floats inside.

2. Set exclusion space correctly. We used to add an "infinitely" tall
exclusion, which would cause the containing block (the formatting
context root) to become "infinitely" tall. Set it to the amount of space
left in the fragmentainer instead.

Bug: 829028
Change-Id: I316d7a9b50b9a502d203d83021389274713d2429
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2438494
Commit-Queue: Morten Stenshorne <mstensho@chromium.org>
Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#812595}
parent 4e8ea8d3
......@@ -163,6 +163,8 @@ void NGBoxFragmentBuilder::AddBreakBeforeChild(
if (!has_inflow_child_break_inside_)
has_inflow_child_break_inside_ = !child.IsFloatingOrOutOfFlowPositioned();
if (!has_float_break_inside_)
has_float_break_inside_ = child.IsFloating();
if (auto* child_inline_node = DynamicTo<NGInlineNode>(child)) {
if (inline_break_tokens_.IsEmpty()) {
......@@ -282,17 +284,19 @@ void NGBoxFragmentBuilder::PropagateBreak(
const NGLayoutResult& child_layout_result) {
if (LIKELY(!has_block_fragmentation_))
return;
if (!has_inflow_child_break_inside_) {
if (!has_inflow_child_break_inside_ || !has_float_break_inside_) {
// Figure out if this child break is in the same flow as this parent. If
// it's an out-of-flow positioned box, it's not. If it's in a parallel flow,
// it's also not.
const auto& child_fragment =
To<NGPhysicalBoxFragment>(child_layout_result.PhysicalFragment());
if (!child_fragment.IsFloatingOrOutOfFlowPositioned()) {
if (const auto* token = child_fragment.BreakToken()) {
if (!token->IsFinished() &&
(!token->IsBlockType() ||
!To<NGBlockBreakToken>(token)->IsAtBlockEnd()))
if (const auto* token = child_fragment.BreakToken()) {
if (!token->IsFinished() &&
(!token->IsBlockType() ||
!To<NGBlockBreakToken>(token)->IsAtBlockEnd())) {
if (child_fragment.IsFloating())
has_float_break_inside_ = true;
else if (!child_fragment.IsOutOfFlowPositioned())
has_inflow_child_break_inside_ = true;
}
}
......
......@@ -275,6 +275,11 @@ class CORE_EXPORT NGBoxFragmentBuilder final
return has_inflow_child_break_inside_;
}
// Return true if we need to break before or inside any floated child. Floats
// are encapsulated by their container if the container establishes a new
// block formatting context.
bool HasFloatBreakInside() const { return has_float_break_inside_; }
// Report space shortage, i.e. how much more space would have been sufficient
// to prevent some piece of content from breaking. This information may be
// used by the column balancer to stretch columns.
......@@ -554,6 +559,7 @@ class CORE_EXPORT NGBoxFragmentBuilder final
bool is_first_for_node_ = true;
bool did_break_self_ = false;
bool has_inflow_child_break_inside_ = false;
bool has_float_break_inside_ = false;
bool has_forced_break_ = false;
bool is_new_fc_ = false;
bool subtree_modified_margin_strut_ = false;
......
......@@ -351,7 +351,8 @@ NGPositionedFloat PositionFloat(NGUnpositionedFloat* unpositioned_float,
// fragmentainer means that the in-flow block also needs to be pushed, while
// if the in-flow block has clear:right, it may still be allowed in the
// current fragmentainer).
NGBfcOffset past_everything(LayoutUnit(), LayoutUnit::Max());
NGBfcOffset past_everything(LayoutUnit(),
FragmentainerSpaceAtBfcStart(parent_space));
scoped_refptr<const NGExclusion> exclusion =
NGExclusion::Create(NGBfcRect(past_everything, past_everything),
node.Style().Floating(parent_space.Direction()));
......
......@@ -379,7 +379,12 @@ bool FinishFragmentation(NGBlockNode node,
// IsNodeFullyGrown() will return true now), we know that we're at the
// end. If block-size is unconstrained (or at least allowed to grow a bit
// more), we're only at the end if no in-flow content inside broke.
if (!builder->HasInflowChildBreakInside() ||
bool was_broken_by_child = builder->HasInflowChildBreakInside();
if (!was_broken_by_child && space.IsNewFormattingContext())
was_broken_by_child = builder->HasFloatBreakInside();
if (!was_broken_by_child ||
IsNodeFullyGrown(node, space, fragments_total_block_size,
builder->BorderPadding(),
builder->InitialBorderBoxSize().inline_size))
......
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<link rel="help" href="https://www.w3.org/TR/css-break-3/">
<link rel="help" href="https://www.w3.org/TR/CSS22/visudet.html#root-height">
<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<div style="columns:2; column-fill:auto; column-gap:0; width:100px; height:100px; background:red;">
<div style="display:flow-root; background:green;">
<div style="float:left; width:50%; height:200px;"></div>
</div>
</div>
<!DOCTYPE html>
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
<link rel="help" href="https://www.w3.org/TR/css-break-3/">
<link rel="help" href="https://www.w3.org/TR/CSS22/visudet.html#root-height">
<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<div style="columns:2; column-fill:auto; column-gap:0; width:100px; height:100px; background:red;">
<div style="display:flow-root; background:green;">
<div style="float:left; width:50%; height:150px;"></div>
<div style="float:left; clear:left; width:50%; height:50px;"></div>
</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