OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/layout/ng/ng_block_layout_algorithm.h" | 5 #include "core/layout/ng/ng_block_layout_algorithm.h" |
6 | 6 |
7 #include "core/layout/ng/ng_absolute_utils.h" | 7 #include "core/layout/ng/ng_absolute_utils.h" |
8 #include "core/layout/ng/ng_block_break_token.h" | 8 #include "core/layout/ng/ng_block_break_token.h" |
9 #include "core/layout/ng/ng_box_fragment.h" | 9 #include "core/layout/ng/ng_box_fragment.h" |
10 #include "core/layout/ng/ng_column_mapper.h" | 10 #include "core/layout/ng/ng_column_mapper.h" |
(...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
411 content_size_ = border_and_padding_.block_start; | 411 content_size_ = border_and_padding_.block_start; |
412 current_child_ = first_child_; | 412 current_child_ = first_child_; |
413 } | 413 } |
414 | 414 |
415 curr_margin_strut_ = ConstraintSpace().MarginStrut(); | 415 curr_margin_strut_ = ConstraintSpace().MarginStrut(); |
416 curr_bfc_offset_ = ConstraintSpace().BfcOffset(); | 416 curr_bfc_offset_ = ConstraintSpace().BfcOffset(); |
417 | 417 |
418 // Margins collapsing: | 418 // Margins collapsing: |
419 // Do not collapse margins between parent and its child if there is | 419 // Do not collapse margins between parent and its child if there is |
420 // border/padding between them. | 420 // border/padding between them. |
421 if (border_and_padding_.block_start || | 421 if (border_and_padding_.block_start) { |
422 ConstraintSpace().IsNewFormattingContext()) { | |
423 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | 422 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
424 builder_->SetBfcOffset(curr_bfc_offset_); | 423 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); |
425 curr_margin_strut_ = NGMarginStrut(); | 424 curr_margin_strut_ = NGMarginStrut(); |
426 } | 425 } |
| 426 |
| 427 // Block that establishes a new BFC knows its BFC offset == {} |
| 428 // If a new formatting context hits the if branch above then the BFC offset is |
| 429 // still {} as the margin strut from the constraint space must also be empty. |
| 430 if (ConstraintSpace().IsNewFormattingContext()) { |
| 431 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); |
| 432 DCHECK_EQ(builder_->BfcOffset().value(), NGLogicalOffset()); |
| 433 DCHECK_EQ(curr_margin_strut_, NGMarginStrut()); |
| 434 } |
| 435 |
427 curr_bfc_offset_.block_offset += content_size_; | 436 curr_bfc_offset_.block_offset += content_size_; |
428 | 437 |
429 while (current_child_) { | 438 while (current_child_) { |
430 if (current_child_->Type() == NGLayoutInputNode::kLegacyBlock) { | 439 if (current_child_->Type() == NGLayoutInputNode::kLegacyBlock) { |
431 NGBlockNode* current_block_child = toNGBlockNode(current_child_); | 440 NGBlockNode* current_block_child = toNGBlockNode(current_child_); |
432 EPosition position = current_block_child->Style().position(); | 441 EPosition position = current_block_child->Style().position(); |
433 if (position == EPosition::kAbsolute || position == EPosition::kFixed) { | 442 if (position == EPosition::kAbsolute || position == EPosition::kFixed) { |
434 builder_->AddOutOfFlowChildCandidate(current_block_child, | 443 builder_->AddOutOfFlowChildCandidate(current_block_child, |
435 GetChildSpaceOffset()); | 444 GetChildSpaceOffset()); |
436 current_child_ = current_block_child->NextSibling(); | 445 current_child_ = current_block_child->NextSibling(); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
468 } | 477 } |
469 | 478 |
470 // Recompute the block-axis size now that we know our content size. | 479 // Recompute the block-axis size now that we know our content size. |
471 block_size = | 480 block_size = |
472 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); | 481 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); |
473 builder_->SetBlockSize(block_size); | 482 builder_->SetBlockSize(block_size); |
474 | 483 |
475 // Layout our absolute and fixed positioned children. | 484 // Layout our absolute and fixed positioned children. |
476 NGOutOfFlowLayoutPart(Style(), builder_.get()).Run(); | 485 NGOutOfFlowLayoutPart(Style(), builder_.get()).Run(); |
477 | 486 |
478 // Non empty blocks always know their position in space: | 487 // Non-empty blocks always know their position in space: |
479 if (block_size) { | 488 if (block_size) { |
480 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | 489 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
481 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); | 490 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); |
482 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), | 491 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), |
483 builder_.get()); | 492 builder_.get()); |
484 } | 493 } |
485 | 494 |
486 // Margins collapsing: | 495 // Margins collapsing: |
487 // Do not collapse margins between the last in-flow child and bottom margin | 496 // Do not collapse margins between the last in-flow child and bottom margin |
488 // of its parent if the parent has height != auto() | 497 // of its parent if the parent has height != auto() |
(...skipping 26 matching lines...) Expand all Loading... |
515 line_builder.CopyFragmentDataToLayoutBlockFlow(); | 524 line_builder.CopyFragmentDataToLayoutBlockFlow(); |
516 FinishCurrentChildLayout(child_fragment.get()); | 525 FinishCurrentChildLayout(child_fragment.get()); |
517 current_child_ = nullptr; | 526 current_child_ = nullptr; |
518 } | 527 } |
519 | 528 |
520 void NGBlockLayoutAlgorithm::FinishCurrentChildLayout( | 529 void NGBlockLayoutAlgorithm::FinishCurrentChildLayout( |
521 RefPtr<NGPhysicalBoxFragment> physical_fragment) { | 530 RefPtr<NGPhysicalBoxFragment> physical_fragment) { |
522 NGBoxFragment fragment(ConstraintSpace().WritingMode(), | 531 NGBoxFragment fragment(ConstraintSpace().WritingMode(), |
523 physical_fragment.get()); | 532 physical_fragment.get()); |
524 | 533 |
525 if (!physical_fragment->UnpositionedFloats().isEmpty()) | |
526 DCHECK(!builder_->BfcOffset()) << "Parent BFC offset shouldn't be set here"; | |
527 // Pull out unpositioned floats to the current fragment. This may needed if | 534 // Pull out unpositioned floats to the current fragment. This may needed if |
528 // for example the child fragment could not position its floats because it's | 535 // for example the child fragment could not position its floats because it's |
529 // empty and therefore couldn't determine its position in space. | 536 // empty and therefore couldn't determine its position in space. |
530 builder_->MutableUnpositionedFloats().appendVector( | 537 builder_->MutableUnpositionedFloats().appendVector( |
531 physical_fragment->UnpositionedFloats()); | 538 physical_fragment->UnpositionedFloats()); |
532 | 539 |
533 if (current_child_->Type() == NGLayoutInputNode::kLegacyBlock && | 540 if (current_child_->Type() == NGLayoutInputNode::kLegacyBlock && |
534 CurrentChildStyle().isFloating()) { | 541 CurrentChildStyle().isFloating()) { |
535 NGFloatingObject* floating_object = | 542 NGFloatingObject* floating_object = |
536 new NGFloatingObject(physical_fragment.get(), space_for_current_child_, | 543 new NGFloatingObject(physical_fragment.get(), space_for_current_child_, |
(...skipping 16 matching lines...) Expand all Loading... |
553 // Determine the fragment's position in the parent space either by using | 560 // Determine the fragment's position in the parent space either by using |
554 // content_size_ or known fragment's BFC offset. | 561 // content_size_ or known fragment's BFC offset. |
555 WTF::Optional<NGLogicalOffset> bfc_offset; | 562 WTF::Optional<NGLogicalOffset> bfc_offset; |
556 if (CurrentChildConstraintSpace().IsNewFormattingContext()) { | 563 if (CurrentChildConstraintSpace().IsNewFormattingContext()) { |
557 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | 564 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
558 bfc_offset = curr_bfc_offset_; | 565 bfc_offset = curr_bfc_offset_; |
559 } else if (fragment.BfcOffset()) { | 566 } else if (fragment.BfcOffset()) { |
560 // Fragment that knows its offset can be used to set parent's BFC position. | 567 // Fragment that knows its offset can be used to set parent's BFC position. |
561 curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset; | 568 curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset; |
562 bfc_offset = curr_bfc_offset_; | 569 bfc_offset = curr_bfc_offset_; |
| 570 } else if (builder_->BfcOffset()) { |
| 571 // Fragment doesn't know its offset but we can still calculate its BFC |
| 572 // position because the parent fragment's BFC is known. |
| 573 // Example: |
| 574 // BFC Offset is known here because of the padding. |
| 575 // <div style="padding: 1px"> |
| 576 // <div id="empty-div" style="margins: 1px"></div> |
| 577 bfc_offset = curr_bfc_offset_; |
| 578 bfc_offset.value().block_offset += curr_margin_strut_.Sum(); |
563 } | 579 } |
564 if (bfc_offset) { | 580 if (bfc_offset) { |
565 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); | 581 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); |
566 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), | 582 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), |
567 builder_.get()); | 583 builder_.get()); |
568 } | 584 } |
569 NGLogicalOffset logical_offset = CalculateLogicalOffset(bfc_offset); | 585 NGLogicalOffset logical_offset = CalculateLogicalOffset(bfc_offset); |
570 | 586 |
571 if (fragmentainer_mapper_) | 587 if (fragmentainer_mapper_) |
572 fragmentainer_mapper_->ToVisualOffset(logical_offset); | 588 fragmentainer_mapper_->ToVisualOffset(logical_offset); |
573 else | 589 else |
574 logical_offset.block_offset -= PreviousBreakOffset(); | 590 logical_offset.block_offset -= PreviousBreakOffset(); |
575 | 591 |
576 // Update margin strut. | 592 // Update margin strut. |
577 curr_margin_strut_ = fragment.EndMarginStrut(); | 593 curr_margin_strut_ = fragment.EndMarginStrut(); |
578 curr_margin_strut_.Append(curr_child_margins_.block_end); | 594 curr_margin_strut_.Append(curr_child_margins_.block_end); |
579 | 595 |
580 content_size_ = fragment.BlockSize() + logical_offset.block_offset; | 596 // Only modify content_size if BlockSize is not empty. It's needed to prevent |
| 597 // the situation when logical_offset is included in content_size for empty |
| 598 // blocks. Example: |
| 599 // <div style="overflow:hidden"> |
| 600 // <div style="margin-top: 8px"></div> |
| 601 // <div style="margin-top: 10px"></div> |
| 602 // </div> |
| 603 if (fragment.BlockSize()) |
| 604 content_size_ = fragment.BlockSize() + logical_offset.block_offset; |
581 max_inline_size_ = | 605 max_inline_size_ = |
582 std::max(max_inline_size_, fragment.InlineSize() + | 606 std::max(max_inline_size_, fragment.InlineSize() + |
583 curr_child_margins_.InlineSum() + | 607 curr_child_margins_.InlineSum() + |
584 border_and_padding_.InlineSum()); | 608 border_and_padding_.InlineSum()); |
585 | 609 |
586 builder_->AddChild(std::move(physical_fragment), logical_offset); | 610 builder_->AddChild(std::move(physical_fragment), logical_offset); |
587 } | 611 } |
588 | 612 |
589 bool NGBlockLayoutAlgorithm::ProceedToNextUnfinishedSibling( | 613 bool NGBlockLayoutAlgorithm::ProceedToNextUnfinishedSibling( |
590 NGPhysicalFragment* child_fragment) { | 614 NGPhysicalFragment* child_fragment) { |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
788 if (!content_size_) { | 812 if (!content_size_) { |
789 curr_margin_strut_ = NGMarginStrut(); | 813 curr_margin_strut_ = NGMarginStrut(); |
790 curr_child_margins_.block_start = LayoutUnit(); | 814 curr_child_margins_.block_start = LayoutUnit(); |
791 } | 815 } |
792 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), | 816 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), |
793 builder_.get()); | 817 builder_.get()); |
794 AdjustToClearance(constraint_space_->Exclusions(), current_child_style, | 818 AdjustToClearance(constraint_space_->Exclusions(), current_child_style, |
795 builder_->BfcOffset().value(), &content_size_); | 819 builder_->BfcOffset().value(), &content_size_); |
796 } | 820 } |
797 | 821 |
798 // Append the current margin strut with child's block start margin. | |
799 // Non empty border/padding use cases are handled inside of the child's | |
800 // layout. | |
801 curr_margin_strut_.Append(curr_child_margins_.block_start); | |
802 space_builder_->SetMarginStrut(curr_margin_strut_); | |
803 | |
804 // Set estimated BFC offset to the next child's constraint space. | 822 // Set estimated BFC offset to the next child's constraint space. |
805 curr_bfc_offset_ = builder_->BfcOffset() ? builder_->BfcOffset().value() | 823 curr_bfc_offset_ = builder_->BfcOffset() ? builder_->BfcOffset().value() |
806 : ConstraintSpace().BfcOffset(); | 824 : ConstraintSpace().BfcOffset(); |
807 curr_bfc_offset_.block_offset += content_size_; | 825 curr_bfc_offset_.block_offset += content_size_; |
808 curr_bfc_offset_.inline_offset += border_and_padding_.inline_start; | 826 curr_bfc_offset_.inline_offset += border_and_padding_.inline_start; |
809 | 827 |
810 // Floats margins are not included in child's CS because they are used to | 828 // Floats margins are not included in child's CS because |
811 // calculate floating exclusions. | 829 // 1) Floats do not participate in margins collapsing |
| 830 // 2) Floats margins are used separately to calculate floating exclusions. |
812 if (!CurrentChildStyle().isFloating()) { | 831 if (!CurrentChildStyle().isFloating()) { |
813 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start; | 832 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start; |
| 833 // Append the current margin strut with child's block start margin. |
| 834 // Non empty border/padding use cases are handled inside of the child's |
| 835 // layout. |
| 836 curr_margin_strut_.Append(curr_child_margins_.block_start); |
| 837 space_builder_->SetMarginStrut(curr_margin_strut_); |
814 } | 838 } |
815 | 839 |
816 space_builder_->SetBfcOffset(curr_bfc_offset_); | 840 space_builder_->SetBfcOffset(curr_bfc_offset_); |
817 | 841 |
818 return space_builder_->ToConstraintSpace( | 842 return space_builder_->ToConstraintSpace( |
819 FromPlatformWritingMode(current_child_style.getWritingMode())); | 843 FromPlatformWritingMode(current_child_style.getWritingMode())); |
820 } | 844 } |
821 | 845 |
822 } // namespace blink | 846 } // namespace blink |
OLD | NEW |