Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/layout/ng/ng_block_layout_algorithm.h" | 5 #include "core/layout/ng/ng_block_layout_algorithm.h" |
| 6 | 6 |
| 7 #include "core/layout/ng/ng_box.h" | 7 #include "core/layout/ng/ng_box.h" |
| 8 #include "core/layout/ng/ng_constraint_space.h" | 8 #include "core/layout/ng/ng_constraint_space.h" |
| 9 #include "core/layout/ng/ng_physical_fragment.h" | 9 #include "core/layout/ng/ng_physical_fragment.h" |
| 10 #include "core/layout/ng/ng_length_utils.h" | 10 #include "core/layout/ng/ng_length_utils.h" |
| 11 #include "core/style/ComputedStyle.h" | 11 #include "core/style/ComputedStyle.h" |
| 12 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
| 13 | 13 |
| 14 namespace blink { | 14 namespace blink { |
| 15 namespace { | 15 namespace { |
| 16 | 16 |
| 17 class NGBlockLayoutAlgorithmTest : public ::testing::Test { | 17 class NGBlockLayoutAlgorithmTest : public ::testing::Test { |
| 18 protected: | 18 protected: |
| 19 void SetUp() override { style_ = ComputedStyle::create(); } | 19 void SetUp() override { style_ = ComputedStyle::create(); } |
| 20 | 20 |
| 21 NGPhysicalFragment* RunBlockLayoutAlgorithm(const NGConstraintSpace* space, | |
| 22 NGBox* first_child) { | |
| 23 NGBlockLayoutAlgorithm algorithm(style_, first_child); | |
| 24 NGPhysicalFragment* frag; | |
| 25 while (!algorithm.Layout(space, &frag)) | |
| 26 ; | |
|
cbiesinger
2016/09/13 18:59:48
I recently learned that the style guide actually d
Gleb Lanbin
2016/09/13 19:33:44
Done.
| |
| 27 return frag; | |
| 28 } | |
| 29 | |
| 21 RefPtr<ComputedStyle> style_; | 30 RefPtr<ComputedStyle> style_; |
| 22 }; | 31 }; |
| 23 | 32 |
| 24 TEST_F(NGBlockLayoutAlgorithmTest, FixedSize) { | 33 TEST_F(NGBlockLayoutAlgorithmTest, FixedSize) { |
| 25 style_->setWidth(Length(30, Fixed)); | 34 style_->setWidth(Length(30, Fixed)); |
| 26 style_->setHeight(Length(40, Fixed)); | 35 style_->setHeight(Length(40, Fixed)); |
| 27 | 36 |
| 28 NGConstraintSpace* space = new NGConstraintSpace( | 37 NGConstraintSpace* space = new NGConstraintSpace( |
| 29 HorizontalTopBottom, NGLogicalSize(LayoutUnit(100), NGSizeIndefinite)); | 38 HorizontalTopBottom, NGLogicalSize(LayoutUnit(100), NGSizeIndefinite)); |
| 30 | 39 |
| 31 NGBlockLayoutAlgorithm algorithm(style_, nullptr); | 40 NGBlockLayoutAlgorithm algorithm(style_, nullptr); |
| 32 NGPhysicalFragment* frag; | 41 NGPhysicalFragment* frag; |
| 33 while (!algorithm.Layout(space, &frag)) | 42 while (!algorithm.Layout(space, &frag)) |
| 34 ; | 43 ; |
| 35 EXPECT_EQ(frag->Width(), LayoutUnit(30)); | 44 EXPECT_EQ(frag->Width(), LayoutUnit(30)); |
| 36 EXPECT_EQ(frag->Height(), LayoutUnit(40)); | 45 EXPECT_EQ(frag->Height(), LayoutUnit(40)); |
| 37 } | 46 } |
| 38 | 47 |
| 39 // Verifies that two children are laid out with the correct size and position. | 48 // Verifies that two children are laid out with the correct size and position. |
| 40 TEST_F(NGBlockLayoutAlgorithmTest, LayoutBlockChildren) { | 49 TEST_F(NGBlockLayoutAlgorithmTest, LayoutBlockChildren) { |
| 41 const int kWidth = 30; | 50 const int kWidth = 30; |
| 42 const int kHeight1 = 20; | 51 const int kHeight1 = 20; |
| 43 const int kHeight2 = 30; | 52 const int kHeight2 = 30; |
| 44 const int kMarginTop = 5; | 53 const int kMarginTop = 5; |
| 45 const int kMarginBottom = 20; | 54 const int kMarginBottom = 20; |
| 46 style_->setWidth(Length(kWidth, Fixed)); | 55 style_->setWidth(Length(kWidth, Fixed)); |
| 47 | 56 |
| 48 NGConstraintSpace* space = new NGConstraintSpace( | |
| 49 HorizontalTopBottom, NGLogicalSize(LayoutUnit(100), NGSizeIndefinite)); | |
| 50 | |
| 51 RefPtr<ComputedStyle> first_style = ComputedStyle::create(); | 57 RefPtr<ComputedStyle> first_style = ComputedStyle::create(); |
| 52 first_style->setHeight(Length(kHeight1, Fixed)); | 58 first_style->setHeight(Length(kHeight1, Fixed)); |
| 53 NGBox* first_child = new NGBox(first_style.get()); | 59 NGBox* first_child = new NGBox(first_style.get()); |
| 54 | 60 |
| 55 RefPtr<ComputedStyle> second_style = ComputedStyle::create(); | 61 RefPtr<ComputedStyle> second_style = ComputedStyle::create(); |
| 56 second_style->setHeight(Length(kHeight2, Fixed)); | 62 second_style->setHeight(Length(kHeight2, Fixed)); |
| 57 second_style->setMarginTop(Length(kMarginTop, Fixed)); | 63 second_style->setMarginTop(Length(kMarginTop, Fixed)); |
| 58 second_style->setMarginBottom(Length(kMarginBottom, Fixed)); | 64 second_style->setMarginBottom(Length(kMarginBottom, Fixed)); |
| 59 NGBox* second_child = new NGBox(second_style.get()); | 65 NGBox* second_child = new NGBox(second_style.get()); |
| 60 | 66 |
| 61 first_child->SetNextSibling(second_child); | 67 first_child->SetNextSibling(second_child); |
| 62 | 68 |
| 63 NGBlockLayoutAlgorithm algorithm(style_, first_child); | 69 auto space = new NGConstraintSpace( |
|
cbiesinger
2016/09/13 18:59:49
auto* please, for all of these -- I think that was
ikilpatrick
2016/09/13 19:08:39
auto*
Gleb Lanbin
2016/09/13 19:33:44
Done.
Gleb Lanbin
2016/09/13 19:33:44
Done.
| |
| 64 NGPhysicalFragment* frag; | 70 HorizontalTopBottom, NGLogicalSize(LayoutUnit(100), NGSizeIndefinite)); |
| 65 while (!algorithm.Layout(space, &frag)) | 71 NGPhysicalFragment* frag = RunBlockLayoutAlgorithm(space, first_child); |
| 66 ; | 72 |
| 67 EXPECT_EQ(frag->Width(), LayoutUnit(kWidth)); | 73 EXPECT_EQ(frag->Width(), LayoutUnit(kWidth)); |
| 68 EXPECT_EQ(frag->Height(), LayoutUnit(kHeight1 + kHeight2 + kMarginTop)); | 74 EXPECT_EQ(frag->Height(), LayoutUnit(kHeight1 + kHeight2 + kMarginTop)); |
| 69 EXPECT_EQ(frag->Type(), NGPhysicalFragmentBase::FragmentBox); | 75 EXPECT_EQ(frag->Type(), NGPhysicalFragmentBase::FragmentBox); |
| 70 ASSERT_EQ(frag->Children().size(), 2UL); | 76 ASSERT_EQ(frag->Children().size(), 2UL); |
| 71 | 77 |
| 72 const NGPhysicalFragmentBase* child = frag->Children()[0]; | 78 const NGPhysicalFragmentBase* child = frag->Children()[0]; |
| 73 EXPECT_EQ(child->Height(), kHeight1); | 79 EXPECT_EQ(child->Height(), kHeight1); |
| 74 EXPECT_EQ(child->TopOffset(), 0); | 80 EXPECT_EQ(child->TopOffset(), 0); |
| 75 | 81 |
| 76 child = frag->Children()[1]; | 82 child = frag->Children()[1]; |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 99 div1_style->setMarginTop(Length(kDiv1MarginTop, Fixed)); | 105 div1_style->setMarginTop(Length(kDiv1MarginTop, Fixed)); |
| 100 NGBox* div1 = new NGBox(div1_style.get()); | 106 NGBox* div1 = new NGBox(div1_style.get()); |
| 101 | 107 |
| 102 // DIV2 | 108 // DIV2 |
| 103 RefPtr<ComputedStyle> div2_style = ComputedStyle::create(); | 109 RefPtr<ComputedStyle> div2_style = ComputedStyle::create(); |
| 104 div2_style->setMarginTop(Length(kDiv2MarginTop, Fixed)); | 110 div2_style->setMarginTop(Length(kDiv2MarginTop, Fixed)); |
| 105 NGBox* div2 = new NGBox(div2_style.get()); | 111 NGBox* div2 = new NGBox(div2_style.get()); |
| 106 | 112 |
| 107 div1->SetFirstChild(div2); | 113 div1->SetFirstChild(div2); |
| 108 | 114 |
| 109 NGConstraintSpace* space = new NGConstraintSpace( | 115 auto* space = new NGConstraintSpace( |
| 110 HorizontalTopBottom, NGLogicalSize(LayoutUnit(100), NGSizeIndefinite)); | 116 HorizontalTopBottom, NGLogicalSize(LayoutUnit(100), NGSizeIndefinite)); |
| 111 NGBlockLayoutAlgorithm algorithm(style_, div1); | 117 NGPhysicalFragment* frag = RunBlockLayoutAlgorithm(space, div1); |
| 112 NGPhysicalFragment* frag; | |
| 113 while (!algorithm.Layout(space, &frag)) | |
| 114 ; | |
| 115 | 118 |
| 116 EXPECT_EQ(frag->MarginStrut().margin_block_start, kDiv1MarginTop); | 119 EXPECT_EQ(frag->MarginStrut(), NGMarginStrut({LayoutUnit(kDiv1MarginTop)})); |
| 117 ASSERT_EQ(frag->Children().size(), 1UL); | 120 ASSERT_EQ(frag->Children().size(), 1UL); |
| 118 const NGPhysicalFragmentBase* div2_fragment = frag->Children()[0]; | 121 const NGPhysicalFragmentBase* div2_fragment = frag->Children()[0]; |
| 119 EXPECT_EQ(div2_fragment->MarginStrut().margin_block_start, kDiv2MarginTop); | 122 EXPECT_EQ(div2_fragment->MarginStrut(), |
| 123 NGMarginStrut({LayoutUnit(kDiv2MarginTop)})); | |
| 120 } | 124 } |
| 121 | 125 |
| 122 // Verifies the collapsing margins case for the next pair: | 126 // Verifies the collapsing margins case for the next pair: |
| 123 // - bottom margin of box and top margin of its next in-flow following sibling. | 127 // - bottom margin of box and top margin of its next in-flow following sibling. |
| 124 // | 128 // |
| 125 // Test case's HTML representation: | 129 // Test case's HTML representation: |
| 126 // <div style="margin-bottom: 20px; height: 50px;"> <!-- DIV1 --> | 130 // <div style="margin-bottom: 20px; height: 50px;"> <!-- DIV1 --> |
| 127 // <div style="margin-bottom: -15px"></div> <!-- DIV2 --> | 131 // <div style="margin-bottom: -15px"></div> <!-- DIV2 --> |
| 128 // </div> | 132 // </div> |
| 129 // <div style="margin-top: 10px; height: 50px;"> <!-- DIV3 --> | 133 // <div style="margin-top: 10px; height: 50px;"> <!-- DIV3 --> |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 161 | 165 |
| 162 // DIV4 | 166 // DIV4 |
| 163 RefPtr<ComputedStyle> div4_style = ComputedStyle::create(); | 167 RefPtr<ComputedStyle> div4_style = ComputedStyle::create(); |
| 164 div4_style->setMarginTop(Length(kDiv4MarginTop, Fixed)); | 168 div4_style->setMarginTop(Length(kDiv4MarginTop, Fixed)); |
| 165 NGBox* div4 = new NGBox(div4_style.get()); | 169 NGBox* div4 = new NGBox(div4_style.get()); |
| 166 | 170 |
| 167 div1->SetFirstChild(div2); | 171 div1->SetFirstChild(div2); |
| 168 div3->SetFirstChild(div4); | 172 div3->SetFirstChild(div4); |
| 169 div1->SetNextSibling(div3); | 173 div1->SetNextSibling(div3); |
| 170 | 174 |
| 171 NGConstraintSpace* space = new NGConstraintSpace( | 175 auto space = new NGConstraintSpace( |
|
ikilpatrick
2016/09/13 19:08:39
auto*
Gleb Lanbin
2016/09/13 19:33:44
Done.
| |
| 172 HorizontalTopBottom, NGLogicalSize(LayoutUnit(100), NGSizeIndefinite)); | 176 HorizontalTopBottom, NGLogicalSize(LayoutUnit(100), NGSizeIndefinite)); |
| 173 NGBlockLayoutAlgorithm algorithm(style_, div1); | 177 NGPhysicalFragment* frag = RunBlockLayoutAlgorithm(space, div1); |
| 174 NGPhysicalFragment* frag; | |
| 175 while (!algorithm.Layout(space, &frag)) | |
| 176 ; | |
| 177 | 178 |
| 178 ASSERT_EQ(frag->Children().size(), 2UL); | 179 ASSERT_EQ(frag->Children().size(), 2UL); |
| 179 | 180 |
| 180 const NGPhysicalFragmentBase* child = frag->Children()[0]; | 181 const NGPhysicalFragmentBase* child = frag->Children()[0]; |
| 181 EXPECT_EQ(child->Height(), kHeight); | 182 EXPECT_EQ(child->Height(), kHeight); |
| 182 EXPECT_EQ(child->TopOffset(), 0); | 183 EXPECT_EQ(child->TopOffset(), 0); |
| 183 | 184 |
| 184 child = frag->Children()[1]; | 185 child = frag->Children()[1]; |
| 185 EXPECT_EQ(child->Height(), kHeight); | 186 EXPECT_EQ(child->Height(), kHeight); |
| 186 EXPECT_EQ(child->TopOffset(), kHeight + kExpectedCollapsedMargin); | 187 EXPECT_EQ(child->TopOffset(), kHeight + kExpectedCollapsedMargin); |
| 187 } | 188 } |
| 188 | 189 |
| 190 // Verifies the collapsing margins case for the next pair: | |
| 191 // - bottom margin of a last in-flow child and bottom margin of its parent if | |
| 192 // the parent has 'auto' computed height | |
| 193 // | |
| 194 // Test case's HTML representation: | |
| 195 // <div style="margin-bottom: 20px; height: 50px;"> <!-- DIV1 --> | |
| 196 // <div style="margin-bottom: 200px; height: 50px;"/> <!-- DIV2 --> | |
| 197 // </div> | |
| 198 // | |
| 199 // Expected: | |
| 200 // 1) Margins are collapsed with the result = std::max(20, 200) | |
| 201 // if DIV1.height == auto | |
| 202 // 2) Margins are NOT collapsed if DIV1.height != auto | |
| 203 TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsCase3) { | |
| 204 const int kHeight = 50; | |
| 205 const int kDiv1MarginBottom = 20; | |
| 206 const int kDiv2MarginBottom = 200; | |
| 207 | |
| 208 // DIV1 | |
| 209 RefPtr<ComputedStyle> div1_style = ComputedStyle::create(); | |
| 210 div1_style->setMarginBottom(Length(kDiv1MarginBottom, Fixed)); | |
| 211 NGBox* div1 = new NGBox(div1_style.get()); | |
| 212 | |
| 213 // DIV2 | |
| 214 RefPtr<ComputedStyle> div2_style = ComputedStyle::create(); | |
| 215 div2_style->setHeight(Length(kHeight, Fixed)); | |
| 216 div2_style->setMarginBottom(Length(kDiv2MarginBottom, Fixed)); | |
| 217 NGBox* div2 = new NGBox(div2_style.get()); | |
| 218 | |
| 219 div1->SetFirstChild(div2); | |
| 220 | |
| 221 auto space = new NGConstraintSpace( | |
| 222 HorizontalTopBottom, NGLogicalSize(LayoutUnit(100), NGSizeIndefinite)); | |
| 223 NGPhysicalFragment* frag = RunBlockLayoutAlgorithm(space, div1); | |
| 224 | |
| 225 // Verify that margins are collapsed. | |
| 226 EXPECT_EQ(frag->MarginStrut(), | |
| 227 NGMarginStrut({LayoutUnit(0), LayoutUnit(kDiv2MarginBottom)})); | |
| 228 | |
| 229 // Verify that margins are NOT collapsed. | |
| 230 div1_style->setHeight(Length(kHeight, Fixed)); | |
| 231 frag = RunBlockLayoutAlgorithm(space, div1); | |
| 232 EXPECT_EQ(frag->MarginStrut(), | |
| 233 NGMarginStrut({LayoutUnit(0), LayoutUnit(kDiv1MarginBottom)})); | |
| 234 } | |
| 235 | |
| 189 // Verifies that a box's size includes its borders and padding, and that | 236 // Verifies that a box's size includes its borders and padding, and that |
| 190 // children are positioned inside the content box. | 237 // children are positioned inside the content box. |
| 191 // | 238 // |
| 192 // Test case's HTML representation: | 239 // Test case's HTML representation: |
| 193 // <style> | 240 // <style> |
| 194 // #div1 { width:100px; height:100px; } | 241 // #div1 { width:100px; height:100px; } |
| 195 // #div1 { border-style:solid; border-width:1px 2px 3px 4px; } | 242 // #div1 { border-style:solid; border-width:1px 2px 3px 4px; } |
| 196 // #div1 { padding:5px 6px 7px 8px; } | 243 // #div1 { padding:5px 6px 7px 8px; } |
| 197 // </style> | 244 // </style> |
| 198 // <div id="div1"> | 245 // <div id="div1"> |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 227 div1_style->setPaddingRight(Length(kPaddingRight, Fixed)); | 274 div1_style->setPaddingRight(Length(kPaddingRight, Fixed)); |
| 228 div1_style->setPaddingBottom(Length(kPaddingBottom, Fixed)); | 275 div1_style->setPaddingBottom(Length(kPaddingBottom, Fixed)); |
| 229 div1_style->setPaddingLeft(Length(kPaddingLeft, Fixed)); | 276 div1_style->setPaddingLeft(Length(kPaddingLeft, Fixed)); |
| 230 NGBox* div1 = new NGBox(div1_style.get()); | 277 NGBox* div1 = new NGBox(div1_style.get()); |
| 231 | 278 |
| 232 RefPtr<ComputedStyle> div2_style = ComputedStyle::create(); | 279 RefPtr<ComputedStyle> div2_style = ComputedStyle::create(); |
| 233 NGBox* div2 = new NGBox(div2_style.get()); | 280 NGBox* div2 = new NGBox(div2_style.get()); |
| 234 | 281 |
| 235 div1->SetFirstChild(div2); | 282 div1->SetFirstChild(div2); |
| 236 | 283 |
| 237 NGConstraintSpace* space = new NGConstraintSpace( | 284 auto space = new NGConstraintSpace( |
| 238 HorizontalTopBottom, NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite)); | 285 HorizontalTopBottom, NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite)); |
| 239 NGBlockLayoutAlgorithm algorithm(style_, div1); | 286 NGPhysicalFragment* frag = RunBlockLayoutAlgorithm(space, div1); |
| 240 NGPhysicalFragment* frag; | |
| 241 while (!algorithm.Layout(space, &frag)) | |
| 242 ; | |
| 243 | 287 |
| 244 ASSERT_EQ(frag->Children().size(), 1UL); | 288 ASSERT_EQ(frag->Children().size(), 1UL); |
| 245 | 289 |
| 246 // div1 | 290 // div1 |
| 247 const NGPhysicalFragmentBase* child = frag->Children()[0]; | 291 const NGPhysicalFragmentBase* child = frag->Children()[0]; |
| 248 EXPECT_EQ(kBorderLeft + kPaddingLeft + kWidth + kPaddingRight + kBorderRight, | 292 EXPECT_EQ(kBorderLeft + kPaddingLeft + kWidth + kPaddingRight + kBorderRight, |
| 249 child->Width()); | 293 child->Width()); |
| 250 EXPECT_EQ(kBorderTop + kPaddingTop + kHeight + kPaddingBottom + kBorderBottom, | 294 EXPECT_EQ(kBorderTop + kPaddingTop + kHeight + kPaddingBottom + kBorderBottom, |
| 251 child->Height()); | 295 child->Height()); |
| 252 | 296 |
| 253 ASSERT_TRUE(child->Type() == NGPhysicalFragmentBase::FragmentBox); | 297 ASSERT_TRUE(child->Type() == NGPhysicalFragmentBase::FragmentBox); |
| 254 ASSERT_EQ(static_cast<const NGPhysicalFragment*>(child)->Children().size(), | 298 ASSERT_EQ(static_cast<const NGPhysicalFragment*>(child)->Children().size(), |
| 255 1UL); | 299 1UL); |
| 256 | 300 |
| 257 // div2 | 301 // div2 |
| 258 child = static_cast<const NGPhysicalFragment*>(child)->Children()[0]; | 302 child = static_cast<const NGPhysicalFragment*>(child)->Children()[0]; |
| 259 EXPECT_EQ(kBorderTop + kPaddingTop, child->TopOffset()); | 303 EXPECT_EQ(kBorderTop + kPaddingTop, child->TopOffset()); |
| 260 EXPECT_EQ(kBorderLeft + kPaddingLeft, child->LeftOffset()); | 304 EXPECT_EQ(kBorderLeft + kPaddingLeft, child->LeftOffset()); |
| 261 } | 305 } |
| 262 } // namespace | 306 } // namespace |
| 263 } // namespace blink | 307 } // namespace blink |
| OLD | NEW |