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

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

Issue 2711803007: Add ClearanceOffset to LayoutNG Constraint space. (Closed)
Patch Set: 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
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/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 23 matching lines...) Expand all
34 FromPlatformWritingMode(child_style.getWritingMode()); 34 FromPlatformWritingMode(child_style.getWritingMode());
35 // Whether the child and the containing block are parallel to each other. 35 // Whether the child and the containing block are parallel to each other.
36 // Example: vertical-rl and vertical-lr 36 // Example: vertical-rl and vertical-lr
37 bool is_in_parallel_flow = 37 bool is_in_parallel_flow =
38 IsParallelWritingMode(parent_space.WritingMode(), child_writing_mode); 38 IsParallelWritingMode(parent_space.WritingMode(), child_writing_mode);
39 39
40 return child_style.display() == EDisplay::InlineBlock || 40 return child_style.display() == EDisplay::InlineBlock ||
41 child_style.isFloating() || !is_in_parallel_flow; 41 child_style.isFloating() || !is_in_parallel_flow;
42 } 42 }
43 43
44 // Updates the fragment's BFC offset if it's not already set. 44 // Returns max of 2 {@code WTF::Optional} values.
45 void UpdateFragmentBfcOffset(const NGLogicalOffset& offset, 45 template <typename T>
46 NGFragmentBuilder* builder) { 46 WTF::Optional<T> OptionalMax(const WTF::Optional<T>& value1,
47 if (!builder->BfcOffset()) 47 const WTF::Optional<T>& value2) {
48 builder->SetBfcOffset(offset); 48 if (value1 && value2) {
49 return std::max(value1.value(), value2.value());
50 } else if (value1) {
51 return value1;
52 }
53 return value2;
49 } 54 }
50 55
51 // Adjusts content_size to respect the CSS "clear" property. 56 WTF::Optional<LayoutUnit> GetClearanceOffset(
52 // Picks up the maximum between left/right exclusions and content_size depending 57 const std::shared_ptr<NGExclusions>& exclusions,
53 // on the value of style.clear() property. 58 const ComputedStyle& style) {
54 void AdjustToClearance(const std::shared_ptr<NGExclusions>& exclusions,
55 const ComputedStyle& style,
56 const NGLogicalOffset& from_offset,
57 LayoutUnit* content_size) {
58 DCHECK(content_size) << "content_size cannot be null here";
59 const NGExclusion* right_exclusion = exclusions->last_right_float; 59 const NGExclusion* right_exclusion = exclusions->last_right_float;
60 const NGExclusion* left_exclusion = exclusions->last_left_float; 60 const NGExclusion* left_exclusion = exclusions->last_left_float;
61 61
62 LayoutUnit left_block_end_offset = *content_size; 62 WTF::Optional<LayoutUnit> left_offset;
63 if (left_exclusion) { 63 if (left_exclusion) {
64 left_block_end_offset = std::max( 64 left_offset = left_exclusion->rect.BlockEndOffset();
65 left_exclusion->rect.BlockEndOffset() - from_offset.block_offset,
66 *content_size);
67 } 65 }
68 LayoutUnit right_block_end_offset = *content_size; 66 WTF::Optional<LayoutUnit> right_offset;
69 if (right_exclusion) { 67 if (right_exclusion) {
70 right_block_end_offset = std::max( 68 right_offset = right_exclusion->rect.BlockEndOffset();
71 right_exclusion->rect.BlockEndOffset() - from_offset.block_offset,
72 *content_size);
73 } 69 }
74 70
75 switch (style.clear()) { 71 switch (style.clear()) {
76 case EClear::kNone: 72 case EClear::kNone:
77 return; // nothing to do here. 73 return WTF::nullopt; // nothing to do here.
78 case EClear::kLeft: 74 case EClear::kLeft:
79 *content_size = left_block_end_offset; 75 return left_offset;
80 break;
81 case EClear::kRight: 76 case EClear::kRight:
82 *content_size = right_block_end_offset; 77 return right_offset;
83 break;
84 case EClear::kBoth: 78 case EClear::kBoth:
85 *content_size = std::max(left_block_end_offset, right_block_end_offset); 79 return OptionalMax<LayoutUnit>(left_offset, right_offset);
86 break;
87 default: 80 default:
88 ASSERT_NOT_REACHED(); 81 ASSERT_NOT_REACHED();
89 } 82 }
83 return WTF::nullopt;
90 } 84 }
91 85
92 // Creates an exclusion from the fragment that will be placed in the provided 86 // Creates an exclusion from the fragment that will be placed in the provided
93 // layout opportunity. 87 // layout opportunity.
94 NGExclusion CreateExclusion(const NGFragment& fragment, 88 NGExclusion CreateExclusion(const NGFragment& fragment,
95 const NGLayoutOpportunity& opportunity, 89 const NGLayoutOpportunity& opportunity,
96 const LayoutUnit float_offset, 90 const LayoutUnit float_offset,
97 const NGBoxStrut& margins, 91 const NGBoxStrut& margins,
98 NGExclusion::Type exclusion_type) { 92 NGExclusion::Type exclusion_type) {
99 NGExclusion exclusion; 93 NGExclusion exclusion;
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after
410 } 404 }
411 405
412 curr_margin_strut_ = ConstraintSpace().MarginStrut(); 406 curr_margin_strut_ = ConstraintSpace().MarginStrut();
413 curr_bfc_offset_ = ConstraintSpace().BfcOffset(); 407 curr_bfc_offset_ = ConstraintSpace().BfcOffset();
414 408
415 // Margins collapsing: 409 // Margins collapsing:
416 // Do not collapse margins between parent and its child if there is 410 // Do not collapse margins between parent and its child if there is
417 // border/padding between them. 411 // border/padding between them.
418 if (border_and_padding_.block_start) { 412 if (border_and_padding_.block_start) {
419 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); 413 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
420 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); 414 UpdateFragmentBfcOffset(curr_bfc_offset_);
421 curr_margin_strut_ = NGMarginStrut(); 415 curr_margin_strut_ = NGMarginStrut();
422 } 416 }
423 417
424 // Block that establishes a new BFC knows its BFC offset == {} 418 // Block that establishes a new BFC knows its BFC offset == {}
425 // If a new formatting context hits the if branch above then the BFC offset is 419 // If a new formatting context hits the if branch above then the BFC offset is
426 // still {} as the margin strut from the constraint space must also be empty. 420 // still {} as the margin strut from the constraint space must also be empty.
427 if (ConstraintSpace().IsNewFormattingContext()) { 421 if (ConstraintSpace().IsNewFormattingContext()) {
428 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); 422 UpdateFragmentBfcOffset(curr_bfc_offset_);
429 DCHECK_EQ(builder_->BfcOffset().value(), NGLogicalOffset()); 423 DCHECK_EQ(builder_->BfcOffset().value(), NGLogicalOffset());
430 DCHECK_EQ(curr_margin_strut_, NGMarginStrut()); 424 DCHECK_EQ(curr_margin_strut_, NGMarginStrut());
431 } 425 }
432 426
433 curr_bfc_offset_.block_offset += content_size_; 427 curr_bfc_offset_.block_offset += content_size_;
434 428
435 while (current_child_) { 429 while (current_child_) {
436 if (current_child_->Type() == NGLayoutInputNode::kLegacyBlock) { 430 if (current_child_->Type() == NGLayoutInputNode::kLegacyBlock) {
437 NGBlockNode* current_block_child = toNGBlockNode(current_child_); 431 NGBlockNode* current_block_child = toNGBlockNode(current_child_);
438 EPosition position = current_block_child->Style().position(); 432 EPosition position = current_block_child->Style().position();
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
477 block_size = 471 block_size =
478 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); 472 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_);
479 builder_->SetBlockSize(block_size); 473 builder_->SetBlockSize(block_size);
480 474
481 // Layout our absolute and fixed positioned children. 475 // Layout our absolute and fixed positioned children.
482 NGOutOfFlowLayoutPart(Style(), builder_.get()).Run(); 476 NGOutOfFlowLayoutPart(Style(), builder_.get()).Run();
483 477
484 // Non-empty blocks always know their position in space: 478 // Non-empty blocks always know their position in space:
485 if (block_size) { 479 if (block_size) {
486 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); 480 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
487 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); 481 UpdateFragmentBfcOffset(curr_bfc_offset_);
488 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), 482 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(),
489 builder_.get()); 483 builder_.get());
490 } 484 }
491 485
492 // Margins collapsing: 486 // Margins collapsing:
493 // Do not collapse margins between the last in-flow child and bottom margin 487 // Do not collapse margins between the last in-flow child and bottom margin
494 // of its parent if the parent has height != auto() 488 // of its parent if the parent has height != auto()
495 if (!Style().logicalHeight().isAuto()) { 489 if (!Style().logicalHeight().isAuto()) {
496 // TODO(glebl): handle minLogicalHeight, maxLogicalHeight. 490 // TODO(glebl): handle minLogicalHeight, maxLogicalHeight.
497 curr_margin_strut_ = NGMarginStrut(); 491 curr_margin_strut_ = NGMarginStrut();
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 // Fragment doesn't know its offset but we can still calculate its BFC 562 // Fragment doesn't know its offset but we can still calculate its BFC
569 // position because the parent fragment's BFC is known. 563 // position because the parent fragment's BFC is known.
570 // Example: 564 // Example:
571 // BFC Offset is known here because of the padding. 565 // BFC Offset is known here because of the padding.
572 // <div style="padding: 1px"> 566 // <div style="padding: 1px">
573 // <div id="empty-div" style="margins: 1px"></div> 567 // <div id="empty-div" style="margins: 1px"></div>
574 bfc_offset = curr_bfc_offset_; 568 bfc_offset = curr_bfc_offset_;
575 bfc_offset.value().block_offset += curr_margin_strut_.Sum(); 569 bfc_offset.value().block_offset += curr_margin_strut_.Sum();
576 } 570 }
577 if (bfc_offset) { 571 if (bfc_offset) {
578 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); 572 UpdateFragmentBfcOffset(curr_bfc_offset_);
579 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), 573 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(),
580 builder_.get()); 574 builder_.get());
581 } 575 }
582 NGLogicalOffset logical_offset = CalculateLogicalOffset(bfc_offset); 576 NGLogicalOffset logical_offset = CalculateLogicalOffset(bfc_offset);
583 577
584 if (fragmentainer_mapper_) 578 if (fragmentainer_mapper_)
585 fragmentainer_mapper_->ToVisualOffset(logical_offset); 579 fragmentainer_mapper_->ToVisualOffset(logical_offset);
586 else 580 else
587 logical_offset.block_offset -= PreviousBreakOffset(); 581 logical_offset.block_offset -= PreviousBreakOffset();
588 582
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
792 space_builder_->SetIsNewFormattingContext(is_new_bfc) 786 space_builder_->SetIsNewFormattingContext(is_new_bfc)
793 .SetIsShrinkToFit( 787 .SetIsShrinkToFit(
794 ShouldShrinkToFit(ConstraintSpace(), CurrentChildStyle())) 788 ShouldShrinkToFit(ConstraintSpace(), CurrentChildStyle()))
795 .SetTextDirection(current_child_style.direction()); 789 .SetTextDirection(current_child_style.direction());
796 LayoutUnit space_available = SpaceAvailableForCurrentChild(); 790 LayoutUnit space_available = SpaceAvailableForCurrentChild();
797 space_builder_->SetFragmentainerSpaceAvailable(space_available); 791 space_builder_->SetFragmentainerSpaceAvailable(space_available);
798 792
799 // Clearance : 793 // Clearance :
800 // - Collapse margins 794 // - Collapse margins
801 // - Update curr_bfc_offset and parent BFC offset if needed. 795 // - Update curr_bfc_offset and parent BFC offset if needed.
802 // - Position all pending floats as position is known now. 796 // - Position all pending floats since the fragment's BFC offset is known.
803 // TODO(glebl): Fix the use case with clear: left and an intruding right. 797 // - Set the clearance offset on constraint space's builder.
804 // https://software.hixie.ch/utilities/js/live-dom-viewer/saved/4847
805 if (current_child_style.clear() != EClear::kNone) { 798 if (current_child_style.clear() != EClear::kNone) {
806 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); 799 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
ikilpatrick 2017/02/24 17:36:57 Are we able to do this here? I.e. does it handle s
Gleb Lanbin 2017/02/24 18:37:00 thanks for the test case. It works as expected, up
807 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); 800 UpdateFragmentBfcOffset(curr_bfc_offset_);
808 // Only collapse margins if it's an adjoining block with clearance. 801 // Only collapse margins if it's an adjoining block with clearance.
809 if (!content_size_) { 802 if (!content_size_) {
810 curr_margin_strut_ = NGMarginStrut(); 803 curr_margin_strut_ = NGMarginStrut();
811 curr_child_margins_.block_start = LayoutUnit(); 804 curr_child_margins_.block_start = LayoutUnit();
812 } 805 }
813 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), 806 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(),
814 builder_.get()); 807 builder_.get());
815 AdjustToClearance(constraint_space_->Exclusions(), current_child_style, 808 WTF::Optional<LayoutUnit> clearance_offset = GetClearanceOffset(
816 builder_->BfcOffset().value(), &content_size_); 809 constraint_space_->Exclusions(), current_child_style);
810 space_builder_->SetClearanceOffset(clearance_offset);
817 } 811 }
818 812
819 // Set estimated BFC offset to the next child's constraint space. 813 // Set estimated BFC offset to the next child's constraint space.
820 curr_bfc_offset_ = builder_->BfcOffset() ? builder_->BfcOffset().value() 814 curr_bfc_offset_ = builder_->BfcOffset() ? builder_->BfcOffset().value()
821 : ConstraintSpace().BfcOffset(); 815 : ConstraintSpace().BfcOffset();
822 curr_bfc_offset_.block_offset += content_size_; 816 curr_bfc_offset_.block_offset += content_size_;
823 curr_bfc_offset_.inline_offset += border_and_padding_.inline_start; 817 curr_bfc_offset_.inline_offset += border_and_padding_.inline_start;
824 818
825 // Floats margins are not included in child's CS because 819 // Floats margins are not included in child's CS because
826 // 1) Floats do not participate in margins collapsing 820 // 1) Floats do not participate in margins collapsing
827 // 2) Floats margins are used separately to calculate floating exclusions. 821 // 2) Floats margins are used separately to calculate floating exclusions.
828 if (!CurrentChildStyle().isFloating()) { 822 if (!CurrentChildStyle().isFloating()) {
829 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start; 823 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start;
830 // Append the current margin strut with child's block start margin. 824 // Append the current margin strut with child's block start margin.
831 // Non empty border/padding use cases are handled inside of the child's 825 // Non empty border/padding use cases are handled inside of the child's
832 // layout. 826 // layout.
833 curr_margin_strut_.Append(curr_child_margins_.block_start); 827 curr_margin_strut_.Append(curr_child_margins_.block_start);
834 space_builder_->SetMarginStrut(curr_margin_strut_); 828 space_builder_->SetMarginStrut(curr_margin_strut_);
835 } 829 }
836 830
837 space_builder_->SetBfcOffset(curr_bfc_offset_); 831 space_builder_->SetBfcOffset(curr_bfc_offset_);
838 832
839 return space_builder_->ToConstraintSpace( 833 return space_builder_->ToConstraintSpace(
840 FromPlatformWritingMode(current_child_style.getWritingMode())); 834 FromPlatformWritingMode(current_child_style.getWritingMode()));
841 } 835 }
842 836
837 void NGBlockLayoutAlgorithm::UpdateFragmentBfcOffset(
838 const NGLogicalOffset& offset) {
839 if (!builder_->BfcOffset()) {
840 NGLogicalOffset bfc_offset = offset;
841 if (ConstraintSpace().ClearanceOffset()) {
842 bfc_offset.block_offset = std::max(
843 ConstraintSpace().ClearanceOffset().value(), offset.block_offset);
844 }
845 builder_->SetBfcOffset(bfc_offset);
846 }
847 }
848
843 } // namespace blink 849 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698