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

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