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