| 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 |