Commit ceeabef2 authored by Morten Stenshorne's avatar Morten Stenshorne Committed by Commit Bot

[LayoutNG] Let the column layout algorithm abort when out of space.

If we're in a nested fragmentation context (multicol in multicol, for
instance), we may end up in a situation where we have no outer
fragmentainer space left to lay out inner columns. In such cases, if we
cannot fit anything at all, we'll now abort the column layout algorithm,
produce no fragment, and break before the multicol container (or even
earlier), and try again in the next outer fragmentainer.

This introduces another non-successful status for NGLayoutResult, which
all Layout() invokers need to handle as part of block fragmentation.
This doesn't really add much complexity, though: To participate in block
fragmentation, one needs to invoke MovePastBreakpoint() somehow
(possibly via BreakBeforeChildIfNeeded()) anyway, which will refuse to
move past if layout aborted. Apart from that, the only thing callers
need to take care of, is check if layout was successful before trying to
access the physical fragment of the result (since there'll be none if
layout was unsuccessful).

This CL only aborts multicol layout - we still lay out regular blocks
even in cases where we could have told up front that we're past the
fragmentainer boundary. Actually, even if there's a forced break before
a child, we'll lay it out, and let the container break before it
afterwards (and thus discard the fragment that we wasted time on
producing). We might want to change that as well in the future, if it
gives any benefits apart from minuscule performance improvements.

Bug: 829028
Change-Id: I473e7106fcc62921d71567d9496ca4c8a9729b05
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2023833Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Commit-Queue: Morten Stenshorne <mstensho@chromium.org>
Cr-Commit-Position: refs/heads/master@{#736279}
parent 9736e4a7
......@@ -1017,6 +1017,10 @@ void NGBlockLayoutAlgorithm::HandleFloat(
PositionFloat(&unpositioned_float, &exclusion_space_);
const NGLayoutResult& layout_result = *positioned_float.layout_result;
// TODO(mstensho): Handle abortions caused by block fragmentation.
DCHECK_EQ(layout_result.Status(), NGLayoutResult::kSuccess);
const auto& physical_fragment = layout_result.PhysicalFragment();
if (const NGBreakToken* token = physical_fragment.BreakToken()) {
DCHECK(ConstraintSpace().HasBlockFragmentation());
......@@ -1243,6 +1247,10 @@ NGLayoutResult::EStatus NGBlockLayoutAlgorithm::HandleNewFormattingContext(
return NGLayoutResult::kSuccess;
if (break_status == NGBreakStatus::kNeedsEarlierBreak)
return NGLayoutResult::kNeedsEarlierBreak;
// If the child aborted layout, we cannot continue.
DCHECK_EQ(layout_result->Status(), NGLayoutResult::kSuccess);
EBreakBetween break_after = JoinFragmentainerBreakValues(
layout_result->FinalBreakAfter(), child.Style().BreakAfter());
container_builder_.SetPreviousBreakAfter(break_after);
......@@ -1380,6 +1388,12 @@ NGBlockLayoutAlgorithm::LayoutNewFormattingContext(
// should be returned.
DCHECK(layout_result->ExclusionSpace().IsEmpty());
if (layout_result->Status() != NGLayoutResult::kSuccess) {
DCHECK_EQ(layout_result->Status(),
NGLayoutResult::kOutOfFragmentainerSpace);
return layout_result;
}
NGFragment fragment(writing_mode, layout_result->PhysicalFragment());
// Check if the fragment will fit in this layout opportunity, if not proceed
......
......@@ -137,10 +137,16 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::Layout() {
intrinsic_block_size_ = border_scrollbar_padding_.block_start;
if (!LayoutChildren()) {
NGBreakStatus break_status = LayoutChildren();
if (break_status == NGBreakStatus::kNeedsEarlierBreak) {
// We need to discard this layout and do it again. We found an earlier break
// point that's more appealing than the one we ran out of space at.
return RelayoutAndBreakEarlier();
} else if (break_status == NGBreakStatus::kBrokeBefore) {
// If we want to break before, make sure that we're actually at the start.
DCHECK(!BreakToken());
return container_builder_.Abort(NGLayoutResult::kOutOfFragmentainerSpace);
}
// Figure out how much space we've already been able to process in previous
......@@ -223,7 +229,7 @@ base::Optional<MinMaxSize> NGColumnLayoutAlgorithm::ComputeMinMaxSize(
return sizes;
}
bool NGColumnLayoutAlgorithm::LayoutChildren() {
NGBreakStatus NGColumnLayoutAlgorithm::LayoutChildren() {
NGMarginStrut margin_strut;
// First extract incoming child break tokens.
......@@ -280,7 +286,7 @@ bool NGColumnLayoutAlgorithm::LayoutChildren() {
PushSpannerBreakTokens(std::move(spanner_break_token),
std::move(next_column_token),
&container_builder_);
return true;
return NGBreakStatus::kContinue;
}
} else {
// Breaking before the first element in the fragmentainer isn't allowed,
......@@ -290,7 +296,7 @@ bool NGColumnLayoutAlgorithm::LayoutChildren() {
}
if (BreakToken() && BreakToken()->HasSeenAllChildren() && !next_column_token)
return true;
return NGBreakStatus::kContinue;
// Entering the child main loop. Here we'll alternate between laying out
// column content and column spanners, until we're either done, or until
......@@ -300,6 +306,26 @@ bool NGColumnLayoutAlgorithm::LayoutChildren() {
do {
scoped_refptr<const NGLayoutResult> result =
LayoutRow(next_column_token.get(), &margin_strut);
if (!result) {
// Not enough outer fragmentainer space to produce any columns at all.
container_builder_.SetDidBreak();
if (intrinsic_block_size_) {
// We have preceding initial border/padding, or a column spanner
// (possibly preceded by other spanners or even column content). So we
// need to break inside the multicol container. Stop walking the
// children, but "continue" layout, so that we produce a fragment. Note
// that we normally don't want to break right after initial
// border/padding, but will do so as a last resort. It's up to our
// containing block to decide what's best.
FinishAfterBreakBeforeRow(std::move(next_column_token));
return NGBreakStatus::kContinue;
}
// Otherwise we have nothing here, and need to break before the multicol
// container. No fragment will be produced.
return NGBreakStatus::kBrokeBefore;
}
next_column_token =
To<NGBlockBreakToken>(result->PhysicalFragment().BreakToken());
......@@ -319,7 +345,7 @@ bool NGColumnLayoutAlgorithm::LayoutChildren() {
container_builder_.AddBreakBeforeChild(
spanner_node, kBreakAppealPerfect, /* is_forced_break */ false);
FinishAfterBreakBeforeSpanner(std::move(next_column_token));
return true;
return NGBreakStatus::kContinue;
}
}
......@@ -327,18 +353,18 @@ bool NGColumnLayoutAlgorithm::LayoutChildren() {
NGBreakStatus break_status = LayoutSpanner(
spanner_node, nullptr, &margin_strut, &spanner_break_token);
if (break_status == NGBreakStatus::kNeedsEarlierBreak) {
return false;
return break_status;
} else if (break_status == NGBreakStatus::kBrokeBefore) {
DCHECK(ConstraintSpace().HasBlockFragmentation());
FinishAfterBreakBeforeSpanner(std::move(next_column_token));
return true;
return NGBreakStatus::kContinue;
} else if (spanner_break_token) {
DCHECK_EQ(break_status, NGBreakStatus::kContinue);
// We broke inside the spanner. This may happen if we're nested inside
// another fragmentation context.
PushSpannerBreakTokens(std::move(spanner_break_token),
std::move(next_column_token), &container_builder_);
return true;
return NGBreakStatus::kContinue;
}
} while (next_column_token);
......@@ -361,7 +387,7 @@ bool NGColumnLayoutAlgorithm::LayoutChildren() {
intrinsic_block_size_ += margin_strut.Sum();
}
return true;
return NGBreakStatus::kContinue;
}
scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::LayoutRow(
......@@ -400,13 +426,23 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::LayoutRow(
LayoutUnit column_block_offset = intrinsic_block_size_ + margin_strut->Sum();
bool needs_more_fragments_in_outer = false;
bool zero_outer_space_left = false;
if (is_constrained_by_outer_fragmentation_context_) {
LayoutUnit available_outer_space =
FragmentainerSpaceAtBfcStart(ConstraintSpace()) - column_block_offset;
// TODO(mstensho): This should never be negative, or even zero. Turn into a
// DCHECK when the underlying problem is fixed.
available_outer_space = available_outer_space.ClampNegativeToZero();
if (available_outer_space <= LayoutUnit()) {
if (available_outer_space < LayoutUnit()) {
// We're past the end of the outer fragmentainer (typically due to a
// margin). Nothing will fit here, not even zero-size content.
return nullptr;
}
// We are out of space, but we're exactly at the end of the outer
// fragmentainer. If none of our contents take up space, we're going to
// fit, otherwise not. Lay out and find out.
zero_outer_space_left = true;
}
// Check if we can fit everything (that's remaining), block-wise, within the
// current outer fragmentainer. If we can't, we need to adjust the block
......@@ -497,6 +533,11 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::LayoutRow(
if (ConstraintSpace().HasBlockFragmentation() && column_break_token &&
actual_column_count >= used_column_count_ &&
needs_more_fragments_in_outer) {
// We cannot keep any of this if we have zero space left. Then we need
// to resume in the next outer fragmentainer.
if (zero_outer_space_left)
return nullptr;
container_builder_.SetDidBreak();
container_builder_.SetBreakAppeal(kBreakAppealPerfect);
break;
......@@ -763,6 +804,10 @@ LayoutUnit NGColumnLayoutAlgorithm::CalculateBalancedColumnBlockSize(
NGBlockLayoutAlgorithm balancing_algorithm(
{Node(), fragment_geometry, space, break_token.get()});
scoped_refptr<const NGLayoutResult> result = balancing_algorithm.Layout();
// This algorithm should never abort.
DCHECK_EQ(result->Status(), NGLayoutResult::kSuccess);
const NGPhysicalBoxFragment& fragment =
To<NGPhysicalBoxFragment>(result->PhysicalFragment());
LayoutUnit column_block_size = CalculateColumnContentBlockSize(
......@@ -855,6 +900,20 @@ LayoutUnit NGColumnLayoutAlgorithm::ConstrainColumnBlockSize(
return size - extra;
}
void NGColumnLayoutAlgorithm::FinishAfterBreakBeforeRow(
scoped_refptr<const NGBlockBreakToken> next_column_token) {
// We broke before a row for columns. We're done here. Take up the remaining
// space in the outer fragmentation context.
intrinsic_block_size_ = FragmentainerSpaceAtBfcStart(ConstraintSpace());
// If we were about to resume column layout after a spanner, add a break token
// for this, so that we resume there in the next outer fragmentainer. If
// there's no such break token, it means that we're at the start of the
// multicol container.
if (next_column_token)
container_builder_.AddBreakToken(std::move(next_column_token));
}
void NGColumnLayoutAlgorithm::FinishAfterBreakBeforeSpanner(
scoped_refptr<const NGBlockBreakToken> next_column_token) {
// We broke before the spanner. We're done here. Take up the remaining space
......
......@@ -30,13 +30,17 @@ class CORE_EXPORT NGColumnLayoutAlgorithm
const MinMaxSizeInput&) const override;
private:
// Lay out as many children as we can. If false is returned, it means that we
// ran out of space at an unappealing location, and need to relayout and break
// earlier (because we have a better breakpoint there).
bool LayoutChildren();
// Lay out as many children as we can. If |kNeedsEarlierBreak| is returned, it
// means that we ran out of space at an unappealing location, and need to
// relayout and break earlier (because we have a better breakpoint there). If
// |kBrokeBefore| is returned, it means that we need to break before the
// multicol container, and retry in the next fragmentainer.
NGBreakStatus LayoutChildren();
// Lay out one row of columns. The layout result returned is for the last
// column that was laid out. The rows themselves don't create fragments.
// column that was laid out. The rows themselves don't create fragments. If
// we're in a nested fragmentation context and completely out of outer
// fragmentainer space, nullptr will be returned.
scoped_refptr<const NGLayoutResult> LayoutRow(
const NGBlockBreakToken* next_column_token,
NGMarginStrut*);
......@@ -66,6 +70,10 @@ class CORE_EXPORT NGColumnLayoutAlgorithm
return intrinsic_block_size_ - border_scrollbar_padding_.block_start;
}
// Finalize layout after breaking before column contents.
void FinishAfterBreakBeforeRow(
scoped_refptr<const NGBlockBreakToken> next_column_token);
// Finalize layout after breaking before a spanner.
void FinishAfterBreakBeforeSpanner(
scoped_refptr<const NGBlockBreakToken> next_column_token);
......
......@@ -4313,6 +4313,168 @@ TEST_F(NGColumnLayoutAlgorithmTest, NestedUnbalancedInnerAutoHeight) {
EXPECT_EQ(expectation, dump);
}
TEST_F(NGColumnLayoutAlgorithmTest, NestedAtOuterBoundary) {
SetBodyInnerHTML(R"HTML(
<style>
.outer { columns:3; height:100px; width:320px; }
.inner { columns:2; height:50px; }
.outer, .inner { column-gap:10px; column-fill:auto; }
</style>
<div id="container">
<div class="outer">
<div style="width:11px; height:100px;"></div>
<div class="inner">
<div style="width:22px; height:70px;"></div>
</div>
</div>
</div>
)HTML");
String dump = DumpFragmentTree(GetElementById("container"));
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x100
offset:0,0 size:320x100
offset:0,0 size:100x100
offset:0,0 size:11x100
offset:110,0 size:100x100
offset:0,0 size:100x50
offset:0,0 size:45x50
offset:0,0 size:22x50
offset:55,0 size:45x50
offset:0,0 size:22x20
)DUMP";
EXPECT_EQ(expectation, dump);
}
TEST_F(NGColumnLayoutAlgorithmTest, NestedZeroHeightAtOuterBoundary) {
SetBodyInnerHTML(R"HTML(
<style>
.outer { columns:3; height:100px; width:320px; }
.inner { columns:2; }
.outer, .inner { column-gap:10px; column-fill:auto; }
</style>
<div id="container">
<div class="outer">
<div style="width:11px; height:100px;"></div>
<div class="inner">
<div style="width:22px;"></div>
</div>
</div>
</div>
)HTML");
String dump = DumpFragmentTree(GetElementById("container"));
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x100
offset:0,0 size:320x100
offset:0,0 size:100x100
offset:0,0 size:11x100
offset:0,100 size:100x0
offset:0,0 size:45x1
offset:0,0 size:22x0
)DUMP";
EXPECT_EQ(expectation, dump);
}
TEST_F(NGColumnLayoutAlgorithmTest, NestedWithMarginAtOuterBoundary) {
SetBodyInnerHTML(R"HTML(
<style>
.outer { columns:3; height:100px; width:320px; }
.inner { columns:2; height:50px; margin-top:20px; }
.outer, .inner { column-gap:10px; column-fill:auto; }
</style>
<div id="container">
<div class="outer">
<div style="width:11px; height:90px;"></div>
<div class="inner">
<div style="width:22px; height:70px;"></div>
</div>
</div>
</div>
)HTML");
String dump = DumpFragmentTree(GetElementById("container"));
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x100
offset:0,0 size:320x100
offset:0,0 size:100x100
offset:0,0 size:11x90
offset:110,0 size:100x100
offset:0,0 size:100x50
offset:0,0 size:45x50
offset:0,0 size:22x50
offset:55,0 size:45x50
offset:0,0 size:22x20
)DUMP";
EXPECT_EQ(expectation, dump);
}
TEST_F(NGColumnLayoutAlgorithmTest, NestedWithTallBorder) {
SetBodyInnerHTML(R"HTML(
<style>
.outer { columns:3; height:100px; width:320px; }
.inner { columns:2; height:50px; border-top:100px solid; }
.outer, .inner { column-gap:10px; column-fill:auto; }
</style>
<div id="container">
<div class="outer">
<div class="inner">
<div style="width:22px; height:70px;"></div>
</div>
</div>
</div>
)HTML");
String dump = DumpFragmentTree(GetElementById("container"));
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x100
offset:0,0 size:320x100
offset:0,0 size:100x100
offset:0,0 size:100x100
offset:110,0 size:100x100
offset:0,0 size:100x50
offset:0,0 size:45x50
offset:0,0 size:22x50
offset:55,0 size:45x50
offset:0,0 size:22x20
)DUMP";
EXPECT_EQ(expectation, dump);
}
TEST_F(NGColumnLayoutAlgorithmTest, NestedWithTallSpanner) {
SetBodyInnerHTML(R"HTML(
<style>
.outer { columns:3; height:100px; width:320px; column-fill:auto; }
.inner { columns:2; }
.outer, .inner { column-gap:10px; }
</style>
<div id="container">
<div class="outer">
<div class="inner">
<div style="column-span:all; width:22px; height:100px;"></div>
<div style="width:22px; height:70px;"></div>
</div>
</div>
</div>
)HTML");
String dump = DumpFragmentTree(GetElementById("container"));
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x100
offset:0,0 size:320x100
offset:0,0 size:100x100
offset:0,0 size:100x100
offset:0,0 size:22x100
offset:110,0 size:100x100
offset:0,0 size:100x35
offset:0,0 size:45x35
offset:0,0 size:22x35
offset:55,0 size:45x35
offset:0,0 size:22x35
)DUMP";
EXPECT_EQ(expectation, dump);
}
TEST_F(NGColumnLayoutAlgorithmTest, AbsposFitsInOneColumn) {
SetBodyInnerHTML(R"HTML(
<div id="container">
......
......@@ -59,6 +59,10 @@ scoped_refptr<const NGLayoutResult> NGFieldsetLayoutAlgorithm::Layout() {
auto legend_space =
CreateConstraintSpaceForLegend(legend, content_box_size);
auto result = legend.Layout(legend_space, BreakToken());
// TODO(layout-dev): Handle abortions caused by block fragmentation.
DCHECK_EQ(result->Status(), NGLayoutResult::kSuccess);
const auto& physical_fragment = result->PhysicalFragment();
NGBoxStrut legend_margins =
ComputeMarginsFor(legend_space, legend.Style(), ConstraintSpace());
......@@ -105,6 +109,10 @@ scoped_refptr<const NGLayoutResult> NGFieldsetLayoutAlgorithm::Layout() {
auto child_space =
CreateConstraintSpaceForFieldsetContent(adjusted_padding_box_size);
auto result = fieldset_content.Layout(child_space, BreakToken());
// TODO(layout-dev): Handle abortions caused by block fragmentation.
DCHECK_EQ(result->Status(), NGLayoutResult::kSuccess);
const auto& physical_fragment = result->PhysicalFragment();
container_builder_.AddChild(physical_fragment,
borders_with_legend.StartOffset());
......
......@@ -702,6 +702,10 @@ scoped_refptr<const NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
NGConstraintSpace child_space = space_builder.ToConstraintSpace();
flex_item.layout_result =
flex_item.ng_input_node.Layout(child_space, nullptr /*break token*/);
// TODO(layout-dev): Handle abortions caused by block fragmentation.
DCHECK_EQ(flex_item.layout_result->Status(), NGLayoutResult::kSuccess);
flex_item.cross_axis_size =
is_horizontal_flow_
? flex_item.layout_result->PhysicalFragment().Size().height
......
......@@ -271,11 +271,13 @@ void BreakBeforeChild(const NGConstraintSpace& space,
bool is_forced_break,
NGBoxFragmentBuilder* builder) {
#if DCHECK_IS_ON()
// In order to successfully break before a node, this has to be its first
// fragment.
const auto& physical_fragment = layout_result.PhysicalFragment();
DCHECK(!physical_fragment.IsBox() ||
To<NGPhysicalBoxFragment>(physical_fragment).IsFirstForNode());
if (layout_result.Status() == NGLayoutResult::kSuccess) {
// In order to successfully break before a node, this has to be its first
// fragment.
const auto& physical_fragment = layout_result.PhysicalFragment();
DCHECK(!physical_fragment.IsBox() ||
To<NGPhysicalBoxFragment>(physical_fragment).IsFirstForNode());
}
#endif
// Report space shortage. Note that we're not doing this for line boxes here
......@@ -310,7 +312,10 @@ void PropagateSpaceShortage(const NGConstraintSpace& space,
LayoutUnit space_shortage;
if (layout_result.MinimalSpaceShortage() == LayoutUnit::Max()) {
// Calculate space shortage: Figure out how much more space would have been
// sufficient to make the child fit right here in the current fragment.
// sufficient to make the child fragment fit right here in the current
// fragmentainer. If layout aborted, though, we can't propagate anything.
if (layout_result.Status() != NGLayoutResult::kSuccess)
return;
NGFragment fragment(space.GetWritingMode(),
layout_result.PhysicalFragment());
space_shortage = fragmentainer_block_offset + fragment.BlockSize() -
......@@ -335,6 +340,13 @@ bool MovePastBreakpoint(const NGConstraintSpace& space,
LayoutUnit fragmentainer_block_offset,
NGBreakAppeal appeal_before,
NGBoxFragmentBuilder* builder) {
if (layout_result.Status() != NGLayoutResult::kSuccess) {
// Layout aborted - no fragment was produced. There's nothing to move
// past. We need to break before.
DCHECK_EQ(layout_result.Status(), NGLayoutResult::kOutOfFragmentainerSpace);
return false;
}
const auto& physical_fragment = layout_result.PhysicalFragment();
NGFragment fragment(space.GetWritingMode(), physical_fragment);
......
......@@ -41,6 +41,7 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
kSuccess = 0,
kBfcBlockOffsetResolved = 1,
kNeedsEarlierBreak = 2,
kOutOfFragmentainerSpace = 3,
// When adding new values, make sure the bit size of |Bitfields::status| is
// large enough to store.
};
......
......@@ -636,6 +636,9 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
GenerateFragment(node, container_content_size_in_candidate_writing_mode,
block_estimate, node_position);
// TODO(layout-dev): Handle abortions caused by block fragmentation.
DCHECK(layout_result->Status() != NGLayoutResult::kOutOfFragmentainerSpace);
NGFragment fragment(candidate_writing_mode,
layout_result->PhysicalFragment());
......@@ -723,6 +726,9 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
block_estimate, node_position);
}
// TODO(layout-dev): Handle abortions caused by block fragmentation.
DCHECK_EQ(layout_result->Status(), NGLayoutResult::kSuccess);
// TODO(mstensho): Move the rest of this method back into LayoutCandidate().
if (node.GetLayoutBox()->IsLayoutNGObject()) {
......
......@@ -1047,7 +1047,6 @@ crbug.com/591099 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/mult
crbug.com/591099 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-rule-003.xht [ Failure ]
crbug.com/792435 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-rule-004.xht [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-rule-color-001.xht [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-rule-color-inherit-001.xht [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-rule-fraction-001.xht [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-rule-fraction-002.xht [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-rule-fraction-003.xht [ Crash Failure ]
......@@ -1216,7 +1215,6 @@ crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/nested-auto-height.h
crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/nested-auto-height-short-first-row.html [ Failure ]
crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/nested-balanced-inner-column-count-1-with-forced-break.html [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/nested-balanced-inner-with-many-breaks-2.html [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/nested-balanced-inner-with-many-breaks.html [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/nested-balanced-with-strut-before-first-line.html [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/nested-columns.html [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/nested-fixed-height-with-struts.html [ Failure ]
......
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