Commit 2c852be8 authored by Alison Maher's avatar Alison Maher Committed by Commit Bot

[LayoutNG] Fieldset content with negative margin block start

Handle fragmentation for fieldset content with a negative margin block
start. The following was required to accomplish this:

1. Don't wait to layout fieldset content until there is available
space in the current fragment.
2. Break before fieldset content if necessary.

Bug: 875235
Change-Id: I0c95fe37694e2a0022ed9222db0a7af13cc958b9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2099284
Commit-Queue: Alison Maher <almaher@microsoft.com>
Reviewed-by: default avatarMorten Stenshorne <mstensho@chromium.org>
Cr-Commit-Position: refs/heads/master@{#750233}
parent 44bdde21
...@@ -173,24 +173,16 @@ scoped_refptr<const NGLayoutResult> NGFieldsetLayoutAlgorithm::Layout() { ...@@ -173,24 +173,16 @@ scoped_refptr<const NGLayoutResult> NGFieldsetLayoutAlgorithm::Layout() {
borders_with_legend.block_start = block_start_padding_edge; borders_with_legend.block_start = block_start_padding_edge;
LogicalSize adjusted_padding_box_size = LogicalSize adjusted_padding_box_size =
ShrinkAvailableSize(border_box_size, borders_with_legend); ShrinkAvailableSize(border_box_size, borders_with_legend);
if (content_break_token || if ((IsResumingLayout(content_break_token.get())) ||
(!block_start_padding_edge_adjusted && IsResumingLayout(BreakToken()))) { (!block_start_padding_edge_adjusted && IsResumingLayout(BreakToken()))) {
borders_with_legend.block_start = LayoutUnit(); borders_with_legend.block_start = LayoutUnit();
} }
LayoutUnit intrinsic_block_size = borders_with_legend.BlockSum(); LayoutUnit intrinsic_block_size = borders_with_legend.BlockSum();
bool has_space_left = true;
if (ConstraintSpace().HasKnownFragmentainerBlockSize()) {
LayoutUnit space_left =
FragmentainerSpaceAtBfcStart(ConstraintSpace()) - intrinsic_block_size;
has_space_left = space_left > 0;
}
// Proceed with normal fieldset children (excluding the rendered legend). They // Proceed with normal fieldset children (excluding the rendered legend). They
// 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 (has_space_left && fieldset_content && if (fieldset_content && (content_break_token || !has_seen_all_children)) {
(content_break_token || !has_seen_all_children)) {
auto child_space = CreateConstraintSpaceForFieldsetContent( auto child_space = CreateConstraintSpaceForFieldsetContent(
fieldset_content, adjusted_padding_box_size, fieldset_content, adjusted_padding_box_size,
borders_with_legend.block_start); borders_with_legend.block_start);
...@@ -200,26 +192,34 @@ scoped_refptr<const NGLayoutResult> NGFieldsetLayoutAlgorithm::Layout() { ...@@ -200,26 +192,34 @@ scoped_refptr<const NGLayoutResult> NGFieldsetLayoutAlgorithm::Layout() {
// TODO(layout-dev): Handle abortions caused by block fragmentation. // TODO(layout-dev): Handle abortions caused by block fragmentation.
DCHECK_EQ(result->Status(), NGLayoutResult::kSuccess); DCHECK_EQ(result->Status(), NGLayoutResult::kSuccess);
container_builder_.AddResult(*result, borders_with_legend.StartOffset()); NGBreakStatus break_status = NGBreakStatus::kContinue;
if (ConstraintSpace().HasBlockFragmentation()) {
LayoutUnit block_offset =
ConstraintSpace().FragmentainerOffsetAtBfc() + intrinsic_block_size;
break_status = BreakBeforeChildIfNeeded(
ConstraintSpace(), fieldset_content, *result.get(), block_offset,
/*has_container_separation*/ true, &container_builder_);
}
const auto& physical_fragment = result->PhysicalFragment(); if (break_status == NGBreakStatus::kContinue) {
intrinsic_block_size += container_builder_.AddResult(*result, borders_with_legend.StartOffset());
NGFragment(writing_mode, physical_fragment).BlockSize(); intrinsic_block_size +=
container_builder_.SetHasSeenAllChildren(); NGFragment(writing_mode, result->PhysicalFragment()).BlockSize();
container_builder_.SetHasSeenAllChildren();
}
} }
LayoutUnit consumed_block_size =
BreakToken() ? BreakToken()->ConsumedBlockSize() : LayoutUnit();
if (!fieldset_content) { if (!fieldset_content) {
container_builder_.SetHasSeenAllChildren(); container_builder_.SetHasSeenAllChildren();
// There was no anonymous child to provide the padding, so we have to add it // There was no anonymous child to provide the padding, so we have to add it
// ourselves. Subtract out the consumed block size to avoid over-calculating // ourselves.
// the block size when the fieldset's height is auto.
intrinsic_block_size += padding.BlockSum(); intrinsic_block_size += padding.BlockSum();
} }
intrinsic_block_size = ClampIntrinsicBlockSize( intrinsic_block_size = ClampIntrinsicBlockSize(
ConstraintSpace(), Node(), adjusted_border_padding, intrinsic_block_size); ConstraintSpace(), Node(), adjusted_border_padding, intrinsic_block_size);
LayoutUnit consumed_block_size =
BreakToken() ? BreakToken()->ConsumedBlockSize() : LayoutUnit();
// Recompute the block-axis size now that we know our content size. // Recompute the block-axis size now that we know our content size.
border_box_size.block_size = border_box_size.block_size =
......
...@@ -514,7 +514,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, MinMax) { ...@@ -514,7 +514,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, MinMax) {
// line. // line.
TEST_F(NGFieldsetLayoutAlgorithmTest, NoFragmentation) { TEST_F(NGFieldsetLayoutAlgorithmTest, NoFragmentation) {
SetBodyInnerHTML(R"HTML( SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
<style> <style>
fieldset { fieldset {
border:3px solid; margin:0; padding:10px; width: 150px; height: 100px; border:3px solid; margin:0; padding:10px; width: 150px; height: 100px;
...@@ -541,7 +540,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, NoFragmentation) { ...@@ -541,7 +540,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, NoFragmentation) {
// Tests that a fieldset will fragment if it reaches the fragmentation line. // Tests that a fieldset will fragment if it reaches the fragmentation line.
TEST_F(NGFieldsetLayoutAlgorithmTest, SimpleFragmentation) { TEST_F(NGFieldsetLayoutAlgorithmTest, SimpleFragmentation) {
SetBodyInnerHTML(R"HTML( SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
<style> <style>
#fieldset { #fieldset {
border:3px solid; margin:0; padding:10px; width: 150px; height: 500px; border:3px solid; margin:0; padding:10px; width: 150px; height: 500px;
...@@ -617,7 +615,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, FragmentationNoPadding) { ...@@ -617,7 +615,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, FragmentationNoPadding) {
// the fragmentation line. // the fragmentation line.
TEST_F(NGFieldsetLayoutAlgorithmTest, FieldsetContentFragmentationAutoHeight) { TEST_F(NGFieldsetLayoutAlgorithmTest, FieldsetContentFragmentationAutoHeight) {
SetBodyInnerHTML(R"HTML( SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
<style> <style>
#fieldset { #fieldset {
border:3px solid; margin:0; padding:10px; width: 150px; border:3px solid; margin:0; padding:10px; width: 150px;
...@@ -680,7 +677,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, FieldsetContentFragmentationAutoHeight) { ...@@ -680,7 +677,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, FieldsetContentFragmentationAutoHeight) {
// reaches the fragmentation line. // reaches the fragmentation line.
TEST_F(NGFieldsetLayoutAlgorithmTest, FieldsetContentFragmentation) { TEST_F(NGFieldsetLayoutAlgorithmTest, FieldsetContentFragmentation) {
SetBodyInnerHTML(R"HTML( SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
<style> <style>
#fieldset { #fieldset {
border:3px solid; margin:0; padding:10px; width: 150px; height: 100px; border:3px solid; margin:0; padding:10px; width: 150px; height: 100px;
...@@ -743,7 +739,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, FieldsetContentFragmentation) { ...@@ -743,7 +739,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, FieldsetContentFragmentation) {
// the fragmentation line. // the fragmentation line.
TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentationAutoHeight) { TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentationAutoHeight) {
SetBodyInnerHTML(R"HTML( SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
<style> <style>
#fieldset { #fieldset {
border:3px solid; margin:0; padding:10px; width: 150px; border:3px solid; margin:0; padding:10px; width: 150px;
...@@ -805,7 +800,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentationAutoHeight) { ...@@ -805,7 +800,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentationAutoHeight) {
// encompass the legend. // encompass the legend.
TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentation) { TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentation) {
SetBodyInnerHTML(R"HTML( SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
<style> <style>
#fieldset { #fieldset {
border:3px solid; margin:0; padding:10px; width: 150px; height: 100px; border:3px solid; margin:0; padding:10px; width: 150px; height: 100px;
...@@ -866,7 +860,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentation) { ...@@ -866,7 +860,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentation) {
// reaches the fragmentation line. // reaches the fragmentation line.
TEST_F(NGFieldsetLayoutAlgorithmTest, LegendAndContentFragmentationAutoHeight) { TEST_F(NGFieldsetLayoutAlgorithmTest, LegendAndContentFragmentationAutoHeight) {
SetBodyInnerHTML(R"HTML( SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
<style> <style>
#fieldset { #fieldset {
border:3px solid; margin:0; padding:10px; width: 150px; border:3px solid; margin:0; padding:10px; width: 150px;
...@@ -944,7 +937,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendAndContentFragmentationAutoHeight) { ...@@ -944,7 +937,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendAndContentFragmentationAutoHeight) {
// reaches the fragmentation line. // reaches the fragmentation line.
TEST_F(NGFieldsetLayoutAlgorithmTest, LegendAndContentFragmentation) { TEST_F(NGFieldsetLayoutAlgorithmTest, LegendAndContentFragmentation) {
SetBodyInnerHTML(R"HTML( SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
<style> <style>
#fieldset { #fieldset {
border:3px solid; margin:0; padding:10px; width: 150px; height: 100px; border:3px solid; margin:0; padding:10px; width: 150px; height: 100px;
...@@ -1021,7 +1013,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendAndContentFragmentation) { ...@@ -1021,7 +1013,6 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendAndContentFragmentation) {
// Tests fragmentation when a legend's child content overflows. // Tests fragmentation when a legend's child content overflows.
TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentationWithOverflow) { TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentationWithOverflow) {
SetBodyInnerHTML(R"HTML( SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
<style> <style>
fieldset, legend { margin:0; border:none; padding:0; } fieldset, legend { margin:0; border:none; padding:0; }
</style> </style>
...@@ -1070,5 +1061,62 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentationWithOverflow) { ...@@ -1070,5 +1061,62 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentationWithOverflow) {
EXPECT_EQ(expectation, dump); EXPECT_EQ(expectation, dump);
} }
// Tests that fragmentation works as expected when the fieldset content has a
// negative margin block start.
TEST_F(NGFieldsetLayoutAlgorithmTest,
LegendAndContentFragmentationNegativeMargin) {
SetBodyInnerHTML(R"HTML(
<style>
#fieldset {
border:none; margin:0; padding:0px; width: 150px; height: 100px;
}
#legend {
padding:0px; margin:0; width: 50px; height: 100px;
}
#child {
margin-top: -20px; width: 100px; height: 40px;
}
</style>
<fieldset id="fieldset">
<legend id="legend"></legend>
<div id="child"></div>
</fieldset>
)HTML");
LayoutUnit kFragmentainerSpaceAvailable(100);
NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
WritingMode::kHorizontalTb, TextDirection::kLtr,
LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
scoped_refptr<const NGPhysicalBoxFragment> fragment =
NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
ASSERT_FALSE(fragment->BreakToken()->IsFinished());
String dump = DumpFragmentTree(fragment.get());
String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:150x100
offset:0,0 size:50x100
offset:0,100 size:150x0
offset:0,-20 size:100x20
)DUMP";
EXPECT_EQ(expectation, dump);
fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
node, space, fragment->BreakToken());
ASSERT_FALSE(fragment->BreakToken());
// TODO(almaher): The second node should not be 100px tall.
dump = DumpFragmentTree(fragment.get());
expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
offset:unplaced size:150x0
offset:0,0 size:150x100
offset:0,0 size:100x20
)DUMP";
EXPECT_EQ(expectation, dump);
}
} // anonymous namespace } // anonymous namespace
} // namespace blink } // namespace blink
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