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" |
11 #include "core/layout/ng/ng_constraint_space.h" | 11 #include "core/layout/ng/ng_constraint_space.h" |
12 #include "core/layout/ng/ng_constraint_space_builder.h" | 12 #include "core/layout/ng/ng_constraint_space_builder.h" |
13 #include "core/layout/ng/ng_fragment.h" | 13 #include "core/layout/ng/ng_fragment.h" |
14 #include "core/layout/ng/ng_fragment_builder.h" | 14 #include "core/layout/ng/ng_fragment_builder.h" |
15 #include "core/layout/ng/ng_layout_opportunity_iterator.h" | 15 #include "core/layout/ng/ng_layout_opportunity_iterator.h" |
16 #include "core/layout/ng/ng_length_utils.h" | 16 #include "core/layout/ng/ng_length_utils.h" |
17 #include "core/layout/ng/ng_out_of_flow_layout_part.h" | 17 #include "core/layout/ng/ng_out_of_flow_layout_part.h" |
18 #include "core/layout/ng/ng_units.h" | 18 #include "core/layout/ng/ng_units.h" |
19 #include "core/style/ComputedStyle.h" | 19 #include "core/style/ComputedStyle.h" |
20 #include "platform/LengthFunctions.h" | 20 #include "platform/LengthFunctions.h" |
21 #include "wtf/Optional.h" | 21 #include "wtf/Optional.h" |
22 | 22 |
23 namespace blink { | 23 namespace blink { |
24 namespace { | 24 namespace { |
25 | 25 |
26 // Adjusts content's offset to CSS "clear" property. | 26 // Adjusts content_size to CSS "clear" property. |
ikilpatrick
2017/01/30 22:26:48
Adjusts content_size to respect the CSS "clear" pr
Gleb Lanbin
2017/01/31 00:25:02
Done.
| |
27 // TODO(glebl): Support margin collapsing edge cases, e.g. margin collapsing | 27 // Picks up the maximum between left/right exclusions and content_size depending |
28 // should not occur if "clear" is applied to non-floating blocks. | 28 // on the value of style.clear() property. |
29 // TODO(layout-ng): the call to AdjustToClearance should be moved to | 29 void AdjustToClearance(const std::shared_ptr<NGExclusions>& exclusions, |
30 // CreateConstraintSpaceForChild once ConstraintSpaceBuilder is sharing the | |
31 // exclusion information between constraint spaces. | |
32 void AdjustToClearance(const NGConstraintSpace& space, | |
33 const ComputedStyle& style, | 30 const ComputedStyle& style, |
31 const NGLogicalOffset& from_offset, | |
34 LayoutUnit* content_size) { | 32 LayoutUnit* content_size) { |
35 const NGExclusion* right_exclusion = space.Exclusions()->last_right_float; | 33 DCHECK(content_size) << "content_size cannot be null here"; |
36 const NGExclusion* left_exclusion = space.Exclusions()->last_left_float; | 34 const NGExclusion* right_exclusion = exclusions->last_right_float; |
35 const NGExclusion* left_exclusion = exclusions->last_left_float; | |
37 | 36 |
38 // Calculates Left/Right block end offset from left/right float exclusions or | 37 // Exclusions(stored in BFC coordinates), content_size can be negative or 0 |
ikilpatrick
2017/01/30 22:26:48
space between "s("
ikilpatrick
2017/01/30 22:26:49
consider re-wording this line, not sure what it is
Gleb Lanbin
2017/01/31 00:25:02
I also found it's confusing. I tried to rephrase i
| |
39 // use the default content offset position. | 38 // If left or right exclusion are available then convert them to the relative |
40 LayoutUnit left_block_end_offset = | 39 // offset(exclusion.BlockEnd - from_offset) and compare them with content_size |
ikilpatrick
2017/01/30 22:26:48
.nit period.
Gleb Lanbin
2017/01/31 00:25:02
Done.
| |
41 left_exclusion ? left_exclusion->rect.BlockEndOffset() : *content_size; | 40 LayoutUnit left_block_end_offset = *content_size; |
42 LayoutUnit right_block_end_offset = | 41 if (left_exclusion) { |
43 right_exclusion ? right_exclusion->rect.BlockEndOffset() : *content_size; | 42 left_block_end_offset = std::max( |
43 left_exclusion->rect.BlockEndOffset() - from_offset.block_offset, | |
44 *content_size); | |
45 } | |
46 LayoutUnit right_block_end_offset = *content_size; | |
47 if (right_exclusion) { | |
48 right_block_end_offset = std::max( | |
49 right_exclusion->rect.BlockEndOffset() - from_offset.block_offset, | |
50 *content_size); | |
51 } | |
44 | 52 |
45 switch (style.clear()) { | 53 switch (style.clear()) { |
46 case EClear::ClearNone: | 54 case EClear::ClearNone: |
47 return; // nothing to do here. | 55 return; // nothing to do here. |
48 case EClear::ClearLeft: | 56 case EClear::ClearLeft: |
49 *content_size = left_block_end_offset; | 57 *content_size = left_block_end_offset; |
50 break; | 58 break; |
51 case EClear::ClearRight: | 59 case EClear::ClearRight: |
52 *content_size = right_block_end_offset; | 60 *content_size = right_block_end_offset; |
53 break; | 61 break; |
54 case EClear::ClearBoth: | 62 case EClear::ClearBoth: |
55 *content_size = std::max(left_block_end_offset, right_block_end_offset); | 63 *content_size = std::max(left_block_end_offset, right_block_end_offset); |
56 break; | 64 break; |
57 default: | 65 default: |
58 ASSERT_NOT_REACHED(); | 66 ASSERT_NOT_REACHED(); |
59 } | 67 } |
60 } | 68 } |
61 | 69 |
62 LayoutUnit ComputeCollapsedMarginBlockStart( | |
63 const NGDeprecatedMarginStrut& prev_margin_strut, | |
64 const NGDeprecatedMarginStrut& curr_margin_strut) { | |
65 return std::max(prev_margin_strut.margin_block_end, | |
66 curr_margin_strut.margin_block_start) - | |
67 std::max(prev_margin_strut.negative_margin_block_end.abs(), | |
68 curr_margin_strut.negative_margin_block_start.abs()); | |
69 } | |
70 | |
71 // Creates an exclusion from the fragment that will be placed in the provided | 70 // Creates an exclusion from the fragment that will be placed in the provided |
72 // layout opportunity. | 71 // layout opportunity. |
73 NGExclusion CreateExclusion(const NGFragment& fragment, | 72 NGExclusion CreateExclusion(const NGFragment& fragment, |
74 const NGLayoutOpportunity& opportunity, | 73 const NGLayoutOpportunity& opportunity, |
75 LayoutUnit float_offset, | 74 const LayoutUnit float_offset, |
76 NGBoxStrut margins, | 75 const NGBoxStrut& margins, |
77 NGExclusion::Type exclusion_type) { | 76 NGExclusion::Type exclusion_type) { |
78 NGExclusion exclusion; | 77 NGExclusion exclusion; |
79 exclusion.type = exclusion_type; | 78 exclusion.type = exclusion_type; |
80 NGLogicalRect& rect = exclusion.rect; | 79 NGLogicalRect& rect = exclusion.rect; |
81 rect.offset = opportunity.offset; | 80 rect.offset = opportunity.offset; |
82 rect.offset.inline_offset += float_offset; | 81 rect.offset.inline_offset += float_offset; |
83 | 82 |
84 rect.size.inline_size = fragment.InlineSize(); | 83 rect.size.inline_size = fragment.InlineSize() + margins.InlineSum(); |
85 rect.size.block_size = fragment.BlockSize(); | 84 rect.size.block_size = fragment.BlockSize() + margins.BlockSum(); |
85 return exclusion; | |
86 } | |
86 | 87 |
87 // Adjust to child's margin. | 88 // Adjusts the provided offset to the top edge alignment rule. |
88 rect.size.block_size += margins.BlockSum(); | 89 // Top edge alignment rule: the outer top of a floating box may not be higher |
89 rect.size.inline_size += margins.InlineSum(); | 90 // than the outer top of any block or floated box generated by an element |
90 | 91 // earlier in the source document |
ikilpatrick
2017/01/30 22:26:48
.nit period
Gleb Lanbin
2017/01/31 00:25:02
Done.
| |
91 return exclusion; | 92 NGLogicalOffset AdjustToTopEdgeAlignmentRule(const NGConstraintSpace& space, |
93 const NGLogicalOffset& offset) { | |
94 NGLogicalOffset adjusted_offset = offset; | |
95 LayoutUnit& adjusted_block_offset = adjusted_offset.block_offset; | |
96 if (space.Exclusions()->last_left_float) | |
97 adjusted_block_offset = | |
98 std::max(adjusted_block_offset, | |
99 space.Exclusions()->last_left_float->rect.BlockStartOffset()); | |
100 if (space.Exclusions()->last_right_float) | |
101 adjusted_block_offset = | |
102 std::max(adjusted_block_offset, | |
103 space.Exclusions()->last_right_float->rect.BlockStartOffset()); | |
104 return adjusted_offset; | |
92 } | 105 } |
93 | 106 |
94 // Finds a layout opportunity for the fragment. | 107 // Finds a layout opportunity for the fragment. |
95 // It iterates over all layout opportunities in the constraint space and returns | 108 // It iterates over all layout opportunities in the constraint space and returns |
96 // the first layout opportunity that is wider than the fragment or returns the | 109 // the first layout opportunity that is wider than the fragment or returns the |
97 // last one which is always the widest. | 110 // last one which is always the widest. |
98 // | 111 // |
99 // @param space Constraint space that is used to find layout opportunity for | 112 // @param space Constraint space that is used to find layout opportunity for |
100 // the fragment. | 113 // the fragment. |
101 // @param fragment Fragment that needs to be placed. | 114 // @param fragment Fragment that needs to be placed. |
115 // @param origin_point {@code space}'s offset relative to the space that | |
116 // establishes a new formatting context that we're currently | |
117 // in and where all our exclusions reside. | |
102 // @param margins Margins of the fragment. | 118 // @param margins Margins of the fragment. |
103 // @return Layout opportunity for the fragment. | 119 // @return Layout opportunity for the fragment. |
104 const NGLayoutOpportunity FindLayoutOpportunityForFragment( | 120 const NGLayoutOpportunity FindLayoutOpportunityForFragment( |
105 NGConstraintSpace* space, | 121 NGConstraintSpace* space, |
106 const NGFragment& fragment, | 122 const NGFragment& fragment, |
123 const NGLogicalOffset& origin_point, | |
107 const NGBoxStrut& margins) { | 124 const NGBoxStrut& margins) { |
108 NGLayoutOpportunityIterator* opportunity_iter = space->LayoutOpportunities(); | 125 NGLogicalOffset adjusted_origin_point = |
126 AdjustToTopEdgeAlignmentRule(*space, origin_point); | |
127 | |
128 NGLayoutOpportunityIterator* opportunity_iter = | |
129 space->LayoutOpportunities(adjusted_origin_point); | |
109 NGLayoutOpportunity opportunity; | 130 NGLayoutOpportunity opportunity; |
110 NGLayoutOpportunity opportunity_candidate = opportunity_iter->Next(); | 131 NGLayoutOpportunity opportunity_candidate = opportunity_iter->Next(); |
111 | 132 |
112 while (!opportunity_candidate.IsEmpty()) { | 133 while (!opportunity_candidate.IsEmpty()) { |
113 opportunity = opportunity_candidate; | 134 opportunity = opportunity_candidate; |
114 // Checking opportunity's block size is not necessary as a float cannot be | 135 // Checking opportunity's block size is not necessary as a float cannot be |
115 // positioned on top of another float inside of the same constraint space. | 136 // positioned on top of another float inside of the same constraint space. |
116 auto fragment_inline_size = fragment.InlineSize() + margins.InlineSum(); | 137 auto fragment_inline_size = fragment.InlineSize() + margins.InlineSum(); |
117 if (opportunity.size.inline_size > fragment_inline_size) | 138 if (opportunity.size.inline_size >= fragment_inline_size) |
118 break; | 139 break; |
119 | |
120 opportunity_candidate = opportunity_iter->Next(); | 140 opportunity_candidate = opportunity_iter->Next(); |
121 } | 141 } |
122 | |
123 return opportunity; | 142 return opportunity; |
124 } | 143 } |
125 | 144 |
126 // Calculates the logical offset for opportunity. | 145 // Calculates the logical offset for opportunity. |
127 NGLogicalOffset CalculateLogicalOffsetForOpportunity( | 146 NGLogicalOffset CalculateLogicalOffsetForOpportunity( |
128 const NGLayoutOpportunity& opportunity, | 147 const NGLayoutOpportunity& opportunity, |
129 LayoutUnit float_offset, | 148 const LayoutUnit float_offset, |
130 NGBoxStrut margins) { | 149 const NGBoxStrut& margins, |
150 const NGLogicalOffset& space_offset) { | |
131 // Adjust to child's margin. | 151 // Adjust to child's margin. |
132 LayoutUnit inline_offset = margins.inline_start; | 152 LayoutUnit inline_offset = margins.inline_start; |
133 LayoutUnit block_offset = margins.block_start; | 153 LayoutUnit block_offset = margins.block_start; |
134 | 154 |
135 // Offset from the opportunity's block/inline start. | 155 // Offset from the opportunity's block/inline start. |
136 inline_offset += opportunity.offset.inline_offset; | 156 inline_offset += opportunity.offset.inline_offset; |
137 block_offset += opportunity.offset.block_offset; | 157 block_offset += opportunity.offset.block_offset; |
138 | 158 |
139 inline_offset += float_offset; | 159 inline_offset += float_offset; |
140 | 160 |
161 block_offset -= space_offset.block_offset; | |
162 inline_offset -= space_offset.inline_offset; | |
163 | |
141 return NGLogicalOffset(inline_offset, block_offset); | 164 return NGLogicalOffset(inline_offset, block_offset); |
142 } | 165 } |
143 | 166 |
167 // Calculates the relative position from {@code from_offset} of the | |
168 // floating object that is requested to be positioned from {@code origin_point}. | |
169 NGLogicalOffset PositionFloat(const NGLogicalOffset& origin_point, | |
170 const NGLogicalOffset& from_offset, | |
171 NGFloatingObject* floating_object) { | |
172 NGConstraintSpace* float_space = floating_object->space; | |
173 DCHECK(floating_object->fragment) << "Fragment cannot be null here"; | |
174 NGBoxFragment* float_fragment = | |
175 new NGBoxFragment(float_space->WritingMode(), float_space->Direction(), | |
176 toNGPhysicalBoxFragment(floating_object->fragment)); | |
177 // Find a layout opportunity that will fit our float. | |
178 const NGLayoutOpportunity opportunity = | |
179 FindLayoutOpportunityForFragment(floating_object->space, *float_fragment, | |
180 origin_point, floating_object->margins); | |
181 DCHECK(!opportunity.IsEmpty()) << "Opportunity is empty but it shouldn't be"; | |
182 | |
183 // Calculate the float offset if needed. | |
184 LayoutUnit float_offset; | |
185 if (floating_object->exclusion_type == NGExclusion::kFloatRight) { | |
186 float_offset = opportunity.size.inline_size - float_fragment->InlineSize(); | |
187 } | |
188 | |
189 // Add the float as an exclusion. | |
190 const NGExclusion exclusion = CreateExclusion( | |
191 *float_fragment, opportunity, float_offset, floating_object->margins, | |
192 floating_object->exclusion_type); | |
193 float_space->AddExclusion(exclusion); | |
194 | |
195 return CalculateLogicalOffsetForOpportunity( | |
196 opportunity, float_offset, floating_object->margins, from_offset); | |
197 } | |
198 | |
199 // Positions pending floats stored on the fragment builder starting from | |
200 // {@code origin_point}. | |
201 void PositionPendingFloats(const NGLogicalOffset& origin_point, | |
202 NGFragmentBuilder* builder) { | |
203 DCHECK(builder->BfcOffset()) << "Parent BFC offset should be known here"; | |
204 NGLogicalOffset from_offset = builder->BfcOffset().value(); | |
205 | |
206 for (auto& floating_object : builder->UnpositionedFloats()) { | |
207 NGLogicalOffset float_fragment_offset = | |
208 PositionFloat(origin_point, from_offset, floating_object); | |
209 builder->AddFloatingObject(floating_object, float_fragment_offset); | |
210 } | |
211 builder->MutableUnpositionedFloats().clear(); | |
212 } | |
213 | |
144 // Whether an in-flow block-level child creates a new formatting context. | 214 // Whether an in-flow block-level child creates a new formatting context. |
145 // | 215 // |
146 // This will *NOT* check the following cases: | 216 // This will *NOT* check the following cases: |
147 // - The child is out-of-flow, e.g. floating or abs-pos. | 217 // - The child is out-of-flow, e.g. floating or abs-pos. |
148 // - The child is a inline-level, e.g. "display: inline-block". | 218 // - The child is a inline-level, e.g. "display: inline-block". |
149 // - The child establishes a new formatting context, but should be a child of | 219 // - The child establishes a new formatting context, but should be a child of |
150 // another layout algorithm, e.g. "display: table-caption" or flex-item. | 220 // another layout algorithm, e.g. "display: table-caption" or flex-item. |
151 bool IsNewFormattingContextForInFlowBlockLevelChild( | 221 bool IsNewFormattingContextForInFlowBlockLevelChild( |
152 const NGConstraintSpace& space, | 222 const NGConstraintSpace& space, |
153 const ComputedStyle& style) { | 223 const ComputedStyle& style) { |
(...skipping 29 matching lines...) Expand all Loading... | |
183 PassRefPtr<const ComputedStyle> style, | 253 PassRefPtr<const ComputedStyle> style, |
184 NGBlockNode* first_child, | 254 NGBlockNode* first_child, |
185 NGConstraintSpace* constraint_space, | 255 NGConstraintSpace* constraint_space, |
186 NGBreakToken* break_token) | 256 NGBreakToken* break_token) |
187 : NGLayoutAlgorithm(kBlockLayoutAlgorithm), | 257 : NGLayoutAlgorithm(kBlockLayoutAlgorithm), |
188 style_(style), | 258 style_(style), |
189 first_child_(first_child), | 259 first_child_(first_child), |
190 constraint_space_(constraint_space), | 260 constraint_space_(constraint_space), |
191 break_token_(break_token), | 261 break_token_(break_token), |
192 builder_(new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox, | 262 builder_(new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox, |
193 layout_object)), | 263 layout_object)) { |
194 is_fragment_margin_strut_block_start_updated_(false) { | |
195 DCHECK(style_); | 264 DCHECK(style_); |
196 } | 265 } |
197 | 266 |
198 bool NGBlockLayoutAlgorithm::ComputeMinAndMaxContentSizes( | 267 bool NGBlockLayoutAlgorithm::ComputeMinAndMaxContentSizes( |
199 MinAndMaxContentSizes* sizes) const { | 268 MinAndMaxContentSizes* sizes) const { |
200 sizes->min_content = LayoutUnit(); | 269 sizes->min_content = LayoutUnit(); |
201 sizes->max_content = LayoutUnit(); | 270 sizes->max_content = LayoutUnit(); |
202 | 271 |
203 // Size-contained elements don't consider their contents for intrinsic sizing. | 272 // Size-contained elements don't consider their contents for intrinsic sizing. |
204 if (Style().containsSize()) | 273 if (Style().containsSize()) |
(...skipping 10 matching lines...) Expand all Loading... | |
215 ComputeMinAndMaxContentContribution(*node->Style(), child_minmax); | 284 ComputeMinAndMaxContentContribution(*node->Style(), child_minmax); |
216 | 285 |
217 sizes->min_content = std::max(sizes->min_content, child_sizes.min_content); | 286 sizes->min_content = std::max(sizes->min_content, child_sizes.min_content); |
218 sizes->max_content = std::max(sizes->max_content, child_sizes.max_content); | 287 sizes->max_content = std::max(sizes->max_content, child_sizes.max_content); |
219 } | 288 } |
220 | 289 |
221 sizes->max_content = std::max(sizes->min_content, sizes->max_content); | 290 sizes->max_content = std::max(sizes->min_content, sizes->max_content); |
222 return true; | 291 return true; |
223 } | 292 } |
224 | 293 |
294 NGLogicalOffset NGBlockLayoutAlgorithm::PositionFragmentWithKnownBfcOffset( | |
ikilpatrick
2017/01/30 22:26:48
It might be worth just placing this function inlin
Gleb Lanbin
2017/01/31 00:25:02
PTAL
| |
295 const NGLogicalOffset& offset) { | |
296 curr_bfc_offset_.block_offset = offset.block_offset; | |
297 // First block that knows its position. Update the parent's BFC offset. | |
298 if (!builder_->BfcOffset()) { | |
299 NGLogicalOffset parent_bfc_offset = | |
300 ConstraintSpace().IsNewFormattingContext() ? NGLogicalOffset() | |
301 : curr_bfc_offset_; | |
302 builder_->SetBfcOffset(parent_bfc_offset); | |
303 } | |
304 | |
305 // OK to position pending floats. curr_bfc_offset_ and parent's BFC offset | |
306 // are accurate here. | |
307 PositionPendingFloats(curr_bfc_offset_, builder_); | |
308 | |
309 LayoutUnit block_offset = | |
310 offset.block_offset - builder_->BfcOffset().value().block_offset; | |
311 LayoutUnit inline_offset = | |
312 border_and_padding_.inline_start + curr_child_margins_.inline_start; | |
313 return {inline_offset, block_offset}; | |
314 } | |
315 | |
225 NGPhysicalFragment* NGBlockLayoutAlgorithm::Layout() { | 316 NGPhysicalFragment* NGBlockLayoutAlgorithm::Layout() { |
226 WTF::Optional<MinAndMaxContentSizes> sizes; | 317 WTF::Optional<MinAndMaxContentSizes> sizes; |
227 if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style())) { | 318 if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style())) { |
228 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return | 319 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return |
229 // MinAndMaxContentSizes. | 320 // MinAndMaxContentSizes. |
230 sizes = MinAndMaxContentSizes(); | 321 sizes = MinAndMaxContentSizes(); |
231 ComputeMinAndMaxContentSizes(&*sizes); | 322 ComputeMinAndMaxContentSizes(&*sizes); |
232 } | 323 } |
233 | 324 |
234 border_and_padding_ = | 325 border_and_padding_ = |
(...skipping 26 matching lines...) Expand all Loading... | |
261 } | 352 } |
262 space_builder_->SetAvailableSize( | 353 space_builder_->SetAvailableSize( |
263 NGLogicalSize(adjusted_inline_size, adjusted_block_size)); | 354 NGLogicalSize(adjusted_inline_size, adjusted_block_size)); |
264 space_builder_->SetPercentageResolutionSize( | 355 space_builder_->SetPercentageResolutionSize( |
265 NGLogicalSize(adjusted_inline_size, adjusted_block_size)); | 356 NGLogicalSize(adjusted_inline_size, adjusted_block_size)); |
266 | 357 |
267 builder_->SetDirection(constraint_space_->Direction()); | 358 builder_->SetDirection(constraint_space_->Direction()); |
268 builder_->SetWritingMode(constraint_space_->WritingMode()); | 359 builder_->SetWritingMode(constraint_space_->WritingMode()); |
269 builder_->SetInlineSize(inline_size).SetBlockSize(block_size); | 360 builder_->SetInlineSize(inline_size).SetBlockSize(block_size); |
270 | 361 |
362 // TODO(glebl): fix multicol after the new margin collapsing/floats algorithm | |
363 // based on BFCOffset is checked in. | |
271 if (NGBlockBreakToken* token = CurrentBlockBreakToken()) { | 364 if (NGBlockBreakToken* token = CurrentBlockBreakToken()) { |
272 // Resume after a previous break. | 365 // Resume after a previous break. |
273 content_size_ = token->BreakOffset(); | 366 content_size_ = token->BreakOffset(); |
274 current_child_ = token->InputNode(); | 367 current_child_ = token->InputNode(); |
275 } else { | 368 } else { |
276 content_size_ = border_and_padding_.block_start; | 369 content_size_ = border_and_padding_.block_start; |
277 current_child_ = first_child_; | 370 current_child_ = first_child_; |
278 } | 371 } |
279 | 372 |
373 curr_margin_strut_ = ConstraintSpace().MarginStrut(); | |
374 curr_bfc_offset_ = ConstraintSpace().BfcOffset(); | |
375 | |
376 // Margins collapsing: | |
377 // Do not collapse margins between parent and its child if there is | |
378 // border/padding between them. | |
379 if (border_and_padding_.block_start) { | |
380 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | |
381 builder_->SetBfcOffset(curr_bfc_offset_); | |
382 curr_margin_strut_ = NGMarginStrut(); | |
383 } | |
384 curr_bfc_offset_.block_offset += content_size_; | |
385 | |
280 while (current_child_) { | 386 while (current_child_) { |
281 EPosition position = current_child_->Style()->position(); | 387 EPosition position = current_child_->Style()->position(); |
282 if (position == AbsolutePosition || position == FixedPosition) { | 388 if (position == AbsolutePosition || position == FixedPosition) { |
283 builder_->AddOutOfFlowChildCandidate(current_child_, | 389 builder_->AddOutOfFlowChildCandidate(current_child_, |
284 GetChildSpaceOffset()); | 390 GetChildSpaceOffset()); |
285 current_child_ = current_child_->NextSibling(); | 391 current_child_ = current_child_->NextSibling(); |
286 continue; | 392 continue; |
287 } | 393 } |
288 | 394 |
289 DCHECK(!ConstraintSpace().HasBlockFragmentation() || | 395 DCHECK(!ConstraintSpace().HasBlockFragmentation() || |
290 SpaceAvailableForCurrentChild() > LayoutUnit()); | 396 SpaceAvailableForCurrentChild() > LayoutUnit()); |
291 space_for_current_child_ = CreateConstraintSpaceForCurrentChild(); | 397 space_for_current_child_ = CreateConstraintSpaceForCurrentChild(); |
292 | 398 |
293 NGPhysicalFragment* child_fragment = | 399 NGPhysicalFragment* child_fragment = |
294 current_child_->Layout(space_for_current_child_); | 400 current_child_->Layout(space_for_current_child_); |
295 | 401 |
296 FinishCurrentChildLayout(new NGBoxFragment( | 402 FinishCurrentChildLayout(new NGBoxFragment( |
297 ConstraintSpace().WritingMode(), ConstraintSpace().Direction(), | 403 ConstraintSpace().WritingMode(), ConstraintSpace().Direction(), |
298 toNGPhysicalBoxFragment(child_fragment))); | 404 toNGPhysicalBoxFragment(child_fragment))); |
299 | 405 |
300 if (!ProceedToNextUnfinishedSibling(child_fragment)) | 406 if (!ProceedToNextUnfinishedSibling(child_fragment)) |
301 break; | 407 break; |
302 } | 408 } |
303 | 409 |
410 // Margins collapsing: | |
411 // Bottom margins of an in-flow block box doesn't collapse with its last | |
412 // in-flow block-level child's bottom margin if the box has bottom | |
413 // border/padding. | |
304 content_size_ += border_and_padding_.block_end; | 414 content_size_ += border_and_padding_.block_end; |
415 if (border_and_padding_.block_end || | |
416 ConstraintSpace().IsNewFormattingContext()) { | |
417 content_size_ += curr_margin_strut_.Sum(); | |
ikilpatrick
2017/01/30 22:26:48
is there a test case for this?
Gleb Lanbin
2017/01/31 00:25:02
I believe it's covered in CollapsingMarginsCase4
/
| |
418 curr_margin_strut_ = NGMarginStrut(); | |
419 } | |
305 | 420 |
306 // Recompute the block-axis size now that we know our content size. | 421 // Recompute the block-axis size now that we know our content size. |
307 block_size = | 422 block_size = |
308 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); | 423 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); |
309 builder_->SetBlockSize(block_size); | 424 builder_->SetBlockSize(block_size); |
310 | 425 |
311 LayoutOutOfFlowChildren(); | 426 LayoutOutOfFlowChildren(); |
ikilpatrick
2017/01/30 22:26:48
you may need to rebase :)
Gleb Lanbin
2017/01/31 00:25:02
Done.
| |
312 | 427 |
428 // Set out BFC offset if the size is not empty. | |
429 if (block_size && !builder_->BfcOffset()) { | |
430 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | |
431 builder_->SetBfcOffset(curr_bfc_offset_); | |
432 } | |
433 | |
434 // Margins collapsing: | |
435 // Do not collapse margins between the last in-flow child and bottom margin | |
436 // of its parent if the parent has height != auto() | |
437 if (!Style().logicalHeight().isAuto()) { | |
438 // TODO(glebl): handle minLogicalHeight, maxLogicalHeight. | |
439 curr_margin_strut_ = NGMarginStrut(); | |
440 } | |
441 builder_->SetEndMarginStrut(curr_margin_strut_); | |
442 | |
313 builder_->SetInlineOverflow(max_inline_size_).SetBlockOverflow(content_size_); | 443 builder_->SetInlineOverflow(max_inline_size_).SetBlockOverflow(content_size_); |
314 | 444 |
315 if (ConstraintSpace().HasBlockFragmentation()) | 445 if (ConstraintSpace().HasBlockFragmentation()) |
316 FinalizeForFragmentation(); | 446 FinalizeForFragmentation(); |
317 | 447 |
318 NGPhysicalFragment* fragment = builder_->ToBoxFragment(); | 448 NGPhysicalFragment* fragment = builder_->ToBoxFragment(); |
319 | 449 |
320 return fragment; | 450 return fragment; |
321 } | 451 } |
322 | 452 |
323 void NGBlockLayoutAlgorithm::FinishCurrentChildLayout(NGFragment* fragment) { | 453 void NGBlockLayoutAlgorithm::FinishCurrentChildLayout( |
324 NGBoxStrut child_margins = ComputeMargins( | 454 NGFragment* base_fragment) { |
325 *space_for_current_child_, CurrentChildStyle(), | 455 const NGBoxFragment& fragment = *toNGBoxFragment(base_fragment); |
326 constraint_space_->WritingMode(), constraint_space_->Direction()); | 456 // Pull out unpositioned floats to the current fragment. This may needed if |
327 NGLogicalOffset fragment_offset; | 457 // for example the child fragment could not position its floats because it's |
458 // empty and therefore couldn't determine its position in space. | |
459 builder_->MutableUnpositionedFloats().appendVector( | |
460 fragment.PhysicalFragment()->UnpositionedFloats()); | |
ikilpatrick
2017/01/30 22:26:49
is it worth adding a DCHECK if there are unpositio
Gleb Lanbin
2017/01/31 00:25:02
Done.
| |
461 | |
328 if (CurrentChildStyle().isFloating()) { | 462 if (CurrentChildStyle().isFloating()) { |
329 fragment_offset = PositionFloatFragment(*fragment, child_margins); | 463 NGFloatingObject* floating_object = new NGFloatingObject( |
330 } else { | 464 fragment.PhysicalFragment(), space_for_current_child_, current_child_, |
331 ApplyAutoMargins(*space_for_current_child_, CurrentChildStyle(), | 465 CurrentChildStyle(), curr_child_margins_); |
332 fragment->InlineSize(), &child_margins); | 466 builder_->AddUnpositionedFloat(floating_object); |
333 fragment_offset = PositionFragment(*fragment, child_margins); | 467 // No need to postpone the positioning as we know the correct offset. |
ikilpatrick
2017/01/30 22:26:48
// No need to postpone the positioning if we know
Gleb Lanbin
2017/01/31 00:25:02
Done.
| |
468 if (builder_->BfcOffset()) { | |
469 NGLogicalOffset origin_point = curr_bfc_offset_; | |
470 // Adjust origin point to the margins of the last child. | |
471 // Example: <div style="margin-bottom: 20px"><float></div> | |
472 // <div style="margin-bottom: 30px"></div> | |
473 origin_point.block_offset += curr_margin_strut_.Sum(); | |
474 PositionPendingFloats(origin_point, builder_); | |
475 } | |
476 return; | |
334 } | 477 } |
478 | |
479 // Collapse empty block's margins. | |
480 if (!fragment.BlockSize()) { | |
ikilpatrick
2017/01/30 22:26:48
You can remove this? This happens below:
498 /
Gleb Lanbin
2017/01/31 00:25:02
thanks.
| |
481 curr_margin_strut_.Append(curr_child_margins_.block_end); | |
482 } | |
483 | |
484 NGLogicalOffset fragment_offset = { | |
485 border_and_padding_.inline_start + curr_child_margins_.inline_start, | |
486 content_size_}; | |
487 if (fragment.BfcOffset()) | |
488 fragment_offset = | |
489 PositionFragmentWithKnownBfcOffset(fragment.BfcOffset().value()); | |
490 | |
335 if (fragmentainer_mapper_) | 491 if (fragmentainer_mapper_) |
336 fragmentainer_mapper_->ToVisualOffset(fragment_offset); | 492 fragmentainer_mapper_->ToVisualOffset(fragment_offset); |
337 else | 493 else |
338 fragment_offset.block_offset -= PreviousBreakOffset(); | 494 fragment_offset.block_offset -= PreviousBreakOffset(); |
339 builder_->AddChild(fragment, fragment_offset); | 495 |
496 builder_->AddChild(base_fragment, fragment_offset); | |
497 | |
498 // Update margin strut. | |
499 curr_margin_strut_ = fragment.EndMarginStrut(); | |
500 curr_margin_strut_.Append(curr_child_margins_.block_end); | |
501 | |
502 content_size_ = fragment.BlockSize() + fragment_offset.block_offset; | |
503 max_inline_size_ = | |
504 std::max(max_inline_size_, fragment.InlineSize() + | |
505 curr_child_margins_.InlineSum() + | |
506 border_and_padding_.InlineSum()); | |
340 } | 507 } |
341 | 508 |
342 void NGBlockLayoutAlgorithm::LayoutOutOfFlowChildren() { | 509 void NGBlockLayoutAlgorithm::LayoutOutOfFlowChildren() { |
343 HeapLinkedHashSet<WeakMember<NGBlockNode>> out_of_flow_candidates; | 510 HeapLinkedHashSet<WeakMember<NGBlockNode>> out_of_flow_candidates; |
344 Vector<NGStaticPosition> out_of_flow_candidate_positions; | 511 Vector<NGStaticPosition> out_of_flow_candidate_positions; |
345 builder_->GetAndClearOutOfFlowDescendantCandidates( | 512 builder_->GetAndClearOutOfFlowDescendantCandidates( |
346 &out_of_flow_candidates, &out_of_flow_candidate_positions); | 513 &out_of_flow_candidates, &out_of_flow_candidate_positions); |
347 | 514 |
348 Member<NGOutOfFlowLayoutPart> out_of_flow_layout = | 515 Member<NGOutOfFlowLayoutPart> out_of_flow_layout = |
349 new NGOutOfFlowLayoutPart(&Style(), builder_->Size()); | 516 new NGOutOfFlowLayoutPart(&Style(), builder_->Size()); |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
498 if (fragmentainer_mapper_) | 665 if (fragmentainer_mapper_) |
499 space_left = fragmentainer_mapper_->BlockSize(); | 666 space_left = fragmentainer_mapper_->BlockSize(); |
500 else if (ConstraintSpace().HasBlockFragmentation()) | 667 else if (ConstraintSpace().HasBlockFragmentation()) |
501 space_left = ConstraintSpace().FragmentainerSpaceAvailable(); | 668 space_left = ConstraintSpace().FragmentainerSpaceAvailable(); |
502 else | 669 else |
503 return NGSizeIndefinite; | 670 return NGSizeIndefinite; |
504 space_left -= BorderEdgeForCurrentChild() - PreviousBreakOffset(); | 671 space_left -= BorderEdgeForCurrentChild() - PreviousBreakOffset(); |
505 return space_left; | 672 return space_left; |
506 } | 673 } |
507 | 674 |
508 NGBoxStrut NGBlockLayoutAlgorithm::CollapseMargins( | |
509 const NGBoxStrut& margins, | |
510 const NGBoxFragment& fragment) { | |
511 bool is_zero_height_box = !fragment.BlockSize() && margins.IsEmpty() && | |
512 fragment.MarginStrut().IsEmpty(); | |
513 // Create the current child's margin strut from its children's margin strut or | |
514 // use margin strut from the the last non-empty child. | |
515 NGDeprecatedMarginStrut curr_margin_strut = | |
516 is_zero_height_box ? prev_child_margin_strut_ : fragment.MarginStrut(); | |
517 | |
518 // Calculate borders and padding for the current child. | |
519 NGBoxStrut border_and_padding = | |
520 ComputeBorders(CurrentChildStyle()) + | |
521 ComputePadding(ConstraintSpace(), CurrentChildStyle()); | |
522 | |
523 // Collapse BLOCK-START margins if there is no padding or border between | |
524 // parent (current child) and its first in-flow child. | |
525 if (border_and_padding.block_start) { | |
526 curr_margin_strut.SetMarginBlockStart(margins.block_start); | |
527 } else { | |
528 curr_margin_strut.AppendMarginBlockStart(margins.block_start); | |
529 } | |
530 | |
531 // Collapse BLOCK-END margins if | |
532 // 1) there is no padding or border between parent (current child) and its | |
533 // first/last in-flow child | |
534 // 2) parent's logical height is auto. | |
535 if (CurrentChildStyle().logicalHeight().isAuto() && | |
536 !border_and_padding.block_end) { | |
537 curr_margin_strut.AppendMarginBlockEnd(margins.block_end); | |
538 } else { | |
539 curr_margin_strut.SetMarginBlockEnd(margins.block_end); | |
540 } | |
541 | |
542 NGBoxStrut result_margins; | |
543 // Margins of the newly established formatting context do not participate | |
544 // in Collapsing Margins: | |
545 // - Compute margins block start for adjoining blocks *including* 1st block. | |
546 // - Compute margins block end for the last block. | |
547 // - Do not set the computed margins to the parent fragment. | |
548 if (constraint_space_->IsNewFormattingContext()) { | |
549 result_margins.block_start = ComputeCollapsedMarginBlockStart( | |
550 prev_child_margin_strut_, curr_margin_strut); | |
551 bool is_last_child = !current_child_->NextSibling(); | |
552 if (is_last_child) | |
553 result_margins.block_end = curr_margin_strut.BlockEndSum(); | |
554 return result_margins; | |
555 } | |
556 | |
557 // Zero-height boxes are ignored and do not participate in margin collapsing. | |
558 if (is_zero_height_box) | |
559 return result_margins; | |
560 | |
561 // Compute the margin block start for adjoining blocks *excluding* 1st block | |
562 if (is_fragment_margin_strut_block_start_updated_) { | |
563 result_margins.block_start = ComputeCollapsedMarginBlockStart( | |
564 prev_child_margin_strut_, curr_margin_strut); | |
565 } | |
566 | |
567 // Update the parent fragment's margin strut | |
568 UpdateMarginStrut(curr_margin_strut); | |
569 | |
570 prev_child_margin_strut_ = curr_margin_strut; | |
571 return result_margins; | |
572 } | |
573 | |
574 NGLogicalOffset NGBlockLayoutAlgorithm::PositionFragment( | |
575 const NGFragment& fragment, | |
576 const NGBoxStrut& margins) { | |
577 const NGBoxStrut collapsed_margins = | |
578 CollapseMargins(margins, toNGBoxFragment(fragment)); | |
579 | |
580 AdjustToClearance(ConstraintSpace(), CurrentChildStyle(), &content_size_); | |
581 | |
582 LayoutUnit inline_offset = | |
583 border_and_padding_.inline_start + margins.inline_start; | |
584 LayoutUnit block_offset = content_size_ + collapsed_margins.block_start; | |
585 | |
586 content_size_ += fragment.BlockSize() + collapsed_margins.BlockSum(); | |
587 max_inline_size_ = | |
588 std::max(max_inline_size_, fragment.InlineSize() + margins.InlineSum() + | |
589 border_and_padding_.InlineSum()); | |
590 return NGLogicalOffset(inline_offset, block_offset); | |
591 } | |
592 | |
593 NGLogicalOffset NGBlockLayoutAlgorithm::PositionFloatFragment( | |
594 const NGFragment& fragment, | |
595 const NGBoxStrut& margins) { | |
596 // TODO(glebl@chromium.org): Support the top edge alignment rule. | |
597 // Find a layout opportunity that will fit our float. | |
598 | |
599 // Update offset if there is a clearance. | |
600 NGLogicalOffset offset = CurrentChildConstraintSpace().Offset(); | |
601 AdjustToClearance(ConstraintSpace(), CurrentChildStyle(), | |
602 &offset.block_offset); | |
603 space_for_current_child_->SetOffset(offset); | |
604 | |
605 const NGLayoutOpportunity opportunity = FindLayoutOpportunityForFragment( | |
606 space_for_current_child_, fragment, margins); | |
607 DCHECK(!opportunity.IsEmpty()) << "Opportunity is empty but it shouldn't be"; | |
608 | |
609 NGExclusion::Type exclusion_type = NGExclusion::kFloatLeft; | |
610 // Calculate the float offset if needed. | |
611 LayoutUnit float_offset; | |
612 if (CurrentChildStyle().floating() == EFloat::kRight) { | |
613 float_offset = opportunity.size.inline_size - fragment.InlineSize(); | |
614 exclusion_type = NGExclusion::kFloatRight; | |
615 } | |
616 | |
617 // Add the float as an exclusion. | |
618 const NGExclusion exclusion = CreateExclusion( | |
619 fragment, opportunity, float_offset, margins, exclusion_type); | |
620 constraint_space_->AddExclusion(exclusion); | |
621 | |
622 return CalculateLogicalOffsetForOpportunity(opportunity, float_offset, | |
623 margins); | |
624 } | |
625 | |
626 void NGBlockLayoutAlgorithm::UpdateMarginStrut( | |
627 const NGDeprecatedMarginStrut& from) { | |
628 if (!is_fragment_margin_strut_block_start_updated_) { | |
629 builder_->SetMarginStrutBlockStart(from); | |
630 is_fragment_margin_strut_block_start_updated_ = true; | |
631 } | |
632 builder_->SetMarginStrutBlockEnd(from); | |
633 } | |
634 | |
635 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins( | 675 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins( |
636 const NGConstraintSpace& space, | 676 const NGConstraintSpace& space, |
637 const ComputedStyle& style) { | 677 const ComputedStyle& style) { |
638 WTF::Optional<MinAndMaxContentSizes> sizes; | 678 WTF::Optional<MinAndMaxContentSizes> sizes; |
639 if (NeedMinAndMaxContentSizes(space, style)) { | 679 if (NeedMinAndMaxContentSizes(space, style)) { |
640 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return | 680 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return |
641 // MinAndMaxContentSizes. | 681 // MinAndMaxContentSizes. |
642 sizes = current_child_->ComputeMinAndMaxContentSizesSync(); | 682 sizes = current_child_->ComputeMinAndMaxContentSizesSync(); |
643 } | 683 } |
644 LayoutUnit child_inline_size = | 684 LayoutUnit child_inline_size = |
645 ComputeInlineSizeForFragment(space, style, sizes); | 685 ComputeInlineSizeForFragment(space, style, sizes); |
646 NGBoxStrut margins = | 686 NGBoxStrut margins = |
647 ComputeMargins(space, style, space.WritingMode(), space.Direction()); | 687 ComputeMargins(space, style, space.WritingMode(), space.Direction()); |
648 if (!style.isFloating()) { | 688 if (!style.isFloating()) { |
649 ApplyAutoMargins(space, style, child_inline_size, &margins); | 689 ApplyAutoMargins(space, style, child_inline_size, &margins); |
650 } | 690 } |
651 return margins; | 691 return margins; |
652 } | 692 } |
653 | 693 |
654 NGConstraintSpace* | 694 NGConstraintSpace* |
655 NGBlockLayoutAlgorithm::CreateConstraintSpaceForCurrentChild() { | 695 NGBlockLayoutAlgorithm::CreateConstraintSpaceForCurrentChild() { |
656 // TODO(layout-ng): Orthogonal children should also shrink to fit (in *their* | 696 // TODO(layout-ng): Orthogonal children should also shrink to fit (in *their* |
657 // inline axis) | 697 // inline axis) |
658 // We have to keep this commented out for now until we correctly compute | 698 // We have to keep this commented out for now until we correctly compute |
659 // min/max content sizes in Layout(). | 699 // min/max content sizes in Layout(). |
660 bool shrink_to_fit = CurrentChildStyle().display() == EDisplay::InlineBlock || | 700 bool shrink_to_fit = CurrentChildStyle().display() == EDisplay::InlineBlock || |
661 CurrentChildStyle().isFloating(); | 701 CurrentChildStyle().isFloating(); |
662 DCHECK(current_child_); | 702 DCHECK(current_child_); |
663 space_builder_ | 703 bool is_new_bfc = IsNewFormattingContextForInFlowBlockLevelChild( |
664 ->SetIsNewFormattingContext( | 704 ConstraintSpace(), CurrentChildStyle()); |
665 IsNewFormattingContextForInFlowBlockLevelChild(ConstraintSpace(), | 705 space_builder_->SetIsNewFormattingContext(is_new_bfc) |
666 CurrentChildStyle())) | |
667 .SetIsShrinkToFit(shrink_to_fit) | 706 .SetIsShrinkToFit(shrink_to_fit) |
668 .SetWritingMode( | 707 .SetWritingMode( |
669 FromPlatformWritingMode(CurrentChildStyle().getWritingMode())) | 708 FromPlatformWritingMode(CurrentChildStyle().getWritingMode())) |
670 .SetTextDirection(CurrentChildStyle().direction()); | 709 .SetTextDirection(CurrentChildStyle().direction()); |
671 LayoutUnit space_available = SpaceAvailableForCurrentChild(); | 710 LayoutUnit space_available = SpaceAvailableForCurrentChild(); |
672 space_builder_->SetFragmentainerSpaceAvailable(space_available); | 711 space_builder_->SetFragmentainerSpaceAvailable(space_available); |
673 | 712 |
674 curr_child_margins_ = CalculateMargins(*space_builder_->ToConstraintSpace(), | 713 curr_child_margins_ = CalculateMargins(*space_builder_->ToConstraintSpace(), |
675 CurrentChildStyle()); | 714 CurrentChildStyle()); |
676 | 715 |
677 NGConstraintSpace* child_space = space_builder_->ToConstraintSpace(); | 716 // Clearance : |
717 // - Collapse margins | |
718 // - Update curr_bfc_offset and parent BFC offset if needed. | |
719 // - Position all pending floats as position is known now. | |
720 // TODO(glebl): Fix the use case with clear: left and an intruding right. | |
721 // https://software.hixie.ch/utilities/js/live-dom-viewer/saved/4847 | |
722 if (CurrentChildStyle().clear()) { | |
723 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | |
724 if (!builder_->BfcOffset()) { | |
725 builder_->SetBfcOffset(curr_bfc_offset_); | |
726 } | |
727 // Only collapse margins if it's an adjoining block with clearance. | |
728 if (!content_size_) { | |
729 curr_margin_strut_ = NGMarginStrut(); | |
730 curr_child_margins_.block_start = LayoutUnit(); | |
731 } | |
732 PositionPendingFloats(curr_bfc_offset_, builder_); | |
733 AdjustToClearance(constraint_space_->Exclusions(), CurrentChildStyle(), | |
734 builder_->BfcOffset().value(), &content_size_); | |
735 } | |
678 | 736 |
679 // TODO(layout-ng): Set offset through the space builder. | 737 // Append the current margin strut with child's block start margin. |
680 child_space->SetOffset(GetChildSpaceOffset()); | 738 // Non empty border/padding use cases are handled inside of the child's |
681 return child_space; | 739 // layout. |
740 curr_margin_strut_.Append(curr_child_margins_.block_start); | |
741 space_builder_->SetMarginStrut(curr_margin_strut_); | |
742 | |
743 // Set estimated BFC offset to the next child's constraint space. | |
744 curr_bfc_offset_ = builder_->BfcOffset() ? builder_->BfcOffset().value() | |
745 : ConstraintSpace().BfcOffset(); | |
746 curr_bfc_offset_.block_offset += content_size_; | |
747 curr_bfc_offset_.inline_offset += border_and_padding_.inline_start; | |
748 if (ConstraintSpace().IsNewFormattingContext()) { | |
749 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start; | |
750 } | |
751 space_builder_->SetBfcOffset(curr_bfc_offset_); | |
752 | |
753 return space_builder_->ToConstraintSpace(); | |
682 } | 754 } |
683 | 755 |
684 DEFINE_TRACE(NGBlockLayoutAlgorithm) { | 756 DEFINE_TRACE(NGBlockLayoutAlgorithm) { |
685 NGLayoutAlgorithm::trace(visitor); | 757 NGLayoutAlgorithm::trace(visitor); |
686 visitor->trace(first_child_); | 758 visitor->trace(first_child_); |
687 visitor->trace(constraint_space_); | 759 visitor->trace(constraint_space_); |
688 visitor->trace(break_token_); | 760 visitor->trace(break_token_); |
689 visitor->trace(builder_); | 761 visitor->trace(builder_); |
690 visitor->trace(space_builder_); | 762 visitor->trace(space_builder_); |
691 visitor->trace(space_for_current_child_); | 763 visitor->trace(space_for_current_child_); |
692 visitor->trace(current_child_); | 764 visitor->trace(current_child_); |
693 visitor->trace(fragmentainer_mapper_); | 765 visitor->trace(fragmentainer_mapper_); |
694 } | 766 } |
695 | 767 |
696 } // namespace blink | 768 } // namespace blink |
OLD | NEW |