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::kNone: | 60 case EClear::kNone: |
47 return; // nothing to do here. | 61 return; // nothing to do here. |
48 case EClear::kLeft: | 62 case EClear::kLeft: |
49 *content_size = left_block_end_offset; | 63 *content_size = left_block_end_offset; |
50 break; | 64 break; |
51 case EClear::kRight: | 65 case EClear::kRight: |
52 *content_size = right_block_end_offset; | 66 *content_size = right_block_end_offset; |
53 break; | 67 break; |
54 case EClear::kBoth: | 68 case EClear::kBoth: |
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 // Non empty blocks always know their position in space: |
| 426 if (block_size) { |
| 427 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
| 428 UpdateFragmentBfcOffset(curr_bfc_offset_, ConstraintSpace(), builder_); |
| 429 PositionPendingFloats(curr_bfc_offset_, builder_); |
| 430 } |
| 431 |
| 432 // Margins collapsing: |
| 433 // Do not collapse margins between the last in-flow child and bottom margin |
| 434 // of its parent if the parent has height != auto() |
| 435 if (!Style().logicalHeight().isAuto()) { |
| 436 // TODO(glebl): handle minLogicalHeight, maxLogicalHeight. |
| 437 curr_margin_strut_ = NGMarginStrut(); |
| 438 } |
| 439 builder_->SetEndMarginStrut(curr_margin_strut_); |
| 440 |
314 builder_->SetInlineOverflow(max_inline_size_).SetBlockOverflow(content_size_); | 441 builder_->SetInlineOverflow(max_inline_size_).SetBlockOverflow(content_size_); |
315 | 442 |
316 if (ConstraintSpace().HasBlockFragmentation()) | 443 if (ConstraintSpace().HasBlockFragmentation()) |
317 FinalizeForFragmentation(); | 444 FinalizeForFragmentation(); |
318 | 445 |
319 NGPhysicalFragment* fragment = builder_->ToBoxFragment(); | 446 NGPhysicalFragment* fragment = builder_->ToBoxFragment(); |
320 | 447 |
321 return fragment; | 448 return fragment; |
322 } | 449 } |
323 | 450 |
324 void NGBlockLayoutAlgorithm::FinishCurrentChildLayout(NGFragment* fragment) { | 451 void NGBlockLayoutAlgorithm::FinishCurrentChildLayout( |
325 NGBoxStrut child_margins = ComputeMargins( | 452 NGFragment* base_fragment) { |
326 *space_for_current_child_, CurrentChildStyle(), | 453 const NGBoxFragment& fragment = *toNGBoxFragment(base_fragment); |
327 constraint_space_->WritingMode(), constraint_space_->Direction()); | 454 if (!fragment.PhysicalFragment()->UnpositionedFloats().isEmpty()) |
328 NGLogicalOffset fragment_offset; | 455 DCHECK(!builder_->BfcOffset()) << "Parent BFC offset shouldn't be set here"; |
| 456 // Pull out unpositioned floats to the current fragment. This may needed if |
| 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()); |
| 461 |
329 if (CurrentChildStyle().isFloating()) { | 462 if (CurrentChildStyle().isFloating()) { |
330 fragment_offset = PositionFloatFragment(*fragment, child_margins); | 463 NGFloatingObject* floating_object = new NGFloatingObject( |
331 } else { | 464 fragment.PhysicalFragment(), space_for_current_child_, current_child_, |
332 ApplyAutoMargins(*space_for_current_child_, CurrentChildStyle(), | 465 CurrentChildStyle(), curr_child_margins_); |
333 fragment->InlineSize(), &child_margins); | 466 builder_->AddUnpositionedFloat(floating_object); |
334 fragment_offset = PositionFragment(*fragment, child_margins); | 467 // No need to postpone the positioning if we know the correct offset. |
| 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; |
335 } | 477 } |
| 478 |
| 479 // Fragment that knows its offset can be used to set parent's BFC position. |
| 480 if (fragment.BfcOffset()) { |
| 481 curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset; |
| 482 UpdateFragmentBfcOffset(curr_bfc_offset_, ConstraintSpace(), builder_); |
| 483 PositionPendingFloats(curr_bfc_offset_, builder_); |
| 484 } |
| 485 NGLogicalOffset fragment_offset = CalculateRelativeOffset(fragment); |
| 486 |
336 if (fragmentainer_mapper_) | 487 if (fragmentainer_mapper_) |
337 fragmentainer_mapper_->ToVisualOffset(fragment_offset); | 488 fragmentainer_mapper_->ToVisualOffset(fragment_offset); |
338 else | 489 else |
339 fragment_offset.block_offset -= PreviousBreakOffset(); | 490 fragment_offset.block_offset -= PreviousBreakOffset(); |
340 builder_->AddChild(fragment, fragment_offset); | 491 |
| 492 builder_->AddChild(base_fragment, fragment_offset); |
| 493 |
| 494 // Update margin strut. |
| 495 curr_margin_strut_ = fragment.EndMarginStrut(); |
| 496 curr_margin_strut_.Append(curr_child_margins_.block_end); |
| 497 |
| 498 content_size_ = fragment.BlockSize() + fragment_offset.block_offset; |
| 499 max_inline_size_ = |
| 500 std::max(max_inline_size_, fragment.InlineSize() + |
| 501 curr_child_margins_.InlineSum() + |
| 502 border_and_padding_.InlineSum()); |
341 } | 503 } |
342 | 504 |
343 bool NGBlockLayoutAlgorithm::ProceedToNextUnfinishedSibling( | 505 bool NGBlockLayoutAlgorithm::ProceedToNextUnfinishedSibling( |
344 NGPhysicalFragment* child_fragment) { | 506 NGPhysicalFragment* child_fragment) { |
345 DCHECK(current_child_); | 507 DCHECK(current_child_); |
346 NGBlockNode* finished_child = current_child_; | 508 NGBlockNode* finished_child = current_child_; |
347 current_child_ = current_child_->NextSibling(); | 509 current_child_ = current_child_->NextSibling(); |
348 if (!ConstraintSpace().HasBlockFragmentation() && !fragmentainer_mapper_) | 510 if (!ConstraintSpace().HasBlockFragmentation() && !fragmentainer_mapper_) |
349 return true; | 511 return true; |
350 // If we're resuming layout after a fragmentainer break, we need to skip | 512 // 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_) | 635 if (fragmentainer_mapper_) |
474 space_left = fragmentainer_mapper_->BlockSize(); | 636 space_left = fragmentainer_mapper_->BlockSize(); |
475 else if (ConstraintSpace().HasBlockFragmentation()) | 637 else if (ConstraintSpace().HasBlockFragmentation()) |
476 space_left = ConstraintSpace().FragmentainerSpaceAvailable(); | 638 space_left = ConstraintSpace().FragmentainerSpaceAvailable(); |
477 else | 639 else |
478 return NGSizeIndefinite; | 640 return NGSizeIndefinite; |
479 space_left -= BorderEdgeForCurrentChild() - PreviousBreakOffset(); | 641 space_left -= BorderEdgeForCurrentChild() - PreviousBreakOffset(); |
480 return space_left; | 642 return space_left; |
481 } | 643 } |
482 | 644 |
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( | 645 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins( |
611 const NGConstraintSpace& space, | 646 const NGConstraintSpace& space, |
612 const ComputedStyle& style) { | 647 const ComputedStyle& style) { |
613 WTF::Optional<MinAndMaxContentSizes> sizes; | 648 WTF::Optional<MinAndMaxContentSizes> sizes; |
614 if (NeedMinAndMaxContentSizes(space, style)) { | 649 if (NeedMinAndMaxContentSizes(space, style)) { |
615 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return | 650 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return |
616 // MinAndMaxContentSizes. | 651 // MinAndMaxContentSizes. |
617 sizes = current_child_->ComputeMinAndMaxContentSizes(); | 652 sizes = current_child_->ComputeMinAndMaxContentSizes(); |
618 } | 653 } |
619 LayoutUnit child_inline_size = | 654 LayoutUnit child_inline_size = |
620 ComputeInlineSizeForFragment(space, style, sizes); | 655 ComputeInlineSizeForFragment(space, style, sizes); |
621 NGBoxStrut margins = | 656 NGBoxStrut margins = |
622 ComputeMargins(space, style, space.WritingMode(), space.Direction()); | 657 ComputeMargins(space, style, space.WritingMode(), space.Direction()); |
623 if (!style.isFloating()) { | 658 if (!style.isFloating()) { |
624 ApplyAutoMargins(space, style, child_inline_size, &margins); | 659 ApplyAutoMargins(space, style, child_inline_size, &margins); |
625 } | 660 } |
626 return margins; | 661 return margins; |
627 } | 662 } |
628 | 663 |
629 NGConstraintSpace* | 664 NGConstraintSpace* |
630 NGBlockLayoutAlgorithm::CreateConstraintSpaceForCurrentChild() { | 665 NGBlockLayoutAlgorithm::CreateConstraintSpaceForCurrentChild() { |
631 // TODO(layout-ng): Orthogonal children should also shrink to fit (in *their* | 666 // TODO(layout-ng): Orthogonal children should also shrink to fit (in *their* |
632 // inline axis) | 667 // inline axis) |
633 // We have to keep this commented out for now until we correctly compute | 668 // We have to keep this commented out for now until we correctly compute |
634 // min/max content sizes in Layout(). | 669 // min/max content sizes in Layout(). |
635 bool shrink_to_fit = CurrentChildStyle().display() == EDisplay::InlineBlock || | 670 bool shrink_to_fit = CurrentChildStyle().display() == EDisplay::InlineBlock || |
636 CurrentChildStyle().isFloating(); | 671 CurrentChildStyle().isFloating(); |
637 DCHECK(current_child_); | 672 DCHECK(current_child_); |
638 space_builder_ | 673 bool is_new_bfc = IsNewFormattingContextForInFlowBlockLevelChild( |
639 ->SetIsNewFormattingContext( | 674 ConstraintSpace(), CurrentChildStyle()); |
640 IsNewFormattingContextForInFlowBlockLevelChild(ConstraintSpace(), | 675 space_builder_->SetIsNewFormattingContext(is_new_bfc) |
641 CurrentChildStyle())) | |
642 .SetIsShrinkToFit(shrink_to_fit) | 676 .SetIsShrinkToFit(shrink_to_fit) |
643 .SetWritingMode( | 677 .SetWritingMode( |
644 FromPlatformWritingMode(CurrentChildStyle().getWritingMode())) | 678 FromPlatformWritingMode(CurrentChildStyle().getWritingMode())) |
645 .SetTextDirection(CurrentChildStyle().direction()); | 679 .SetTextDirection(CurrentChildStyle().direction()); |
646 LayoutUnit space_available = SpaceAvailableForCurrentChild(); | 680 LayoutUnit space_available = SpaceAvailableForCurrentChild(); |
647 space_builder_->SetFragmentainerSpaceAvailable(space_available); | 681 space_builder_->SetFragmentainerSpaceAvailable(space_available); |
648 | 682 |
649 curr_child_margins_ = CalculateMargins(*space_builder_->ToConstraintSpace(), | 683 curr_child_margins_ = CalculateMargins(*space_builder_->ToConstraintSpace(), |
650 CurrentChildStyle()); | 684 CurrentChildStyle()); |
651 | 685 |
652 NGConstraintSpace* child_space = space_builder_->ToConstraintSpace(); | 686 // Clearance : |
| 687 // - Collapse margins |
| 688 // - Update curr_bfc_offset and parent BFC offset if needed. |
| 689 // - Position all pending floats as position is known now. |
| 690 // TODO(glebl): Fix the use case with clear: left and an intruding right. |
| 691 // https://software.hixie.ch/utilities/js/live-dom-viewer/saved/4847 |
| 692 if (CurrentChildStyle().clear() != EClear::kNone) { |
| 693 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
| 694 UpdateFragmentBfcOffset(curr_bfc_offset_, ConstraintSpace(), builder_); |
| 695 // Only collapse margins if it's an adjoining block with clearance. |
| 696 if (!content_size_) { |
| 697 curr_margin_strut_ = NGMarginStrut(); |
| 698 curr_child_margins_.block_start = LayoutUnit(); |
| 699 } |
| 700 PositionPendingFloats(curr_bfc_offset_, builder_); |
| 701 AdjustToClearance(constraint_space_->Exclusions(), CurrentChildStyle(), |
| 702 builder_->BfcOffset().value(), &content_size_); |
| 703 } |
653 | 704 |
654 // TODO(layout-ng): Set offset through the space builder. | 705 // Append the current margin strut with child's block start margin. |
655 child_space->SetOffset(GetChildSpaceOffset()); | 706 // Non empty border/padding use cases are handled inside of the child's |
656 return child_space; | 707 // layout. |
| 708 curr_margin_strut_.Append(curr_child_margins_.block_start); |
| 709 space_builder_->SetMarginStrut(curr_margin_strut_); |
| 710 |
| 711 // Set estimated BFC offset to the next child's constraint space. |
| 712 curr_bfc_offset_ = builder_->BfcOffset() ? builder_->BfcOffset().value() |
| 713 : ConstraintSpace().BfcOffset(); |
| 714 curr_bfc_offset_.block_offset += content_size_; |
| 715 curr_bfc_offset_.inline_offset += border_and_padding_.inline_start; |
| 716 if (ConstraintSpace().IsNewFormattingContext()) { |
| 717 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start; |
| 718 } |
| 719 space_builder_->SetBfcOffset(curr_bfc_offset_); |
| 720 |
| 721 return space_builder_->ToConstraintSpace(); |
657 } | 722 } |
658 | 723 |
659 DEFINE_TRACE(NGBlockLayoutAlgorithm) { | 724 DEFINE_TRACE(NGBlockLayoutAlgorithm) { |
660 NGLayoutAlgorithm::trace(visitor); | 725 NGLayoutAlgorithm::trace(visitor); |
661 visitor->trace(first_child_); | 726 visitor->trace(first_child_); |
662 visitor->trace(constraint_space_); | 727 visitor->trace(constraint_space_); |
663 visitor->trace(break_token_); | 728 visitor->trace(break_token_); |
664 visitor->trace(builder_); | 729 visitor->trace(builder_); |
665 visitor->trace(space_builder_); | 730 visitor->trace(space_builder_); |
666 visitor->trace(space_for_current_child_); | 731 visitor->trace(space_for_current_child_); |
667 visitor->trace(current_child_); | 732 visitor->trace(current_child_); |
668 visitor->trace(fragmentainer_mapper_); | 733 visitor->trace(fragmentainer_mapper_); |
669 } | 734 } |
670 | 735 |
671 } // namespace blink | 736 } // namespace blink |
OLD | NEW |