Commit e090d82a authored by Alison Maher's avatar Alison Maher Committed by Commit Bot

[LayoutNG] Legend break inside avoid

If the legend sets break-inside to avoid, and we can break before the
fieldset, we should do so if it is a more appealing break point.

This, however, was not the case because the fieldset content, if empty,
would get laid out and override the break appeal of the builder,
which is why the fieldset did not know to break before.

This change fixes this issue by avoiding laying out the fieldset content
if we've run out of space from laying out the legend.

Bug: 875235
Change-Id: I2db2554fb1032d8297c6df954d9d8f6194b041d9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2116834
Commit-Queue: Alison Maher <almaher@microsoft.com>
Reviewed-by: default avatarMorten Stenshorne <mstensho@chromium.org>
Cr-Commit-Position: refs/heads/master@{#753279}
parent d00acdcc
...@@ -199,9 +199,17 @@ NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutChildren() { ...@@ -199,9 +199,17 @@ NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutChildren() {
// all live inside an anonymous child box of the fieldset container. // all live inside an anonymous child box of the fieldset container.
auto fieldset_content = Node().GetFieldsetContent(); auto fieldset_content = Node().GetFieldsetContent();
if (fieldset_content && (content_break_token || !has_seen_all_children)) { if (fieldset_content && (content_break_token || !has_seen_all_children)) {
NGBreakStatus break_status = LayoutUnit fragmentainer_block_offset;
LayoutFieldsetContent(fieldset_content, content_break_token, if (ConstraintSpace().HasBlockFragmentation()) {
adjusted_padding_box_size, !!legend); fragmentainer_block_offset =
ConstraintSpace().FragmentainerOffsetAtBfc() + intrinsic_block_size_;
if (legend_broke_ &&
IsFragmentainerOutOfSpace(fragmentainer_block_offset))
return NGBreakStatus::kContinue;
}
NGBreakStatus break_status = LayoutFieldsetContent(
fieldset_content, content_break_token, adjusted_padding_box_size,
fragmentainer_block_offset, !!legend);
if (break_status == NGBreakStatus::kNeedsEarlierBreak) if (break_status == NGBreakStatus::kNeedsEarlierBreak)
return break_status; return break_status;
} }
...@@ -257,6 +265,7 @@ NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutLegend( ...@@ -257,6 +265,7 @@ NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutLegend(
} }
const auto& physical_fragment = result->PhysicalFragment(); const auto& physical_fragment = result->PhysicalFragment();
legend_broke_ = physical_fragment.BreakToken();
// We have already adjusted the legend block offset, no need to adjust // We have already adjusted the legend block offset, no need to adjust
// again. // again.
...@@ -305,6 +314,7 @@ NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutFieldsetContent( ...@@ -305,6 +314,7 @@ NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutFieldsetContent(
NGBlockNode& fieldset_content, NGBlockNode& fieldset_content,
scoped_refptr<const NGBlockBreakToken> content_break_token, scoped_refptr<const NGBlockBreakToken> content_break_token,
LogicalSize adjusted_padding_box_size, LogicalSize adjusted_padding_box_size,
LayoutUnit fragmentainer_block_offset,
bool has_legend) { bool has_legend) {
auto child_space = CreateConstraintSpaceForFieldsetContent( auto child_space = CreateConstraintSpaceForFieldsetContent(
fieldset_content, adjusted_padding_box_size, fieldset_content, adjusted_padding_box_size,
...@@ -316,11 +326,10 @@ NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutFieldsetContent( ...@@ -316,11 +326,10 @@ NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutFieldsetContent(
NGBreakStatus break_status = NGBreakStatus::kContinue; NGBreakStatus break_status = NGBreakStatus::kContinue;
if (ConstraintSpace().HasBlockFragmentation()) { if (ConstraintSpace().HasBlockFragmentation()) {
LayoutUnit block_offset =
ConstraintSpace().FragmentainerOffsetAtBfc() + intrinsic_block_size_;
// TODO(almaher): The legend should be treated as out-of-flow. // TODO(almaher): The legend should be treated as out-of-flow.
break_status = BreakBeforeChildIfNeeded( break_status = BreakBeforeChildIfNeeded(
ConstraintSpace(), fieldset_content, *result.get(), block_offset, ConstraintSpace(), fieldset_content, *result.get(),
fragmentainer_block_offset,
/*has_container_separation*/ has_legend, &container_builder_); /*has_container_separation*/ has_legend, &container_builder_);
EBreakBetween break_after = JoinFragmentainerBreakValues( EBreakBetween break_after = JoinFragmentainerBreakValues(
result->FinalBreakAfter(), fieldset_content.Style().BreakAfter()); result->FinalBreakAfter(), fieldset_content.Style().BreakAfter());
...@@ -337,6 +346,13 @@ NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutFieldsetContent( ...@@ -337,6 +346,13 @@ NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutFieldsetContent(
return break_status; return break_status;
} }
bool NGFieldsetLayoutAlgorithm::IsFragmentainerOutOfSpace(
LayoutUnit block_offset) const {
if (!ConstraintSpace().HasKnownFragmentainerBlockSize())
return false;
return block_offset >= FragmentainerSpaceAtBfcStart(ConstraintSpace());
}
base::Optional<MinMaxSizes> NGFieldsetLayoutAlgorithm::ComputeMinMaxSizes( base::Optional<MinMaxSizes> NGFieldsetLayoutAlgorithm::ComputeMinMaxSizes(
const MinMaxSizesInput& input) const { const MinMaxSizesInput& input) const {
MinMaxSizes sizes; MinMaxSizes sizes;
......
...@@ -37,6 +37,7 @@ class CORE_EXPORT NGFieldsetLayoutAlgorithm ...@@ -37,6 +37,7 @@ class CORE_EXPORT NGFieldsetLayoutAlgorithm
NGBlockNode& fieldset_content, NGBlockNode& fieldset_content,
scoped_refptr<const NGBlockBreakToken> content_break_token, scoped_refptr<const NGBlockBreakToken> content_break_token,
LogicalSize adjusted_padding_box_size, LogicalSize adjusted_padding_box_size,
LayoutUnit fragmentainer_block_offset,
bool has_legend); bool has_legend);
const NGConstraintSpace CreateConstraintSpaceForLegend( const NGConstraintSpace CreateConstraintSpaceForLegend(
...@@ -49,6 +50,8 @@ class CORE_EXPORT NGFieldsetLayoutAlgorithm ...@@ -49,6 +50,8 @@ class CORE_EXPORT NGFieldsetLayoutAlgorithm
LogicalSize padding_box_size, LogicalSize padding_box_size,
LayoutUnit block_offset); LayoutUnit block_offset);
bool IsFragmentainerOutOfSpace(LayoutUnit block_offset) const;
const WritingMode writing_mode_; const WritingMode writing_mode_;
const NGBoxStrut border_padding_; const NGBoxStrut border_padding_;
...@@ -75,6 +78,10 @@ class CORE_EXPORT NGFieldsetLayoutAlgorithm ...@@ -75,6 +78,10 @@ class CORE_EXPORT NGFieldsetLayoutAlgorithm
// If true, this indicates the block_start_padding_edge_ had changed from its // If true, this indicates the block_start_padding_edge_ had changed from its
// initial value during the current layout pass. // initial value during the current layout pass.
bool block_start_padding_edge_adjusted_ = false; bool block_start_padding_edge_adjusted_ = false;
// If true, this indicates that the legend broke during the current layout
// pass.
bool legend_broke_ = false;
}; };
} // namespace blink } // namespace blink
......
...@@ -1302,7 +1302,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, BreakInsideAvoid) { ...@@ -1302,7 +1302,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, BreakInsideAvoid) {
<fieldset id="fieldset"> <fieldset id="fieldset">
<legend id="legend" style="width:10px; height:50px;"></legend> <legend id="legend" style="width:10px; height:50px;"></legend>
<div style="break-inside:avoid; width:20px; height:70px;"></div> <div style="break-inside:avoid; width:20px; height:70px;"></div>
</fieldsest> </fieldset>
)HTML"); )HTML");
LayoutUnit kFragmentainerSpaceAvailable(100); LayoutUnit kFragmentainerSpaceAvailable(100);
...@@ -1354,7 +1354,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, BreakInsideAvoidTallBlock) { ...@@ -1354,7 +1354,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, BreakInsideAvoidTallBlock) {
<fieldset id="fieldset"> <fieldset id="fieldset">
<legend id="legend" style="width:10px; height:50px;"></legend> <legend id="legend" style="width:10px; height:50px;"></legend>
<div style="break-inside:avoid; width:20px; height:170px;"></div> <div style="break-inside:avoid; width:20px; height:170px;"></div>
</fieldsest> </fieldset>
)HTML"); )HTML");
LayoutUnit kFragmentainerSpaceAvailable(100); LayoutUnit kFragmentainerSpaceAvailable(100);
...@@ -1416,7 +1416,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendBreakInsideAvoid) { ...@@ -1416,7 +1416,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendBreakInsideAvoid) {
<fieldset id="fieldset"> <fieldset id="fieldset">
<legend id="legend" style="break-inside:avoid; width:10px; height:60px;"> <legend id="legend" style="break-inside:avoid; width:10px; height:60px;">
</legend> </legend>
</fieldsest> </fieldset>
</div> </div>
)HTML"); )HTML");
...@@ -1432,15 +1432,10 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendBreakInsideAvoid) { ...@@ -1432,15 +1432,10 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendBreakInsideAvoid) {
NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(node, space); NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(node, space);
ASSERT_FALSE(fragment->BreakToken()->IsFinished()); ASSERT_FALSE(fragment->BreakToken()->IsFinished());
// TODO(almaher): Breaking before the fieldset has higher appeal than
// breaking inside the legend
String dump = DumpFragmentTree(fragment.get()); String dump = DumpFragmentTree(fragment.get());
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x100 offset:unplaced size:1000x100
offset:0,0 size:20x50 offset:0,0 size:20x50
offset:0,50 size:100x50
offset:0,0 size:10x50
offset:0,50 size:100x0
)DUMP"; )DUMP";
EXPECT_EQ(expectation, dump); EXPECT_EQ(expectation, dump);
...@@ -1450,9 +1445,10 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendBreakInsideAvoid) { ...@@ -1450,9 +1445,10 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendBreakInsideAvoid) {
dump = DumpFragmentTree(fragment.get()); dump = DumpFragmentTree(fragment.get());
expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:1000x10 offset:unplaced size:1000x60
offset:0,0 size:100x10 offset:0,0 size:100x60
offset:0,0 size:10x10 offset:0,0 size:10x60
offset:0,60 size:100x0
)DUMP"; )DUMP";
EXPECT_EQ(expectation, dump); EXPECT_EQ(expectation, dump);
} }
...@@ -1473,7 +1469,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, BreakBeforeAvoid) { ...@@ -1473,7 +1469,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, BreakBeforeAvoid) {
<legend id="legend" style="width:10px; height:25px;"></legend> <legend id="legend" style="width:10px; height:25px;"></legend>
<div style="width:30px; height:25px;"></div> <div style="width:30px; height:25px;"></div>
<div style="break-before:avoid; width:15px; height:25px;"></div> <div style="break-before:avoid; width:15px; height:25px;"></div>
</fieldsest> </fieldset>
</div> </div>
)HTML"); )HTML");
...@@ -1527,7 +1523,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendBreakBeforeAvoid) { ...@@ -1527,7 +1523,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendBreakBeforeAvoid) {
<div style="width:20px; height:90px;"></div> <div style="width:20px; height:90px;"></div>
<fieldset id="fieldset"> <fieldset id="fieldset">
<legend id="legend" style="break-before:avoid;"></legend> <legend id="legend" style="break-before:avoid;"></legend>
</fieldsest> </fieldset>
</div> </div>
)HTML"); )HTML");
...@@ -1580,7 +1576,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, BreakAfterAvoid) { ...@@ -1580,7 +1576,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, BreakAfterAvoid) {
<legend id="legend" style="width:10px; height:25px;"></legend> <legend id="legend" style="width:10px; height:25px;"></legend>
<div style="break-after:avoid; width:30px; height:25px;"></div> <div style="break-after:avoid; width:30px; height:25px;"></div>
<div style="width:15px; height:25px;"></div> <div style="width:15px; height:25px;"></div>
</fieldsest> </fieldset>
</div> </div>
)HTML"); )HTML");
...@@ -1635,7 +1631,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendBreakAfterAvoid) { ...@@ -1635,7 +1631,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendBreakAfterAvoid) {
<fieldset id="fieldset"> <fieldset id="fieldset">
<legend id="legend" style="break-after:avoid;"></legend> <legend id="legend" style="break-after:avoid;"></legend>
<div style="width:15px; height:25px;"></div> <div style="width:15px; height:25px;"></div>
</fieldsest> </fieldset>
</div> </div>
)HTML"); )HTML");
...@@ -1690,7 +1686,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, MarginTopPastEndOfFragmentainer) { ...@@ -1690,7 +1686,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, MarginTopPastEndOfFragmentainer) {
<fieldset id="fieldset"> <fieldset id="fieldset">
<legend id="legend" style="margin-top:60px; width:10px; height:20px;"></legend> <legend id="legend" style="margin-top:60px; width:10px; height:20px;"></legend>
<div style="width:20px; height:20px;"></div> <div style="width:20px; height:20px;"></div>
</fieldsest> </fieldset>
)HTML"); )HTML");
LayoutUnit kFragmentainerSpaceAvailable(50); LayoutUnit kFragmentainerSpaceAvailable(50);
...@@ -1742,7 +1738,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, MarginBottomPastEndOfFragmentainer) { ...@@ -1742,7 +1738,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, MarginBottomPastEndOfFragmentainer) {
<fieldset id="fieldset"> <fieldset id="fieldset">
<legend id="legend" style="margin-bottom:20px; height:90px;"></legend> <legend id="legend" style="margin-bottom:20px; height:90px;"></legend>
<div style="width:20px; height:20px;"></div> <div style="width:20px; height:20px;"></div>
</fieldsest> </fieldset>
)HTML"); )HTML");
LayoutUnit kFragmentainerSpaceAvailable(100); LayoutUnit kFragmentainerSpaceAvailable(100);
......
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