OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/layout/ng/ng_block_layout_algorithm.h" | 5 #include "core/layout/ng/ng_block_layout_algorithm.h" |
6 | 6 |
7 #include "core/layout/ng/inline/ng_inline_node.h" | 7 #include "core/layout/ng/inline/ng_inline_node.h" |
8 #include "core/layout/ng/ng_absolute_utils.h" | 8 #include "core/layout/ng/ng_absolute_utils.h" |
9 #include "core/layout/ng/ng_block_child_iterator.h" | 9 #include "core/layout/ng/ng_block_child_iterator.h" |
10 #include "core/layout/ng/ng_constraint_space.h" | 10 #include "core/layout/ng/ng_constraint_space.h" |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, | 231 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, |
232 &container_builder_); | 232 &container_builder_); |
233 DCHECK_EQ(curr_margin_strut_, NGMarginStrut()); | 233 DCHECK_EQ(curr_margin_strut_, NGMarginStrut()); |
234 DCHECK_EQ(container_builder_.BfcOffset().value(), NGLogicalOffset()); | 234 DCHECK_EQ(container_builder_.BfcOffset().value(), NGLogicalOffset()); |
235 curr_bfc_offset_ = {}; | 235 curr_bfc_offset_ = {}; |
236 } | 236 } |
237 | 237 |
238 curr_bfc_offset_.block_offset += content_size_; | 238 curr_bfc_offset_.block_offset += content_size_; |
239 | 239 |
240 while (child) { | 240 while (child) { |
241 // TODO(ikilpatrick): Refactor the inside of this loop. | 241 if (child->IsOutOfFlowPositioned()) { |
242 if (child->IsBlock()) { | 242 DCHECK(!child_break_token); |
243 EPosition position = child->Style().GetPosition(); | 243 HandleOutOfFlowPositioned(ToNGBlockNode(child)); |
244 if (position == EPosition::kAbsolute || position == EPosition::kFixed) { | 244 } else if (child->IsFloating()) { |
245 NGLogicalOffset offset = {border_and_padding_.inline_start, | 245 HandleFloating(ToNGBlockNode(child), |
246 content_size_}; | 246 ToNGBlockBreakToken(child_break_token)); |
247 | |
248 // We only include the margin strut in the OOF static-position if we | |
249 // know we aren't going to be a zero-block-size fragment. | |
250 if (container_builder_.BfcOffset()) | |
251 offset.block_offset += curr_margin_strut_.Sum(); | |
252 | |
253 container_builder_.AddOutOfFlowChildCandidate(ToNGBlockNode(child), | |
254 offset); | |
255 NGBlockChildIterator::Entry entry = child_iterator.NextChild(); | |
256 child = entry.node; | |
257 child_break_token = entry.token; | |
258 continue; | |
259 } | |
260 } | |
261 | |
262 NGLogicalOffset child_bfc_offset = PrepareChildLayout(child); | |
263 | |
264 if (child->IsFloating()) { | |
265 FinishFloatChildLayout(child->Style(), ToNGBlockNode(child), | |
266 ToNGBlockBreakToken(child_break_token)); | |
267 } else { | 247 } else { |
| 248 NGLogicalOffset child_bfc_offset = PrepareChildLayout(child); |
268 RefPtr<NGConstraintSpace> child_space = | 249 RefPtr<NGConstraintSpace> child_space = |
269 CreateConstraintSpaceForChild(child_bfc_offset, *child); | 250 CreateConstraintSpaceForChild(child_bfc_offset, *child); |
270 RefPtr<NGLayoutResult> layout_result = | 251 RefPtr<NGLayoutResult> layout_result = |
271 child->Layout(child_space.Get(), child_break_token); | 252 child->Layout(child_space.Get(), child_break_token); |
272 FinishChildLayout(*child_space, child, layout_result.Get()); | 253 FinishChildLayout(*child_space, child, layout_result.Get()); |
273 } | 254 } |
274 | 255 |
275 entry = child_iterator.NextChild(); | 256 entry = child_iterator.NextChild(); |
276 child = entry.node; | 257 child = entry.node; |
277 child_break_token = entry.token; | 258 child_break_token = entry.token; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 // We only finalize for fragmentation if the fragment has a BFC offset. This | 305 // We only finalize for fragmentation if the fragment has a BFC offset. This |
325 // may occur with a zero block size fragment. We need to know the BFC offset | 306 // may occur with a zero block size fragment. We need to know the BFC offset |
326 // to determine where the fragmentation line is relative to us. | 307 // to determine where the fragmentation line is relative to us. |
327 if (container_builder_.BfcOffset() && | 308 if (container_builder_.BfcOffset() && |
328 ConstraintSpace().HasBlockFragmentation()) | 309 ConstraintSpace().HasBlockFragmentation()) |
329 FinalizeForFragmentation(); | 310 FinalizeForFragmentation(); |
330 | 311 |
331 return container_builder_.ToBoxFragment(); | 312 return container_builder_.ToBoxFragment(); |
332 } | 313 } |
333 | 314 |
| 315 void NGBlockLayoutAlgorithm::HandleOutOfFlowPositioned(NGBlockNode* child) { |
| 316 NGLogicalOffset offset = {border_and_padding_.inline_start, content_size_}; |
| 317 |
| 318 // We only include the margin strut in the OOF static-position if we know we |
| 319 // aren't going to be a zero-block-size fragment. |
| 320 if (container_builder_.BfcOffset()) |
| 321 offset.block_offset += curr_margin_strut_.Sum(); |
| 322 |
| 323 container_builder_.AddOutOfFlowChildCandidate(child, offset); |
| 324 } |
| 325 |
| 326 void NGBlockLayoutAlgorithm::HandleFloating(NGBlockNode* child, |
| 327 NGBlockBreakToken* token) { |
| 328 // TODO(ikilpatrick): Pass in BFC offset from previous in-flow child. |
| 329 curr_bfc_offset_ = container_builder_.BfcOffset() |
| 330 ? container_builder_.BfcOffset().value() |
| 331 : ConstraintSpace().BfcOffset(); |
| 332 curr_bfc_offset_.block_offset += content_size_; |
| 333 |
| 334 // Calculate margins in the BFC's writing mode. |
| 335 curr_child_margins_ = CalculateMargins(child); |
| 336 |
| 337 NGLogicalOffset origin_offset = constraint_space_->BfcOffset(); |
| 338 origin_offset.inline_offset += border_and_padding_.inline_start; |
| 339 RefPtr<NGUnpositionedFloat> unpositioned_float = NGUnpositionedFloat::Create( |
| 340 child_available_size_, child_percentage_size_, origin_offset, |
| 341 constraint_space_->BfcOffset(), curr_child_margins_, child, token); |
| 342 container_builder_.AddUnpositionedFloat(unpositioned_float); |
| 343 |
| 344 // If there is a break token for a float we must be resuming layout, we must |
| 345 // always know our position in the BFC. |
| 346 DCHECK(!token || container_builder_.BfcOffset()); |
| 347 |
| 348 // No need to postpone the positioning if we know the correct offset. |
| 349 if (container_builder_.BfcOffset()) { |
| 350 NGLogicalOffset origin_point = curr_bfc_offset_; |
| 351 // Adjust origin point to the margins of the last child. |
| 352 // Example: <div style="margin-bottom: 20px"><float></div> |
| 353 // <div style="margin-bottom: 30px"></div> |
| 354 origin_point.block_offset += curr_margin_strut_.Sum(); |
| 355 PositionPendingFloats(origin_point.block_offset, &container_builder_, |
| 356 MutableConstraintSpace()); |
| 357 } |
| 358 } |
| 359 |
334 NGLogicalOffset NGBlockLayoutAlgorithm::PrepareChildLayout( | 360 NGLogicalOffset NGBlockLayoutAlgorithm::PrepareChildLayout( |
335 NGLayoutInputNode* child) { | 361 NGLayoutInputNode* child) { |
336 DCHECK(child); | 362 DCHECK(child); |
| 363 DCHECK(!child->IsFloating()); |
337 | 364 |
| 365 // TODO(ikilpatrick): Pass in BFC offset from previous in-flow child. |
338 curr_bfc_offset_ = container_builder_.BfcOffset() | 366 curr_bfc_offset_ = container_builder_.BfcOffset() |
339 ? container_builder_.BfcOffset().value() | 367 ? container_builder_.BfcOffset().value() |
340 : ConstraintSpace().BfcOffset(); | 368 : ConstraintSpace().BfcOffset(); |
341 curr_bfc_offset_.block_offset += content_size_; | 369 curr_bfc_offset_.block_offset += content_size_; |
342 | 370 |
343 // Calculate margins in parent's writing mode. | 371 // Calculate margins in parent's writing mode. |
344 curr_child_margins_ = CalculateMargins(child); | 372 curr_child_margins_ = CalculateMargins(child); |
345 | 373 |
346 bool should_position_pending_floats = | 374 bool should_position_pending_floats = |
347 !child->IsFloating() && | |
348 !IsNewFormattingContextForBlockLevelChild(Style(), *child) && | 375 !IsNewFormattingContextForBlockLevelChild(Style(), *child) && |
349 ClearanceMayAffectLayout(ConstraintSpace(), | 376 ClearanceMayAffectLayout(ConstraintSpace(), |
350 container_builder_.UnpositionedFloats(), | 377 container_builder_.UnpositionedFloats(), |
351 child->Style()); | 378 child->Style()); |
352 | 379 |
353 // Children which may clear a float need to force all the pending floats to | 380 // Children which may clear a float need to force all the pending floats to |
354 // be positioned before layout. This also resolves the fragment's bfc offset. | 381 // be positioned before layout. This also resolves the fragment's bfc offset. |
355 if (should_position_pending_floats) { | 382 if (should_position_pending_floats) { |
356 LayoutUnit origin_point_block_offset = | 383 LayoutUnit origin_point_block_offset = |
357 curr_bfc_offset_.block_offset + curr_margin_strut_.Sum(); | 384 curr_bfc_offset_.block_offset + curr_margin_strut_.Sum(); |
358 MaybeUpdateFragmentBfcOffset( | 385 MaybeUpdateFragmentBfcOffset( |
359 ConstraintSpace(), | 386 ConstraintSpace(), |
360 {curr_bfc_offset_.inline_offset, origin_point_block_offset}, | 387 {curr_bfc_offset_.inline_offset, origin_point_block_offset}, |
361 &container_builder_); | 388 &container_builder_); |
362 PositionPendingFloats(origin_point_block_offset, &container_builder_, | 389 PositionPendingFloats(origin_point_block_offset, &container_builder_, |
363 MutableConstraintSpace()); | 390 MutableConstraintSpace()); |
364 } | 391 } |
365 | 392 |
366 bool is_inflow = child->IsInline() || !child->IsFloating(); | 393 NGLogicalOffset child_bfc_offset = curr_bfc_offset_; |
| 394 child_bfc_offset.inline_offset += |
| 395 {border_and_padding_.inline_start + curr_child_margins_.inline_start}; |
367 | 396 |
368 NGLogicalOffset child_bfc_offset = curr_bfc_offset_; | 397 // Append the current margin strut with child's block start margin. |
369 child_bfc_offset.inline_offset += border_and_padding_.inline_start; | 398 // Non empty border/padding, and new FC use cases are handled inside of the |
370 // Only inflow children (e.g. not floats) are included in the child's margin | 399 // child's layout. |
371 // strut as they do not participate in margin collapsing. | 400 if (!IsNewFormattingContextForBlockLevelChild(Style(), *child)) |
372 if (is_inflow) { | 401 curr_margin_strut_.Append(curr_child_margins_.block_start); |
373 child_bfc_offset.inline_offset += curr_child_margins_.inline_start; | |
374 // Append the current margin strut with child's block start margin. | |
375 // Non empty border/padding, and new FC use cases are handled inside of the | |
376 // child's layout. | |
377 if (!IsNewFormattingContextForBlockLevelChild(Style(), *child)) | |
378 curr_margin_strut_.Append(curr_child_margins_.block_start); | |
379 } | |
380 | 402 |
381 // TODO(crbug.com/716930): We should also collapse margins below once we | 403 // TODO(crbug.com/716930): We should also collapse margins below once we |
382 // remove LayoutInline splitting. | 404 // remove LayoutInline splitting. |
383 | 405 |
384 // Should collapse margins if our child is a legacy block. | 406 // Should collapse margins if our child is a legacy block. |
385 if (IsLegacyBlock(*child)) { | 407 if (IsLegacyBlock(*child)) { |
386 curr_bfc_offset_ += | 408 curr_bfc_offset_ += |
387 {border_and_padding_.inline_start + curr_child_margins_.inline_start, | 409 {border_and_padding_.inline_start + curr_child_margins_.inline_start, |
388 curr_margin_strut_.Sum()}; | 410 curr_margin_strut_.Sum()}; |
389 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, | 411 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 &container_builder_, MutableConstraintSpace()); | 544 &container_builder_, MutableConstraintSpace()); |
523 return curr_bfc_offset_; | 545 return curr_bfc_offset_; |
524 } | 546 } |
525 | 547 |
526 NGLogicalOffset NGBlockLayoutAlgorithm::PositionLegacy( | 548 NGLogicalOffset NGBlockLayoutAlgorithm::PositionLegacy( |
527 const NGConstraintSpace& child_space) { | 549 const NGConstraintSpace& child_space) { |
528 AdjustToClearance(child_space.ClearanceOffset(), &curr_bfc_offset_); | 550 AdjustToClearance(child_space.ClearanceOffset(), &curr_bfc_offset_); |
529 return curr_bfc_offset_; | 551 return curr_bfc_offset_; |
530 } | 552 } |
531 | 553 |
532 void NGBlockLayoutAlgorithm::FinishFloatChildLayout( | |
533 const ComputedStyle& child_style, | |
534 NGBlockNode* child, | |
535 NGBlockBreakToken* token) { | |
536 NGLogicalOffset origin_offset = constraint_space_->BfcOffset(); | |
537 origin_offset.inline_offset += border_and_padding_.inline_start; | |
538 RefPtr<NGUnpositionedFloat> unpositioned_float = NGUnpositionedFloat::Create( | |
539 child_available_size_, child_percentage_size_, origin_offset, | |
540 constraint_space_->BfcOffset(), curr_child_margins_, child, token); | |
541 container_builder_.AddUnpositionedFloat(unpositioned_float); | |
542 | |
543 // If there is a break token for a float we must be resuming layout, we must | |
544 // always know our position in the BFC. | |
545 DCHECK(!token || container_builder_.BfcOffset()); | |
546 | |
547 // No need to postpone the positioning if we know the correct offset. | |
548 if (container_builder_.BfcOffset()) { | |
549 NGLogicalOffset origin_point = curr_bfc_offset_; | |
550 // Adjust origin point to the margins of the last child. | |
551 // Example: <div style="margin-bottom: 20px"><float></div> | |
552 // <div style="margin-bottom: 30px"></div> | |
553 origin_point.block_offset += curr_margin_strut_.Sum(); | |
554 PositionPendingFloats(origin_point.block_offset, &container_builder_, | |
555 MutableConstraintSpace()); | |
556 } | |
557 } | |
558 | |
559 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() { | 554 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() { |
560 LayoutUnit used_block_size = | 555 LayoutUnit used_block_size = |
561 BreakToken() ? BreakToken()->UsedBlockSize() : LayoutUnit(); | 556 BreakToken() ? BreakToken()->UsedBlockSize() : LayoutUnit(); |
562 LayoutUnit block_size = ComputeBlockSizeForFragment( | 557 LayoutUnit block_size = ComputeBlockSizeForFragment( |
563 ConstraintSpace(), Style(), used_block_size + content_size_); | 558 ConstraintSpace(), Style(), used_block_size + content_size_); |
564 | 559 |
565 block_size -= used_block_size; | 560 block_size -= used_block_size; |
566 DCHECK_GE(block_size, LayoutUnit()) | 561 DCHECK_GE(block_size, LayoutUnit()) |
567 << "Adding and subtracting the used_block_size shouldn't leave the " | 562 << "Adding and subtracting the used_block_size shouldn't leave the " |
568 "block_size for this fragment smaller than zero."; | 563 "block_size for this fragment smaller than zero."; |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
626 RefPtr<NGConstraintSpace> NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild( | 621 RefPtr<NGConstraintSpace> NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild( |
627 const NGLogicalOffset& child_bfc_offset, | 622 const NGLogicalOffset& child_bfc_offset, |
628 const NGLayoutInputNode& child) { | 623 const NGLayoutInputNode& child) { |
629 NGConstraintSpaceBuilder space_builder(MutableConstraintSpace()); | 624 NGConstraintSpaceBuilder space_builder(MutableConstraintSpace()); |
630 space_builder.SetAvailableSize(child_available_size_) | 625 space_builder.SetAvailableSize(child_available_size_) |
631 .SetPercentageResolutionSize(child_percentage_size_); | 626 .SetPercentageResolutionSize(child_percentage_size_); |
632 | 627 |
633 const ComputedStyle& child_style = child.Style(); | 628 const ComputedStyle& child_style = child.Style(); |
634 bool is_new_bfc = IsNewFormattingContextForBlockLevelChild(Style(), child); | 629 bool is_new_bfc = IsNewFormattingContextForBlockLevelChild(Style(), child); |
635 space_builder.SetIsNewFormattingContext(is_new_bfc) | 630 space_builder.SetIsNewFormattingContext(is_new_bfc) |
636 .SetBfcOffset(child_bfc_offset); | 631 .SetBfcOffset(child_bfc_offset) |
637 | 632 .SetMarginStrut(curr_margin_strut_); |
638 // Float's margins are not included in child's space because: | |
639 // 1) Floats do not participate in margins collapsing. | |
640 // 2) Floats margins are used separately to calculate floating exclusions. | |
641 space_builder.SetMarginStrut(child.IsFloating() ? NGMarginStrut() | |
642 : curr_margin_strut_); | |
643 | 633 |
644 if (!is_new_bfc) { | 634 if (!is_new_bfc) { |
645 space_builder.SetUnpositionedFloats( | 635 space_builder.SetUnpositionedFloats( |
646 container_builder_.MutableUnpositionedFloats()); | 636 container_builder_.MutableUnpositionedFloats()); |
647 } | 637 } |
648 | 638 |
649 if (child.IsInline()) { | 639 if (child.IsInline()) { |
650 // TODO(kojii): Setup space_builder appropriately for inline child. | 640 // TODO(kojii): Setup space_builder appropriately for inline child. |
651 space_builder.SetClearanceOffset(ConstraintSpace().ClearanceOffset()); | 641 space_builder.SetClearanceOffset(ConstraintSpace().ClearanceOffset()); |
652 return space_builder.ToConstraintSpace( | 642 return space_builder.ToConstraintSpace( |
(...skipping 15 matching lines...) Expand all Loading... |
668 if (is_new_bfc) { | 658 if (is_new_bfc) { |
669 space_available -= child_bfc_offset.block_offset; | 659 space_available -= child_bfc_offset.block_offset; |
670 } | 660 } |
671 } | 661 } |
672 space_builder.SetFragmentainerSpaceAvailable(space_available); | 662 space_builder.SetFragmentainerSpaceAvailable(space_available); |
673 | 663 |
674 return space_builder.ToConstraintSpace( | 664 return space_builder.ToConstraintSpace( |
675 FromPlatformWritingMode(child_style.GetWritingMode())); | 665 FromPlatformWritingMode(child_style.GetWritingMode())); |
676 } | 666 } |
677 } // namespace blink | 667 } // namespace blink |
OLD | NEW |