| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h" |
| |
| #include "third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h" |
| #include "third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h" |
| #include "third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h" |
| #include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h" |
| #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" |
| #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" |
| |
| namespace blink { |
| namespace { |
| |
| class NGColumnLayoutAlgorithmTest |
| : public NGBaseLayoutAlgorithmTest, |
| private ScopedLayoutNGBlockFragmentationForTest { |
| protected: |
| NGColumnLayoutAlgorithmTest() |
| : ScopedLayoutNGBlockFragmentationForTest(true) {} |
| |
| scoped_refptr<const NGPhysicalBoxFragment> RunBlockLayoutAlgorithm( |
| Element* element) { |
| NGBlockNode container(element->GetLayoutBox()); |
| NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace( |
| {WritingMode::kHorizontalTb, TextDirection::kLtr}, |
| LogicalSize(LayoutUnit(1000), kIndefiniteSize)); |
| return NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(container, space); |
| } |
| |
| String DumpFragmentTree(const NGPhysicalBoxFragment* fragment) { |
| NGPhysicalFragment::DumpFlags flags = |
| NGPhysicalFragment::DumpHeaderText | NGPhysicalFragment::DumpSubtree | |
| NGPhysicalFragment::DumpIndentation | NGPhysicalFragment::DumpOffset | |
| NGPhysicalFragment::DumpSize; |
| |
| return fragment->DumpFragmentTree(flags); |
| } |
| |
| String DumpFragmentTree(Element* element) { |
| auto fragment = RunBlockLayoutAlgorithm(element); |
| return DumpFragmentTree(fragment.get()); |
| } |
| }; |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, EmptyMulticol) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 2; |
| column-fill: auto; |
| column-gap: 10px; |
| height: 100px; |
| width: 210px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"></div> |
| </div> |
| )HTML"); |
| |
| NGBlockNode container(GetLayoutBoxByElementId("container")); |
| NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace( |
| {WritingMode::kHorizontalTb, TextDirection::kLtr}, |
| LogicalSize(LayoutUnit(1000), kIndefiniteSize)); |
| scoped_refptr<const NGPhysicalBoxFragment> parent_fragment = |
| NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(container, space); |
| FragmentChildIterator iterator(parent_fragment.get()); |
| const auto* fragment = iterator.NextChild(); |
| ASSERT_TRUE(fragment); |
| EXPECT_EQ(PhysicalSize(210, 100), fragment->Size()); |
| EXPECT_EQ(1UL, fragment->Children().size()); |
| EXPECT_FALSE(iterator.NextChild()); |
| |
| // A multicol container will always create at least one fragmentainer. |
| fragment = FragmentChildIterator(fragment).NextChild(); |
| ASSERT_TRUE(fragment); |
| EXPECT_EQ(PhysicalSize(100, 100), fragment->Size()); |
| EXPECT_EQ(0UL, fragment->Children().size()); |
| |
| EXPECT_FALSE(iterator.NextChild()); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, EmptyBlock) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 2; |
| column-fill: auto; |
| column-gap: 10px; |
| height: 100px; |
| width: 210px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div id="child"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| NGBlockNode container(GetLayoutBoxByElementId("container")); |
| NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace( |
| {WritingMode::kHorizontalTb, TextDirection::kLtr}, |
| LogicalSize(LayoutUnit(1000), kIndefiniteSize)); |
| scoped_refptr<const NGPhysicalBoxFragment> parent_fragment = |
| NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(container, space); |
| FragmentChildIterator iterator(parent_fragment.get()); |
| const auto* fragment = iterator.NextChild(); |
| EXPECT_EQ(PhysicalSize(210, 100), fragment->Size()); |
| ASSERT_TRUE(fragment); |
| EXPECT_FALSE(iterator.NextChild()); |
| iterator.SetParent(fragment); |
| |
| // first column fragment |
| PhysicalOffset offset; |
| fragment = iterator.NextChild(&offset); |
| ASSERT_TRUE(fragment); |
| EXPECT_EQ(PhysicalOffset(), offset); |
| EXPECT_EQ(PhysicalSize(100, 100), fragment->Size()); |
| EXPECT_FALSE(iterator.NextChild()); |
| |
| // #child fragment in first column |
| iterator.SetParent(fragment); |
| fragment = iterator.NextChild(&offset); |
| ASSERT_TRUE(fragment); |
| EXPECT_EQ(PhysicalOffset(), offset); |
| EXPECT_EQ(PhysicalSize(100, 0), fragment->Size()); |
| EXPECT_EQ(0UL, fragment->Children().size()); |
| EXPECT_FALSE(iterator.NextChild()); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BlockInOneColumn) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 2; |
| column-fill: auto; |
| column-gap: 10px; |
| height: 100px; |
| width: 310px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div id="child" style="width:60%; height:100%"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| NGBlockNode container(GetLayoutBoxByElementId("container")); |
| NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace( |
| {WritingMode::kHorizontalTb, TextDirection::kLtr}, |
| LogicalSize(LayoutUnit(1000), kIndefiniteSize)); |
| scoped_refptr<const NGPhysicalBoxFragment> parent_fragment = |
| NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(container, space); |
| |
| FragmentChildIterator iterator(parent_fragment.get()); |
| const auto* fragment = iterator.NextChild(); |
| ASSERT_TRUE(fragment); |
| EXPECT_EQ(PhysicalSize(310, 100), fragment->Size()); |
| EXPECT_FALSE(iterator.NextChild()); |
| iterator.SetParent(fragment); |
| |
| // first column fragment |
| PhysicalOffset offset; |
| fragment = iterator.NextChild(&offset); |
| ASSERT_TRUE(fragment); |
| EXPECT_EQ(PhysicalOffset(), offset); |
| EXPECT_EQ(PhysicalSize(150, 100), fragment->Size()); |
| EXPECT_FALSE(iterator.NextChild()); |
| |
| // #child fragment in first column |
| iterator.SetParent(fragment); |
| fragment = iterator.NextChild(&offset); |
| ASSERT_TRUE(fragment); |
| EXPECT_EQ(PhysicalOffset(), offset); |
| EXPECT_EQ(PhysicalSize(90, 100), fragment->Size()); |
| EXPECT_EQ(0UL, fragment->Children().size()); |
| EXPECT_FALSE(iterator.NextChild()); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ZeroHeightBlockAtFragmentainerBoundary) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 2; |
| column-fill: auto; |
| column-gap: 10px; |
| height: 100px; |
| width: 210px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:33px; height:200px;"></div> |
| <div style="width:44px;"></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:210x100 |
| offset:0,0 size:100x100 |
| offset:0,0 size:33x100 |
| offset:110,0 size:100x100 |
| offset:0,0 size:33x100 |
| offset:0,100 size:44x0 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BlockInTwoColumns) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 2; |
| column-fill: auto; |
| column-gap: 10px; |
| height: 100px; |
| width: 210px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div id="child" style="width:75%; height:150px"></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:210x100 |
| offset:0,0 size:100x100 |
| offset:0,0 size:75x100 |
| offset:110,0 size:100x100 |
| offset:0,0 size:75x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BlockInThreeColumns) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| height: 100px; |
| width: 320px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div id="child" style="width:75%; height:250px;"></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:75x100 |
| offset:110,0 size:100x100 |
| offset:0,0 size:75x100 |
| offset:220,0 size:100x100 |
| offset:0,0 size:75x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ActualColumnCountGreaterThanSpecified) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 2; |
| column-fill: auto; |
| column-gap: 10px; |
| height: 100px; |
| width: 210px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div id="child" style="width:1px; height:250px;"></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:210x100 |
| offset:0,0 size:100x100 |
| offset:0,0 size:1x100 |
| offset:110,0 size:100x100 |
| offset:0,0 size:1x100 |
| offset:220,0 size:100x100 |
| offset:0,0 size:1x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, TwoBlocksInTwoColumns) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| height: 100px; |
| width: 320px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div id="child1" style="width:75%; height:60px;"></div> |
| <div id="child2" style="width:85%; height:60px;"></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:75x60 |
| offset:0,60 size:85x40 |
| offset:110,0 size:100x100 |
| offset:0,0 size:85x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ZeroHeight) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| height: 0; |
| width: 320px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"></div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x0 |
| offset:0,0 size:320x0 |
| offset:0,0 size:100x0 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ZeroHeightWithContent) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| height: 0; |
| width: 320px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:20px; height:5px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x0 |
| offset:0,0 size:320x0 |
| offset:0,0 size:100x0 |
| offset:0,0 size:20x1 |
| offset:110,0 size:100x0 |
| offset:0,0 size:20x1 |
| offset:220,0 size:100x0 |
| offset:0,0 size:20x1 |
| offset:330,0 size:100x0 |
| offset:0,0 size:20x1 |
| offset:440,0 size:100x0 |
| offset:0,0 size:20x1 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, OverflowedBlock) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| height: 100px; |
| width: 320px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div id="child1" style="width:75%; height:60px;"> |
| <div id="grandchild1" style="width:50px; height:120px;"></div> |
| <div id="grandchild2" style="width:40px; height:20px;"></div> |
| </div> |
| <div id="child2" style="width:85%; height:10px;"></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:75x60 |
| offset:0,0 size:50x100 |
| offset:0,60 size:85x10 |
| offset:110,0 size:100x100 |
| offset:0,0 size:75x0 |
| offset:0,0 size:50x20 |
| offset:0,20 size:40x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, OverflowedBlock2) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| height: 100px; |
| width: 320px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:75%; height:10px;"> |
| <div style="width:50px; height:220px;"></div> |
| </div> |
| <div style="width:85%; height:10px;"></div> |
| <div style="width:65%; height:10px;"> |
| <div style="width:51px; height:220px;"></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:75x10 |
| offset:0,0 size:50x100 |
| offset:0,10 size:85x10 |
| offset:0,20 size:65x10 |
| offset:0,0 size:51x80 |
| offset:110,0 size:100x100 |
| offset:0,0 size:75x0 |
| offset:0,0 size:50x100 |
| offset:0,0 size:65x0 |
| offset:0,0 size:51x100 |
| offset:220,0 size:100x100 |
| offset:0,0 size:75x0 |
| offset:0,0 size:50x20 |
| offset:0,0 size:65x0 |
| offset:0,0 size:51x40 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, OverflowedBlock3) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| height: 100px; |
| width: 320px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:75%; height:60px;"> |
| <div style="width:50px; height:220px;"></div> |
| </div> |
| <div style="width:85%; height:10px;"></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:75x60 |
| offset:0,0 size:50x100 |
| offset:0,60 size:85x10 |
| offset:110,0 size:100x100 |
| offset:0,0 size:75x0 |
| offset:0,0 size:50x100 |
| offset:220,0 size:100x100 |
| offset:0,0 size:75x0 |
| offset:0,0 size:50x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, UnusedSpaceInBlock) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| height: 100px; |
| width: 320px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="height:300px;"> |
| <div style="width:20px; height:20px;"></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:20x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x100 |
| offset:220,0 size:100x100 |
| offset:0,0 size:100x100 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, FloatInOneColumn) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| height: 100px; |
| width: 320px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div id="child" style="float:left; width:75%; height:100px;"></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:75x100 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, TwoFloatsInOneColumn) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div id="child1" style="float:left; width:15%; height:100px;"></div> |
| <div id="child2" style="float:right; width:16%; height:100px;"></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:15x100 |
| offset:84,0 size:16x100 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, TwoFloatsInTwoColumns) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div id="child1" style="float:left; width:15%; height:150px;"></div> |
| <div id="child2" style="float:right; width:16%; height:150px;"></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:15x100 |
| offset:84,0 size:16x100 |
| offset:110,0 size:100x100 |
| offset:0,0 size:15x50 |
| offset:84,0 size:16x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, FloatWithForcedBreak) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="height:50px;"></div> |
| <div style="float:left; width:77px;"> |
| <div style="width:66px; height:30px;"></div> |
| <div style="break-before:column; width:55px; height:30px;"></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:100x50 |
| offset:0,50 size:77x50 |
| offset:0,0 size:66x30 |
| offset:110,0 size:100x100 |
| offset:0,0 size:77x30 |
| offset:0,0 size:55x30 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, FloatWithMargin) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="float:left; width:77px; margin-top:10px; height:140px;"></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,10 size:77x90 |
| offset:110,0 size:100x100 |
| offset:0,0 size:77x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, FloatWithMarginBelowFloat) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="float:left; width:66px; height:40px;"></div> |
| <div style="float:left; width:77px; margin-top:10px; height:70px;"></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:66x40 |
| offset:0,50 size:77x50 |
| offset:110,0 size:100x100 |
| offset:0,0 size:77x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, FloatWithLastResortBreak) { |
| // Breaking inside the line is not possible, and breaking between the |
| // block-start content edge and the first child should be avoided. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:99px; height:90px;"></div> |
| <div style="float:left; width:88px;"> |
| <br> |
| </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:99x90 |
| offset:110,0 size:100x100 |
| offset:0,0 size:88x20 |
| offset:0,0 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, FloatWithAvoidBreak) { |
| // We want to avoid breaking inside the float child, and breaking before it |
| // should be avoided (not a valid breakpoint). |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:99px; height:90px;"></div> |
| <div style="float:left; width:88px;"> |
| <div class="content" style="width:77px;"></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:99x90 |
| offset:110,0 size:100x100 |
| offset:0,0 size:88x20 |
| offset:0,0 size:77x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, FloatWithMarginAndAvoidBreak) { |
| // We want to avoid breaking inside the float child, and breaking before it |
| // should be avoided (not a valid breakpoint). The top margin should be kept |
| // in the next column. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:99px; height:90px;"></div> |
| <div style="float:left; width:88px; margin-top:5px;"> |
| <div class="content" style="width:77px;"></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:99x90 |
| offset:110,0 size:100x100 |
| offset:0,5 size:88x20 |
| offset:0,0 size:77x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, UnbreakableFloatBeforeBreakable) { |
| // https://www.w3.org/TR/CSS22/visuren.html#float-position |
| // |
| // "The outer top of a floating box may not be higher than the outer top of |
| // any block or floated box generated by an element earlier in the source |
| // document." |
| // |
| // This means that if we decide to break before one float, we also need to |
| // break before all subsequent floats, even if such floats don't require that |
| // on their own. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:99px; height:90px;"></div> |
| <div style="float:left; width:22px; height:50px;"> |
| <div class="content" style="width:11px;"></div> |
| </div> |
| <div style="float:left; width:33px; height:50px;"></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:99x90 |
| offset:110,0 size:100x100 |
| offset:0,0 size:22x50 |
| offset:0,0 size:11x20 |
| offset:22,0 size:33x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BlockWithTopMarginInThreeColumns) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:50px; height:70px;"></div> |
| <div style="margin-top:10px; width:60px; height:150px;"></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:50x70 |
| offset:0,80 size:60x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:60x100 |
| offset:220,0 size:100x100 |
| offset:0,0 size:60x30 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BlockStartAtColumnBoundary) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:50px; height:100px;"></div> |
| <div style="width:60px; height:100px;"></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:50x100 |
| offset:110,0 size:100x100 |
| offset:0,0 size:60x100 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, NestedBlockAfterBlock) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="height:10px;"></div> |
| <div> |
| <div style="width:60px; height:120px;"></div> |
| <div style="width:50px; height:20px;"></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:100x10 |
| offset:0,10 size:100x90 |
| offset:0,0 size:60x90 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x50 |
| offset:0,0 size:60x30 |
| offset:0,30 size:50x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BreakInsideAvoid) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:10px; height:50px;"></div> |
| <div style="break-inside:avoid; width:20px; height:70px;"></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:10x50 |
| offset:110,0 size:100x100 |
| offset:0,0 size:20x70 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BreakInsideAvoidColumn) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:10px; height:50px;"></div> |
| <div style="break-inside:avoid-column; width:20px; height:70px;"></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:10x50 |
| offset:110,0 size:100x100 |
| offset:0,0 size:20x70 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BreakInsideAvoidPage) { |
| // break-inside:avoid-page has no effect, unless we're breaking into pages. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:10px; height:50px;"></div> |
| <div style="break-inside:avoid-page; width:20px; height:70px;"></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:10x50 |
| offset:0,50 size:20x50 |
| offset:110,0 size:100x100 |
| offset:0,0 size:20x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BreakInsideAvoidTallBlock) { |
| // The block that has break-inside:avoid is too tall to fit in one |
| // fragmentainer. So a break is unavoidable. Let's check that: |
| // 1. The block is still shifted to the start of the next fragmentainer |
| // 2. We give up shifting it any further (would cause infinite an loop) |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:10px; height:50px;"></div> |
| <div style="break-inside:avoid; width:20px; height:170px;"></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:10x50 |
| offset:110,0 size:100x100 |
| offset:0,0 size:20x100 |
| offset:220,0 size:100x100 |
| offset:0,0 size:20x70 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, NestedBreakInsideAvoid) { |
| // If there were no break-inside:avoid on the outer DIV here, there'd be a |
| // break between the two inner ones, since they wouldn't both fit in the first |
| // column. However, since the outer DIV does have such a declaration, |
| // everything is supposed to be pushed to the second column, with no space |
| // between the children. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:10px; height:50px;"></div> |
| <div style="break-inside:avoid; width:30px;"> |
| <div style="break-inside:avoid; width:21px; height:30px;"></div> |
| <div style="break-inside:avoid; width:22px; height:30px;"></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:10x50 |
| offset:110,0 size:100x100 |
| offset:0,0 size:30x60 |
| offset:0,0 size:21x30 |
| offset:0,30 size:22x30 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, NestedBreakInsideAvoidTall) { |
| // Here the outer DIV with break-inside:avoid is too tall to fit where it |
| // occurs naturally, so it needs to be pushed to the second column. It's not |
| // going to fit fully there either, though, since its two children don't fit |
| // together. Its second child wants to avoid breaks inside, so it will be |
| // moved to the third column. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:10px; height:50px;"></div> |
| <div style="break-inside:avoid; width:30px;"> |
| <div style="width:21px; height:30px;"></div> |
| <div style="break-inside:avoid; width:22px; height:80px;"></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:10x50 |
| offset:110,0 size:100x100 |
| offset:0,0 size:30x100 |
| offset:0,0 size:21x30 |
| offset:220,0 size:100x100 |
| offset:0,0 size:30x80 |
| offset:0,0 size:22x80 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BreakInsideAvoidAtColumnBoundary) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="height:90px;"></div> |
| <div> |
| <div style="break-inside:avoid; width:20px; height:20px;"></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:100x90 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x20 |
| offset:0,0 size:20x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, MarginTopPastEndOfFragmentainer) { |
| // A block whose border box would start past the end of the current |
| // fragmentainer should start exactly at the start of the next fragmentainer, |
| // discarding what's left of the margin. |
| // https://www.w3.org/TR/css-break-3/#break-margins |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="height:90px;"></div> |
| <div style="margin-top:20px; width:20px; height:20px;"></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:100x90 |
| offset:110,0 size:100x100 |
| offset:0,0 size:20x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, MarginBottomPastEndOfFragmentainer) { |
| // A block whose border box would start past the end of the current |
| // fragmentainer should start exactly at the start of the next fragmentainer, |
| // discarding what's left of the margin. |
| // https://www.w3.org/TR/css-break-3/#break-margins |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="margin-bottom:20px; height:90px;"></div> |
| <div style="width:20px; height:20px;"></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:100x90 |
| offset:110,0 size:100x100 |
| offset:0,0 size:20x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, MarginTopAtEndOfFragmentainer) { |
| // A block whose border box is flush with the end of the fragmentainer |
| // shouldn't produce an empty fragment there - only one fragment in the next |
| // fragmentainer. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="height:90px;"></div> |
| <div style="margin-top:10px; width:20px; height:20px;"></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:100x90 |
| offset:110,0 size:100x100 |
| offset:0,0 size:20x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, MarginBottomAtEndOfFragmentainer) { |
| // A block whose border box is flush with the end of the fragmentainer |
| // shouldn't produce an empty fragment there - only one fragment in the next |
| // fragmentainer. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="margin-bottom:10px; height:90px;"></div> |
| <div style="width:20px; height:20px;"></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:100x90 |
| offset:110,0 size:100x100 |
| offset:0,0 size:20x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, LinesInMulticolExtraSpace) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 50px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br> |
| <br> |
| <br> |
| <br> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x50 |
| offset:0,0 size:320x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:110,0 size:100x50 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, LinesInMulticolExactFit) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 40px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br> |
| <br> |
| <br> |
| <br> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x40 |
| offset:0,0 size:320x40 |
| offset:0,0 size:100x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:110,0 size:100x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, LinesInMulticolChildExtraSpace) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 50px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:77px;"> |
| <br> |
| <br> |
| <br> |
| <br> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x50 |
| offset:0,0 size:320x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:77x50 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:110,0 size:100x50 |
| offset:0,0 size:77x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, LinesInMulticolChildExactFit) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 40px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:77px;"> |
| <br> |
| <br> |
| <br> |
| <br> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x40 |
| offset:0,0 size:320x40 |
| offset:0,0 size:100x40 |
| offset:0,0 size:77x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:110,0 size:100x40 |
| offset:0,0 size:77x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, LinesInMulticolChildNoSpaceForFirst) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 50px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="height:50px;"></div> |
| <div style="width:77px;"> |
| <br> |
| <br> |
| <br> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x50 |
| offset:0,0 size:320x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:100x50 |
| offset:110,0 size:100x50 |
| offset:0,0 size:77x50 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:220,0 size:100x50 |
| offset:0,0 size:77x20 |
| offset:0,0 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, |
| LinesInMulticolChildInsufficientSpaceForFirst) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 50px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="height:40px;"></div> |
| <div style="width:77px;"> |
| <br> |
| <br> |
| <br> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x50 |
| offset:0,0 size:320x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:100x40 |
| offset:110,0 size:100x50 |
| offset:0,0 size:77x50 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:220,0 size:100x50 |
| offset:0,0 size:77x20 |
| offset:0,0 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, LineAtColumnBoundaryInFirstBlock) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 50px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:66px; padding-top:40px;"> |
| <br> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| // It's not ideal to break before a first child that's flush with the content |
| // edge of its container, but if there are no earlier break opportunities, we |
| // may still have to do that. There's no class A, B or C break point [1] |
| // between the DIV and the line established for the BR, but since a line is |
| // monolithic content [1], we really have to try to avoid breaking inside it. |
| // |
| // [1] https://www.w3.org/TR/css-break-3/#possible-breaks |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x50 |
| offset:0,0 size:320x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:66x50 |
| offset:110,0 size:100x50 |
| offset:0,0 size:66x20 |
| offset:0,0 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, LinesAndFloatsMulticol) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 70px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br> |
| <div style="float:left; width:10px; height:120px;"></div> |
| <br> |
| <div style="float:left; width:11px; height:120px;"></div> |
| <br> |
| <br> |
| <br> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x70 |
| offset:0,0 size:320x70 |
| offset:0,0 size:100x70 |
| offset:0,0 size:0x20 |
| offset:10,20 size:0x20 |
| offset:21,40 size:0x20 |
| offset:110,0 size:100x70 |
| offset:0,0 size:10x70 |
| offset:10,0 size:11x70 |
| offset:21,0 size:0x20 |
| offset:21,20 size:0x20 |
| offset:220,0 size:100x70 |
| offset:0,0 size:11x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, FloatBelowLastLineInColumn) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 70px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br> |
| <br> |
| <br> |
| <div style="float:left; width:11px; height:120px;"></div> |
| <br> |
| <br> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x70 |
| offset:0,0 size:320x70 |
| offset:0,0 size:100x70 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| offset:110,0 size:100x70 |
| offset:11,0 size:0x20 |
| offset:11,20 size:0x20 |
| offset:220,0 size:100x70 |
| offset:0,0 size:11x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, Orphans) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 90px; |
| line-height: 20px; |
| orphans: 3; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="height:40px;"></div> |
| <div style="width:77px;"> |
| <br> |
| <br> |
| <br> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x90 |
| offset:0,0 size:320x90 |
| offset:0,0 size:100x90 |
| offset:0,0 size:100x40 |
| offset:110,0 size:100x90 |
| offset:0,0 size:77x60 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, OrphansUnsatisfiable) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 90px; |
| line-height: 20px; |
| orphans: 100; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br> |
| <br> |
| <br> |
| <br> |
| <br> |
| <br> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x90 |
| offset:0,0 size:320x90 |
| offset:0,0 size:100x90 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| offset:0,60 size:0x20 |
| offset:110,0 size:100x90 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, Widows) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 110px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 3; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br> |
| <br> |
| <br> |
| <br> |
| <br> |
| <br> |
| <br> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x110 |
| offset:0,0 size:320x110 |
| offset:0,0 size:100x110 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| offset:0,60 size:0x20 |
| offset:110,0 size:100x110 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, WidowsUnsatisfiable) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 90px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 100; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br> |
| <br> |
| <br> |
| <br> |
| <br> |
| <br> |
| <br> |
| <br> |
| <br> |
| <br> |
| <br> |
| <br> |
| <br> |
| <br> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x90 |
| offset:0,0 size:320x90 |
| offset:0,0 size:100x90 |
| offset:0,0 size:0x20 |
| offset:110,0 size:100x90 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| offset:0,60 size:0x20 |
| offset:220,0 size:100x90 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| offset:0,60 size:0x20 |
| offset:330,0 size:100x90 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| offset:0,60 size:0x20 |
| offset:440,0 size:100x90 |
| offset:0,0 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, OrphansAndUnsatisfiableWidows) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 70px; |
| line-height: 20px; |
| orphans: 2; |
| widows: 3; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br> |
| <br> |
| <br> |
| <br> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x70 |
| offset:0,0 size:320x70 |
| offset:0,0 size:100x70 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:110,0 size:100x70 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, UnsatisfiableOrphansAndWidows) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 70px; |
| line-height: 20px; |
| orphans: 4; |
| widows: 4; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br> |
| <br> |
| <br> |
| <br> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x70 |
| offset:0,0 size:320x70 |
| offset:0,0 size:100x70 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| offset:110,0 size:100x70 |
| offset:0,0 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, WidowsAndAbspos) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 70px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 3; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="position:relative;"> |
| <br> |
| <br> |
| <br> |
| <br> |
| <div style="position:absolute; width:33px; height:33px;"></div> |
| <br> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x70 |
| offset:0,0 size:320x70 |
| offset:0,0 size:100x70 |
| offset:0,0 size:100x70 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:110,0 size:100x70 |
| offset:0,0 size:100x60 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| offset:0,40 size:33x30 |
| offset:220,0 size:100x70 |
| offset:0,0 size:33x3 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BreakBetweenLinesNotBefore) { |
| // Just breaking where we run out of space is perfect, since it won't violate |
| // the orphans/widows requirement, since there'll be two lines both before and |
| // after the break. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| line-height: 20px; |
| orphans: 2; |
| widows: 2; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:44px; height:60px;"></div> |
| <div style="width:55px;"> |
| <br> |
| <br> |
| <br> |
| <br> |
| </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:44x60 |
| offset:0,60 size:55x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:55x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BreakBetweenLinesNotBefore2) { |
| // Prefer breaking between lines and violate an orphans requirement, rather |
| // than violating break-before:avoid. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| line-height: 20px; |
| orphans: 2; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:44px; height:80px;"></div> |
| <div style="break-before:avoid; width:55px;"> |
| <br> |
| <br> |
| </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:44x80 |
| offset:0,80 size:55x20 |
| offset:0,0 size:0x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:55x20 |
| offset:0,0 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BreakBetweenLinesNotBefore3) { |
| // Prefer breaking between lines and violate a widows requirement, rather than |
| // violating break-before:avoid. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 2; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:44px; height:80px;"></div> |
| <div style="break-before:avoid; width:55px;"> |
| <br> |
| <br> |
| </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:44x80 |
| offset:0,80 size:55x20 |
| offset:0,0 size:0x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:55x20 |
| offset:0,0 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, FloatInBlockMovedByOrphans) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 70px; |
| line-height: 20px; |
| orphans: 2; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:11px; height:40px;"></div> |
| <div style="width:77px;"> |
| <br> |
| <div style="float:left; width:10px; height:10px;"></div> |
| <br> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x70 |
| offset:0,0 size:320x70 |
| offset:0,0 size:100x70 |
| offset:0,0 size:11x40 |
| offset:110,0 size:100x70 |
| offset:0,0 size:77x40 |
| offset:0,0 size:0x20 |
| offset:10,20 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, FloatMovedWithWidows) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 90px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 4; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br> |
| <br> |
| <br> |
| <div style="float:left; width:10px; height:10px;"></div> |
| <br> |
| <br> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x90 |
| offset:0,0 size:320x90 |
| offset:0,0 size:100x90 |
| offset:0,0 size:0x20 |
| offset:110,0 size:100x90 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:10,40 size:0x20 |
| offset:0,60 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BorderAndPadding) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent" style="border:3px solid; padding:2px;"> |
| <div style="width:30px; height:150px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x110 |
| offset:0,0 size:330x110 |
| offset:5,5 size:100x100 |
| offset:0,0 size:30x100 |
| offset:115,5 size:100x100 |
| offset:0,0 size:30x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BreakInsideWithBorder) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="height:85px;"></div> |
| <div style="border:10px solid;"> |
| <div style="height:10px;"></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:100x85 |
| offset:0,85 size:100x15 |
| offset:10,10 size:80x5 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x15 |
| offset:10,0 size:80x5 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreaks) { |
| // This tests that forced breaks are honored, but only at valid class A break |
| // points (i.e. *between* in-flow block siblings). |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="float:left; width:1px; height:1px;"></div> |
| <div style="break-before:column; break-after:column;"> |
| <div style="float:left; width:1px; height:1px;"></div> |
| <div style="break-after:column; width:50px; height:10px;"></div> |
| <div style="break-before:column; width:60px; height:10px;"></div> |
| <div> |
| <div> |
| <div style="break-after:column; width:70px; height:10px;"></div> |
| </div> |
| </div> |
| <div style="width:80px; height:10px;"></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:1x1 |
| offset:0,0 size:100x100 |
| offset:1,0 size:1x1 |
| offset:0,0 size:50x10 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x100 |
| offset:0,0 size:60x10 |
| offset:0,10 size:100x10 |
| offset:0,0 size:100x10 |
| offset:0,0 size:70x10 |
| offset:220,0 size:100x100 |
| offset:0,0 size:100x10 |
| offset:0,0 size:80x10 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreakInSecondChild) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:33px; height:20px;"></div> |
| <div style="width:34px;"> |
| <div style="width:35px; height:20px;"></div> |
| <div style="break-before:column; width:36px; height:20px;"></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:33x20 |
| offset:0,20 size:34x80 |
| offset:0,0 size:35x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:34x20 |
| offset:0,0 size:36x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ForcedAndUnforcedBreaksAtSameBoundary) { |
| // We have two parallel flows, one with a forced break inside and one with an |
| // unforced break. Check that we handle the block-start margins correctly |
| // (i.e. truncate at unforced breaks but not at forced breaks). |
| // |
| // Note about the #blockchildifier DIV in the test: it's there to force block |
| // layout, as our fragmentation support for floats inside an inline formatting |
| // context is borked; see crbug.com/915929 |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div id="blockchildifier"></div> |
| <div style="float:left; width:33px;"> |
| <div style="width:10px; height:70px;"></div> |
| <div style="break-before:column; margin-top:50px; width:20px; height:20px;"></div> |
| </div> |
| <div style="float:left; width:34px;"> |
| <div style="width:10px; height:70px;"></div> |
| <div style="margin-top:50px; width:20px; height:20px;"></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:100x0 |
| offset:0,0 size:33x100 |
| offset:0,0 size:10x70 |
| offset:33,0 size:34x100 |
| offset:0,0 size:10x70 |
| offset:110,0 size:100x100 |
| offset:0,0 size:33x70 |
| offset:0,50 size:20x20 |
| offset:33,0 size:34x20 |
| offset:0,0 size:20x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ResumeInsideFormattingContextRoot) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="display:flow-root; width:33px;"> |
| <div style="width:10px; height:70px;"></div> |
| <div style="margin-top:50px; width:20px; height:20px;"></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:33x100 |
| offset:0,0 size:10x70 |
| offset:110,0 size:100x100 |
| offset:0,0 size:33x20 |
| offset:0,0 size:20x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, NewFcAtColumnBoundary) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:22px; height:100px;"></div> |
| <div style="display:flow-root; width:33px; height:50px;"></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:22x100 |
| offset:110,0 size:100x100 |
| offset:0,0 size:33x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, NewFcWithMargin) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:22px; height:50px;"></div> |
| <div style="display:flow-root; margin-top:30px; width:33px; height:50px;"></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:22x50 |
| offset:0,80 size:33x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:33x30 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, NewFcBelowFloat) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="float:left; width:22px; height:50px;"></div> |
| <div style="display:flow-root; margin-top:40px; width:88px; height:70px;"></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:22x50 |
| offset:0,50 size:88x50 |
| offset:110,0 size:100x100 |
| offset:0,0 size:88x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, NewFcWithMarginPastColumnBoundary) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:22px; height:80px;"></div> |
| <div style="display:flow-root; margin-top:30px; width:33px; height:50px;"></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:22x80 |
| offset:110,0 size:100x100 |
| offset:0,0 size:33x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, MinMax) { |
| // The multicol container here contains two inline-blocks with a line break |
| // opportunity between them. We'll test what min/max values we get for the |
| // multicol container when specifying both column-count and column-width, only |
| // column-count, and only column-width. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #multicol { |
| column-gap: 10px; |
| width: fit-content; |
| } |
| #multicol span { display:inline-block; width:50px; height:50px; } |
| </style> |
| <div id="container"> |
| <div id="multicol"> |
| <div> |
| <span></span><wbr><span></span> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| LayoutObject* layout_object = GetLayoutObjectByElementId("multicol"); |
| ASSERT_TRUE(layout_object); |
| NGBlockNode node = NGBlockNode(To<LayoutBox>(layout_object)); |
| scoped_refptr<ComputedStyle> style = |
| ComputedStyle::Clone(layout_object->StyleRef()); |
| layout_object->SetStyle(style); |
| NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace( |
| {WritingMode::kHorizontalTb, TextDirection::kLtr}, |
| LogicalSize(LayoutUnit(1000), kIndefiniteSize)); |
| NGFragmentGeometry fragment_geometry = |
| CalculateInitialFragmentGeometry(space, node); |
| NGColumnLayoutAlgorithm algorithm({node, fragment_geometry, space}); |
| base::Optional<MinMaxSizes> sizes; |
| MinMaxSizesInput zero_input( |
| /* percentage_resolution_block_size */ LayoutUnit(), |
| MinMaxSizesType::kContent); |
| |
| // Both column-count and column-width set. |
| style->SetColumnCount(3); |
| style->SetColumnWidth(80); |
| sizes = algorithm.ComputeMinMaxSizes(zero_input).sizes; |
| ASSERT_TRUE(sizes.has_value()); |
| EXPECT_EQ(LayoutUnit(260), sizes->min_size); |
| EXPECT_EQ(LayoutUnit(320), sizes->max_size); |
| |
| // Only column-count set. |
| style->SetHasAutoColumnWidth(); |
| sizes = algorithm.ComputeMinMaxSizes(zero_input).sizes; |
| ASSERT_TRUE(sizes.has_value()); |
| EXPECT_EQ(LayoutUnit(170), sizes->min_size); |
| EXPECT_EQ(LayoutUnit(320), sizes->max_size); |
| |
| // Only column-width set. |
| style->SetColumnWidth(80); |
| style->SetHasAutoColumnCount(); |
| sizes = algorithm.ComputeMinMaxSizes(zero_input).sizes; |
| ASSERT_TRUE(sizes.has_value()); |
| EXPECT_EQ(LayoutUnit(80), sizes->min_size); |
| EXPECT_EQ(LayoutUnit(100), sizes->max_size); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancing) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent" style="border:3px solid; padding:2px;"> |
| <div style="width:30px; height:150px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x60 |
| offset:0,0 size:330x60 |
| offset:5,5 size:100x50 |
| offset:0,0 size:30x50 |
| offset:115,5 size:100x50 |
| offset:0,0 size:30x50 |
| offset:225,5 size:100x50 |
| offset:0,0 size:30x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingFixedHeightExactMatch) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| height: 50px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent" style="border:3px solid; padding:2px;"> |
| <div style="width:30px; height:150px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x60 |
| offset:0,0 size:330x60 |
| offset:5,5 size:100x50 |
| offset:0,0 size:30x50 |
| offset:115,5 size:100x50 |
| offset:0,0 size:30x50 |
| offset:225,5 size:100x50 |
| offset:0,0 size:30x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingFixedHeightLessContent) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent" style="border:3px solid; padding:2px;"> |
| <div style="width:30px; height:150px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x110 |
| offset:0,0 size:330x110 |
| offset:5,5 size:100x50 |
| offset:0,0 size:30x50 |
| offset:115,5 size:100x50 |
| offset:0,0 size:30x50 |
| offset:225,5 size:100x50 |
| offset:0,0 size:30x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, |
| ColumnBalancingFixedHeightOverflowingContent) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| height: 35px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent" style="border:3px solid; padding:2px;"> |
| <div style="width:30px; height:150px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x45 |
| offset:0,0 size:330x45 |
| offset:5,5 size:100x35 |
| offset:0,0 size:30x35 |
| offset:115,5 size:100x35 |
| offset:0,0 size:30x35 |
| offset:225,5 size:100x35 |
| offset:0,0 size:30x35 |
| offset:335,5 size:100x35 |
| offset:0,0 size:30x35 |
| offset:445,5 size:100x35 |
| offset:0,0 size:30x10 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingMinHeight) { |
| // Min-height has no effect on the columns, only on the multicol |
| // container. Balanced columns should never be taller than they have to be. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| min-height:70px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent" style="border:3px solid; padding:2px;"> |
| <div style="width:30px; height:150px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x80 |
| offset:0,0 size:330x80 |
| offset:5,5 size:100x50 |
| offset:0,0 size:30x50 |
| offset:115,5 size:100x50 |
| offset:0,0 size:30x50 |
| offset:225,5 size:100x50 |
| offset:0,0 size:30x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingMaxHeight) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| max-height:40px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent" style="border:3px solid; padding:2px;"> |
| <div style="width:30px; height:150px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x50 |
| offset:0,0 size:330x50 |
| offset:5,5 size:100x40 |
| offset:0,0 size:30x40 |
| offset:115,5 size:100x40 |
| offset:0,0 size:30x40 |
| offset:225,5 size:100x40 |
| offset:0,0 size:30x40 |
| offset:335,5 size:100x40 |
| offset:0,0 size:30x30 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, |
| ColumnBalancingMinHeightLargerThanMaxHeight) { |
| // Min-height has no effect on the columns, only on the multicol |
| // container. Balanced columns should never be taller than they have to be. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| min-height:70px; |
| max-height:50px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent" style="border:3px solid; padding:2px;"> |
| <div style="width:30px; height:150px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x80 |
| offset:0,0 size:330x80 |
| offset:5,5 size:100x50 |
| offset:0,0 size:30x50 |
| offset:115,5 size:100x50 |
| offset:0,0 size:30x50 |
| offset:225,5 size:100x50 |
| offset:0,0 size:30x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingFixedHeightMinHeight) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| height:40px; |
| max-height:30px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent" style="border:3px solid; padding:2px;"> |
| <div style="width:30px; height:150px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x40 |
| offset:0,0 size:330x40 |
| offset:5,5 size:100x30 |
| offset:0,0 size:30x30 |
| offset:115,5 size:100x30 |
| offset:0,0 size:30x30 |
| offset:225,5 size:100x30 |
| offset:0,0 size:30x30 |
| offset:335,5 size:100x30 |
| offset:0,0 size:30x30 |
| offset:445,5 size:100x30 |
| offset:0,0 size:30x30 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancing100By3) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { columns: 3; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="height:100px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| scoped_refptr<const NGPhysicalBoxFragment> parent_fragment = |
| RunBlockLayoutAlgorithm(GetElementById("container")); |
| |
| FragmentChildIterator iterator(parent_fragment.get()); |
| const auto* multicol = iterator.NextChild(); |
| ASSERT_TRUE(multicol); |
| |
| // Actual column-count should be 3. I.e. no overflow columns. |
| EXPECT_EQ(3U, multicol->Children().size()); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingEmpty) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"></div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x0 |
| offset:0,0 size:320x0 |
| offset:0,0 size:100x0 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingEmptyBlock) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:20px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x0 |
| offset:0,0 size:320x0 |
| offset:0,0 size:100x0 |
| offset:0,0 size:20x0 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingSingleLine) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| line-height: 20px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x20 |
| offset:0,0 size:320x20 |
| offset:0,0 size:100x20 |
| offset:0,0 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingSingleLineInNested) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| line-height: 20px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="columns:2; column-gap:10px;"> |
| <br> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x20 |
| offset:0,0 size:320x20 |
| offset:0,0 size:100x20 |
| offset:0,0 size:100x20 |
| offset:0,0 size:45x20 |
| offset:0,0 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingSingleLineInNestedSpanner) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| line-height: 20px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="columns:2; column-gap:0;"> |
| <div style="column-span:all;"> |
| <br> |
| </div> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x20 |
| offset:0,0 size:320x20 |
| offset:0,0 size:100x20 |
| offset:0,0 size:100x20 |
| offset:0,0 size:50x0 |
| offset:0,0 size:100x20 |
| offset:0,0 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingOverflow) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:30px; height:20px;"> |
| <div style="width:33px; height:300px;"></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:30x20 |
| offset:0,0 size:33x100 |
| offset:110,0 size:100x100 |
| offset:0,0 size:30x0 |
| offset:0,0 size:33x100 |
| offset:220,0 size:100x100 |
| offset:0,0 size:30x0 |
| offset:0,0 size:33x100 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingLines) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br><br><br><br><br> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x40 |
| offset:0,0 size:320x40 |
| offset:0,0 size:100x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:110,0 size:100x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:220,0 size:100x40 |
| offset:0,0 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingLinesOrphans) { |
| // We have 6 lines and 3 columns. If we make the columns tall enough to hold 2 |
| // lines each, it should all fit. But then there's an orphans request that 3 |
| // lines be placed together in the same column... |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br> |
| <div style="orphans:3;"> |
| <br><br><br> |
| </div> |
| <br><br> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x60 |
| offset:0,0 size:320x60 |
| offset:0,0 size:100x60 |
| offset:0,0 size:100x20 |
| offset:0,0 size:0x20 |
| offset:110,0 size:100x60 |
| offset:0,0 size:100x60 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| offset:220,0 size:100x60 |
| offset:0,0 size:100x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingLinesForcedBreak) { |
| // We have 6 lines and 3 columns. If we make the columns tall enough to hold 2 |
| // lines each, it should all fit. But then there's a forced break after the |
| // first line, so that the remaining 5 lines have to be distributed into the 2 |
| // remaining columns... |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br> |
| <div style="break-before:column;"> |
| <br><br><br><br><br> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x60 |
| offset:0,0 size:320x60 |
| offset:0,0 size:100x60 |
| offset:0,0 size:100x20 |
| offset:0,0 size:0x20 |
| offset:110,0 size:100x60 |
| offset:0,0 size:100x60 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| offset:220,0 size:100x60 |
| offset:0,0 size:100x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingLinesForcedBreak2) { |
| // We have 7+5 lines and 3 columns. There's a forced break after 7 lines, then |
| // 5 more lines. There will be another implicit break among the first 7 lines, |
| // while the columns will have to fit 5 lines, because of the 5 lines after |
| // the forced break. The first column will have 5 lines. The second one will |
| // have 2. The third one (after the break) will have 5. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br><br><br><br><br><br><br> |
| <div style="width:99px; break-before:column;"></div> |
| <br><br><br><br><br> |
| </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:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| offset:0,60 size:0x20 |
| offset:0,80 size:0x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:220,0 size:100x100 |
| offset:0,0 size:99x0 |
| offset:0,0 size:100x100 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| offset:0,60 size:0x20 |
| offset:0,80 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingLinesForcedBreak3) { |
| // We have 7+5 lines and 3 columns. There's a forced break after 7 lines, then |
| // 5 more lines. There will be another implicit break among the first 7 lines, |
| // while the columns will have to fit 5 lines, because of the 5 lines after |
| // the forced break. The first column will have 5 lines. The second one will |
| // have 2. The third one (after the break) will have 5. The lines are wrapped |
| // inside a block child of the multicol container. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:66px;"> |
| <br><br><br><br><br><br><br> |
| <div style="width:99px; break-before:column;"></div> |
| <br><br><br><br><br> |
| </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:66x100 |
| offset:0,0 size:66x100 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| offset:0,60 size:0x20 |
| offset:0,80 size:0x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:66x100 |
| offset:0,0 size:66x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:220,0 size:100x100 |
| offset:0,0 size:66x100 |
| offset:0,0 size:99x0 |
| offset:0,0 size:66x100 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| offset:0,60 size:0x20 |
| offset:0,80 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingLinesAvoidBreakInside) { |
| // We have 6 lines and 3 columns. If we make the columns tall enough to hold 2 |
| // lines each, it should all fit. But then there's a block with 3 lines and |
| // break-inside:avoid... |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br> |
| <div style="break-inside:avoid;"> |
| <br><br><br> |
| </div> |
| <br><br> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x60 |
| offset:0,0 size:320x60 |
| offset:0,0 size:100x60 |
| offset:0,0 size:100x20 |
| offset:0,0 size:0x20 |
| offset:110,0 size:100x60 |
| offset:0,0 size:100x60 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| offset:220,0 size:100x60 |
| offset:0,0 size:100x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingLinesAvoidBreakInside2) { |
| // We have 5 lines and 3 columns. If we make the columns tall enough to hold 2 |
| // lines each, it should all fit. But then there's a block with 3 lines and |
| // break-inside:avoid... |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br> |
| <div style="break-inside:avoid;"> |
| <br><br><br> |
| </div> |
| <br> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x60 |
| offset:0,0 size:320x60 |
| offset:0,0 size:100x60 |
| offset:0,0 size:100x20 |
| offset:0,0 size:0x20 |
| offset:110,0 size:100x60 |
| offset:0,0 size:100x60 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| offset:220,0 size:100x60 |
| offset:0,0 size:100x20 |
| offset:0,0 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingUnderflow) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="break-inside:avoid; margin-top:-100px; width:55px; height:110px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x10 |
| offset:0,0 size:320x10 |
| offset:0,0 size:100x10 |
| offset:0,-100 size:55x110 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ClassCBreakPointBeforeBfc) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height:100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:50px; height:50px;"></div> |
| <div style="float:left; width:100%; height:40px;"></div> |
| <div style="width:55px;"> |
| <div style="display:flow-root; break-inside:avoid; width:44px; height:60px;"></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:50x50 |
| offset:0,50 size:100x40 |
| offset:0,50 size:55x50 |
| offset:110,0 size:100x100 |
| offset:0,0 size:55x60 |
| offset:0,0 size:44x60 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, NoClassCBreakPointBeforeBfc) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height:100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:50px; height:50px;"></div> |
| <div style="float:left; width:100%; height:40px;"></div> |
| <div id="container" style="clear:both; width:55px;"> |
| <div style="display:flow-root; break-inside:avoid; width:44px; height:60px;"></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:50x50 |
| offset:0,50 size:100x40 |
| offset:110,0 size:100x100 |
| offset:0,0 size:55x60 |
| offset:0,0 size:44x60 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ClassCBreakPointBeforeBfcWithClearance) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height:100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:50px; height:50px;"></div> |
| <div style="float:left; width:1px; height:40px;"></div> |
| <div style="width:55px;"> |
| <div style="clear:both; display:flow-root; break-inside:avoid; width:44px; height:60px;"></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:50x50 |
| offset:0,50 size:1x40 |
| offset:0,50 size:55x50 |
| offset:110,0 size:100x100 |
| offset:0,0 size:55x60 |
| offset:0,0 size:44x60 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ClassCBreakPointBeforeBfcWithMargin) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height:100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:50px; height:50px;"></div> |
| <div style="float:left; width:100%; height:40px;"></div> |
| <div style="width:55px;"> |
| <div style="margin-top:39px; display:flow-root; break-inside:avoid; width:44px; height:60px;"></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:50x50 |
| offset:0,50 size:100x40 |
| offset:0,50 size:55x50 |
| offset:110,0 size:100x100 |
| offset:0,0 size:55x60 |
| offset:0,0 size:44x60 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, |
| ClassCBreakPointBeforeBlockMarginCollapsing) { |
| // We get a class C break point here, because we get clearance, because the |
| // (collapsed) margin isn't large enough to take the block below the float on |
| // its own. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height:100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:50px; height:70px;"></div> |
| <div style="float:left; width:100%; height:20px;"></div> |
| <div style="border:1px solid; width:55px;"> |
| <div style="clear:left; width:44px; margin-top:10px;"> |
| <div style="margin-top:18px; break-inside:avoid; width:33px; height:20px;"></div> |
| </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:50x70 |
| offset:0,70 size:100x20 |
| offset:0,70 size:57x30 |
| offset:110,0 size:100x100 |
| offset:0,0 size:57x21 |
| offset:1,0 size:44x20 |
| offset:0,0 size:33x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, |
| NoClassCBreakPointBeforeBlockMarginCollapsing) { |
| // No class C break point here, because there's no clearance, because the |
| // (collapsed) margin is large enough to take the block below the float on its |
| // own. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height:100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:50px; height:70px;"></div> |
| <div style="float:left; width:100%; height:20px;"></div> |
| <div style="border:1px solid; width:55px;"> |
| <div style="clear:left; width:44px; margin-top:10px;"> |
| <div style="margin-top:19px; break-inside:avoid; width:33px; height:20px;"></div> |
| </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:50x70 |
| offset:0,70 size:100x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:57x41 |
| offset:1,20 size:44x20 |
| offset:0,0 size:33x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ClassCBreakPointBeforeLine) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height:100px; |
| line-height: 20px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:50px; height:70px;"></div> |
| <div style="float:left; width:100%; height:20px;"></div> |
| <div style="width:55px;"> |
| <div style="display:inline-block; width:33px; height:11px; vertical-align:top;"></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:50x70 |
| offset:0,70 size:100x20 |
| offset:0,70 size:55x30 |
| offset:110,0 size:100x100 |
| offset:0,0 size:55x20 |
| offset:0,0 size:33x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreakAtClassCBreakPoint) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height:100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:50px; height:50px;"></div> |
| <div style="float:left; width:100%; height:40px;"></div> |
| <div style="width:55px;"> |
| <div style="display:flow-root; break-before:column; width:44px; height:20px;"></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:50x50 |
| offset:0,50 size:100x40 |
| offset:0,50 size:55x50 |
| offset:110,0 size:100x100 |
| offset:0,0 size:55x20 |
| offset:0,0 size:44x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, Nested) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; height:50px; column-fill:auto; width:320px; } |
| .inner { columns:2; height:100px; column-fill:auto; padding:1px; } |
| .outer, .inner { column-gap:10px; } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="content" style="width:5px;"></div> |
| <div class="inner"> |
| <div class="content" style="width:10px;"></div> |
| <div class="content" style="width:20px;"></div> |
| <div class="content" style="width:30px;"></div> |
| <div class="content" style="width:40px;"></div> |
| <div class="content" style="width:50px;"></div> |
| <div class="content" style="width:60px;"></div> |
| <div class="content" style="width:70px;"></div> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x50 |
| offset:0,0 size:320x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:5x20 |
| offset:0,20 size:100x30 |
| offset:1,1 size:44x29 |
| offset:0,0 size:10x20 |
| offset:55,1 size:44x29 |
| offset:0,0 size:20x20 |
| offset:110,0 size:100x50 |
| offset:0,0 size:100x50 |
| offset:1,0 size:44x50 |
| offset:0,0 size:30x20 |
| offset:0,20 size:40x20 |
| offset:55,0 size:44x50 |
| offset:0,0 size:50x20 |
| offset:0,20 size:60x20 |
| offset:220,0 size:100x50 |
| offset:0,0 size:100x22 |
| offset:1,0 size:44x21 |
| offset:0,0 size:70x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, NestedWithEdibleMargin) { |
| // There's a block-start margin after an unforced break. It should be eaten by |
| // the fragmentainer boundary. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; height:50px; column-fill:auto; width:320px; } |
| .inner { columns:2; height:100px; column-fill:auto; } |
| .outer, .inner { column-gap:10px; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="inner"> |
| <div style="width:5px; height:80px;"></div> |
| <div style="break-inside:avoid; margin-top:30px; width:10px; height:10px;"></div> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x50 |
| offset:0,0 size:320x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:45x50 |
| offset:0,0 size:5x50 |
| offset:55,0 size:45x50 |
| offset:0,0 size:5x30 |
| offset:110,0 size:100x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:45x50 |
| offset:0,0 size:10x10 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, NestedNoInnerContent) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; height:50px; column-fill:auto; width:320px; } |
| .inner { columns:2; height:100px; column-fill:auto; padding:1px; } |
| .outer, .inner { column-gap:10px; } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="content" style="width:5px;"></div> |
| <div class="inner"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x50 |
| offset:0,0 size:320x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:5x20 |
| offset:0,20 size:100x30 |
| offset:1,1 size:44x29 |
| offset:110,0 size:100x50 |
| offset:0,0 size:100x50 |
| offset:220,0 size:100x50 |
| offset:0,0 size:100x22 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, NestedSomeInnerContent) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; height:50px; column-fill:auto; width:320px; } |
| .inner { columns:2; height:100px; column-fill:auto; padding:1px; } |
| .outer, .inner { column-gap:10px; } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="content" style="width:5px;"></div> |
| <div class="inner"> |
| <div class="content" style="width:6px;"></div> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x50 |
| offset:0,0 size:320x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:5x20 |
| offset:0,20 size:100x30 |
| offset:1,1 size:44x29 |
| offset:0,0 size:6x20 |
| offset:110,0 size:100x50 |
| offset:0,0 size:100x50 |
| offset:220,0 size:100x50 |
| offset:0,0 size:100x22 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, NestedLimitedHeight) { |
| // This tests that we don't advance to the next outer fragmentainer when we've |
| // reached the bottom of an inner multicol container. We should create inner |
| // columns that overflow in the inline direction in that case. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:2; height:50px; column-fill:auto; width:210px; } |
| .inner { columns:2; height:80px; column-fill:auto; } |
| .outer, .inner { column-gap:10px; } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="content" style="width:5px;"></div> |
| <div class="inner"> |
| <div class="content" style="width:10px;"></div> |
| <div class="content" style="width:20px;"></div> |
| <div class="content" style="width:30px;"></div> |
| <div class="content" style="width:40px;"></div> |
| <div class="content" style="width:50px;"></div> |
| <div class="content" style="width:60px;"></div> |
| <div class="content" style="width:70px;"></div> |
| <div class="content" style="width:80px;"></div> |
| <div class="content" style="width:90px;"></div> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x50 |
| offset:0,0 size:210x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:5x20 |
| offset:0,20 size:100x30 |
| offset:0,0 size:45x30 |
| offset:0,0 size:10x20 |
| offset:55,0 size:45x30 |
| offset:0,0 size:20x20 |
| offset:110,0 size:100x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:45x50 |
| offset:0,0 size:30x20 |
| offset:0,20 size:40x20 |
| offset:55,0 size:45x50 |
| offset:0,0 size:50x20 |
| offset:0,20 size:60x20 |
| offset:110,0 size:45x50 |
| offset:0,0 size:70x20 |
| offset:0,20 size:80x20 |
| offset:165,0 size:45x50 |
| offset:0,0 size:90x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, NestedLimitedHeightWithPadding) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; width:320px; height:100px; } |
| .inner { columns:2; height:100px; padding-top:50px; } |
| .outer, .inner { column-gap:10px; column-fill:auto; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="inner"> |
| <div style="width:22px; height:200px;"></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,50 size:45x50 |
| offset:0,0 size:22x50 |
| offset:55,50 size:45x50 |
| offset:0,0 size:22x50 |
| 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:22x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, NestedUnbalancedInnerAutoHeight) { |
| // The fragments generated by an inner multicol are block-size constrained by |
| // the outer multicol, so if column-fill is auto, we shouldn't forcefully |
| // balance. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:2; height:50px; column-fill:auto; width:210px; } |
| .inner { columns:2; column-fill:auto; } |
| .outer, .inner { column-gap:10px; } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="inner"> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x50 |
| offset:0,0 size:210x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:45x50 |
| offset:0,0 size:45x20 |
| offset:0,20 size:45x20 |
| offset:55,0 size:45x50 |
| offset:0,0 size:45x20 |
| offset:0,20 size:45x20 |
| offset:110,0 size:100x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:45x50 |
| offset:0,0 size:45x20 |
| offset:0,20 size:45x20 |
| )DUMP"; |
| 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:45x0 |
| 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:45x0 |
| 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"> |
| <div style="columns:3; width:320px; height:100px; column-gap:10px; column-fill:auto;"> |
| <div style="position:relative; width:222px; height:250px;"> |
| <div style="position:absolute; width:111px; height:50px;"></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:222x100 |
| offset:0,0 size:111x50 |
| offset:110,0 size:100x100 |
| offset:0,0 size:222x100 |
| offset:220,0 size:100x100 |
| offset:0,0 size:222x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, Spanner) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| border: 1px solid; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div style="column-span:all; height:44px;"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x126 |
| offset:0,0 size:322x126 |
| offset:1,1 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:111,1 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:221,1 size:100x40 |
| offset:0,0 size:100x20 |
| offset:1,41 size:320x44 |
| offset:1,85 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:111,85 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:221,85 size:100x40 |
| offset:0,0 size:100x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, SpannerWithContent) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| border: 1px solid; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div style="column-span:all; padding:1px;"> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| </div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x144 |
| offset:0,0 size:322x144 |
| offset:1,1 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:111,1 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:221,1 size:100x40 |
| offset:0,0 size:100x20 |
| offset:1,41 size:320x62 |
| offset:1,1 size:318x20 |
| offset:1,21 size:318x20 |
| offset:1,41 size:318x20 |
| offset:1,103 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:111,103 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:221,103 size:100x40 |
| offset:0,0 size:100x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, TwoSpannersPercentWidth) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| border: 1px solid; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div style="column-span:all; width:50%; height:44px;"></div> |
| <div style="column-span:all; width:50%; height:1px;"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x127 |
| offset:0,0 size:322x127 |
| offset:1,1 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:111,1 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:221,1 size:100x40 |
| offset:0,0 size:100x20 |
| offset:1,41 size:160x44 |
| offset:1,85 size:160x1 |
| offset:1,86 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:111,86 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:221,86 size:100x40 |
| offset:0,0 size:100x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, SpannerNoBalancing) { |
| // Even if column-fill is auto and block-size is restricted, we have to |
| // balance column contents in front of a spanner (but not after). |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| height: 200px; |
| width: 320px; |
| border: 1px solid; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div style="column-span:all; height:44px;"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x202 |
| offset:0,0 size:322x202 |
| offset:1,1 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:111,1 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:221,1 size:100x40 |
| offset:0,0 size:100x20 |
| offset:1,41 size:320x44 |
| offset:1,85 size:100x116 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:0,40 size:100x20 |
| offset:0,60 size:100x20 |
| offset:0,80 size:100x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, SpannerAtStart) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| border: 1px solid; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="column-span:all; height:44px;"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x86 |
| offset:0,0 size:322x86 |
| offset:1,1 size:100x0 |
| offset:1,1 size:320x44 |
| offset:1,45 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:111,45 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:221,45 size:100x40 |
| offset:0,0 size:100x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, SpannerAtEnd) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| border: 1px solid; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div style="column-span:all; height:44px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x86 |
| offset:0,0 size:322x86 |
| offset:1,1 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:111,1 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:221,1 size:100x40 |
| offset:0,0 size:100x20 |
| offset:1,41 size:320x44 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, SpannerAlone) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| border: 1px solid; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="column-span:all; height:44px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x46 |
| offset:0,0 size:322x46 |
| offset:1,1 size:100x0 |
| offset:1,1 size:320x44 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, SpannerInBlock) { |
| // Spanners don't have to be direct children of the multicol container, but |
| // have to be defined in the same block formatting context as the one |
| // established by the multicol container. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| border: 1px solid; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:11px;"> |
| <div style="column-span:all; height:44px;"></div> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x46 |
| offset:0,0 size:322x46 |
| offset:1,1 size:100x0 |
| offset:0,0 size:11x0 |
| offset:1,1 size:320x44 |
| offset:1,45 size:100x0 |
| offset:0,0 size:11x0 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, SpannerWithSiblingsInBlock) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| border: 1px solid; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:11px;"> |
| <div style="column-span:all; height:44px;"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x86 |
| offset:0,0 size:322x86 |
| offset:1,1 size:100x0 |
| offset:0,0 size:11x0 |
| offset:1,1 size:320x44 |
| offset:1,45 size:100x40 |
| offset:0,0 size:11x40 |
| offset:0,0 size:11x20 |
| offset:0,20 size:11x20 |
| offset:111,45 size:100x40 |
| offset:0,0 size:11x40 |
| offset:0,0 size:11x20 |
| offset:0,20 size:11x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, SpannerInBlockWithSiblings) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| border: 1px solid; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:11px;"> |
| <div style="column-span:all; height:44px;"></div> |
| </div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div class="content"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x86 |
| offset:0,0 size:322x86 |
| offset:1,1 size:100x0 |
| offset:0,0 size:11x0 |
| offset:1,1 size:320x44 |
| offset:1,45 size:100x40 |
| offset:0,0 size:11x0 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| offset:111,45 size:100x40 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, SpannerMargins) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="column-span:all; margin:10px; width:33px; height:10px;"></div> |
| <div class="content"></div> |
| <div style="column-span:all; margin:10px auto; width:44px; height:10px;"></div> |
| <div style="column-span:all; margin:20px; width:55px;"></div> |
| <div style="column-span:all; margin:10px; width:66px; height:10px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x130 |
| offset:0,0 size:320x130 |
| offset:0,0 size:100x0 |
| offset:10,10 size:33x10 |
| offset:0,30 size:100x20 |
| offset:0,0 size:100x20 |
| offset:138,60 size:44x10 |
| offset:20,90 size:55x0 |
| offset:10,110 size:66x10 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, SpannerMarginsRtl) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| direction: rtl; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="column-span:all; margin:10px; width:33px; height:10px;"></div> |
| <div class="content"></div> |
| <div style="column-span:all; margin:10px auto; width:44px; height:10px;"></div> |
| <div style="column-span:all; margin:20px; width:55px;"></div> |
| <div style="column-span:all; margin:10px; width:66px; height:10px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x130 |
| offset:0,0 size:320x130 |
| offset:220,0 size:100x0 |
| offset:277,10 size:33x10 |
| offset:220,30 size:100x20 |
| offset:0,0 size:100x20 |
| offset:138,60 size:44x10 |
| offset:245,90 size:55x0 |
| offset:244,110 size:66x10 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, FixedSizeMulticolWithSpanner) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 300px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:33px; height:300px;"></div> |
| <div style="column-span:all; width:44px; height:50px;"></div> |
| <div style="width:55px; height:450px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x300 |
| offset:0,0 size:320x300 |
| offset:0,0 size:100x100 |
| offset:0,0 size:33x100 |
| offset:110,0 size:100x100 |
| offset:0,0 size:33x100 |
| offset:220,0 size:100x100 |
| offset:0,0 size:33x100 |
| offset:0,100 size:44x50 |
| offset:0,150 size:100x150 |
| offset:0,0 size:55x150 |
| offset:110,150 size:100x150 |
| offset:0,0 size:55x150 |
| offset:220,150 size:100x150 |
| offset:0,0 size:55x150 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, MarginAndBorderTopWithSpanner) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-fill: auto; |
| column-gap: 10px; |
| width: 320px; |
| height: 300px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:22px; margin-top:200px; border-top:100px solid;"> |
| <div style="column-span:all; width:33px; height:100px;"></div> |
| <div style="width:44px; height:300px;"></div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x300 |
| offset:0,0 size:320x300 |
| offset:0,0 size:100x100 |
| offset:110,0 size:100x100 |
| offset:0,0 size:22x100 |
| offset:0,100 size:33x100 |
| offset:0,200 size:100x100 |
| offset:0,0 size:22x100 |
| offset:0,0 size:44x100 |
| offset:110,200 size:100x100 |
| offset:0,0 size:22x100 |
| offset:0,0 size:44x100 |
| offset:220,200 size:100x100 |
| offset:0,0 size:22x100 |
| offset:0,0 size:44x100 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BreakInsideSpannerWithMargins) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| column-fill: auto; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="columns:2; column-gap:0;"> |
| <div style="column-span:all; margin-top:10px; margin-bottom:20px; width:33px; height:100px;"></div> |
| <div style="column-span:all; width:44px; height:10px;"></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:50x0 |
| offset:0,10 size:33x90 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x40 |
| offset:0,0 size:33x10 |
| offset:0,30 size:44x10 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, InvalidSpanners) { |
| // Spanners cannot exist inside new formatting context roots. They will just |
| // be treated as normal column content then. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| width: 320px; |
| border: 1px solid; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="float:left; width:10px;"> |
| <div style="column-span:all; height:30px;"></div> |
| </div> |
| <div style="display:flow-root;"> |
| <div style="column-span:all; height:30px;"></div> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x12 |
| offset:0,0 size:322x12 |
| offset:1,1 size:100x10 |
| offset:0,0 size:10x10 |
| offset:0,0 size:10x10 |
| offset:10,0 size:90x10 |
| offset:0,0 size:90x10 |
| offset:111,1 size:100x10 |
| offset:0,0 size:10x10 |
| offset:0,0 size:10x10 |
| offset:10,0 size:90x10 |
| offset:0,0 size:90x10 |
| offset:221,1 size:100x10 |
| offset:0,0 size:10x10 |
| offset:0,0 size:10x10 |
| offset:10,0 size:90x10 |
| offset:0,0 size:90x10 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BreakInsideSpanner) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; height:50px; column-fill:auto; width:320px; } |
| .inner { columns:2; height:100px; column-fill:auto; padding:1px; } |
| .outer, .inner { column-gap:10px; } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="content"></div> |
| <div class="inner"> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div style="column-span:all; height:35px;"></div> |
| <div class="content" style="width:7px;"></div> |
| <div class="content" style="width:8px;"></div> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x50 |
| offset:0,0 size:320x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x30 |
| offset:1,1 size:44x20 |
| offset:0,0 size:44x20 |
| offset:55,1 size:44x20 |
| offset:0,0 size:44x20 |
| offset:1,21 size:98x9 |
| offset:110,0 size:100x50 |
| offset:0,0 size:100x50 |
| offset:1,0 size:98x26 |
| offset:1,26 size:44x24 |
| offset:0,0 size:7x20 |
| offset:55,26 size:44x24 |
| offset:0,0 size:8x20 |
| offset:220,0 size:100x50 |
| offset:0,0 size:100x22 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BreakInsideSpannerTwice) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; height:50px; column-fill:auto; width:320px; } |
| .inner { columns:2; height:150px; column-fill:auto; padding:1px; } |
| .outer, .inner { column-gap:10px; } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="content"></div> |
| <div class="inner"> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div style="column-span:all; height:85px;"></div> |
| <div class="content" style="width:7px;"></div> |
| <div class="content" style="width:8px;"></div> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x50 |
| offset:0,0 size:320x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:100x20 |
| offset:0,20 size:100x30 |
| offset:1,1 size:44x20 |
| offset:0,0 size:44x20 |
| offset:55,1 size:44x20 |
| offset:0,0 size:44x20 |
| offset:1,21 size:98x9 |
| offset:110,0 size:100x50 |
| offset:0,0 size:100x50 |
| offset:1,0 size:98x50 |
| offset:220,0 size:100x50 |
| offset:0,0 size:100x50 |
| offset:1,0 size:98x26 |
| offset:1,26 size:44x24 |
| offset:0,0 size:7x20 |
| offset:55,26 size:44x24 |
| offset:0,0 size:8x20 |
| offset:330,0 size:100x50 |
| offset:0,0 size:100x22 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, BreakInsideSpannerWithContent) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; height:50px; column-fill:auto; width:320px; } |
| .inner { columns:2; height:98px; column-fill:auto; padding:1px; } |
| .outer, .inner { column-gap:10px; } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="inner"> |
| <div class="content"></div> |
| <div class="content"></div> |
| <div style="column-span:all;"> |
| <div style="width:3px;" class="content"></div> |
| <div style="width:4px;" class="content"></div> |
| </div> |
| <div class="content" style="width:7px;"></div> |
| <div class="content" style="width:8px;"></div> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x50 |
| offset:0,0 size:320x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:100x50 |
| offset:1,1 size:44x20 |
| offset:0,0 size:44x20 |
| offset:55,1 size:44x20 |
| offset:0,0 size:44x20 |
| offset:1,21 size:98x29 |
| offset:0,0 size:3x20 |
| offset:110,0 size:100x50 |
| offset:0,0 size:100x50 |
| offset:1,0 size:98x20 |
| offset:0,0 size:4x20 |
| offset:1,20 size:44x29 |
| offset:0,0 size:7x20 |
| offset:55,20 size:44x29 |
| offset:0,0 size:8x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreakBetweenSpanners) { |
| // There are two spanners in a nested multicol. They could fit in the same |
| // outer column, but there's a forced break between them. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } |
| .inner { columns:2; column-gap:0; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="inner"> |
| <div style="column-span:all; break-inside:avoid; width:55px; height:40px;"></div> |
| <div style="column-span:all; break-before:column; break-inside:avoid; width:66px; height:40px;"></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:50x0 |
| offset:0,0 size:55x40 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x40 |
| offset:0,0 size:66x40 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreakBetweenSpanners2) { |
| // There are two spanners in a nested multicol. They could fit in the same |
| // outer column, but there's a forced break between them. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } |
| .inner { columns:2; column-gap:0; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="inner"> |
| <div style="column-span:all; break-after:column; break-inside:avoid; width:55px; height:40px;"></div> |
| <div style="column-span:all; break-inside:avoid; width:66px; height:40px;"></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:50x0 |
| offset:0,0 size:55x40 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x40 |
| offset:0,0 size:66x40 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreakBetweenSpanners3) { |
| // There are two spanners in a nested multicol. They could fit in the same |
| // outer column, but there's a forced break after the last child of the first |
| // spanner. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } |
| .inner { columns:2; column-gap:0; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="inner"> |
| <div style="column-span:all; break-inside:avoid; width:55px; height:40px;"> |
| <div style="width:33px; height:10px;"></div> |
| <div style="break-after:column; width:44px; height:10px;"></div> |
| </div> |
| <div style="column-span:all; break-inside:avoid; width:66px; height:40px;"></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:50x0 |
| offset:0,0 size:55x40 |
| offset:0,0 size:33x10 |
| offset:0,10 size:44x10 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x40 |
| offset:0,0 size:66x40 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreakBetweenSpanners4) { |
| // There are two spanners in a nested multicol. They could fit in the same |
| // outer column, but there's a forced break before the first child of the |
| // last spanner. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } |
| .inner { columns:2; column-gap:0; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="inner"> |
| <div style="column-span:all; break-inside:avoid; width:55px; height:40px;"></div> |
| <div style="column-span:all; break-inside:avoid; width:66px; height:40px;"> |
| <div style="break-before:column; width:33px; height:10px;"></div> |
| <div style="width:44px; height:10px;"></div> |
| </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:50x0 |
| offset:0,0 size:55x40 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x40 |
| offset:0,0 size:66x40 |
| offset:0,0 size:33x10 |
| offset:0,10 size:44x10 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, ForcedBreakBetweenSpanners5) { |
| // There are two spanners in a nested multicol. They could fit in the same |
| // outer column, but there's a forced break between them. The second spanner |
| // has a top margin, which should be retained, due to the forced break. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } |
| .inner { columns:2; column-gap:0; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="inner"> |
| <div style="column-span:all; break-inside:avoid; width:55px; height:40px;"></div> |
| <div style="column-span:all; break-before:column; break-inside:avoid; width:66px; height:40px; margin-top:10px;"></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:50x0 |
| offset:0,0 size:55x40 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x50 |
| offset:0,10 size:66x40 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, SoftBreakBetweenSpanners) { |
| // There are two spanners in a nested multicol. They won't fit in the same |
| // outer column, and we don't want to break inside. So we should break between |
| // them. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } |
| .inner { columns:2; column-gap:0; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="inner"> |
| <div style="column-span:all; break-inside:avoid; width:55px; height:60px;"></div> |
| <div style="column-span:all; break-inside:avoid; width:66px; height:60px;"></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:50x0 |
| offset:0,0 size:55x60 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x60 |
| offset:0,0 size:66x60 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, SoftBreakBetweenSpanners2) { |
| // There are two spanners in a nested multicol. They won't fit in the same |
| // outer column, and we don't want to break inside. So we should break between |
| // them. The second spanner has a top margin, but it should be truncated since |
| // it's at a soft break. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } |
| .inner { columns:2; column-gap:0; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="inner"> |
| <div style="column-span:all; break-inside:avoid; width:55px; height:60px;"></div> |
| <div style="column-span:all; break-inside:avoid; width:66px; height:60px; margin-top:10px;"></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:50x0 |
| offset:0,0 size:55x60 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x60 |
| offset:0,0 size:66x60 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, AvoidSoftBreakBetweenSpanners) { |
| // There are three spanners in a nested multicol. The first two could fit in |
| // the same outer column, but the third one is too tall, and we also don't |
| // want to break before that one.So we should break between the two first |
| // spanners. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } |
| .inner { columns:2; column-gap:0; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="inner"> |
| <div style="column-span:all; break-inside:avoid; width:55px; height:40px;"></div> |
| <div style="column-span:all; break-inside:avoid; width:66px; height:40px;"></div> |
| <div style="column-span:all; break-inside:avoid; break-before:avoid; width:77px; height:60px;"></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:50x0 |
| offset:0,0 size:55x40 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x100 |
| offset:0,0 size:66x40 |
| offset:0,40 size:77x60 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, AvoidSoftBreakBetweenSpanners2) { |
| // There are two spanners in a nested multicol. They won't fit in the same |
| // outer column, but we don't want to break inside the second one, and also |
| // not between the spanners. The first spanner is breakable, so we should |
| // break at the most appealing breakpoint there, i.e. before its last child. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; height:100px; column-fill:auto; column-gap:10px; width:320px; } |
| .inner { columns:2; column-gap:0; } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="inner"> |
| <div style="column-span:all; width:11px;"> |
| <div class="content" style="width:22px;"></div> |
| <div class="content" style="width:33px;"></div> |
| <div class="content" style="width:44px;"></div> |
| </div> |
| <div style="column-span:all; break-inside:avoid; break-before:avoid; width:55px; height:60px;"></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:50x0 |
| offset:0,0 size:11x100 |
| offset:0,0 size:22x20 |
| offset:0,20 size:33x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x80 |
| offset:0,0 size:11x20 |
| offset:0,0 size:44x20 |
| offset:0,20 size:55x60 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, AvoidSoftBreakBetweenSpanners3) { |
| // Violate orphans and widows requests rather than break-between avoidance |
| // requests. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { |
| columns:3; |
| height:100px; |
| column-fill:auto; |
| column-gap:10px; |
| width:320px; |
| line-height: 20px; |
| orphans: 3; |
| widows: 3; |
| } |
| .inner { columns:2; column-gap:0; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="inner"> |
| <div style="column-span:all; width:11px;"> |
| <br> |
| <br> |
| <br> |
| </div> |
| <div style="column-span:all; break-inside:avoid; break-before:avoid; width:55px; height:60px;"></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:50x0 |
| offset:0,0 size:11x100 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x80 |
| offset:0,0 size:11x20 |
| offset:0,0 size:0x20 |
| offset:0,20 size:55x60 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, SoftBreakBetweenRowAndSpanner) { |
| // We have a nested multicol with some column content, followed by a |
| // spanner. Everything won't fit in the same outer column, and we don't want |
| // to break inside the spanner. Break between the row of columns and the |
| // spanner. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { |
| columns:3; |
| height:100px; |
| column-fill:auto; |
| column-gap:10px; |
| width:320px; |
| } |
| .inner { columns:2; column-gap:10px; } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="inner"> |
| <div class="content" style="width:11px;"></div> |
| <div class="content" style="width:22px;"></div> |
| <div class="content" style="width:33px;"></div> |
| <div style="column-span:all; break-inside:avoid; width:44px; 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:45x40 |
| offset:0,0 size:11x20 |
| offset:0,20 size:22x20 |
| offset:55,0 size:45x40 |
| offset:0,0 size:33x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x70 |
| offset:0,0 size:44x70 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, SpannerAsMulticol) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| .outer { columns:3; height:50px; column-fill:auto; width:320px; } |
| .middle { columns:2; height:140px; column-fill:auto; } |
| .inner { column-span:all; columns:2; height:80px; column-fill:auto; } |
| .outer, .middle, .inner { column-gap:10px; } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div class="outer"> |
| <div class="middle"> |
| <div class="inner"> |
| <div class="content" style="width:131px;"></div> |
| <div class="content" style="width:132px;"></div> |
| <div class="content" style="width:133px;"></div> |
| <div class="content" style="width:134px;"></div> |
| <div class="content" style="width:135px;"></div> |
| <div class="content" style="width:136px;"></div> |
| </div> |
| </div> |
| </div> |
| </div> |
| )HTML"); |
| |
| String dump = DumpFragmentTree(GetElementById("container")); |
| String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::. |
| offset:unplaced size:1000x50 |
| offset:0,0 size:320x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:45x0 |
| offset:0,0 size:100x50 |
| offset:0,0 size:45x50 |
| offset:0,0 size:131x20 |
| offset:0,20 size:132x20 |
| offset:55,0 size:45x50 |
| offset:0,0 size:133x20 |
| offset:0,20 size:134x20 |
| offset:110,0 size:100x50 |
| offset:0,0 size:100x50 |
| offset:0,0 size:100x30 |
| offset:0,0 size:45x30 |
| offset:0,0 size:135x20 |
| offset:55,0 size:45x30 |
| offset:0,0 size:136x20 |
| offset:220,0 size:100x50 |
| offset:0,0 size:100x40 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBetween) { |
| // Breaking exactly where we run out of space would violate a |
| // break-before:avoid rule. There's a perfect break opportunity before the |
| // previous sibling, so use that one instead. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 100px; |
| } |
| .content { break-inside:avoid; height:30px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div class="content" style="width:81px;"></div> |
| <div class="content" style="width:82px;"></div> |
| <div class="content" style="width:83px;"></div> |
| <div class="content" style="width:84px; break-before:avoid;"></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:81x30 |
| offset:0,30 size:82x30 |
| offset:110,0 size:100x100 |
| offset:0,0 size:83x30 |
| offset:0,30 size:84x30 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, AvoidAndForceBreakBetween) { |
| // If we're both told to avoid and force breaking at a breakpoint, forcing |
| // always wins. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 100px; |
| } |
| .content { break-inside:avoid; height:30px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div class="content" style="width:81px;"></div> |
| <div class="content" style="width:82px;"></div> |
| <div class="content" style="width:83px; break-after:column;"></div> |
| <div class="content" style="width:84px; break-before:avoid;"></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:81x30 |
| offset:0,30 size:82x30 |
| offset:0,60 size:83x30 |
| offset:110,0 size:100x100 |
| offset:0,0 size:84x30 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBetweenInFloat) { |
| // There are two parallel flows here; one for the float, and one for its |
| // sibling. They don't affect each other as far as breaking is concerned. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 100px; |
| } |
| .content { break-inside:avoid; height:30px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="float:left; width:100%;"> |
| <div class="content" style="width:81px;"></div> |
| <div class="content" style="width:82px;"></div> |
| <div class="content" style="width:83px;"></div> |
| <div class="content" style="width:84px; break-before:avoid;"></div> |
| </div> |
| <div style="height:150px;"></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:81x30 |
| offset:0,30 size:82x30 |
| offset:0,0 size:100x100 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x60 |
| offset:0,0 size:83x30 |
| offset:0,30 size:84x30 |
| offset:0,0 size:100x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, |
| IgnoreBreakInsideAvoidBecauseBreakBetweenAvoid) { |
| // We want to avoid breaks between all the children, and at the same time |
| // avoid breaks inside of them. This is impossible to honor in this test, |
| // since the content is taller than one column. There are no ideal |
| // breakpoints; all are equally bad. The spec is explicit about the fact that |
| // it "does not suggest a precise algorithm" when it comes to picking which |
| // breaking rule to violate before others, so whether we should drop |
| // break-before or break-inside first is undefined. However, the spec does |
| // also mention that we should break as few times as possible, which suggests |
| // that we should favor whatever gives more progression. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 100px; |
| } |
| .content { break-inside:avoid; height:30px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div class="content" style="width:81px;"></div> |
| <div class="content" style="width:82px; break-before:avoid;"></div> |
| <div class="content" style="width:83px; break-before:avoid;"></div> |
| <div class="content" style="width:84px; break-before:avoid;"></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:81x30 |
| offset:0,30 size:82x30 |
| offset:0,60 size:83x30 |
| offset:0,90 size:84x10 |
| offset:110,0 size:100x100 |
| offset:0,0 size:84x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBetweenAndInsideIgnoreInside) { |
| // This one isn't obvious, spec-wise, since it's not defined which rules to |
| // disregard first (break-inside vs. break-before, and break-inside on a child |
| // vs. on its container), but it seems right to disregard break-inside:avoid |
| // on the container, and at the same time honor break avoidance specified |
| // further within (smaller pieces, more progression), rather than e.g. giving |
| // up on everything and breaking wherever. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 100px; |
| } |
| .content { break-inside:avoid; height:30px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="break-inside:avoid;"> |
| <div style="width:80px; height:20px;"></div> |
| <div class="content" style="width:81px;"></div> |
| <div class="content" style="width:82px;"></div> |
| <div class="content" style="width:83px; break-before:avoid;"></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:80x20 |
| offset:0,20 size:81x30 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x60 |
| offset:0,0 size:82x30 |
| offset:0,30 size:83x30 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBetweenAndInside) { |
| // When looking for possible breaks inside #middle, we need to take into |
| // account that we're supposed to avoid breaking inside. The only breakpoint |
| // that doesn't violate any rules in this test is *before* #middle. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 100px; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div class="content" style="width:32px;"></div> |
| <div id="middle" style="break-inside:avoid; break-after:avoid;"> |
| <div class="content" style="width:33px;"></div> |
| <div class="content" style="width:34px;"></div> |
| <div class="content" style="width:35px;"></div> |
| <div class="content" style="width:36px;"></div> |
| </div> |
| <div class="content" style="width:37px;"></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:32x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x80 |
| offset:0,0 size:33x20 |
| offset:0,20 size:34x20 |
| offset:0,40 size:35x20 |
| offset:0,60 size:36x20 |
| offset:0,80 size:37x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBetweenInsideBreakableParent) { |
| // There's a perfect breakpoint between the two direct children of the |
| // multicol container - i.e. between #first and #second. We should avoid |
| // breaking between between any of the children of #second (we run out of |
| // space between the third and the fourth child). There are no restrictions on |
| // breaking between the children inside #first, but we should progress as much |
| // as possible, so the correct thing to do is to break between #first and |
| // #second. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 100px; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div id="#first"> |
| <div class="content" style="width:33px;"></div> |
| <div class="content" style="width:34px;"></div> |
| </div> |
| <div id="#second"> |
| <div class="content" style="width:35px;"></div> |
| <div class="content" style="width:36px; break-before:avoid;"></div> |
| <div class="content" style="width:37px; break-before:avoid;"></div> |
| <div class="content" style="width:38px; break-before:avoid;"></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:100x40 |
| offset:0,0 size:33x20 |
| offset:0,20 size:34x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x80 |
| offset:0,0 size:35x20 |
| offset:0,20 size:36x20 |
| offset:0,40 size:37x20 |
| offset:0,60 size:38x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBetweenAfterBreakableSibling) { |
| // We should avoid breaking between the two direct children of the multicol |
| // container - i.e. between #first and #second. We should also avoid breaking |
| // between between the children of #second (we run out of space before its |
| // second child). The only restriction inside #first is between the third and |
| // fourth child, while there are perfect breakpoints between the first and the |
| // second, and between the second and the third. We should progress as much as |
| // possible, so the correct thing to do is to break between the second and |
| // third child of #first. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 100px; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="break-after:avoid;"> |
| <div class="content" style="width:33px;"></div> |
| <div class="content" style="width:34px;"></div> |
| <div class="content" style="width:35px;"></div> |
| <div class="content" style="width:36px; break-before:avoid;"></div> |
| </div> |
| <div> |
| <div class="content" style="width:37px;"></div> |
| <div class="content" style="width:38px; break-before:avoid;"></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:33x20 |
| offset:0,20 size:34x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x40 |
| offset:0,0 size:35x20 |
| offset:0,20 size:36x20 |
| offset:0,40 size:100x40 |
| offset:0,0 size:37x20 |
| offset:0,20 size:38x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, |
| AvoidBreakBetweenBreakInsidePreviousSibling) { |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 100px; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div class="content" style="width:32px;"></div> |
| <div style="break-after:avoid;"> |
| <div class="content" style="width:33px;"></div> |
| <div class="content" style="width:34px;"></div> |
| <div class="content" style="width:35px;"></div> |
| <div class="content" style="width:36px;"></div> |
| </div> |
| <div class="content" style="width:37px;"></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:32x20 |
| offset:0,20 size:100x80 |
| offset:0,0 size:33x20 |
| offset:0,20 size:34x20 |
| offset:0,40 size:35x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x20 |
| offset:0,0 size:36x20 |
| offset:0,20 size:37x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBetweenHonorOrphansWidows) { |
| // We run out of space at .content, but this isn't a good location, because of |
| // break-before:avoid. Break between the lines. Honor orphans and widows, so |
| // that two of the four lines will be pushed to the second column. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 100px; |
| line-height: 20px; |
| orphans: 2; |
| widows: 2; |
| } |
| .content { break-inside:avoid; height:30px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <br> |
| <br> |
| <br> |
| <br> |
| <div class="content" style="break-before:avoid;"></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:0x20 |
| offset:0,20 size:0x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:100x30 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBetweenHonorOrphansWidows2) { |
| // We run out of space at .content, but this isn't a good location, because of |
| // break-before:avoid. Break between the first block and the two lines, in |
| // order to honor orphans and widows. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 100px; |
| line-height: 20px; |
| orphans: 2; |
| widows: 2; |
| } |
| .content { break-inside:avoid; height:30px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="height:40px;"></div> |
| <br> |
| <br> |
| <div class="content" style="break-before:avoid;"></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:100x40 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:100x30 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBetweenHonorOrphansWidows3) { |
| // We run out of space between the first and the second line in the second |
| // container, but this isn't a good location, because of the orphans and |
| // widows requirement. Break between the second and third line inside the |
| // first container instead. We should not break between the two containers, |
| // because of break-before:avoid. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 100px; |
| line-height: 20px; |
| orphans: 2; |
| widows: 2; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div> |
| <br> |
| <br> |
| <br> |
| <br> |
| </div> |
| <div style="break-before:avoid;"> |
| <br> |
| <br> |
| <br> |
| </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:0x20 |
| offset:0,20 size:0x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:100x60 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:0x20 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBetweenIgnoreOrphansWidows) { |
| // We run out of space at .content, but this isn't a good location, because of |
| // break-before:avoid. Break between the two lines, even if that will violate |
| // the orphans and widows requirement. According to the spec, this is better |
| // then ignoring the the break-after:avoid declaration on the first child. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 100px; |
| line-height: 20px; |
| orphans: 2; |
| widows: 2; |
| } |
| .content { break-inside:avoid; height:30px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="height:40px; break-after:avoid;"></div> |
| <br> |
| <br> |
| <div class="content" style="break-before:avoid;"></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:100x40 |
| offset:0,40 size:100x60 |
| offset:0,0 size:0x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:100x20 |
| offset:0,0 size:0x20 |
| offset:0,20 size:100x30 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBetweenLinesInsideBreakAvoid) { |
| // We run out of space at the second line inside the last container, and we're |
| // not supposed to break inside it. We're also not supposed to break between |
| // the lines in the previous container (since it has break-inside:avoid, |
| // albeit no orphans/widows restrictions). Breaking before that container |
| // instead is as far as we get without breaking any rules. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 100px; |
| line-height: 20px; |
| orphans: 1; |
| widows: 1; |
| } |
| .content { break-inside:avoid; height:20px; } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div class="content" style="width:33px;"></div> |
| <div class="content" style="width:34px;"></div> |
| <div style="break-inside:avoid; width:35px;"> |
| <br> |
| <br> |
| </div> |
| <div class="content" style="break-before:avoid; width:36px; height:30px;"></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:33x20 |
| offset:0,20 size:34x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:35x40 |
| offset:0,0 size:0x20 |
| offset:0,20 size:0x20 |
| offset:0,40 size:36x30 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBetweenBreakAtEarlyClassC) { |
| // The early break is a class C breakpoint, and this is also exactly where the |
| // BFC block-offset is resolved. There are no possible breaks as long as we |
| // don't know our BFC offset, but breaking just before the box that resolves |
| // the BFC block-offset should be allowed. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:22px;"> |
| <div style="float:left; width:100%; width:33px; height:20px;"></div> |
| <div style="display:flow-root; width:44px; height:20px;"></div> |
| </div> |
| <div style="break-before:avoid; break-inside:avoid; width:55px; height:70px;"></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:22x100 |
| offset:0,0 size:33x20 |
| offset:110,0 size:100x100 |
| offset:0,0 size:22x20 |
| offset:0,0 size:44x20 |
| offset:0,20 size:55x70 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBeforeBlockReplacedContent) { |
| // Replaced content is unbreakable. Don't break right before it if we have |
| // break-before:avoid, though. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <div style="width:22px; height:40px;"></div> |
| <div style="width:33px; height:50px; break-inside:avoid;"></div> |
| <img style="break-before:avoid; display:block; width:44px; height:50px;"> |
| </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:22x40 |
| offset:110,0 size:100x100 |
| offset:0,0 size:33x50 |
| offset:0,50 size:44x50 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| TEST_F(NGColumnLayoutAlgorithmTest, TallReplacedContent) { |
| // Replaced content is unbreakable. Let it overflow the column. |
| SetBodyInnerHTML(R"HTML( |
| <style> |
| #parent { |
| columns: 3; |
| column-gap: 10px; |
| column-fill: auto; |
| width: 320px; |
| height: 100px; |
| } |
| </style> |
| <div id="container"> |
| <div id="parent"> |
| <img style="display:block; width:44px; height:150px;"> |
| </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:44x150 |
| )DUMP"; |
| EXPECT_EQ(expectation, dump); |
| } |
| |
| } // anonymous namespace |
| } // namespace blink |