Chromium Code Reviews| Index: third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc |
| diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc |
| index 8b3ba8b0eb83fbdab73bc81f24824a65454df3a9..530cd0ed48efd9c6fd28913a2c70468af3c36f24 100644 |
| --- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc |
| +++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc |
| @@ -26,15 +26,24 @@ namespace { |
| using testing::ElementsAre; |
| using testing::Pointee; |
| -NGConstraintSpace* ConstructConstraintSpace(NGWritingMode writing_mode, |
| - TextDirection direction, |
| - NGLogicalSize size, |
| - bool shrink_to_fit = false) { |
| +NGConstraintSpace* ConstructConstraintSpace( |
| + NGWritingMode writing_mode, |
| + TextDirection direction, |
| + NGLogicalSize size, |
| + bool shrink_to_fit = false, |
| + LayoutUnit fragmentainer_space_available = LayoutUnit()) { |
| + NGFragmentationType block_fragmentation = |
| + fragmentainer_space_available != LayoutUnit() |
| + ? NGFragmentationType::kFragmentColumn |
| + : NGFragmentationType::kFragmentNone; |
| + |
| return NGConstraintSpaceBuilder(writing_mode) |
| .SetAvailableSize(size) |
| .SetPercentageResolutionSize(size) |
| .SetTextDirection(direction) |
| .SetIsShrinkToFit(shrink_to_fit) |
| + .SetFragmentainerSpaceAvailable(fragmentainer_space_available) |
| + .SetFragmentationType(block_fragmentation) |
| .ToConstraintSpace(writing_mode); |
| } |
| @@ -2096,5 +2105,425 @@ TEST_F(NGBlockLayoutAlgorithmTest, PositionEmptyBlocksInNewBfc) { |
| empty_block2->Offset()); |
| } |
| +// Tests that a block child won't fragment if it doesn't reach the fragmentation |
| +// line. |
| +TEST_F(NGBlockLayoutAlgorithmTest, NoFragmentation) { |
| + setBodyInnerHTML(R"HTML( |
| + <!DOCTYPE html> |
| + <style> |
| + #container { |
| + width: 150px; |
| + height: 200px; |
| + } |
| + </style> |
| + <div id='container'></div> |
| + )HTML"); |
| + |
| + LayoutUnit kFragmentainerSpaceAvailable(200); |
| + |
| + NGBlockNode* node = new NGBlockNode( |
| + toLayoutBlockFlow(getLayoutObjectByElementId("container"))); |
| + auto* space = ConstructConstraintSpace( |
| + kHorizontalTopBottom, TextDirection::kLtr, |
| + NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite), false, |
| + kFragmentainerSpaceAvailable); |
| + |
| + // We should only have one 150x200 fragment with no fragmentation. |
| + RefPtr<const NGPhysicalFragment> fragment = |
| + NGBlockLayoutAlgorithm(node, space).Layout()->PhysicalFragment(); |
| + EXPECT_EQ(LayoutUnit(150), fragment->Width()); |
|
Gleb Lanbin
2017/02/24 21:51:28
.nit
use fragment->Size()
EXPECT_EQ(fragment->Siz
ikilpatrick
2017/02/25 00:57:22
Done.
|
| + EXPECT_EQ(LayoutUnit(200), fragment->Height()); |
| + ASSERT_TRUE(fragment->BreakToken()->IsFinished()); |
| +} |
| + |
| +// Tests that a block child with fragment if it reaches the fragmentation line. |
| +TEST_F(NGBlockLayoutAlgorithmTest, SimpleFragmentation) { |
| + setBodyInnerHTML(R"HTML( |
| + <!DOCTYPE html> |
| + <style> |
| + #container { |
| + width: 150px; |
| + height: 300px; |
| + } |
| + </style> |
| + <div id='container'></div> |
| + )HTML"); |
| + |
| + LayoutUnit kFragmentainerSpaceAvailable(200); |
| + |
| + NGBlockNode* node = new NGBlockNode( |
| + toLayoutBlockFlow(getLayoutObjectByElementId("container"))); |
| + auto* space = ConstructConstraintSpace( |
| + kHorizontalTopBottom, TextDirection::kLtr, |
| + NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite), false, |
| + kFragmentainerSpaceAvailable); |
| + |
| + RefPtr<const NGPhysicalFragment> fragment = |
| + NGBlockLayoutAlgorithm(node, space).Layout()->PhysicalFragment(); |
| + EXPECT_EQ(LayoutUnit(150), fragment->Width()); |
| + EXPECT_EQ(LayoutUnit(200), fragment->Height()); |
| + ASSERT_FALSE(fragment->BreakToken()->IsFinished()); |
| + |
| + fragment = NGBlockLayoutAlgorithm(node, space, |
| + toNGBlockBreakToken(fragment->BreakToken())) |
| + .Layout() |
| + ->PhysicalFragment(); |
| + EXPECT_EQ(LayoutUnit(150), fragment->Width()); |
| + EXPECT_EQ(LayoutUnit(100), fragment->Height()); |
| + ASSERT_TRUE(fragment->BreakToken()->IsFinished()); |
| +} |
| + |
| +// Tests that children inside the same block formatting context fragment when |
| +// reaching a fragmentation line. |
| +TEST_F(NGBlockLayoutAlgorithmTest, InnerChildrenFragmentation) { |
| + setBodyInnerHTML(R"HTML( |
| + <!DOCTYPE html> |
| + <style> |
| + #container { |
| + width: 150px; |
| + padding-top: 20px; |
| + } |
| + #child1 { |
| + height: 200px; |
| + margin-bottom: 20px; |
| + } |
| + #child2 { |
| + height: 100px; |
| + margin-top: 20px; |
| + } |
| + </style> |
| + <div id='container'> |
| + <div id='child1'></div> |
| + <div id='child2'></div> |
| + </div> |
| + )HTML"); |
| + |
| + LayoutUnit kFragmentainerSpaceAvailable(200); |
| + |
| + NGBlockNode* node = new NGBlockNode( |
| + toLayoutBlockFlow(getLayoutObjectByElementId("container"))); |
| + auto* space = ConstructConstraintSpace( |
| + kHorizontalTopBottom, TextDirection::kLtr, |
| + NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite), false, |
| + kFragmentainerSpaceAvailable); |
| + |
| + RefPtr<const NGPhysicalFragment> fragment = |
| + NGBlockLayoutAlgorithm(node, space).Layout()->PhysicalFragment(); |
| + EXPECT_EQ(LayoutUnit(150), fragment->Width()); |
| + EXPECT_EQ(LayoutUnit(200), fragment->Height()); |
| + ASSERT_FALSE(fragment->BreakToken()->IsFinished()); |
| + |
| + FragmentChildIterator iterator(toNGPhysicalBoxFragment(fragment.get())); |
| + const NGPhysicalBoxFragment* child = iterator.NextChild(); |
| + EXPECT_EQ(LayoutUnit(150), child->Width()); |
| + EXPECT_EQ(LayoutUnit(180), child->Height()); |
| + EXPECT_EQ(LayoutUnit(0), child->LeftOffset()); |
| + EXPECT_EQ(LayoutUnit(20), child->TopOffset()); |
| + |
| + EXPECT_FALSE(iterator.NextChild()); |
| + |
| + fragment = NGBlockLayoutAlgorithm(node, space, |
| + toNGBlockBreakToken(fragment->BreakToken())) |
| + .Layout() |
| + ->PhysicalFragment(); |
| + EXPECT_EQ(LayoutUnit(150), fragment->Width()); |
| + EXPECT_EQ(LayoutUnit(140), fragment->Height()); |
| + ASSERT_TRUE(fragment->BreakToken()->IsFinished()); |
| + |
| + iterator.SetParent(toNGPhysicalBoxFragment(fragment.get())); |
| + child = iterator.NextChild(); |
| + EXPECT_EQ(LayoutUnit(150), child->Width()); |
| + EXPECT_EQ(LayoutUnit(20), child->Height()); |
| + EXPECT_EQ(LayoutUnit(0), child->LeftOffset()); |
| + EXPECT_EQ(LayoutUnit(0), child->TopOffset()); |
| + |
| + child = iterator.NextChild(); |
| + EXPECT_EQ(LayoutUnit(150), child->Width()); |
| + EXPECT_EQ(LayoutUnit(100), child->Height()); |
| + EXPECT_EQ(LayoutUnit(0), child->LeftOffset()); |
| + EXPECT_EQ(LayoutUnit(40), child->TopOffset()); |
| + |
| + EXPECT_FALSE(iterator.NextChild()); |
| +} |
| + |
| +// Tests that children inside which establish new formatting contexts fragment |
| +// correctly. |
| +TEST_F(NGBlockLayoutAlgorithmTest, |
| + InnerFormattingContextChildrenFragmentation) { |
| + setBodyInnerHTML(R"HTML( |
| + <!DOCTYPE html> |
| + <style> |
| + #container { |
| + width: 150px; |
| + padding-top: 20px; |
| + } |
| + #child1 { |
| + height: 200px; |
| + margin-bottom: 20px; |
| + contain: paint; |
| + } |
| + #child2 { |
| + height: 100px; |
| + margin-top: 20px; |
| + contain: paint; |
| + } |
| + </style> |
| + <div id='container'> |
| + <div id='child1'></div> |
| + <div id='child2'></div> |
| + </div> |
| + )HTML"); |
| + |
| + LayoutUnit kFragmentainerSpaceAvailable(200); |
| + |
| + NGBlockNode* node = new NGBlockNode( |
| + toLayoutBlockFlow(getLayoutObjectByElementId("container"))); |
| + auto* space = ConstructConstraintSpace( |
| + kHorizontalTopBottom, TextDirection::kLtr, |
| + NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite), false, |
| + kFragmentainerSpaceAvailable); |
| + |
| + RefPtr<const NGPhysicalFragment> fragment = |
| + NGBlockLayoutAlgorithm(node, space).Layout()->PhysicalFragment(); |
| + EXPECT_EQ(LayoutUnit(150), fragment->Width()); |
| + EXPECT_EQ(LayoutUnit(200), fragment->Height()); |
| + ASSERT_FALSE(fragment->BreakToken()->IsFinished()); |
| + |
| + FragmentChildIterator iterator(toNGPhysicalBoxFragment(fragment.get())); |
| + const NGPhysicalBoxFragment* child = iterator.NextChild(); |
| + EXPECT_EQ(LayoutUnit(150), child->Width()); |
| + EXPECT_EQ(LayoutUnit(180), child->Height()); |
| + EXPECT_EQ(LayoutUnit(0), child->LeftOffset()); |
| + EXPECT_EQ(LayoutUnit(20), child->TopOffset()); |
| + |
| + EXPECT_FALSE(iterator.NextChild()); |
| + |
| + fragment = NGBlockLayoutAlgorithm(node, space, |
| + toNGBlockBreakToken(fragment->BreakToken())) |
| + .Layout() |
| + ->PhysicalFragment(); |
| + EXPECT_EQ(LayoutUnit(150), fragment->Width()); |
| + EXPECT_EQ(LayoutUnit(140), fragment->Height()); |
| + ASSERT_TRUE(fragment->BreakToken()->IsFinished()); |
| + |
| + iterator.SetParent(toNGPhysicalBoxFragment(fragment.get())); |
| + child = iterator.NextChild(); |
| + EXPECT_EQ(LayoutUnit(150), child->Width()); |
| + EXPECT_EQ(LayoutUnit(20), child->Height()); |
| + EXPECT_EQ(LayoutUnit(0), child->LeftOffset()); |
| + EXPECT_EQ(LayoutUnit(0), child->TopOffset()); |
| + |
| + child = iterator.NextChild(); |
| + EXPECT_EQ(LayoutUnit(150), child->Width()); |
| + EXPECT_EQ(LayoutUnit(100), child->Height()); |
| + EXPECT_EQ(LayoutUnit(0), child->LeftOffset()); |
| + EXPECT_EQ(LayoutUnit(40), child->TopOffset()); |
| + |
| + EXPECT_FALSE(iterator.NextChild()); |
| +} |
| + |
| +// Tests that children inside which establish new formatting contexts fragment |
| +// correctly. |
| +TEST_F(NGBlockLayoutAlgorithmTest, InnerChildrenFragmentationSmallHeight) { |
| + setBodyInnerHTML(R"HTML( |
| + <!DOCTYPE html> |
| + <style> |
| + #container { |
| + width: 150px; |
| + padding-top: 20px; |
| + height: 50px; |
| + } |
| + #child1 { |
| + height: 200px; |
| + margin-bottom: 20px; |
| + } |
| + #child2 { |
| + height: 100px; |
| + margin-top: 20px; |
| + } |
| + </style> |
| + <div id='container'> |
| + <div id='child1'></div> |
| + <div id='child2'></div> |
| + </div> |
| + )HTML"); |
| + |
| + LayoutUnit kFragmentainerSpaceAvailable(200); |
| + |
| + NGBlockNode* node = new NGBlockNode( |
| + toLayoutBlockFlow(getLayoutObjectByElementId("container"))); |
| + auto* space = ConstructConstraintSpace( |
| + kHorizontalTopBottom, TextDirection::kLtr, |
| + NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite), false, |
| + kFragmentainerSpaceAvailable); |
| + |
| + RefPtr<const NGPhysicalFragment> fragment = |
| + NGBlockLayoutAlgorithm(node, space).Layout()->PhysicalFragment(); |
| + EXPECT_EQ(LayoutUnit(150), fragment->Width()); |
| + EXPECT_EQ(LayoutUnit(70), fragment->Height()); |
| + ASSERT_FALSE(fragment->BreakToken()->IsFinished()); |
| + |
| + FragmentChildIterator iterator(toNGPhysicalBoxFragment(fragment.get())); |
| + const NGPhysicalBoxFragment* child = iterator.NextChild(); |
| + EXPECT_EQ(LayoutUnit(150), child->Width()); |
| + EXPECT_EQ(LayoutUnit(180), child->Height()); |
| + EXPECT_EQ(LayoutUnit(0), child->LeftOffset()); |
| + EXPECT_EQ(LayoutUnit(20), child->TopOffset()); |
| + |
| + EXPECT_FALSE(iterator.NextChild()); |
| + |
| + fragment = NGBlockLayoutAlgorithm(node, space, |
| + toNGBlockBreakToken(fragment->BreakToken())) |
| + .Layout() |
| + ->PhysicalFragment(); |
| + EXPECT_EQ(LayoutUnit(150), fragment->Width()); |
| + EXPECT_EQ(LayoutUnit(0), fragment->Height()); |
| + ASSERT_TRUE(fragment->BreakToken()->IsFinished()); |
| + |
| + iterator.SetParent(toNGPhysicalBoxFragment(fragment.get())); |
| + child = iterator.NextChild(); |
| + EXPECT_EQ(LayoutUnit(150), child->Width()); |
| + EXPECT_EQ(LayoutUnit(20), child->Height()); |
| + EXPECT_EQ(LayoutUnit(0), child->LeftOffset()); |
| + EXPECT_EQ(LayoutUnit(0), child->TopOffset()); |
| + |
| + child = iterator.NextChild(); |
| + EXPECT_EQ(LayoutUnit(150), child->Width()); |
| + EXPECT_EQ(LayoutUnit(100), child->Height()); |
| + EXPECT_EQ(LayoutUnit(0), child->LeftOffset()); |
| + EXPECT_EQ(LayoutUnit(40), child->TopOffset()); |
| + |
| + EXPECT_FALSE(iterator.NextChild()); |
| +} |
| + |
| +/*TEST_F(NGBlockLayoutAlgorithmTest, ParallelFlowFragmentation) { |
|
Gleb Lanbin
2017/02/24 21:51:28
use DISABLED_ prefix and TODO, i.e. DISABLED_Paral
ikilpatrick
2017/02/25 00:57:22
Blah sorry, removed, this was from an older patch,
|
| + setBodyInnerHTML(R"HTML( |
| + <!DOCTYPE html> |
| + <style> |
| + #container { |
| + width: 150px; |
| + } |
| + #float_left { |
| + float: left; |
| + width: 20px; |
| + height: 300px; |
| + } |
| + #float_right { |
| + float: right; |
| + width: 50px; |
| + height: 500px; |
| + } |
| + #in_flow { |
| + height: 550px; |
| + } |
| + </style> |
| + <div id='container'> |
| + <div id='float_left'></div> |
| + <div id='float_right'></div> |
| + <div id='in_flow'></div> |
| + </div> |
| + )HTML"); |
| + |
| + LayoutUnit kFragmentainerSpaceAvailable(200); |
| + |
| + NGBlockNode* node = new NGBlockNode(toLayoutBlockFlow( |
| + document().getElementById("container")->layoutObject())); |
| + auto* space = ConstructConstraintSpace( |
| + kHorizontalTopBottom, TextDirection::kLtr, |
| + NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite), false, |
| + kFragmentainerSpaceAvailable); |
| + |
| + // The first fragment should have ... |
| + RefPtr<const NGPhysicalFragment> fragment = |
| + NGBlockLayoutAlgorithm(node, space).Layout(); |
| + EXPECT_EQ(LayoutUnit(150), fragment->Width()); |
| + EXPECT_EQ(LayoutUnit(200), fragment->Height()); |
| + ASSERT_FALSE(fragment->BreakToken()->IsFinished()); |
| + |
| + FragmentChildIterator iterator(toNGPhysicalBoxFragment(fragment.get())); |
| + |
| + // #float_left child. |
| + const NGPhysicalBoxFragment* child = iterator.NextChild(); |
| + EXPECT_EQ(LayoutUnit(20), child->Width()); |
| + EXPECT_EQ(LayoutUnit(200), child->Height()); |
| + EXPECT_EQ(LayoutUnit(0), child->LeftOffset()); |
| + EXPECT_EQ(LayoutUnit(0), child->TopOffset()); |
| + |
| + // #float_right child. |
| + child = iterator.NextChild(); |
| + EXPECT_EQ(LayoutUnit(50), child->Width()); |
| + EXPECT_EQ(LayoutUnit(200), child->Height()); |
| + EXPECT_EQ(LayoutUnit(100), child->LeftOffset()); |
| + EXPECT_EQ(LayoutUnit(0), child->TopOffset()); |
| + |
| + // #in_flow child. |
| + child = iterator.NextChild(); |
| + EXPECT_EQ(LayoutUnit(150), child->Width()); |
| + EXPECT_EQ(LayoutUnit(200), child->Height()); |
| + EXPECT_EQ(LayoutUnit(0), child->LeftOffset()); |
| + EXPECT_EQ(LayoutUnit(0), child->TopOffset()); |
| + |
| + EXPECT_FALSE(iterator.NextChild()); |
| + |
| + fragment = NGBlockLayoutAlgorithm(node, space, |
| + toNGBlockBreakToken(fragment->BreakToken())) |
| + .Layout(); |
| + EXPECT_EQ(LayoutUnit(150), fragment->Width()); |
| + EXPECT_EQ(LayoutUnit(200), fragment->Height()); |
| + ASSERT_FALSE(fragment->BreakToken()->IsFinished()); |
| + |
| + iterator.SetParent(toNGPhysicalBoxFragment(fragment.get())); |
| + |
| + // #float_left child. |
| + child = iterator.NextChild(); |
| + EXPECT_EQ(LayoutUnit(20), child->Width()); |
| + EXPECT_EQ(LayoutUnit(100), child->Height()); |
| + EXPECT_EQ(LayoutUnit(0), child->LeftOffset()); |
| + EXPECT_EQ(LayoutUnit(0), child->TopOffset()); |
| + EXPECT_TRUE(child->BreakToken()->IsFinished()); |
| + |
| + // #float_right child. |
| + child = iterator.NextChild(); |
| + EXPECT_EQ(LayoutUnit(50), child->Width()); |
| + EXPECT_EQ(LayoutUnit(200), child->Height()); |
| + EXPECT_EQ(LayoutUnit(100), child->LeftOffset()); |
| + EXPECT_EQ(LayoutUnit(0), child->TopOffset()); |
| + |
| + // #in_flow child. |
| + child = iterator.NextChild(); |
| + EXPECT_EQ(LayoutUnit(150), child->Width()); |
| + EXPECT_EQ(LayoutUnit(200), child->Height()); |
| + EXPECT_EQ(LayoutUnit(0), child->LeftOffset()); |
| + EXPECT_EQ(LayoutUnit(0), child->TopOffset()); |
| + |
| + EXPECT_FALSE(iterator.NextChild()); |
| + |
| + fragment = NGBlockLayoutAlgorithm(node, space, |
| + toNGBlockBreakToken(fragment->BreakToken())) |
| + .Layout(); |
| + |
| + EXPECT_EQ(LayoutUnit(150), fragment->Width()); |
| + EXPECT_EQ(LayoutUnit(150), fragment->Height()); |
| + ASSERT_FALSE(fragment->BreakToken()->IsFinished()); |
| + |
| + iterator.SetParent(toNGPhysicalBoxFragment(fragment.get())); |
| + |
| + // #float_right child. |
| + child = iterator.NextChild(); |
| + EXPECT_EQ(LayoutUnit(50), child->Width()); |
| + EXPECT_EQ(LayoutUnit(100), child->Height()); |
| + EXPECT_EQ(LayoutUnit(100), child->LeftOffset()); |
| + EXPECT_EQ(LayoutUnit(0), child->TopOffset()); |
| + |
| + // #in_flow child. |
| + child = iterator.NextChild(); |
| + EXPECT_EQ(LayoutUnit(150), child->Width()); |
| + EXPECT_EQ(LayoutUnit(150), child->Height()); |
| + EXPECT_EQ(LayoutUnit(0), child->LeftOffset()); |
| + EXPECT_EQ(LayoutUnit(0), child->TopOffset()); |
| + |
| + EXPECT_FALSE(iterator.NextChild()); |
| +}*/ |
| + |
| } // namespace |
| } // namespace blink |