Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Side by Side Diff: third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc

Issue 2641253002: Rewrite LayoutNG margin collapsing/floats unit tests (Closed)
Patch Set: fix comments Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | third_party/WebKit/Source/core/layout/ng/ng_units.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/dom/NodeComputedStyle.h"
8 #include "core/dom/TagCollection.h"
9 #include "core/layout/ng/layout_ng_block_flow.h"
7 #include "core/layout/ng/ng_block_node.h" 10 #include "core/layout/ng/ng_block_node.h"
8 #include "core/layout/ng/ng_constraint_space.h" 11 #include "core/layout/ng/ng_constraint_space.h"
9 #include "core/layout/ng/ng_constraint_space_builder.h" 12 #include "core/layout/ng/ng_constraint_space_builder.h"
13 #include "core/layout/ng/ng_floating_object.h"
10 #include "core/layout/ng/ng_length_utils.h" 14 #include "core/layout/ng/ng_length_utils.h"
15 #include "core/layout/LayoutTestHelper.h"
11 #include "core/layout/ng/ng_physical_box_fragment.h" 16 #include "core/layout/ng/ng_physical_box_fragment.h"
12 #include "core/layout/ng/ng_physical_fragment.h" 17 #include "core/layout/ng/ng_physical_fragment.h"
13 #include "core/layout/ng/ng_units.h" 18 #include "core/layout/ng/ng_units.h"
14 #include "core/layout/LayoutTestHelper.h" 19 #include "testing/gmock/include/gmock/gmock.h"
15 #include "core/style/ComputedStyle.h" 20 #include "core/style/ComputedStyle.h"
16 #include "testing/gtest/include/gtest/gtest.h" 21 #include "testing/gtest/include/gtest/gtest.h"
17 22
18 namespace blink { 23 namespace blink {
19 namespace { 24 namespace {
20 25
26 using testing::ElementsAre;
27 using testing::Pointee;
28
21 NGConstraintSpace* ConstructConstraintSpace(NGWritingMode writing_mode, 29 NGConstraintSpace* ConstructConstraintSpace(NGWritingMode writing_mode,
22 TextDirection direction, 30 TextDirection direction,
23 NGLogicalSize size, 31 NGLogicalSize size,
24 bool shrink_to_fit = false) { 32 bool shrink_to_fit = false) {
25 return NGConstraintSpaceBuilder(writing_mode) 33 return NGConstraintSpaceBuilder(writing_mode)
26 .SetAvailableSize(size) 34 .SetAvailableSize(size)
27 .SetPercentageResolutionSize(size) 35 .SetPercentageResolutionSize(size)
28 .SetTextDirection(direction) 36 .SetTextDirection(direction)
29 .SetWritingMode(writing_mode) 37 .SetWritingMode(writing_mode)
30 .SetIsShrinkToFit(shrink_to_fit) 38 .SetIsShrinkToFit(shrink_to_fit)
(...skipping 18 matching lines...) Expand all
49 NGBlockNode* first_child) { 57 NGBlockNode* first_child) {
50 NGBlockNode parent(style_.get()); 58 NGBlockNode parent(style_.get());
51 parent.SetFirstChild(first_child); 59 parent.SetFirstChild(first_child);
52 60
53 NGBlockLayoutAlgorithm algorithm(style_.get(), first_child, space); 61 NGBlockLayoutAlgorithm algorithm(style_.get(), first_child, space);
54 62
55 NGPhysicalFragment* fragment = algorithm.Layout(); 63 NGPhysicalFragment* fragment = algorithm.Layout();
56 return toNGPhysicalBoxFragment(fragment); 64 return toNGPhysicalBoxFragment(fragment);
57 } 65 }
58 66
67 std::pair<NGPhysicalBoxFragment*, NGConstraintSpace*>
68 RunBlockLayoutAlgorithmForElement(Element* element) {
69 LayoutNGBlockFlow* block_flow =
70 toLayoutNGBlockFlow(element->layoutObject());
71 NGConstraintSpace* space =
72 NGConstraintSpace::CreateFromLayoutObject(*block_flow);
73 NGPhysicalBoxFragment* fragment = RunBlockLayoutAlgorithm(
74 space, new NGBlockNode(element->layoutObject()->slowFirstChild()));
75 return std::make_pair(fragment, space);
76 }
77
59 MinAndMaxContentSizes RunComputeMinAndMax(NGBlockNode* first_child) { 78 MinAndMaxContentSizes RunComputeMinAndMax(NGBlockNode* first_child) {
60 // The constraint space is not used for min/max computation, but we need 79 // The constraint space is not used for min/max computation, but we need
61 // it to create the algorithm. 80 // it to create the algorithm.
62 NGConstraintSpace* space = 81 NGConstraintSpace* space =
63 ConstructConstraintSpace(kHorizontalTopBottom, TextDirection::kLtr, 82 ConstructConstraintSpace(kHorizontalTopBottom, TextDirection::kLtr,
64 NGLogicalSize(LayoutUnit(), LayoutUnit())); 83 NGLogicalSize(LayoutUnit(), LayoutUnit()));
65 NGBlockLayoutAlgorithm algorithm(style_.get(), first_child, space); 84 NGBlockLayoutAlgorithm algorithm(style_.get(), first_child, space);
66 MinAndMaxContentSizes sizes; 85 MinAndMaxContentSizes sizes;
67 EXPECT_TRUE(algorithm.ComputeMinAndMaxContentSizes(&sizes)); 86 EXPECT_TRUE(algorithm.ComputeMinAndMaxContentSizes(&sizes));
68 return sizes; 87 return sizes;
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 // DIV2 179 // DIV2
161 child = static_cast<const NGPhysicalBoxFragment*>(child)->Children()[0]; 180 child = static_cast<const NGPhysicalBoxFragment*>(child)->Children()[0];
162 181
163 EXPECT_EQ(kHeight, child->Height()); 182 EXPECT_EQ(kHeight, child->Height());
164 EXPECT_EQ(0, child->TopOffset()); 183 EXPECT_EQ(0, child->TopOffset());
165 EXPECT_EQ(kMarginLeft, child->LeftOffset()); 184 EXPECT_EQ(kMarginLeft, child->LeftOffset());
166 } 185 }
167 186
168 // Verifies the collapsing margins case for the next pair: 187 // Verifies the collapsing margins case for the next pair:
169 // - top margin of a box and top margin of its first in-flow child. 188 // - top margin of a box and top margin of its first in-flow child.
170 // 189 // Verifies that floats are positioned at the top of the first child that can
171 // Test case's HTML representation: 190 // determine its position after margins collapsed.
172 // <div style="margin-top: 20px; height: 50px;"> <!-- DIV1 --> 191 // TODO(glebl): Enable with new the float/margins collapsing algorithm.
173 // <div style="margin-top: 10px"></div> <!-- DIV2 --> 192 TEST_F(NGBlockLayoutAlgorithmTest, DISABLED_CollapsingMarginsCase1WithFloats) {
174 // </div> 193 setBodyInnerHTML(
175 // 194 "<style>"
176 // Expected: 195 " #container {"
177 // - Empty margin strut of the fragment that establishes new formatting context 196 " height: 200px;"
178 // - Margins are collapsed resulting a single margin 20px = max(20px, 10px) 197 " width: 200px;"
179 // - The top offset of DIV2 == 20px 198 " margin-top: 10px;"
180 TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsCase1) { 199 " padding: 0 7px;"
181 const int kHeight = 50; 200 " background-color: red;"
182 const int kDiv1MarginTop = 20; 201 " }"
183 const int kDiv2MarginTop = 10; 202 " #first-child {"
184 203 " margin-top: 20px;"
185 // DIV1 204 " height: 10px;"
186 RefPtr<ComputedStyle> div1_style = ComputedStyle::create(); 205 " background-color: blue;"
187 div1_style->setHeight(Length(kHeight, Fixed)); 206 " }"
188 div1_style->setMarginTop(Length(kDiv1MarginTop, Fixed)); 207 " #float-child-left {"
189 NGBlockNode* div1 = new NGBlockNode(div1_style.get()); 208 " float: left;"
190 209 " height: 10px;"
191 // DIV2 210 " width: 10px;"
192 RefPtr<ComputedStyle> div2_style = ComputedStyle::create(); 211 " padding: 10px;"
193 div2_style->setMarginTop(Length(kDiv2MarginTop, Fixed)); 212 " margin: 10px;"
194 NGBlockNode* div2 = new NGBlockNode(div2_style.get()); 213 " background-color: green;"
195 214 " }"
196 div1->SetFirstChild(div2); 215 " #float-child-right {"
197 216 " float: right;"
198 auto* space = 217 " height: 30px;"
199 NGConstraintSpaceBuilder(kHorizontalTopBottom) 218 " width: 30px;"
200 .SetAvailableSize(NGLogicalSize(LayoutUnit(100), NGSizeIndefinite)) 219 " background-color: pink;"
201 .SetPercentageResolutionSize( 220 " }"
202 NGLogicalSize(LayoutUnit(100), NGSizeIndefinite)) 221 "</style>"
203 .SetTextDirection(TextDirection::kLtr) 222 "<div id='container'>"
204 .SetIsNewFormattingContext(true) 223 " <div id='float-child-left'></div>"
205 .ToConstraintSpace(); 224 " <div id='float-child-right'></div>"
206 NGPhysicalBoxFragment* frag = RunBlockLayoutAlgorithm(space, div1); 225 " <div id='first-child'></div>"
207 226 "</div>");
208 EXPECT_TRUE(frag->MarginStrut().IsEmpty()); 227
209 ASSERT_EQ(frag->Children().size(), 1UL); 228 // ** Run LayoutNG algorithm **
210 const NGPhysicalBoxFragment* div2_fragment = 229 NGConstraintSpace* space;
211 static_cast<const NGPhysicalBoxFragment*>(frag->Children()[0].get()); 230 NGPhysicalBoxFragment* fragment;
212 EXPECT_EQ(NGDeprecatedMarginStrut({LayoutUnit(kDiv2MarginTop)}), 231 std::tie(fragment, space) = RunBlockLayoutAlgorithmForElement(
213 div2_fragment->MarginStrut()); 232 document().getElementsByTagName("html")->item(0));
214 EXPECT_EQ(kDiv1MarginTop, div2_fragment->TopOffset()); 233 ASSERT_EQ(fragment->Children().size(), 1UL);
234 auto* body_fragment = toNGPhysicalBoxFragment(fragment->Children()[0]);
235 // 20 = max(first child's margin top, containers's margin top)
236 int body_top_offset = 20;
237 EXPECT_THAT(LayoutUnit(body_top_offset), body_fragment->TopOffset());
238 // 8 = body's margin
239 int body_left_offset = 8;
240 EXPECT_THAT(LayoutUnit(body_left_offset), body_fragment->LeftOffset());
241 ASSERT_EQ(1UL, body_fragment->Children().size());
242 auto* container_fragment =
243 toNGPhysicalBoxFragment(body_fragment->Children()[0]);
244 // 0 = collapsed with body's margin
245 EXPECT_THAT(LayoutUnit(0), container_fragment->TopOffset());
246 ASSERT_EQ(1UL, container_fragment->Children().size());
247 auto* first_child_fragment =
248 toNGPhysicalBoxFragment(container_fragment->Children()[0]);
249 // 0 = collapsed with container's margin
250 EXPECT_THAT(LayoutUnit(0), first_child_fragment->TopOffset());
251
252 // ** Verify layout tree **
253 Element* first_child = document().getElementById("first-child");
254 int first_child_block_offset = body_top_offset;
255 EXPECT_EQ(first_child_block_offset, first_child->offsetTop());
256
257 // float-child-left is positioned at the top edge of the container padding box
258 Element* float_child_left = document().getElementById("float-child-left");
259 // 30 = std::max(first-child's margin 20, container's margin 10,
260 // body's margin 8) + float-child-left's margin 10
261 int float_child_left_block_offset = 30;
262 EXPECT_EQ(float_child_left_block_offset, float_child_left->offsetTop());
263
264 // float-child-right is positioned at the top edge of container padding box
265 Element* float_child_right = document().getElementById("float-child-right");
266 // Should be equal to first_child_block_offset
267 // 20 = std::max(first-child's margin 20, container's margin 10,
268 // body's margin 8)
269 int float_child_right_block_offset = 20;
270 EXPECT_EQ(float_child_right_block_offset, float_child_right->offsetTop());
271
272 // ** Verify exclusions **
273 // float-child-left's height(10) + padding(2x10) + margin(2x10) = 50px
274 NGLogicalSize exclusion1_size = {LayoutUnit(50), LayoutUnit(50)};
275 // float-child-left's inline offset
276 // 15 = body's margin(8) + container's inline padding(7)
277 NGLogicalOffset exclusion1_offset = {LayoutUnit(15),
278 LayoutUnit(first_child_block_offset)};
279 NGLogicalRect exclusion1_rect = {exclusion1_offset, exclusion1_size};
280 NGExclusion expected_exclusion1 = {exclusion1_rect, NGExclusion::kFloatLeft};
281
282 NGLogicalSize exclusion2_size = {LayoutUnit(30), LayoutUnit(30)};
283 // float-child-right's inline offset
284 // right_float_offset = 200 container's width - right float width 30 = 170
285 // 185 = body's margin(8) + right_float_offset(170) + container's padding(7)
286 NGLogicalOffset exclusion2_offset = {LayoutUnit(185),
287 LayoutUnit(first_child_block_offset)};
288 NGLogicalRect exclusion2_rect = {exclusion2_offset, exclusion2_size};
289 NGExclusion expected_exclusion2 = {exclusion2_rect, NGExclusion::kFloatRight};
290
291 EXPECT_THAT(space->Exclusions()->storage,
292 (ElementsAre(Pointee(expected_exclusion1),
293 Pointee(expected_exclusion2))));
215 } 294 }
216 295
217 // Verifies the collapsing margins case for the next pair: 296 // Verifies the collapsing margins case for the next pair:
218 // - bottom margin of box and top margin of its next in-flow following sibling. 297 // - bottom margin of box and top margin of its next in-flow following sibling.
219 // 298 // - top and bottom margins of a box that does not establish a new block
220 // Test case's HTML representation: 299 // formatting context and that has zero computed 'min-height', zero or 'auto'
221 // <div style="margin-bottom: 20px; height: 50px;"> <!-- DIV1 --> 300 // computed 'height', and no in-flow children
222 // <div style="margin-bottom: -15px"></div> <!-- DIV2 --> 301 // TODO(glebl): Enable with new the float/margins collapsing algorithm.
223 // <div></div> <!-- DIV3 --> 302 TEST_F(NGBlockLayoutAlgorithmTest, DISABLED_CollapsingMarginsCase2WithFloats) {
224 // </div> 303 setBodyInnerHTML(
225 // <div></div> <!-- DIV4 --> 304 "<style>"
226 // <div style="margin-top: 10px; height: 50px;"> <!-- DIV5 --> 305 "#first-child {"
227 // <div></div> <!-- DIV6 --> 306 " background-color: red;"
228 // <div style="margin-top: -30px"></div> <!-- DIV7 --> 307 " height: 50px;"
229 // </div> 308 " margin-bottom: 20px;"
230 // 309 "}"
231 // Expected: 310 "#float-between-empties {"
232 // Margins are collapsed resulting an overlap 311 " background-color: green;"
233 // -10px = max(20px, 10px) - max(abs(-15px), abs(-30px)) 312 " float: left;"
234 // between DIV2 and DIV3. Zero-height blocks are ignored. 313 " height: 30px;"
235 TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsCase2) { 314 " width: 30px;"
236 const int kHeight = 50; 315 "}"
237 const int kDiv1MarginBottom = 20; 316 "#float-between-nonempties {"
238 const int kDiv2MarginBottom = -15; 317 " background-color: lightgreen;"
239 const int kDiv5MarginTop = 10; 318 " float: left;"
240 const int kDiv7MarginTop = -30; 319 " height: 40px;"
241 const int kExpectedCollapsedMargin = -10; 320 " width: 40px;"
242 321 "}"
243 // DIV1 322 "#float-top-align {"
244 RefPtr<ComputedStyle> div1_style = ComputedStyle::create(); 323 " background-color: seagreen;"
245 div1_style->setHeight(Length(kHeight, Fixed)); 324 " float: left;"
246 div1_style->setMarginBottom(Length(kDiv1MarginBottom, Fixed)); 325 " height: 50px;"
247 NGBlockNode* div1 = new NGBlockNode(div1_style.get()); 326 " width: 50px;"
248 327 "}"
249 // DIV2 328 "#second-child {"
250 RefPtr<ComputedStyle> div2_style = ComputedStyle::create(); 329 " background-color: blue;"
251 div2_style->setMarginBottom(Length(kDiv2MarginBottom, Fixed)); 330 " height: 50px;"
252 NGBlockNode* div2 = new NGBlockNode(div2_style.get()); 331 " margin-top: 10px;"
253 332 "}"
254 // Empty DIVs: DIV3, DIV4, DIV6 333 "</style>"
255 NGBlockNode* div3 = new NGBlockNode(ComputedStyle::create().get()); 334 "<div id='first-child'>"
256 NGBlockNode* div4 = new NGBlockNode(ComputedStyle::create().get()); 335 " <div id='empty1' style='margin-bottom: -15px'></div>"
257 NGBlockNode* div6 = new NGBlockNode(ComputedStyle::create().get()); 336 " <div id='float-between-empties'></div>"
258 337 " <div id='empty2'></div>"
259 // DIV5 338 "</div>"
260 RefPtr<ComputedStyle> div5_style = ComputedStyle::create(); 339 "<div id='float-between-nonempties'></div>"
261 div5_style->setHeight(Length(kHeight, Fixed)); 340 "<div id='second-child'>"
262 div5_style->setMarginTop(Length(kDiv5MarginTop, Fixed)); 341 " <div id='float-top-align'></div>"
263 NGBlockNode* div5 = new NGBlockNode(div5_style.get()); 342 " <div id='empty3'></div>"
264 343 " <div id='empty4' style='margin-top: -30px'></div>"
265 // DIV7 344 "</div>"
266 RefPtr<ComputedStyle> div7_style = ComputedStyle::create(); 345 "<div id='empty5'></div>");
267 div7_style->setMarginTop(Length(kDiv7MarginTop, Fixed)); 346
268 NGBlockNode* div7 = new NGBlockNode(div7_style.get()); 347 // ** Run LayoutNG algorithm **
269 348 NGConstraintSpace* space;
270 div1->SetFirstChild(div2); 349 NGPhysicalBoxFragment* fragment;
271 div2->SetNextSibling(div3); 350 std::tie(fragment, space) = RunBlockLayoutAlgorithmForElement(
272 div1->SetNextSibling(div4); 351 document().getElementsByTagName("html")->item(0));
273 div4->SetNextSibling(div5); 352
274 div5->SetFirstChild(div6); 353 auto* body_fragment = toNGPhysicalBoxFragment(fragment->Children()[0]);
275 div6->SetNextSibling(div7); 354 // -7 = empty1's margin(-15) + body's margin(8)
276 355 int body_top_offset = -7;
277 auto* space = ConstructConstraintSpace( 356 EXPECT_THAT(LayoutUnit(body_top_offset), body_fragment->TopOffset());
278 kHorizontalTopBottom, TextDirection::kLtr, 357 int body_left_offset = 8;
279 NGLogicalSize(LayoutUnit(100), NGSizeIndefinite)); 358 EXPECT_THAT(LayoutUnit(body_top_offset), body_fragment->TopOffset());
280 NGPhysicalBoxFragment* frag = RunBlockLayoutAlgorithm(space, div1); 359 ASSERT_EQ(3UL, body_fragment->Children().size());
281 360
282 ASSERT_EQ(frag->Children().size(), 3UL); 361 auto* first_child_fragment =
283 362 toNGPhysicalBoxFragment(body_fragment->Children()[0]);
284 // DIV1 363 EXPECT_THAT(LayoutUnit(), first_child_fragment->TopOffset());
285 const NGPhysicalFragment* child = frag->Children()[0]; 364
286 EXPECT_EQ(kHeight, child->Height()); 365 auto* second_child_fragment =
287 EXPECT_EQ(0, child->TopOffset()); 366 toNGPhysicalBoxFragment(body_fragment->Children()[1]);
288 367 // 40 = first_child's height(50) - margin's collapsing result(10)
289 // DIV5 368 int second_child_block_offset = 40;
290 child = frag->Children()[2]; 369 EXPECT_THAT(LayoutUnit(second_child_block_offset),
291 EXPECT_EQ(kHeight, child->Height()); 370 second_child_fragment->TopOffset());
292 EXPECT_EQ(kHeight + kExpectedCollapsedMargin, child->TopOffset()); 371
372 auto* empty5_fragment = toNGPhysicalBoxFragment(body_fragment->Children()[2]);
373 // 90 = first_child's height(50) + collapsed margins(-10) +
374 // second child's height(50)
375 int empty5_fragment_block_offset = 90;
376 EXPECT_THAT(LayoutUnit(empty5_fragment_block_offset),
377 empty5_fragment->TopOffset());
378
379 ASSERT_EQ(3UL, body_fragment->PositionedFloats().size());
380 auto float_nonempties_fragment =
381 body_fragment->PositionedFloats().at(1)->fragment;
382 // 70 = first_child's height(50) + first child's margin-bottom(20)
383 EXPECT_THAT(LayoutUnit(70), float_nonempties_fragment->TopOffset());
384 EXPECT_THAT(LayoutUnit(0), float_nonempties_fragment->LeftOffset());
385
386 // ** Verify layout tree **
387 Element* first_child = document().getElementById("first-child");
388 // -7 = body_top_offset
389 EXPECT_EQ(body_top_offset, first_child->offsetTop());
390
391 NGLogicalSize float_empties_exclusion_size = {LayoutUnit(30), LayoutUnit(30)};
392 NGLogicalOffset float_empties_exclusion_offset = {
393 LayoutUnit(body_left_offset), LayoutUnit(body_top_offset)};
394 NGLogicalRect float_empties_exclusion_rect = {float_empties_exclusion_offset,
395 float_empties_exclusion_size};
396 NGExclusion float_empties_exclusion = {float_empties_exclusion_rect,
397 NGExclusion::kFloatLeft};
398
399 NGLogicalSize float_nonempties_exclusion_size = {LayoutUnit(40),
400 LayoutUnit(40)};
401 // 63 = first_child_margin_strut(20) + first-child's height(50) +
402 // body_top_offset(-7)
403 NGLogicalOffset float_nonempties_exclusion_offset = {
404 LayoutUnit(body_left_offset), LayoutUnit(63)};
405 NGLogicalRect float_nonempties_exclusion_rect = {
406 float_nonempties_exclusion_offset, float_nonempties_exclusion_size};
407 NGExclusion float_nonempties_exclusion = {float_nonempties_exclusion_rect,
408 NGExclusion::kFloatLeft};
409
410 NGLogicalSize float_top_align_exclusion_size = {LayoutUnit(50),
411 LayoutUnit(50)};
412 // 63 = float_nonempties_exclusion_offset because of the top edge alignment
413 // rule.
414 // 48 = body's margin + float_nonempties_exclusion_size
415 NGLogicalOffset float_top_align_exclusion_offset = {LayoutUnit(48),
416 LayoutUnit(63)};
417 NGLogicalRect float_top_align_exclusion_rect = {
418 float_top_align_exclusion_offset, float_top_align_exclusion_size};
419 NGExclusion float_top_align_exclusion = {float_top_align_exclusion_rect,
420 NGExclusion::kFloatLeft};
421
422 EXPECT_THAT(space->Exclusions()->storage,
423 (ElementsAre(Pointee(float_empties_exclusion),
424 Pointee(float_nonempties_exclusion),
425 Pointee(float_top_align_exclusion))));
293 } 426 }
294 427
295 // Verifies the collapsing margins case for the next pair: 428 // Verifies the collapsing margins case for the next pair:
296 // - bottom margin of a last in-flow child and bottom margin of its parent if 429 // - bottom margin of a last in-flow child and bottom margin of its parent if
297 // the parent has 'auto' computed height 430 // the parent has 'auto' computed height
298 // 431 // TODO(glebl): Enable with new the float/margins collapsing algorithm.
299 // Test case's HTML representation: 432 TEST_F(NGBlockLayoutAlgorithmTest, DISABLED_CollapsingMarginsCase3) {
300 // <div style="margin-bottom: 20px; height: 50px;"> <!-- DIV1 --> 433 setBodyInnerHTML(
301 // <div style="margin-bottom: 200px; height: 50px;"/> <!-- DIV2 --> 434 "<style>"
302 // </div> 435 " #container {"
303 // 436 " margin-bottom: 20px;"
304 // Expected: 437 " }"
305 // 1) Margins are collapsed with the result = std::max(20, 200) 438 " #child {"
306 // if DIV1.height == auto 439 " margin-bottom: 200px;"
307 // 2) Margins are NOT collapsed if DIV1.height != auto 440 " height: 50px;"
308 TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsCase3) { 441 " }"
309 const int kHeight = 50; 442 "</style>"
310 const int kDiv1MarginBottom = 20; 443 "<div id='container'>"
311 const int kDiv2MarginBottom = 200; 444 " <div id='child'></div>"
312 445 "</div>");
313 // DIV1 446
314 RefPtr<ComputedStyle> div1_style = ComputedStyle::create(); 447 const NGPhysicalBoxFragment* body_fragment;
315 div1_style->setMarginBottom(Length(kDiv1MarginBottom, Fixed)); 448 const NGPhysicalBoxFragment* container_fragment;
316 NGBlockNode* div1 = new NGBlockNode(div1_style.get()); 449 const NGPhysicalBoxFragment* child_fragment;
317 450 const NGPhysicalBoxFragment* fragment;
318 // DIV2 451 auto run_test = [&](const Length& container_height) {
319 RefPtr<ComputedStyle> div2_style = ComputedStyle::create(); 452 Element* container = document().getElementById("container");
320 div2_style->setHeight(Length(kHeight, Fixed)); 453 container->mutableComputedStyle()->setHeight(container_height);
321 div2_style->setMarginBottom(Length(kDiv2MarginBottom, Fixed)); 454 std::tie(fragment, std::ignore) = RunBlockLayoutAlgorithmForElement(
322 NGBlockNode* div2 = new NGBlockNode(div2_style.get()); 455 document().getElementsByTagName("html")->item(0));
323 456 ASSERT_EQ(1UL, fragment->Children().size());
324 div1->SetFirstChild(div2); 457 body_fragment = toNGPhysicalBoxFragment(fragment->Children()[0]);
325 458 container_fragment = toNGPhysicalBoxFragment(body_fragment->Children()[0]);
326 auto* space = ConstructConstraintSpace( 459 ASSERT_EQ(1UL, container_fragment->Children().size());
327 kHorizontalTopBottom, TextDirection::kLtr, 460 child_fragment = toNGPhysicalBoxFragment(container_fragment->Children()[0]);
328 NGLogicalSize(LayoutUnit(100), NGSizeIndefinite)); 461 };
329 NGPhysicalBoxFragment* frag = RunBlockLayoutAlgorithm(space, div1); 462
330 463 // height == auto
331 // Verify that margins are collapsed. 464 run_test(Length(Auto));
332 EXPECT_EQ( 465 // Margins are collapsed with the result 200 = std::max(20, 200)
333 NGDeprecatedMarginStrut({LayoutUnit(0), LayoutUnit(kDiv2MarginBottom)}), 466 // The fragment size 258 == body's margin 8 + child's height 50 + 200
334 frag->MarginStrut()); 467 EXPECT_EQ(NGPhysicalSize(LayoutUnit(800), LayoutUnit(258)), fragment->Size());
335 468 // EXPECT_EQ(NGMarginStrut({LayoutUnit(200)}),
336 // Verify that margins are NOT collapsed. 469 // container_fragment->EndMarginStrut());
337 div1_style->setHeight(Length(kHeight, Fixed)); 470
338 frag = RunBlockLayoutAlgorithm(space, div1); 471 // height == fixed
339 EXPECT_EQ( 472 run_test(Length(50, Fixed));
340 NGDeprecatedMarginStrut({LayoutUnit(0), LayoutUnit(kDiv1MarginBottom)}), 473 // Margins are not collapsed, so fragment still has margins == 20.
341 frag->MarginStrut()); 474 // The fragment size 78 == body's margin 8 + child's height 50 + 20
475 // EXPECT_EQ(NGPhysicalSize(LayoutUnit(800), LayoutUnit(78)),
476 // fragment->Size());
477 // EXPECT_EQ(NGMarginStrut(), container_fragment->EndMarginStrut());
342 } 478 }
343 479
344 // Verifies that 2 adjoining margins are not collapsed if there is padding or 480 // Verifies that 2 adjoining margins are not collapsed if there is padding or
345 // border that separates them. 481 // border that separates them.
346 // 482 // TODO(glebl): Enable with new the float/margins collapsing algorithm.
347 // Test case's HTML representation: 483 TEST_F(NGBlockLayoutAlgorithmTest, DISABLED_CollapsingMarginsCase4) {
348 // <div style="margin: 30px 0px; padding: 20px 0px;"> <!-- DIV1 --> 484 setBodyInnerHTML(
349 // <div style="margin: 200px 0px; height: 50px;"/> <!-- DIV2 --> 485 "<style>"
350 // </div> 486 " #container {"
351 // 487 " margin: 30px 0px;"
352 // Expected: 488 " width: 200px;"
353 // Margins do NOT collapse if there is an interfering padding or border. 489 " }"
354 TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsCase4) { 490 " #child {"
355 const int kHeight = 50; 491 " margin: 200px 0px;"
356 const int kDiv1Margin = 30; 492 " height: 50px;"
357 const int kDiv1Padding = 20; 493 " background-color: blue;"
358 const int kDiv2Margin = 200; 494 " }"
359 495 "</style>"
360 // DIV1 496 "<div id='container'>"
361 RefPtr<ComputedStyle> div1_style = ComputedStyle::create(); 497 " <div id='child'></div>"
362 div1_style->setMarginTop(Length(kDiv1Margin, Fixed)); 498 "</div>");
363 div1_style->setMarginBottom(Length(kDiv1Margin, Fixed)); 499
364 div1_style->setPaddingTop(Length(kDiv1Padding, Fixed)); 500 const NGPhysicalBoxFragment* body_fragment;
365 div1_style->setPaddingBottom(Length(kDiv1Padding, Fixed)); 501 const NGPhysicalBoxFragment* container_fragment;
366 NGBlockNode* div1 = new NGBlockNode(div1_style.get()); 502 const NGPhysicalBoxFragment* child_fragment;
367 503 const NGPhysicalBoxFragment* fragment;
368 // DIV2 504 auto run_test = [&](const Length& container_padding_top) {
369 RefPtr<ComputedStyle> div2_style = ComputedStyle::create(); 505 Element* container = document().getElementById("container");
370 div2_style->setHeight(Length(kHeight, Fixed)); 506 container->mutableComputedStyle()->setPaddingTop(container_padding_top);
371 div2_style->setMarginTop(Length(kDiv2Margin, Fixed)); 507 std::tie(fragment, std::ignore) = RunBlockLayoutAlgorithmForElement(
372 div2_style->setMarginBottom(Length(kDiv2Margin, Fixed)); 508 document().getElementsByTagName("html")->item(0));
373 NGBlockNode* div2 = new NGBlockNode(div2_style.get()); 509 ASSERT_EQ(1UL, fragment->Children().size());
374 510 body_fragment = toNGPhysicalBoxFragment(fragment->Children()[0]);
375 div1->SetFirstChild(div2); 511 container_fragment = toNGPhysicalBoxFragment(body_fragment->Children()[0]);
376 512 ASSERT_EQ(1UL, container_fragment->Children().size());
377 auto* space = ConstructConstraintSpace( 513 child_fragment = toNGPhysicalBoxFragment(container_fragment->Children()[0]);
378 kHorizontalTopBottom, TextDirection::kLtr, 514 };
379 NGLogicalSize(LayoutUnit(100), NGSizeIndefinite)); 515
380 NGPhysicalBoxFragment* frag = RunBlockLayoutAlgorithm(space, div1); 516 // with padding
381 517 run_test(Length(20, Fixed));
382 // Verify that margins do NOT collapse. 518 // 500 = child's height 50 + 2xmargin 400 + paddint-top 20 +
383 frag = RunBlockLayoutAlgorithm(space, div1); 519 // container's margin 30
384 EXPECT_EQ(NGDeprecatedMarginStrut( 520 EXPECT_EQ(NGPhysicalSize(LayoutUnit(800), LayoutUnit(500)), fragment->Size());
385 {LayoutUnit(kDiv1Margin), LayoutUnit(kDiv1Margin)}), 521 // 30 = max(body's margin 8, container margin 30)
386 frag->MarginStrut()); 522 EXPECT_EQ(LayoutUnit(30), body_fragment->TopOffset());
387 ASSERT_EQ(frag->Children().size(), 1UL); 523 // 220 = container's padding top 20 + child's margin
388 524 EXPECT_EQ(LayoutUnit(220), child_fragment->TopOffset());
389 EXPECT_EQ(NGDeprecatedMarginStrut( 525
390 {LayoutUnit(kDiv2Margin), LayoutUnit(kDiv2Margin)}), 526 // without padding
391 static_cast<const NGPhysicalBoxFragment*>(frag->Children()[0].get()) 527 run_test(Length(0, Fixed));
392 ->MarginStrut()); 528 // 450 = 2xmax(body's margin 8, container's margin 30, child's margin 200) +
393 529 // child's height 50
394 // Reset padding and verify that margins DO collapse. 530 EXPECT_EQ(NGPhysicalSize(LayoutUnit(800), LayoutUnit(450)), fragment->Size());
395 div1_style->setPaddingTop(Length(0, Fixed)); 531 // 200 = (body's margin 8, container's margin 30, child's margin 200)
396 div1_style->setPaddingBottom(Length(0, Fixed)); 532 EXPECT_EQ(LayoutUnit(200), body_fragment->TopOffset());
397 frag = RunBlockLayoutAlgorithm(space, div1); 533 // 0 = collapsed margins
398 EXPECT_EQ(NGDeprecatedMarginStrut( 534 EXPECT_EQ(LayoutUnit(0), child_fragment->TopOffset());
399 {LayoutUnit(kDiv2Margin), LayoutUnit(kDiv2Margin)}),
400 frag->MarginStrut());
401 } 535 }
402 536
403 // Verifies that margins of 2 adjoining blocks with different writing modes 537 // Verifies that margins of 2 adjoining blocks with different writing modes
404 // get collapsed. 538 // get collapsed.
405 // 539 //
406 // Test case's HTML representation: 540 // Test case's HTML representation:
407 // <div style="writing-mode: vertical-lr;"> 541 // <div style="writing-mode: vertical-lr;">
408 // <div style="margin-right: 60px; width: 60px;">vertical</div> 542 // <div style="margin-right: 60px; width: 60px;">vertical</div>
409 // <div style="margin-left: 100px; writing-mode: horizontal-tb;"> 543 // <div style="margin-left: 100px; writing-mode: horizontal-tb;">
410 // horizontal 544 // horizontal
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after
625 EXPECT_EQ(NGPhysicalFragment::kFragmentBox, frag->Type()); 759 EXPECT_EQ(NGPhysicalFragment::kFragmentBox, frag->Type());
626 EXPECT_EQ(LayoutUnit(kWidth + kPaddingLeft), frag->WidthOverflow()); 760 EXPECT_EQ(LayoutUnit(kWidth + kPaddingLeft), frag->WidthOverflow());
627 ASSERT_EQ(1UL, frag->Children().size()); 761 ASSERT_EQ(1UL, frag->Children().size());
628 762
629 const NGPhysicalFragment* child = frag->Children()[0]; 763 const NGPhysicalFragment* child = frag->Children()[0];
630 EXPECT_EQ(LayoutUnit(kChildWidth), child->Width()); 764 EXPECT_EQ(LayoutUnit(kChildWidth), child->Width());
631 EXPECT_EQ(LayoutUnit(kPaddingLeft + 10), child->LeftOffset()); 765 EXPECT_EQ(LayoutUnit(kPaddingLeft + 10), child->LeftOffset());
632 EXPECT_EQ(LayoutUnit(0), child->TopOffset()); 766 EXPECT_EQ(LayoutUnit(0), child->TopOffset());
633 } 767 }
634 768
635 // Verifies that 3 Left/Right float fragments and one regular block fragment 769 // Verifies that floats can be correctly positioned if they are inside of nested
636 // are correctly positioned by the algorithm. 770 // empty blocks.
637 // 771 // TODO(glebl): Enable with new the float/margins collapsing algorithm.
638 // Test case's HTML representation: 772 TEST_F(NGBlockLayoutAlgorithmTest, DISABLED_PositionFloatInsideEmptyBlocks) {
639 // <div id="parent" style="width: 200px; height: 200px;"> 773 setBodyInnerHTML(
640 // <div style="float:left; width: 30px; height: 30px; 774 "<!DOCTYPE html>"
641 // margin-top: 10px;"/> <!-- DIV1 --> 775 "<style>"
642 // <div style="width: 30px; height: 30px;"/> <!-- DIV2 --> 776 " #container {"
643 // <div style="float:right; width: 50px; height: 50px;"/> <!-- DIV3 --> 777 " height: 200px;"
644 // <div style="float:left; width: 120px; height: 120px; 778 " width: 200px;"
645 // margin-left: 30px;"/> <!-- DIV4 --> 779 " }"
646 // </div> 780 " #empty1 {"
647 // 781 " margin: 20px;"
648 // Expected: 782 " padding: 0 20px;"
649 // - Left float(DIV1) is positioned at the left. 783 " }"
650 // - Regular block (DIV2) is positioned behind DIV1. 784 " #empty2 {"
651 // - Right float(DIV3) is positioned at the right below DIV2 785 " margin: 15px;"
652 // - Left float(DIV4) is positioned at the left below DIV3. 786 " padding: 0 15px;"
653 TEST_F(NGBlockLayoutAlgorithmTest, PositionFloatFragments) { 787 " }"
654 const int kParentLeftPadding = 10; 788 " #float {"
655 const int kDiv1TopMargin = 10; 789 " float: left;"
656 const int kParentSize = 200; 790 " height: 5px;"
657 const int kDiv1Size = 30; 791 " width: 5px;"
658 const int kDiv2Size = 30; 792 " padding: 10px;"
659 const int kDiv3Size = 50; 793 " margin: 10px;"
660 const int kDiv4Size = kParentSize - kDiv3Size; 794 " background-color: green;"
661 const int kDiv4LeftMargin = kDiv1Size; 795 " }"
662 796 "</style>"
663 style_->setHeight(Length(kParentSize, Fixed)); 797 "<div id='container'>"
664 style_->setWidth(Length(kParentSize, Fixed)); 798 " <div id='empty1'>"
665 style_->setPaddingLeft(Length(kParentLeftPadding, Fixed)); 799 " <div id='empty2'>"
666 800 " <div id='float'></div>"
667 // DIV1 801 " </div>"
668 RefPtr<ComputedStyle> div1_style = ComputedStyle::create(); 802 " </div>"
669 div1_style->setWidth(Length(kDiv1Size, Fixed)); 803 "</div>");
670 div1_style->setHeight(Length(kDiv1Size, Fixed)); 804
671 div1_style->setFloating(EFloat::kLeft); 805 // ** Run LayoutNG algorithm **
672 div1_style->setMarginTop(Length(kDiv1TopMargin, Fixed)); 806 NGConstraintSpace* space;
673 NGBlockNode* div1 = new NGBlockNode(div1_style.get()); 807 NGPhysicalBoxFragment* fragment;
674 808 std::tie(fragment, space) = RunBlockLayoutAlgorithmForElement(
675 // DIV2 809 document().getElementsByTagName("html")->item(0));
676 RefPtr<ComputedStyle> div2_style = ComputedStyle::create(); 810
677 div2_style->setWidth(Length(kDiv2Size, Fixed)); 811 auto* body_fragment = toNGPhysicalBoxFragment(fragment->Children()[0]);
678 div2_style->setHeight(Length(kDiv2Size, Fixed)); 812 // 20 = std::max(empty1's margin, empty2's margin, body's margin)
679 NGBlockNode* div2 = new NGBlockNode(div2_style.get()); 813 int body_top_offset = 20;
680 814 EXPECT_THAT(LayoutUnit(body_top_offset), body_fragment->TopOffset());
681 // DIV3 815 ASSERT_EQ(1UL, body_fragment->Children().size());
682 RefPtr<ComputedStyle> div3_style = ComputedStyle::create(); 816 auto* container_fragment =
683 div3_style->setWidth(Length(kDiv3Size, Fixed)); 817 toNGPhysicalBoxFragment(body_fragment->Children()[0]);
684 div3_style->setHeight(Length(kDiv3Size, Fixed)); 818 ASSERT_EQ(1UL, container_fragment->Children().size());
685 div3_style->setFloating(EFloat::kRight); 819
686 NGBlockNode* div3 = new NGBlockNode(div3_style.get()); 820 auto* empty1_fragment =
687 821 toNGPhysicalBoxFragment(container_fragment->Children()[0]);
688 // DIV4 822 // 0, vertical margins got collapsed
689 RefPtr<ComputedStyle> div4_style = ComputedStyle::create(); 823 EXPECT_THAT(LayoutUnit(), empty1_fragment->TopOffset());
690 div4_style->setWidth(Length(kDiv4Size, Fixed)); 824 // 20 empty1's margin
691 div4_style->setHeight(Length(kDiv4Size, Fixed)); 825 int empty1_inline_offset = 20;
692 div4_style->setMarginLeft(Length(kDiv4LeftMargin, Fixed)); 826 EXPECT_THAT(LayoutUnit(empty1_inline_offset), empty1_fragment->LeftOffset());
693 div4_style->setFloating(EFloat::kLeft); 827 ASSERT_EQ(empty1_fragment->Children().size(), 1UL);
694 NGBlockNode* div4 = new NGBlockNode(div4_style.get()); 828
695 829 auto* empty2_fragment =
696 div1->SetNextSibling(div2); 830 toNGPhysicalBoxFragment(empty1_fragment->Children()[0]);
697 div2->SetNextSibling(div3); 831 // 0, vertical margins got collapsed
698 div3->SetNextSibling(div4); 832 EXPECT_THAT(LayoutUnit(), empty2_fragment->TopOffset());
699 833 // 35 = empty1's padding(20) + empty2's padding(15)
700 auto* space = ConstructConstraintSpace( 834 int empty2_inline_offset = 35;
701 kHorizontalTopBottom, TextDirection::kLtr, 835 EXPECT_THAT(LayoutUnit(empty2_inline_offset), empty2_fragment->LeftOffset());
702 NGLogicalSize(LayoutUnit(kParentSize), LayoutUnit(kParentSize))); 836
703 NGPhysicalBoxFragment* frag = RunBlockLayoutAlgorithm(space, div1); 837 ASSERT_EQ(1UL, body_fragment->PositionedFloats().size());
704 ASSERT_EQ(frag->Children().size(), 4UL); 838 auto float_fragment = body_fragment->PositionedFloats().at(0)->fragment;
705 839 // 10 = float's padding
706 // DIV1 840 EXPECT_THAT(LayoutUnit(10), float_fragment->TopOffset());
707 const NGPhysicalFragment* child1 = frag->Children()[0]; 841 // 25 = empty2's padding(15) + float's padding(10)
708 EXPECT_EQ(kDiv1TopMargin, child1->TopOffset()); 842 int float_inline_offset = 25;
709 EXPECT_EQ(kParentLeftPadding, child1->LeftOffset()); 843 EXPECT_THAT(float_fragment->LeftOffset(), LayoutUnit(float_inline_offset));
710 844
711 // DIV2 845 // ** Verify layout tree **
712 const NGPhysicalFragment* child2 = frag->Children()[1]; 846 Element* left_float = document().getElementById("float");
713 EXPECT_EQ(0, child2->TopOffset()); 847 // 88 = body's margin(8) +
714 EXPECT_EQ(kParentLeftPadding, child2->LeftOffset()); 848 // empty1's padding and margin + empty2's padding and margins + float's
715 849 // padding
716 // DIV3 850 EXPECT_THAT(left_float->offsetLeft(), 88);
717 const NGPhysicalFragment* child3 = frag->Children()[2]; 851 // 30 = body_top_offset(collapsed margins result) + float's padding
718 EXPECT_EQ(kDiv2Size, child3->TopOffset()); 852 EXPECT_THAT(body_top_offset + 10, left_float->offsetTop());
719 EXPECT_EQ(kParentLeftPadding + kParentSize - kDiv3Size, child3->LeftOffset()); 853
720 854 // ** Legacy Floating objects **
721 // DIV4 855 Element* body = document().getElementsByTagName("body")->item(0);
722 const NGPhysicalFragment* child4 = frag->Children()[3]; 856 auto& floating_objects =
723 EXPECT_EQ(kDiv2Size + kDiv3Size, child4->TopOffset()); 857 const_cast<FloatingObjects*>(
724 EXPECT_EQ(kParentLeftPadding + kDiv4LeftMargin, child4->LeftOffset()); 858 toLayoutBlockFlow(body->layoutObject())->floatingObjects())
859 ->mutableSet();
860 ASSERT_EQ(1UL, floating_objects.size());
861 auto floating_object = floating_objects.takeFirst();
862 ASSERT_TRUE(floating_object->isPlaced());
863 // 80 = float_inline_offset(25) + accumulative offset of empty blocks(35 + 20)
864 EXPECT_THAT(LayoutUnit(80), floating_object->x());
865 // 10 = float's padding
866 EXPECT_THAT(LayoutUnit(10), floating_object->y());
725 } 867 }
726 868
869 // Verifies that left/right floating and regular blocks can be positioned
870 // correctly by the algorithm.
871 // TODO(glebl): Enable with new the float/margins collapsing algorithm.
872 TEST_F(NGBlockLayoutAlgorithmTest, DISABLED_PositionFloatFragments) {
873 setBodyInnerHTML(
874 "<style>"
875 " #container {"
876 " height: 200px;"
877 " width: 200px;"
878 " }"
879 " #left-float {"
880 " background-color: red;"
881 " float:left;"
882 " height: 30px;"
883 " width: 30px;"
884 " }"
885 " #left-wide-float {"
886 " background-color: greenyellow;"
887 " float:left;"
888 " height: 30px;"
889 " width: 180px;"
890 " }"
891 " #regular {"
892 " width: 40px;"
893 " height: 40px;"
894 " background-color: green;"
895 " }"
896 " #right-float {"
897 " background-color: cyan;"
898 " float:right;"
899 " width: 50px;"
900 " height: 50px;"
901 " }"
902 " #left-float-with-margin {"
903 " background-color: black;"
904 " float:left;"
905 " height: 120px;"
906 " margin: 10px;"
907 " width: 120px;"
908 " }"
909 "</style>"
910 "<div id='container'>"
911 " <div id='left-float'></div>"
912 " <div id='left-wide-float'></div>"
913 " <div id='regular'></div>"
914 " <div id='right-float'></div>"
915 " <div id='left-float-with-margin'></div>"
916 "</div>");
917
918 // ** Run LayoutNG algorithm **
919 NGConstraintSpace* space;
920 NGPhysicalBoxFragment* fragment;
921 std::tie(fragment, space) = RunBlockLayoutAlgorithmForElement(
922 document().getElementsByTagName("html")->item(0));
923
924 // ** Verify LayoutNG fragments and the list of positioned floats **
925 EXPECT_THAT(LayoutUnit(), fragment->TopOffset());
926 ASSERT_EQ(1UL, fragment->Children().size());
927 auto* body_fragment = toNGPhysicalBoxFragment(fragment->Children()[0]);
928 EXPECT_THAT(LayoutUnit(8), body_fragment->TopOffset());
929 auto* container_fragment =
930 toNGPhysicalBoxFragment(body_fragment->Children()[0]);
931 ASSERT_EQ(1UL, container_fragment->Children().size());
932 ASSERT_EQ(4UL, container_fragment->PositionedFloats().size());
933
934 // ** Verify layout tree **
935 Element* left_float = document().getElementById("left-float");
936 // 8 = body's margin-top
937 int left_float_block_offset = 8;
938 EXPECT_EQ(left_float_block_offset, left_float->offsetTop());
939 auto left_float_fragment =
940 container_fragment->PositionedFloats().at(0)->fragment;
941 EXPECT_THAT(LayoutUnit(), left_float_fragment->TopOffset());
942
943 Element* left_wide_float = document().getElementById("left-wide-float");
944 // left-wide-float is positioned right below left-float as it's too wide.
945 // 38 = left_float_block_offset +
946 // left-float's height 30
947 int left_wide_float_block_offset = 38;
948 EXPECT_EQ(left_wide_float_block_offset, left_wide_float->offsetTop());
949 auto left_wide_float_fragment =
950 container_fragment->PositionedFloats().at(1)->fragment;
951 // 30 = left-float's height.
952 EXPECT_THAT(LayoutUnit(30), left_wide_float_fragment->TopOffset());
953
954 Element* regular = document().getElementById("regular");
955 // regular_block_offset = body's margin-top 8
956 int regular_block_offset = 8;
957 EXPECT_EQ(regular_block_offset, regular->offsetTop());
958 auto* regular_block_fragment =
959 toNGPhysicalBoxFragment(container_fragment->Children()[0]);
960 EXPECT_THAT(LayoutUnit(), regular_block_fragment->TopOffset());
961
962 Element* right_float = document().getElementById("right-float");
963 // 158 = body's margin-left 8 + container's width 200 - right_float's width 50
964 int right_float_inline_offset = 158;
965 // it's positioned right after our left_wide_float
966 // 68 = left_wide_float_block_offset 38 + left-wide-float's height 30
967 int right_float_block_offset = left_wide_float_block_offset + 30;
968 EXPECT_EQ(right_float_inline_offset, right_float->offsetLeft());
969 EXPECT_EQ(right_float_block_offset, right_float->offsetTop());
970 auto right_float_fragment =
971 container_fragment->PositionedFloats().at(2)->fragment;
972 // 60 = right_float_block_offset(68) - body's margin(8)
973 EXPECT_THAT(LayoutUnit(right_float_block_offset - 8),
974 right_float_fragment->TopOffset());
975 // 150 = right_float_inline_offset(158) - body's margin(8)
976 EXPECT_THAT(LayoutUnit(right_float_inline_offset - 8),
977 right_float_fragment->LeftOffset());
978
979 Element* left_float_with_margin =
980 document().getElementById("left-float-with-margin");
981 // 18 = body's margin(8) + left-float-with-margin's margin(10)
982 int left_float_with_margin_inline_offset = 18;
983 EXPECT_EQ(left_float_with_margin_inline_offset,
984 left_float_with_margin->offsetLeft());
985 // 78 = left_wide_float_block_offset 38 + left-wide-float's height 30 +
986 // left-float-with-margin's margin(10)
987 int left_float_with_margin_block_offset = 78;
988 EXPECT_EQ(left_float_with_margin_block_offset,
989 left_float_with_margin->offsetTop());
990 auto left_float_with_margin_fragment =
991 container_fragment->PositionedFloats().at(3)->fragment;
992 // 70 = left_float_with_margin_block_offset(78) - body's margin(8)
993 EXPECT_THAT(LayoutUnit(left_float_with_margin_block_offset - 8),
994 left_float_with_margin_fragment->TopOffset());
995 // 10 = left_float_with_margin_inline_offset(18) - body's margin(8)
996 EXPECT_THAT(LayoutUnit(left_float_with_margin_inline_offset - 8),
997 left_float_with_margin_fragment->LeftOffset());
998
999 // ** Verify exclusions **
1000 NGLogicalSize left_float_exclusion_size = {LayoutUnit(30), LayoutUnit(30)};
1001 // this should be equal to body's margin(8)
1002 NGLogicalOffset left_float_exclusion_offset = {LayoutUnit(8), LayoutUnit(8)};
1003 NGLogicalRect left_float_exclusion_rect = {left_float_exclusion_offset,
1004 left_float_exclusion_size};
1005 NGExclusion left_float_exclusion = {left_float_exclusion_rect,
1006 NGExclusion::kFloatLeft};
1007
1008 NGLogicalSize left_wide_exclusion_size = {LayoutUnit(180), LayoutUnit(30)};
1009 NGLogicalOffset left_wide_exclusion_offset = {
1010 LayoutUnit(8), LayoutUnit(left_wide_float_block_offset)};
1011 NGLogicalRect left_wide_exclusion_rect = {left_wide_exclusion_offset,
1012 left_wide_exclusion_size};
1013 NGExclusion left_wide_exclusion = {left_wide_exclusion_rect,
1014 NGExclusion::kFloatLeft};
1015
1016 NGLogicalSize right_float_exclusion_size = {LayoutUnit(50), LayoutUnit(50)};
1017 NGLogicalOffset right_float_exclusion_offset = {
1018 LayoutUnit(right_float_inline_offset),
1019 LayoutUnit(right_float_block_offset)};
1020 NGLogicalRect right_float_exclusion_rect = {right_float_exclusion_offset,
1021 right_float_exclusion_size};
1022 NGExclusion right_float_exclusion = {right_float_exclusion_rect,
1023 NGExclusion::kFloatRight};
1024
1025 // left-float-with-margin's size(120) + margin(2x10)
1026 NGLogicalSize left_float_with_margin_exclusion_size = {LayoutUnit(140),
1027 LayoutUnit(140)};
1028 // Exclusion starts from the right_float_block_offset position.
1029 NGLogicalOffset left_float_with_margin_exclusion_offset = {
1030 LayoutUnit(8), LayoutUnit(right_float_block_offset)};
1031 NGLogicalRect left_float_with_margin_exclusion_rect = {
1032 left_float_with_margin_exclusion_offset,
1033 left_float_with_margin_exclusion_size};
1034 NGExclusion left_float_with_margin_exclusion = {
1035 left_float_with_margin_exclusion_rect, NGExclusion::kFloatLeft};
1036
1037 EXPECT_THAT(
1038 space->Exclusions()->storage,
1039 (ElementsAre(Pointee(left_float_exclusion), Pointee(left_wide_exclusion),
1040 Pointee(right_float_exclusion),
1041 Pointee(left_float_with_margin_exclusion))));
1042 }
1043
727 // Verifies that NG block layout algorithm respects "clear" CSS property. 1044 // Verifies that NG block layout algorithm respects "clear" CSS property.
728 // 1045 // TODO(glebl): Enable with new the float/margins collapsing algorithm.
729 // Test case's HTML representation: 1046 TEST_F(NGBlockLayoutAlgorithmTest, DISABLED_PositionFragmentsWithClear) {
730 // <div id="parent" style="width: 200px; height: 200px;"> 1047 setBodyInnerHTML(
731 // <div style="float: left; width: 30px; height: 30px;"/> <!-- DIV1 --> 1048 "<style>"
732 // <div style="float: right; width: 40px; height: 40px; 1049 " #container {"
733 // clear: left;"/> <!-- DIV2 --> 1050 " height: 200px;"
734 // <div style="clear: ...; width: 50px; height: 50px;"/> <!-- DIV3 --> 1051 " width: 200px;"
735 // </div> 1052 " }"
736 // 1053 " #float-left {"
737 // Expected: 1054 " background-color: red;"
738 // - DIV2 is positioned below DIV1 because it has clear: left; 1055 " float: left;"
739 // - DIV3 is positioned below DIV1 if clear: left; 1056 " height: 30px;"
740 // - DIV3 is positioned below DIV2 if clear: right; 1057 " width: 30px;"
741 // - DIV3 is positioned below DIV2 if clear: both; 1058 " }"
742 TEST_F(NGBlockLayoutAlgorithmTest, PositionFragmentsWithClear) { 1059 " #float-right {"
743 const int kParentSize = 200; 1060 " background-color: blue;"
744 const int kDiv1Size = 30; 1061 " float: right;"
745 const int kDiv2Size = 40; 1062 " height: 170px;"
746 const int kDiv3Size = 50; 1063 " width: 40px;"
747 1064 " }"
748 style_->setHeight(Length(kParentSize, Fixed)); 1065 " #clearance {"
749 style_->setWidth(Length(kParentSize, Fixed)); 1066 " background-color: yellow;"
750 1067 " height: 60px;"
751 // DIV1 1068 " width: 60px;"
752 RefPtr<ComputedStyle> div1_style = ComputedStyle::create(); 1069 " margin: 20px;"
753 div1_style->setWidth(Length(kDiv1Size, Fixed)); 1070 " }"
754 div1_style->setHeight(Length(kDiv1Size, Fixed)); 1071 " #block {"
755 div1_style->setFloating(EFloat::kLeft); 1072 " margin: 40px;"
756 NGBlockNode* div1 = new NGBlockNode(div1_style.get()); 1073 " background-color: black;"
757 1074 " height: 60px;"
758 // DIV2 1075 " width: 60px;"
759 RefPtr<ComputedStyle> div2_style = ComputedStyle::create(); 1076 " }"
760 div2_style->setWidth(Length(kDiv2Size, Fixed)); 1077 " #adjoining-clearance {"
761 div2_style->setHeight(Length(kDiv2Size, Fixed)); 1078 " background-color: green;"
762 div2_style->setClear(EClear::ClearLeft); 1079 " clear: left;"
763 div2_style->setFloating(EFloat::kRight); 1080 " height: 20px;"
764 NGBlockNode* div2 = new NGBlockNode(div2_style.get()); 1081 " width: 20px;"
765 1082 " margin: 30px;"
766 // DIV3 1083 " }"
767 RefPtr<ComputedStyle> div3_style = ComputedStyle::create(); 1084 "</style>"
768 div3_style->setWidth(Length(kDiv3Size, Fixed)); 1085 "<div id='container'>"
769 div3_style->setHeight(Length(kDiv3Size, Fixed)); 1086 " <div id='float-left'></div>"
770 NGBlockNode* div3 = new NGBlockNode(div3_style.get()); 1087 " <div id='float-right'></div>"
771 1088 " <div id='clearance'></div>"
772 div1->SetNextSibling(div2); 1089 " <div id='block'></div>"
773 div2->SetNextSibling(div3); 1090 " <div id='adjoining-clearance'></div>"
774 1091 "</div>");
775 // clear: left; 1092
776 div3_style->setClear(EClear::ClearLeft); 1093 const NGPhysicalBoxFragment* clerance_fragment;
777 auto* space = ConstructConstraintSpace( 1094 const NGPhysicalBoxFragment* body_fragment;
778 kHorizontalTopBottom, TextDirection::kLtr, 1095 const NGPhysicalBoxFragment* container_fragment;
779 NGLogicalSize(LayoutUnit(kParentSize), LayoutUnit(kParentSize))); 1096 const NGPhysicalBoxFragment* block_fragment;
780 NGPhysicalBoxFragment* frag = RunBlockLayoutAlgorithm(space, div1); 1097 const NGPhysicalBoxFragment* adjoining_clearance_fragment;
781 const NGPhysicalFragment* child3 = frag->Children()[2]; 1098 auto run_with_clearance = [&](EClear clear_value) {
782 EXPECT_EQ(kDiv1Size, child3->TopOffset()); 1099 NGPhysicalBoxFragment* fragment;
783 1100 Element* el_with_clear = document().getElementById("clearance");
784 // clear: right; 1101 el_with_clear->mutableComputedStyle()->setClear(clear_value);
785 div3_style->setClear(EClear::ClearRight); 1102 std::tie(fragment, std::ignore) = RunBlockLayoutAlgorithmForElement(
786 space = ConstructConstraintSpace( 1103 document().getElementsByTagName("html")->item(0));
787 kHorizontalTopBottom, TextDirection::kLtr, 1104 ASSERT_EQ(1UL, fragment->Children().size());
788 NGLogicalSize(LayoutUnit(kParentSize), LayoutUnit(kParentSize))); 1105 body_fragment = toNGPhysicalBoxFragment(fragment->Children()[0]);
789 frag = RunBlockLayoutAlgorithm(space, div1); 1106 container_fragment = toNGPhysicalBoxFragment(body_fragment->Children()[0]);
790 child3 = frag->Children()[2]; 1107 ASSERT_EQ(3UL, container_fragment->Children().size());
791 EXPECT_EQ(kDiv1Size + kDiv2Size, child3->TopOffset()); 1108 clerance_fragment =
792 1109 toNGPhysicalBoxFragment(container_fragment->Children()[0]);
793 // clear: both; 1110 block_fragment = toNGPhysicalBoxFragment(container_fragment->Children()[1]);
794 div3_style->setClear(EClear::ClearBoth); 1111 adjoining_clearance_fragment =
795 space = ConstructConstraintSpace( 1112 toNGPhysicalBoxFragment(container_fragment->Children()[2]);
796 kHorizontalTopBottom, TextDirection::kLtr, 1113 };
797 NGLogicalSize(LayoutUnit(kParentSize), LayoutUnit(kParentSize))); 1114
798 frag = RunBlockLayoutAlgorithm(space, div1); 1115 // clear: none
799 space = ConstructConstraintSpace( 1116 run_with_clearance(EClear::ClearNone);
800 kHorizontalTopBottom, TextDirection::kLtr, 1117 // 20 = std::max(body's margin 8, clearance's margins 20)
801 NGLogicalSize(LayoutUnit(kParentSize), LayoutUnit(kParentSize))); 1118 EXPECT_EQ(LayoutUnit(20), body_fragment->TopOffset());
802 child3 = frag->Children()[2]; 1119 EXPECT_EQ(LayoutUnit(0), container_fragment->TopOffset());
803 EXPECT_EQ(kDiv1Size + kDiv2Size, child3->TopOffset()); 1120 // 0 = collapsed margins
1121 EXPECT_EQ(LayoutUnit(0), clerance_fragment->TopOffset());
1122 // 100 = clearance's height 60 +
1123 // std::max(clearance's margins 20, block's margins 40)
1124 EXPECT_EQ(LayoutUnit(100), block_fragment->TopOffset());
1125 // 200 = 100 + block's height 60 + max(adjoining_clearance's margins 30,
1126 // block's margins 40)
1127 EXPECT_EQ(LayoutUnit(200), adjoining_clearance_fragment->TopOffset());
1128
1129 // clear: right
1130 run_with_clearance(EClear::ClearRight);
1131 // 8 = body's margin. This doesn't collapse its margins with 'clearance' block
1132 // as it's not an adjoining block to body.
1133 EXPECT_EQ(LayoutUnit(8), body_fragment->TopOffset());
1134 EXPECT_EQ(LayoutUnit(0), container_fragment->TopOffset());
1135 // 170 = float-right's height
1136 EXPECT_EQ(LayoutUnit(170), clerance_fragment->TopOffset());
1137 // 270 = float-right's height + clearance's height 60 +
1138 // max(clearance's margin 20, block margin 40)
1139 EXPECT_EQ(LayoutUnit(270), block_fragment->TopOffset());
1140 // 370 = block's offset 270 + block's height 60 +
1141 // std::max(block's margin 40, adjoining_clearance's margin 30)
1142 EXPECT_EQ(LayoutUnit(370), adjoining_clearance_fragment->TopOffset());
1143
1144 // clear: left
1145 run_with_clearance(EClear::ClearLeft);
1146 // 8 = body's margin. This doesn't collapse its margins with 'clearance' block
1147 // as it's not an adjoining block to body.
1148 EXPECT_EQ(LayoutUnit(8), body_fragment->TopOffset());
1149 EXPECT_EQ(LayoutUnit(0), container_fragment->TopOffset());
1150 // 30 = float_left's height
1151 EXPECT_EQ(LayoutUnit(30), clerance_fragment->TopOffset());
1152 // 130 = float_left's height + clearance's height 60 +
1153 // max(clearance's margin 20, block margin 40)
1154 EXPECT_EQ(LayoutUnit(130), block_fragment->TopOffset());
1155 // 230 = block's offset 130 + block's height 60 +
1156 // std::max(block's margin 40, adjoining_clearance's margin 30)
1157 EXPECT_EQ(LayoutUnit(230), adjoining_clearance_fragment->TopOffset());
1158
1159 // clear: both
1160 // same as clear: right
1161 run_with_clearance(EClear::ClearBoth);
1162 EXPECT_EQ(LayoutUnit(8), body_fragment->TopOffset());
1163 EXPECT_EQ(LayoutUnit(0), container_fragment->TopOffset());
1164 EXPECT_EQ(LayoutUnit(170), clerance_fragment->TopOffset());
1165 EXPECT_EQ(LayoutUnit(270), block_fragment->TopOffset());
1166 EXPECT_EQ(LayoutUnit(370), adjoining_clearance_fragment->TopOffset());
804 } 1167 }
805 1168
806 // Verifies that we compute the right min and max-content size. 1169 // Verifies that we compute the right min and max-content size.
807 TEST_F(NGBlockLayoutAlgorithmTest, ComputeMinMaxContent) { 1170 TEST_F(NGBlockLayoutAlgorithmTest, ComputeMinMaxContent) {
808 const int kWidth = 50; 1171 const int kWidth = 50;
809 const int kWidthChild1 = 20; 1172 const int kWidthChild1 = 20;
810 const int kWidthChild2 = 30; 1173 const int kWidthChild2 = 30;
811 1174
812 // This should have no impact on the min/max content size. 1175 // This should have no impact on the min/max content size.
813 style_->setWidth(Length(kWidth, Fixed)); 1176 style_->setWidth(Length(kWidth, Fixed));
(...skipping 749 matching lines...) Expand 10 before | Expand all | Expand 10 after
1563 EXPECT_EQ(LayoutUnit(194), fragment->LeftOffset()); 1926 EXPECT_EQ(LayoutUnit(194), fragment->LeftOffset());
1564 EXPECT_EQ(LayoutUnit(), fragment->TopOffset()); 1927 EXPECT_EQ(LayoutUnit(), fragment->TopOffset());
1565 EXPECT_EQ(LayoutUnit(16), fragment->Width()); 1928 EXPECT_EQ(LayoutUnit(16), fragment->Width());
1566 EXPECT_EQ(LayoutUnit(50), fragment->Height()); 1929 EXPECT_EQ(LayoutUnit(50), fragment->Height());
1567 EXPECT_EQ(0UL, fragment->Children().size()); 1930 EXPECT_EQ(0UL, fragment->Children().size());
1568 EXPECT_FALSE(iterator.NextChild()); 1931 EXPECT_FALSE(iterator.NextChild());
1569 } 1932 }
1570 1933
1571 } // namespace 1934 } // namespace
1572 } // namespace blink 1935 } // namespace blink
OLDNEW
« no previous file with comments | « no previous file | third_party/WebKit/Source/core/layout/ng/ng_units.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698