[LayoutNG] Ensure self-collapsing block relayout when ancestor resolves.
This bug was a combination of older code before we had "forced" BFC
block-offsets.
We didn't correctly detect when we had a self-collapsing block (which
had floats within it) that needed relayout if the initial estimate
was wrong.
This makes sure we give ourselves enough information to detect these
cases.
Bug: 980803
Change-Id: Id1ea5e10d819cb4509fd7664564b75b876f0f7cb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1690720
Commit-Queue: Ian Kilpatrick <ikilpatrick@chromium.org>
Commit-Queue: Emil A Eklund <eae@chromium.org>
Reviewed-by: Emil A Eklund <eae@chromium.org>
Cr-Commit-Position: refs/heads/master@{#675729}
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index 161685c..c918813 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -1280,15 +1280,6 @@
base::Optional<LayoutUnit> child_bfc_block_offset =
layout_result->BfcBlockOffset();
- // TODO(layout-dev): A more optimal version of this is to set
- // relayout_child_when_bfc_resolved only if the child tree itself _added_ any
- // floats that it failed to position. Currently, we risk relaying out the
- // parent block for no reason, because we're not able to make this
- // distinction.
- bool relayout_child_when_bfc_resolved =
- layout_result->AdjoiningFloatTypes() && !child_bfc_block_offset &&
- !child_space.ForcedBfcBlockOffset();
-
bool is_self_collapsing = layout_result->IsSelfCollapsing();
// Only non self-collapsing children (e.g. "normal children") can be pushed
@@ -1327,9 +1318,9 @@
// present, but we shouldn't apply it (instead preferring the child's new
// BFC block-offset).
DCHECK(!ConstraintSpace().AncestorHasClearancePastAdjoiningFloats());
- ResolveBfcBlockOffset(previous_inflow_position, bfc_block_offset,
- /* forced_bfc_block_offset */ base::nullopt);
- return false;
+ if (!ResolveBfcBlockOffset(previous_inflow_position, bfc_block_offset,
+ /* forced_bfc_block_offset */ base::nullopt))
+ return false;
}
// We have special behaviour for a self-collapsing child which gets pushed
@@ -1366,16 +1357,28 @@
return false;
}
+ bool self_collapsing_child_needs_relayout = false;
if (!child_bfc_block_offset) {
// Layout wasn't able to determine the BFC block-offset of the child. This
// has to mean that the child is self-collapsing.
DCHECK(is_self_collapsing);
if (container_builder_.BfcBlockOffset()) {
- // Since we know our own BFC block offset, though, we can calculate that
+ // Since we know our own BFC block-offset, though, we can calculate that
// of the child as well.
child_bfc_block_offset = PositionSelfCollapsingChildWithParentBfc(
child, child_space, *child_data, *layout_result);
+
+ // We may need to relayout this child if it had any objects which were
+ // positioned in the incorrect position.
+ //
+ // TODO(layout-dev): A more optimal version of this is to set this flag
+ // only if the child tree *added* any floats which it failed to position.
+ // Currently, we risk relaying out the sub-tree for no reason, because
+ // we're not able to make this distinction.
+ if (layout_result->AdjoiningFloatTypes() &&
+ !child_space.ForcedBfcBlockOffset())
+ self_collapsing_child_needs_relayout = true;
}
} else if (!child_had_clearance) {
// We shouldn't have any pending floats here, since an in-flow child found
@@ -1411,7 +1414,6 @@
//
// The resulting margin strut in the above example will be {40, -30}. See
// |ComputeInflowPosition| for how this end margin strut is used.
- bool self_collapsing_child_had_clearance_needs_relayout = false;
if (self_collapsing_child_had_clearance) {
NGMarginStrut margin_strut;
margin_strut.Append(child_data->margins.block_start,
@@ -1421,7 +1423,7 @@
// previous one.
if (child_data->margin_strut != margin_strut) {
child_data->margin_strut = margin_strut;
- self_collapsing_child_had_clearance_needs_relayout = true;
+ self_collapsing_child_needs_relayout = true;
}
}
@@ -1430,8 +1432,7 @@
// - It has some unpositioned floats.
// - It was affected by clearance.
if ((layout_result->Status() == NGLayoutResult::kBfcBlockOffsetResolved ||
- relayout_child_when_bfc_resolved ||
- self_collapsing_child_had_clearance_needs_relayout) &&
+ self_collapsing_child_needs_relayout) &&
child_bfc_block_offset) {
NGConstraintSpace new_child_space = CreateConstraintSpaceForChild(
child, *child_data, child_available_size_, /* is_new_fc */ false,
@@ -1455,7 +1456,6 @@
}
DCHECK_EQ(layout_result->Status(), NGLayoutResult::kSuccess);
- relayout_child_when_bfc_resolved = false;
}
// It is now safe to update our version of the exclusion space, and any
@@ -1482,7 +1482,8 @@
// If we are a new formatting context, the child will get re-laid out once it
// has been positioned.
if (!container_builder_.BfcBlockOffset()) {
- abort_when_bfc_block_offset_updated_ |= relayout_child_when_bfc_resolved;
+ abort_when_bfc_block_offset_updated_ |=
+ layout_result->AdjoiningFloatTypes();
// If our BFC block offset is unknown, and the child got pushed down by
// floats, so will we.
if (layout_result->IsPushedByFloats())
@@ -2328,14 +2329,11 @@
// If no previous BFC block offset was set, we need to abort.
if (!ConstraintSpace().ForcedBfcBlockOffset())
return true;
+
// If the previous BFC block offset matches the new one, we can continue.
// Otherwise, we need to abort.
- LayoutUnit old_bfc_block_offset = *ConstraintSpace().ForcedBfcBlockOffset();
-
- // In order to determine if the two offsets are equal, we also need to adjust
- // floats offset by the clearance offset.
- ApplyClearance(ConstraintSpace(), &old_bfc_block_offset);
- return *container_builder_.BfcBlockOffset() != old_bfc_block_offset;
+ return *container_builder_.BfcBlockOffset() !=
+ *ConstraintSpace().ForcedBfcBlockOffset();
}
void NGBlockLayoutAlgorithm::PositionPendingFloats(
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/adjoining-float-nested-forced-clearance-004.html b/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/adjoining-float-nested-forced-clearance-004.html
new file mode 100644
index 0000000..bda89a9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/floats-clear/adjoining-float-nested-forced-clearance-004.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html" />
+<link rel="help" href="https://www.w3.org/TR/CSS22/visuren.html#flow-control" title="9.5.2 Controlling flow next to floats: the 'clear' property">
+<p>Test passes if there is a filled green square.</p>
+<div style="overflow: hidden;"></div>
+<div style="float: left; width: 100px; height: 50px; background: green;"></div>
+<span>
+ <div style="clear: both;">
+ <div style="height: 10px;">
+ <div style="float: left; width: 100px; height: 50px; background: green;">
+ </div>
+ </div>
+</span>