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_constraint_space.h" | 7 #include "core/layout/ng/ng_constraint_space.h" |
8 #include "core/layout/ng/ng_fragment_builder.h" | 8 #include "core/layout/ng/ng_fragment_builder.h" |
9 #include "core/layout/ng/ng_fragment.h" | 9 #include "core/layout/ng/ng_fragment.h" |
10 #include "core/layout/ng/ng_length_utils.h" | 10 #include "core/layout/ng/ng_length_utils.h" |
(...skipping 11 matching lines...) Expand all Loading... |
22 curr_margin_strut.margin_block_start) - | 22 curr_margin_strut.margin_block_start) - |
23 std::max(prev_margin_strut.negative_margin_block_end.abs(), | 23 std::max(prev_margin_strut.negative_margin_block_end.abs(), |
24 curr_margin_strut.negative_margin_block_start.abs()); | 24 curr_margin_strut.negative_margin_block_start.abs()); |
25 } | 25 } |
26 | 26 |
27 } // namespace | 27 } // namespace |
28 | 28 |
29 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm( | 29 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm( |
30 PassRefPtr<const ComputedStyle> style, | 30 PassRefPtr<const ComputedStyle> style, |
31 NGBox* first_child) | 31 NGBox* first_child) |
32 : style_(style), first_child_(first_child), state_(kStateInit) { | 32 : style_(style), |
| 33 first_child_(first_child), |
| 34 state_(kStateInit), |
| 35 is_fragment_margin_strut_block_start_updated_(false) { |
33 DCHECK(style_); | 36 DCHECK(style_); |
34 } | 37 } |
35 | 38 |
36 bool NGBlockLayoutAlgorithm::Layout(const NGConstraintSpace* constraint_space, | 39 bool NGBlockLayoutAlgorithm::Layout(const NGConstraintSpace* constraint_space, |
37 NGPhysicalFragment** out) { | 40 NGPhysicalFragment** out) { |
38 switch (state_) { | 41 switch (state_) { |
39 case kStateInit: { | 42 case kStateInit: { |
40 border_and_padding_ = | 43 border_and_padding_ = |
41 computeBorders(*style_) + computePadding(*constraint_space, *style_); | 44 computeBorders(*style_) + computePadding(*constraint_space, *style_); |
42 | 45 |
(...skipping 28 matching lines...) Expand all Loading... |
71 case kStateChildLayout: { | 74 case kStateChildLayout: { |
72 if (current_child_) { | 75 if (current_child_) { |
73 NGFragment* fragment; | 76 NGFragment* fragment; |
74 if (!current_child_->Layout(constraint_space_for_children_, &fragment)) | 77 if (!current_child_->Layout(constraint_space_for_children_, &fragment)) |
75 return false; | 78 return false; |
76 NGBoxStrut child_margins = computeMargins( | 79 NGBoxStrut child_margins = computeMargins( |
77 *constraint_space_for_children_, *current_child_->Style(), | 80 *constraint_space_for_children_, *current_child_->Style(), |
78 constraint_space_for_children_->WritingMode(), | 81 constraint_space_for_children_->WritingMode(), |
79 constraint_space_for_children_->Direction()); | 82 constraint_space_for_children_->Direction()); |
80 | 83 |
81 LayoutUnit margin_block_start = CollapseMargins( | 84 LayoutUnit margin_block_start = |
82 *constraint_space, child_margins, fragment->MarginStrut()); | 85 CollapseMargins(*constraint_space, child_margins, *fragment); |
83 | 86 |
84 // TODO(layout-ng): Support auto margins | 87 // TODO(layout-ng): Support auto margins |
85 builder_->AddChild(fragment, | 88 builder_->AddChild(fragment, |
86 NGLogicalOffset(border_and_padding_.inline_start + | 89 NGLogicalOffset(border_and_padding_.inline_start + |
87 child_margins.inline_start, | 90 child_margins.inline_start, |
88 content_size_ + margin_block_start)); | 91 content_size_ + margin_block_start)); |
89 | 92 |
90 content_size_ += fragment->BlockSize() + margin_block_start; | 93 content_size_ += fragment->BlockSize() + margin_block_start; |
91 max_inline_size_ = | 94 max_inline_size_ = |
92 std::max(max_inline_size_, fragment->InlineSize() + | 95 std::max(max_inline_size_, fragment->InlineSize() + |
(...skipping 21 matching lines...) Expand all Loading... |
114 } | 117 } |
115 }; | 118 }; |
116 NOTREACHED(); | 119 NOTREACHED(); |
117 *out = nullptr; | 120 *out = nullptr; |
118 return true; | 121 return true; |
119 } | 122 } |
120 | 123 |
121 LayoutUnit NGBlockLayoutAlgorithm::CollapseMargins( | 124 LayoutUnit NGBlockLayoutAlgorithm::CollapseMargins( |
122 const NGConstraintSpace& space, | 125 const NGConstraintSpace& space, |
123 const NGBoxStrut& margins, | 126 const NGBoxStrut& margins, |
124 const NGMarginStrut& children_margin_strut) { | 127 const NGFragment& fragment) { |
125 // Calculate margin strut for the current child. | 128 // TODO(chrome-layout-team): Do not collapse margins for elements that |
126 NGMarginStrut curr_margin_strut = children_margin_strut; | 129 // establish new block formatting contexts |
| 130 |
| 131 // Zero-height boxes are ignored and do not participate in margin collapsing. |
| 132 bool is_zero_height_box = !fragment.BlockSize() && margins.IsEmpty(); |
| 133 if (is_zero_height_box) |
| 134 return LayoutUnit(); |
| 135 |
| 136 // Create the current child's margin strut from its children's margin strut. |
| 137 NGMarginStrut curr_margin_strut = fragment.MarginStrut(); |
127 | 138 |
128 // Calculate borders and padding for the current child. | 139 // Calculate borders and padding for the current child. |
129 NGBoxStrut borders = computeBorders(*current_child_->Style()); | 140 NGBoxStrut border_and_padding = |
130 NGBoxStrut paddings = computePadding(space, *current_child_->Style()); | 141 computeBorders(*current_child_->Style()) + |
131 LayoutUnit border_and_padding_before = | 142 computePadding(space, *current_child_->Style()); |
132 borders.block_start + paddings.block_start; | |
133 LayoutUnit border_and_padding_after = borders.block_end + paddings.block_end; | |
134 | 143 |
135 // Collapse BLOCK-START margins if there is no padding or border between | 144 // Collapse BLOCK-START margins if there is no padding or border between |
136 // parent (current child) and its first in-flow child. | 145 // parent (current child) and its first in-flow child. |
137 if (border_and_padding_before) { | 146 if (border_and_padding.block_start) { |
138 curr_margin_strut.SetMarginBlockStart(margins.block_start); | 147 curr_margin_strut.SetMarginBlockStart(margins.block_start); |
139 } else { | 148 } else { |
140 curr_margin_strut.AppendMarginBlockStart(margins.block_start); | 149 curr_margin_strut.AppendMarginBlockStart(margins.block_start); |
141 } | 150 } |
142 | 151 |
143 // Collapse BLOCK-END margins if | 152 // Collapse BLOCK-END margins if |
144 // 1) there is no padding or border between parent (current child) and its | 153 // 1) there is no padding or border between parent (current child) and its |
145 // first/last in-flow child | 154 // first/last in-flow child |
146 // 2) parent's logical height is auto. | 155 // 2) parent's logical height is auto. |
147 if (current_child_->Style()->logicalHeight().isAuto() && | 156 if (current_child_->Style()->logicalHeight().isAuto() && |
148 !border_and_padding_after) { | 157 !border_and_padding.block_end) { |
149 curr_margin_strut.AppendMarginBlockEnd(margins.block_end); | 158 curr_margin_strut.AppendMarginBlockEnd(margins.block_end); |
150 } else { | 159 } else { |
151 curr_margin_strut.SetMarginBlockEnd(margins.block_end); | 160 curr_margin_strut.SetMarginBlockEnd(margins.block_end); |
152 } | 161 } |
153 | 162 |
154 // Set the margin strut for the resultant fragment if this is the first or | 163 // Update the parent fragment's margin strut |
155 // last child fragment. | 164 UpdateMarginStrut(curr_margin_strut); |
156 if (current_child_ == first_child_) | |
157 builder_->SetMarginStrutBlockStart(curr_margin_strut); | |
158 if (!current_child_->NextSibling()) | |
159 builder_->SetMarginStrutBlockEnd(curr_margin_strut); | |
160 | 165 |
161 // Compute the margin block start for adjoining blocks. | 166 // Compute the margin block start for adjoining blocks. |
162 LayoutUnit margin_block_start; | 167 LayoutUnit margin_block_start; |
163 if (current_child_ != first_child_) | 168 if (is_fragment_margin_strut_block_start_updated_) { |
164 margin_block_start = ComputeCollapsedMarginBlockStart( | 169 margin_block_start = ComputeCollapsedMarginBlockStart( |
165 prev_child_margin_strut_, curr_margin_strut); | 170 prev_child_margin_strut_, curr_margin_strut); |
166 | 171 } |
167 prev_child_margin_strut_ = curr_margin_strut; | 172 prev_child_margin_strut_ = curr_margin_strut; |
168 // TODO(layout-ng): support other Margin Collapsing use cases, | |
169 // i.e. support 0 height elements etc. | |
170 return margin_block_start; | 173 return margin_block_start; |
171 } | 174 } |
172 | 175 |
| 176 void NGBlockLayoutAlgorithm::UpdateMarginStrut(const NGMarginStrut& from) { |
| 177 if (!is_fragment_margin_strut_block_start_updated_) { |
| 178 builder_->SetMarginStrutBlockStart(from); |
| 179 is_fragment_margin_strut_block_start_updated_ = true; |
| 180 } |
| 181 builder_->SetMarginStrutBlockEnd(from); |
| 182 } |
| 183 |
173 } // namespace blink | 184 } // namespace blink |
OLD | NEW |