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/inline/ng_inline_node.h" | 7 #include "core/layout/ng/inline/ng_inline_node.h" |
8 #include "core/layout/ng/ng_absolute_utils.h" | 8 #include "core/layout/ng/ng_absolute_utils.h" |
9 #include "core/layout/ng/ng_block_child_iterator.h" | 9 #include "core/layout/ng/ng_block_child_iterator.h" |
10 #include "core/layout/ng/ng_constraint_space.h" | 10 #include "core/layout/ng/ng_constraint_space.h" |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
54 return false; | 54 return false; |
55 } | 55 } |
56 | 56 |
57 // Whether we've run out of space in this flow. If so, there will be no work | 57 // Whether we've run out of space in this flow. If so, there will be no work |
58 // left to do for this block in this fragmentainer. | 58 // left to do for this block in this fragmentainer. |
59 bool IsOutOfSpace(const NGConstraintSpace& space, LayoutUnit content_size) { | 59 bool IsOutOfSpace(const NGConstraintSpace& space, LayoutUnit content_size) { |
60 return space.HasBlockFragmentation() && | 60 return space.HasBlockFragmentation() && |
61 content_size >= space.FragmentainerSpaceAvailable(); | 61 content_size >= space.FragmentainerSpaceAvailable(); |
62 } | 62 } |
63 | 63 |
64 bool IsEmptyFragment(NGWritingMode writing_mode, | |
65 const NGLayoutResult& layout_result) { | |
66 if (!layout_result.PhysicalFragment()) | |
67 return true; | |
68 | |
69 NGFragment fragment(writing_mode, layout_result.PhysicalFragment().Get()); | |
70 if (!fragment.BlockSize()) | |
71 return true; | |
72 | |
73 return false; | |
74 } | |
75 | |
64 } // namespace | 76 } // namespace |
65 | 77 |
66 // This struct is used for communicating to a child the position of the | 78 bool MaybeUpdateFragmentBfcOffset(const NGConstraintSpace& space, |
67 // previous inflow child. | |
68 struct NGPreviousInflowPosition { | |
69 LayoutUnit bfc_block_offset; | |
70 LayoutUnit logical_block_offset; | |
71 NGMarginStrut margin_strut; | |
72 }; | |
73 | |
74 // This strut holds information for the current inflow child. The data is not | |
75 // useful outside of handling this single inflow child. | |
76 struct NGInflowChildData { | |
77 NGLogicalOffset bfc_offset_estimate; | |
78 NGMarginStrut margin_strut; | |
79 NGBoxStrut margins; | |
80 }; | |
81 | |
82 void MaybeUpdateFragmentBfcOffset(const NGConstraintSpace& space, | |
83 LayoutUnit bfc_block_offset, | 79 LayoutUnit bfc_block_offset, |
84 NGFragmentBuilder* builder) { | 80 NGFragmentBuilder* builder) { |
85 DCHECK(builder); | 81 DCHECK(builder); |
86 if (!builder->BfcOffset()) { | 82 if (!builder->BfcOffset()) { |
87 NGLogicalOffset bfc_offset = {space.BfcOffset().inline_offset, | 83 NGLogicalOffset bfc_offset = {space.BfcOffset().inline_offset, |
88 bfc_block_offset}; | 84 bfc_block_offset}; |
89 AdjustToClearance(space.ClearanceOffset(), &bfc_offset); | 85 AdjustToClearance(space.ClearanceOffset(), &bfc_offset); |
90 builder->SetBfcOffset(bfc_offset); | 86 builder->SetBfcOffset(bfc_offset); |
87 return true; | |
91 } | 88 } |
89 | |
90 return false; | |
92 } | 91 } |
93 | 92 |
94 void PositionPendingFloats(LayoutUnit origin_block_offset, | 93 void PositionPendingFloats( |
95 NGFragmentBuilder* container_builder, | 94 LayoutUnit origin_block_offset, |
96 NGConstraintSpace* space) { | 95 NGFragmentBuilder* container_builder, |
97 DCHECK(container_builder->BfcOffset()) | 96 Vector<RefPtr<NGUnpositionedFloat>>* unpositioned_floats, |
97 NGConstraintSpace* space) { | |
98 DCHECK(container_builder->BfcOffset() || space->FloatsBfcOffset()) | |
98 << "Parent BFC offset should be known here"; | 99 << "Parent BFC offset should be known here"; |
100 LayoutUnit from_block_offset = | |
101 container_builder->BfcOffset() | |
102 ? container_builder->BfcOffset().value().block_offset | |
103 : space->FloatsBfcOffset().value().block_offset; | |
99 | 104 |
100 const auto& unpositioned_floats = container_builder->UnpositionedFloats(); | |
101 const auto positioned_floats = PositionFloats( | 105 const auto positioned_floats = PositionFloats( |
102 origin_block_offset, container_builder->BfcOffset().value().block_offset, | 106 origin_block_offset, from_block_offset, *unpositioned_floats, space); |
103 unpositioned_floats, space); | |
104 | 107 |
105 for (const auto& positioned_float : positioned_floats) | 108 for (const auto& positioned_float : positioned_floats) |
106 container_builder->AddPositionedFloat(positioned_float); | 109 container_builder->AddPositionedFloat(positioned_float); |
107 | 110 |
108 container_builder->MutableUnpositionedFloats().clear(); | 111 unpositioned_floats->clear(); |
109 } | 112 } |
110 | 113 |
111 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm(NGBlockNode node, | 114 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm(NGBlockNode node, |
112 NGConstraintSpace* space, | 115 NGConstraintSpace* space, |
113 NGBlockBreakToken* break_token) | 116 NGBlockBreakToken* break_token) |
114 : NGLayoutAlgorithm(node, space, break_token) {} | 117 : NGLayoutAlgorithm(node, space, break_token) {} |
115 | 118 |
116 Optional<MinMaxContentSize> NGBlockLayoutAlgorithm::ComputeMinMaxContentSize() | 119 Optional<MinMaxContentSize> NGBlockLayoutAlgorithm::ComputeMinMaxContentSize() |
117 const { | 120 const { |
118 MinMaxContentSize sizes; | 121 MinMaxContentSize sizes; |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
192 adjusted_size.block_size = std::max(adjusted_size.block_size, LayoutUnit()); | 195 adjusted_size.block_size = std::max(adjusted_size.block_size, LayoutUnit()); |
193 } | 196 } |
194 adjusted_size.inline_size = std::max(adjusted_size.inline_size, LayoutUnit()); | 197 adjusted_size.inline_size = std::max(adjusted_size.inline_size, LayoutUnit()); |
195 | 198 |
196 child_available_size_ = adjusted_size; | 199 child_available_size_ = adjusted_size; |
197 child_percentage_size_ = adjusted_size; | 200 child_percentage_size_ = adjusted_size; |
198 | 201 |
199 container_builder_.SetDirection(constraint_space_->Direction()); | 202 container_builder_.SetDirection(constraint_space_->Direction()); |
200 container_builder_.SetWritingMode(constraint_space_->WritingMode()); | 203 container_builder_.SetWritingMode(constraint_space_->WritingMode()); |
201 container_builder_.SetSize(size); | 204 container_builder_.SetSize(size); |
202 container_builder_.MutableUnpositionedFloats() = | 205 |
203 constraint_space_->UnpositionedFloats(); | 206 // If we have a list of unpositioned floats as input to this layout, we'll |
207 // need to abort once our BFC offset is resolved. Additionally the | |
208 // FloatsBfcOffset() must not be present in this case. | |
209 unpositioned_floats_ = constraint_space_->UnpositionedFloats(); | |
210 abort_when_bfc_resolved_ = !unpositioned_floats_.IsEmpty(); | |
211 if (abort_when_bfc_resolved_) | |
212 DCHECK(!constraint_space_->FloatsBfcOffset()); | |
204 | 213 |
205 NGBlockChildIterator child_iterator(Node().FirstChild(), BreakToken()); | 214 NGBlockChildIterator child_iterator(Node().FirstChild(), BreakToken()); |
206 NGBlockChildIterator::Entry entry = child_iterator.NextChild(); | 215 NGBlockChildIterator::Entry entry = child_iterator.NextChild(); |
207 NGLayoutInputNode child = entry.node; | 216 NGLayoutInputNode child = entry.node; |
208 NGBreakToken* child_break_token = entry.token; | 217 NGBreakToken* child_break_token = entry.token; |
209 | 218 |
210 // If we are resuming from a break token our start border and padding is | 219 // If we are resuming from a break token our start border and padding is |
211 // within a previous fragment. | 220 // within a previous fragment. |
212 content_size_ = | 221 content_size_ = |
213 BreakToken() ? LayoutUnit() : border_scrollbar_padding_.block_start; | 222 BreakToken() ? LayoutUnit() : border_scrollbar_padding_.block_start; |
214 | 223 |
215 NGMarginStrut input_margin_strut = ConstraintSpace().MarginStrut(); | 224 NGMarginStrut input_margin_strut = ConstraintSpace().MarginStrut(); |
216 LayoutUnit input_bfc_block_offset = | 225 LayoutUnit input_bfc_block_offset = |
217 ConstraintSpace().BfcOffset().block_offset; | 226 ConstraintSpace().BfcOffset().block_offset; |
218 | 227 |
219 // Margins collapsing: | 228 // Margins collapsing: |
220 // Do not collapse margins between parent and its child if there is | 229 // Do not collapse margins between parent and its child if there is |
221 // border/padding between them. | 230 // border/padding between them. |
222 if (border_scrollbar_padding_.block_start) { | 231 if (border_scrollbar_padding_.block_start) { |
223 input_bfc_block_offset += input_margin_strut.Sum(); | 232 input_bfc_block_offset += input_margin_strut.Sum(); |
224 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), input_bfc_block_offset, | 233 bool updated = MaybeUpdateFragmentBfcOffset( |
225 &container_builder_); | 234 ConstraintSpace(), input_bfc_block_offset, &container_builder_); |
235 | |
236 if (updated && abort_when_bfc_resolved_) { | |
237 container_builder_.SwapUnpositionedFloats(&unpositioned_floats_); | |
238 return container_builder_.Abort(NGLayoutResult::kBfcOffsetResolved); | |
239 } | |
240 | |
226 // We reset the block offset here as it may have been effected by clearance. | 241 // We reset the block offset here as it may have been effected by clearance. |
227 input_bfc_block_offset = ContainerBfcOffset().block_offset; | 242 input_bfc_block_offset = ContainerBfcOffset().block_offset; |
228 input_margin_strut = NGMarginStrut(); | 243 input_margin_strut = NGMarginStrut(); |
229 } | 244 } |
230 | 245 |
231 // If a new formatting context hits the margin collapsing if-branch above | 246 // If a new formatting context hits the margin collapsing if-branch above |
232 // then the BFC offset is still {} as the margin strut from the constraint | 247 // then the BFC offset is still {} as the margin strut from the constraint |
233 // space must also be empty. | 248 // space must also be empty. |
234 // If we are resuming layout from a break token the same rule applies. Margin | 249 // If we are resuming layout from a break token the same rule applies. Margin |
235 // struts cannot pass through break tokens. | 250 // struts cannot pass through break tokens. |
236 if (ConstraintSpace().IsNewFormattingContext() || BreakToken()) { | 251 if (ConstraintSpace().IsNewFormattingContext() || BreakToken()) { |
237 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), input_bfc_block_offset, | 252 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), input_bfc_block_offset, |
238 &container_builder_); | 253 &container_builder_); |
239 DCHECK_EQ(input_margin_strut, NGMarginStrut()); | 254 DCHECK_EQ(input_margin_strut, NGMarginStrut()); |
240 DCHECK_EQ(container_builder_.BfcOffset().value(), NGLogicalOffset()); | 255 DCHECK_EQ(container_builder_.BfcOffset().value(), NGLogicalOffset()); |
241 } | 256 } |
242 | 257 |
243 input_bfc_block_offset += content_size_; | 258 input_bfc_block_offset += content_size_; |
244 | 259 |
245 NGPreviousInflowPosition previous_inflow_position = { | 260 WTF::Optional<NGPreviousInflowPosition> previous_inflow_position = |
246 input_bfc_block_offset, content_size_, input_margin_strut}; | 261 NGPreviousInflowPosition{input_bfc_block_offset, content_size_, |
262 input_margin_strut}; | |
247 | 263 |
248 while (child) { | 264 while (child) { |
249 if (child.IsOutOfFlowPositioned()) { | 265 if (child.IsOutOfFlowPositioned()) { |
250 DCHECK(!child_break_token); | 266 DCHECK(!child_break_token); |
251 HandleOutOfFlowPositioned(previous_inflow_position, ToNGBlockNode(child)); | 267 HandleOutOfFlowPositioned(previous_inflow_position.value(), |
268 ToNGBlockNode(child)); | |
252 } else if (child.IsFloating()) { | 269 } else if (child.IsFloating()) { |
253 HandleFloating(previous_inflow_position, ToNGBlockNode(child), | 270 HandleFloating(previous_inflow_position.value(), ToNGBlockNode(child), |
254 ToNGBlockBreakToken(child_break_token)); | 271 ToNGBlockBreakToken(child_break_token)); |
255 } else { | 272 } else { |
256 NGInflowChildData child_data = | 273 // TODO(ikilpatrick): Refactor this else branch. |
257 PrepareChildLayout(previous_inflow_position, child); | 274 WTF::Optional<NGInflowChildData> child_data = |
275 PrepareChildLayout(previous_inflow_position.value(), child); | |
eae
2017/07/10 23:27:49
This is a good use of Optional, it is logically co
| |
276 | |
277 // If PrepareChildLayout resolved our BFC offset, abort the layout. | |
278 if (!child_data) { | |
279 DCHECK(container_builder_.BfcOffset()); | |
280 container_builder_.SwapUnpositionedFloats(&unpositioned_floats_); | |
281 return container_builder_.Abort(NGLayoutResult::kBfcOffsetResolved); | |
282 } | |
283 | |
258 RefPtr<NGConstraintSpace> child_space = | 284 RefPtr<NGConstraintSpace> child_space = |
259 CreateConstraintSpaceForChild(child, child_data); | 285 CreateConstraintSpaceForChild(child, child_data.value()); |
260 RefPtr<NGLayoutResult> layout_result = | 286 RefPtr<NGLayoutResult> layout_result = |
261 child.Layout(child_space.Get(), child_break_token); | 287 child.Layout(child_space.Get(), child_break_token); |
262 previous_inflow_position = | 288 |
263 FinishChildLayout(*child_space, previous_inflow_position, child_data, | 289 // A child may have aborted its layout if it resolved its BFC offset. If |
264 child, layout_result.Get()); | 290 // we don't have a BFC offset yet, we need to propagate the abortion up |
291 // to our parent. | |
292 if (layout_result->Status() == NGLayoutResult::kBfcOffsetResolved && | |
293 !container_builder_.BfcOffset()) { | |
294 MaybeUpdateFragmentBfcOffset( | |
295 ConstraintSpace(), layout_result->BfcOffset().value().block_offset, | |
296 &container_builder_); | |
297 container_builder_.SwapUnpositionedFloats(&unpositioned_floats_); | |
298 return container_builder_.Abort(NGLayoutResult::kBfcOffsetResolved); | |
299 } | |
300 | |
301 previous_inflow_position = FinishChildLayout( | |
302 *child_space, previous_inflow_position.value(), child_data.value(), | |
303 child, child_break_token, std::move(layout_result)); | |
304 | |
305 // If FinishChildLayout resolved our BFC offset, abort the layout. | |
306 if (!previous_inflow_position) { | |
307 container_builder_.SwapUnpositionedFloats(&unpositioned_floats_); | |
308 return container_builder_.Abort(NGLayoutResult::kBfcOffsetResolved); | |
309 } | |
265 } | 310 } |
266 | 311 |
267 entry = child_iterator.NextChild(); | 312 entry = child_iterator.NextChild(); |
268 child = entry.node; | 313 child = entry.node; |
269 child_break_token = entry.token; | 314 child_break_token = entry.token; |
270 | 315 |
271 if (IsOutOfSpace(ConstraintSpace(), content_size_)) | 316 if (IsOutOfSpace(ConstraintSpace(), content_size_)) |
272 break; | 317 break; |
273 } | 318 } |
274 | 319 |
275 NGMarginStrut end_margin_strut = previous_inflow_position.margin_strut; | 320 NGMarginStrut end_margin_strut = previous_inflow_position->margin_strut; |
276 LayoutUnit end_bfc_block_offset = previous_inflow_position.bfc_block_offset; | 321 LayoutUnit end_bfc_block_offset = previous_inflow_position->bfc_block_offset; |
277 | 322 |
278 // Margins collapsing: | 323 // Margins collapsing: |
279 // Bottom margins of an in-flow block box doesn't collapse with its last | 324 // Bottom margins of an in-flow block box doesn't collapse with its last |
280 // in-flow block-level child's bottom margin if the box has bottom | 325 // in-flow block-level child's bottom margin if the box has bottom |
281 // border/padding. | 326 // border/padding. |
282 if (border_scrollbar_padding_.block_end || | 327 if (border_scrollbar_padding_.block_end || |
283 ConstraintSpace().IsNewFormattingContext()) { | 328 ConstraintSpace().IsNewFormattingContext()) { |
284 content_size_ = | 329 content_size_ = |
285 std::max(content_size_, previous_inflow_position.logical_block_offset + | 330 std::max(content_size_, previous_inflow_position->logical_block_offset + |
286 end_margin_strut.Sum()); | 331 end_margin_strut.Sum()); |
287 end_margin_strut = NGMarginStrut(); | 332 end_margin_strut = NGMarginStrut(); |
288 } | 333 } |
289 | 334 |
290 // If the current layout is a new formatting context, we need to encapsulate | 335 // If the current layout is a new formatting context, we need to encapsulate |
291 // all of our floats. | 336 // all of our floats. |
292 if (ConstraintSpace().IsNewFormattingContext()) { | 337 if (ConstraintSpace().IsNewFormattingContext()) { |
293 // We can use the BFC coordinates, as we are a new formatting context. | 338 // We can use the BFC coordinates, as we are a new formatting context. |
294 DCHECK_EQ(container_builder_.BfcOffset().value(), NGLogicalOffset()); | 339 DCHECK_EQ(container_builder_.BfcOffset().value(), NGLogicalOffset()); |
295 | 340 |
296 WTF::Optional<LayoutUnit> float_end_offset = | 341 WTF::Optional<LayoutUnit> float_end_offset = |
297 GetClearanceOffset(ConstraintSpace().Exclusions(), EClear::kBoth); | 342 GetClearanceOffset(ConstraintSpace().Exclusions(), EClear::kBoth); |
298 if (float_end_offset) | 343 if (float_end_offset) |
299 content_size_ = std::max(content_size_, float_end_offset.value()); | 344 content_size_ = std::max(content_size_, float_end_offset.value()); |
300 } | 345 } |
301 | 346 |
302 content_size_ += border_scrollbar_padding_.block_end; | 347 content_size_ += border_scrollbar_padding_.block_end; |
303 | 348 |
304 // Recompute the block-axis size now that we know our content size. | 349 // Recompute the block-axis size now that we know our content size. |
305 size.block_size = | 350 size.block_size = |
306 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); | 351 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); |
307 container_builder_.SetBlockSize(size.block_size); | 352 container_builder_.SetBlockSize(size.block_size); |
308 | 353 |
309 // Layout our absolute and fixed positioned children. | |
310 NGOutOfFlowLayoutPart(ConstraintSpace(), Style(), &container_builder_).Run(); | |
311 | |
312 // Non-empty blocks always know their position in space. | 354 // Non-empty blocks always know their position in space. |
313 // TODO(ikilpatrick): This check for a break token seems error prone. | 355 // TODO(ikilpatrick): This check for a break token seems error prone. |
314 if (size.block_size || BreakToken()) { | 356 if (size.block_size || BreakToken()) { |
315 end_bfc_block_offset += end_margin_strut.Sum(); | 357 end_bfc_block_offset += end_margin_strut.Sum(); |
316 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), end_bfc_block_offset, | 358 bool updated = MaybeUpdateFragmentBfcOffset( |
317 &container_builder_); | 359 ConstraintSpace(), end_bfc_block_offset, &container_builder_); |
360 | |
361 if (updated && abort_when_bfc_resolved_) { | |
362 container_builder_.SwapUnpositionedFloats(&unpositioned_floats_); | |
363 return container_builder_.Abort(NGLayoutResult::kBfcOffsetResolved); | |
364 } | |
365 | |
318 PositionPendingFloats(end_bfc_block_offset, &container_builder_, | 366 PositionPendingFloats(end_bfc_block_offset, &container_builder_, |
319 MutableConstraintSpace()); | 367 &unpositioned_floats_, MutableConstraintSpace()); |
320 } | 368 } |
321 | 369 |
322 // Margins collapsing: | 370 // Margins collapsing: |
323 // Do not collapse margins between the last in-flow child and bottom margin | 371 // Do not collapse margins between the last in-flow child and bottom margin |
324 // of its parent if the parent has height != auto() | 372 // of its parent if the parent has height != auto() |
325 if (!Style().LogicalHeight().IsAuto()) { | 373 if (!Style().LogicalHeight().IsAuto()) { |
326 // TODO(glebl): handle minLogicalHeight, maxLogicalHeight. | 374 // TODO(glebl): handle minLogicalHeight, maxLogicalHeight. |
327 end_margin_strut = NGMarginStrut(); | 375 end_margin_strut = NGMarginStrut(); |
328 } | 376 } |
329 container_builder_.SetEndMarginStrut(end_margin_strut); | 377 container_builder_.SetEndMarginStrut(end_margin_strut); |
330 container_builder_.SetOverflowSize( | 378 container_builder_.SetOverflowSize( |
331 NGLogicalSize(max_inline_size_, content_size_)); | 379 NGLogicalSize(max_inline_size_, content_size_)); |
332 | 380 |
333 // We only finalize for fragmentation if the fragment has a BFC offset. This | 381 // We only finalize for fragmentation if the fragment has a BFC offset. This |
334 // may occur with a zero block size fragment. We need to know the BFC offset | 382 // may occur with a zero block size fragment. We need to know the BFC offset |
335 // to determine where the fragmentation line is relative to us. | 383 // to determine where the fragmentation line is relative to us. |
336 if (container_builder_.BfcOffset() && | 384 if (container_builder_.BfcOffset() && |
337 ConstraintSpace().HasBlockFragmentation()) | 385 ConstraintSpace().HasBlockFragmentation()) |
338 FinalizeForFragmentation(); | 386 FinalizeForFragmentation(); |
339 | 387 |
388 // Only layout absolute and fixed children if we aren't going to revisit this | |
389 // layout. | |
390 if (unpositioned_floats_.IsEmpty()) { | |
391 NGOutOfFlowLayoutPart(ConstraintSpace(), Style(), &container_builder_) | |
392 .Run(); | |
393 } | |
394 | |
395 // If we have any unpositioned floats at this stage, need to tell our parent | |
396 // about this, so that we get relayout with a forced BFC offset. | |
397 if (!unpositioned_floats_.IsEmpty()) { | |
398 DCHECK(!container_builder_.BfcOffset()); | |
399 container_builder_.SwapUnpositionedFloats(&unpositioned_floats_); | |
400 } | |
401 | |
340 return container_builder_.ToBoxFragment(); | 402 return container_builder_.ToBoxFragment(); |
341 } | 403 } |
342 | 404 |
343 void NGBlockLayoutAlgorithm::HandleOutOfFlowPositioned( | 405 void NGBlockLayoutAlgorithm::HandleOutOfFlowPositioned( |
344 const NGPreviousInflowPosition& previous_inflow_position, | 406 const NGPreviousInflowPosition& previous_inflow_position, |
345 NGBlockNode child) { | 407 NGBlockNode child) { |
346 // TODO(ikilpatrick): Determine which of the child's margins need to be | 408 // TODO(ikilpatrick): Determine which of the child's margins need to be |
347 // included for the static position. | 409 // included for the static position. |
348 NGLogicalOffset offset = {border_scrollbar_padding_.inline_start, | 410 NGLogicalOffset offset = {border_scrollbar_padding_.inline_start, |
349 previous_inflow_position.logical_block_offset}; | 411 previous_inflow_position.logical_block_offset}; |
(...skipping 13 matching lines...) Expand all Loading... | |
363 // Calculate margins in the BFC's writing mode. | 425 // Calculate margins in the BFC's writing mode. |
364 NGBoxStrut margins = CalculateMargins(child); | 426 NGBoxStrut margins = CalculateMargins(child); |
365 | 427 |
366 LayoutUnit origin_inline_offset = | 428 LayoutUnit origin_inline_offset = |
367 constraint_space_->BfcOffset().inline_offset + | 429 constraint_space_->BfcOffset().inline_offset + |
368 border_scrollbar_padding_.inline_start; | 430 border_scrollbar_padding_.inline_start; |
369 | 431 |
370 RefPtr<NGUnpositionedFloat> unpositioned_float = NGUnpositionedFloat::Create( | 432 RefPtr<NGUnpositionedFloat> unpositioned_float = NGUnpositionedFloat::Create( |
371 child_available_size_, child_percentage_size_, origin_inline_offset, | 433 child_available_size_, child_percentage_size_, origin_inline_offset, |
372 constraint_space_->BfcOffset().inline_offset, margins, child, token); | 434 constraint_space_->BfcOffset().inline_offset, margins, child, token); |
373 container_builder_.AddUnpositionedFloat(unpositioned_float); | 435 unpositioned_floats_.push_back(std::move(unpositioned_float)); |
374 | 436 |
375 // If there is a break token for a float we must be resuming layout, we must | 437 // If there is a break token for a float we must be resuming layout, we must |
376 // always know our position in the BFC. | 438 // always know our position in the BFC. |
377 DCHECK(!token || container_builder_.BfcOffset()); | 439 DCHECK(!token || container_builder_.BfcOffset()); |
378 | 440 |
379 // No need to postpone the positioning if we know the correct offset. | 441 // No need to postpone the positioning if we know the correct offset. |
380 if (container_builder_.BfcOffset()) { | 442 if (container_builder_.BfcOffset() || ConstraintSpace().FloatsBfcOffset()) { |
381 // Adjust origin point to the margins of the last child. | 443 // Adjust origin point to the margins of the last child. |
382 // Example: <div style="margin-bottom: 20px"><float></div> | 444 // Example: <div style="margin-bottom: 20px"><float></div> |
383 // <div style="margin-bottom: 30px"></div> | 445 // <div style="margin-bottom: 30px"></div> |
384 LayoutUnit origin_block_offset = | 446 LayoutUnit origin_block_offset = |
385 previous_inflow_position.bfc_block_offset + | 447 container_builder_.BfcOffset() |
386 previous_inflow_position.margin_strut.Sum(); | 448 ? previous_inflow_position.bfc_block_offset + |
449 previous_inflow_position.margin_strut.Sum() | |
450 : ConstraintSpace().FloatsBfcOffset().value().block_offset; | |
387 PositionPendingFloats(origin_block_offset, &container_builder_, | 451 PositionPendingFloats(origin_block_offset, &container_builder_, |
388 MutableConstraintSpace()); | 452 &unpositioned_floats_, MutableConstraintSpace()); |
389 } | 453 } |
390 } | 454 } |
391 | 455 |
392 NGInflowChildData NGBlockLayoutAlgorithm::PrepareChildLayout( | 456 WTF::Optional<NGInflowChildData> NGBlockLayoutAlgorithm::PrepareChildLayout( |
393 const NGPreviousInflowPosition& previous_inflow_position, | 457 const NGPreviousInflowPosition& previous_inflow_position, |
394 NGLayoutInputNode child) { | 458 NGLayoutInputNode child) { |
395 DCHECK(child); | 459 DCHECK(child); |
396 DCHECK(!child.IsFloating()); | 460 DCHECK(!child.IsFloating()); |
397 | 461 |
398 LayoutUnit bfc_block_offset = previous_inflow_position.bfc_block_offset; | 462 LayoutUnit bfc_block_offset = previous_inflow_position.bfc_block_offset; |
399 | 463 |
400 // Calculate margins in parent's writing mode. | 464 // Calculate margins in parent's writing mode. |
401 NGBoxStrut margins = CalculateMargins(child); | 465 NGBoxStrut margins = CalculateMargins(child); |
402 NGMarginStrut margin_strut = previous_inflow_position.margin_strut; | 466 NGMarginStrut margin_strut = previous_inflow_position.margin_strut; |
403 | 467 |
404 bool should_position_pending_floats = | 468 bool should_position_pending_floats = |
405 !child.CreatesNewFormattingContext() && | 469 !child.CreatesNewFormattingContext() && |
406 ClearanceMayAffectLayout(ConstraintSpace(), | 470 ClearanceMayAffectLayout(ConstraintSpace(), unpositioned_floats_, |
407 container_builder_.UnpositionedFloats(), | |
408 child.Style()); | 471 child.Style()); |
409 | 472 |
410 // Children which may clear a float need to force all the pending floats to | 473 // Children which may clear a float need to force all the pending floats to |
411 // be positioned before layout. This also resolves the fragment's bfc offset. | 474 // be positioned before layout. This also resolves the fragment's bfc offset. |
412 if (should_position_pending_floats) { | 475 if (should_position_pending_floats) { |
413 LayoutUnit origin_point_block_offset = | 476 LayoutUnit origin_point_block_offset = |
414 bfc_block_offset + margin_strut.Sum(); | 477 bfc_block_offset + margin_strut.Sum(); |
415 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), origin_point_block_offset, | 478 bool updated = MaybeUpdateFragmentBfcOffset( |
416 &container_builder_); | 479 ConstraintSpace(), origin_point_block_offset, &container_builder_); |
480 | |
481 if (updated && abort_when_bfc_resolved_) | |
482 return WTF::nullopt; | |
483 | |
417 // TODO(ikilpatrick): Check if origin_point_block_offset is correct - | 484 // TODO(ikilpatrick): Check if origin_point_block_offset is correct - |
418 // MaybeUpdateFragmentBfcOffset might have changed it due to clearance. | 485 // MaybeUpdateFragmentBfcOffset might have changed it due to clearance. |
419 PositionPendingFloats(origin_point_block_offset, &container_builder_, | 486 PositionPendingFloats(origin_point_block_offset, &container_builder_, |
420 MutableConstraintSpace()); | 487 &unpositioned_floats_, MutableConstraintSpace()); |
421 } | 488 } |
422 | 489 |
423 NGLogicalOffset child_bfc_offset = { | 490 NGLogicalOffset child_bfc_offset = { |
424 ConstraintSpace().BfcOffset().inline_offset + | 491 ConstraintSpace().BfcOffset().inline_offset + |
425 border_scrollbar_padding_.inline_start + margins.inline_start, | 492 border_scrollbar_padding_.inline_start + margins.inline_start, |
426 bfc_block_offset}; | 493 bfc_block_offset}; |
427 | 494 |
428 // Append the current margin strut with child's block start margin. | 495 // Append the current margin strut with child's block start margin. |
429 // Non empty border/padding, and new FC use cases are handled inside of the | 496 // Non empty border/padding, and new FC use cases are handled inside of the |
430 // child's layout. | 497 // child's layout |
431 margin_strut.Append(margins.block_start); | 498 margin_strut.Append(margins.block_start); |
432 | 499 |
433 return {child_bfc_offset, margin_strut, margins}; | 500 return NGInflowChildData{child_bfc_offset, margin_strut, margins}; |
434 } | 501 } |
435 | 502 |
436 NGPreviousInflowPosition NGBlockLayoutAlgorithm::FinishChildLayout( | 503 WTF::Optional<NGPreviousInflowPosition> |
504 NGBlockLayoutAlgorithm::FinishChildLayout( | |
437 const NGConstraintSpace& child_space, | 505 const NGConstraintSpace& child_space, |
438 const NGPreviousInflowPosition& previous_inflow_position, | 506 const NGPreviousInflowPosition& previous_inflow_position, |
439 const NGInflowChildData& child_data, | 507 const NGInflowChildData& child_data, |
440 const NGLayoutInputNode child, | 508 NGLayoutInputNode child, |
441 NGLayoutResult* layout_result) { | 509 NGBreakToken* child_break_token, |
442 // Pull out unpositioned floats to the current fragment. This may needed if | 510 RefPtr<NGLayoutResult> layout_result) { |
443 // for example the child fragment could not position its floats because it's | 511 // TODO(ikilpatrick): Split this function into two - one for positioning, and |
444 // empty and therefore couldn't determine its position in space. | 512 // the other for producing NGPreviousInflowPosition. |
445 container_builder_.MutableUnpositionedFloats().AppendVector( | 513 |
446 layout_result->UnpositionedFloats()); | 514 // If we don't know our BFC offset yet, we need to copy the list of |
515 // unpositioned floats from the child's layout result. | |
516 // | |
517 // If the child had any unpositioned floats, we need to abort our layout if | |
518 // we resolve our BFC offset. | |
519 // | |
520 // If we are a new formatting context, the child will get re-laid out once it | |
521 // has been positioned. | |
522 // | |
523 // TODO(ikilpatrick): a more optimal version of this is to set | |
524 // abort_when_bfc_resolved_, if the child tree _added_ any floats. | |
525 if (!container_builder_.BfcOffset() && | |
526 !child_space.IsNewFormattingContext()) { | |
527 unpositioned_floats_ = layout_result->UnpositionedFloats(); | |
528 abort_when_bfc_resolved_ |= !layout_result->UnpositionedFloats().IsEmpty(); | |
529 if (child_space.FloatsBfcOffset()) | |
530 DCHECK(layout_result->UnpositionedFloats().IsEmpty()); | |
531 } | |
532 | |
533 // Determine the fragment's position in the parent space. | |
534 WTF::Optional<NGLogicalOffset> child_bfc_offset; | |
535 if (child.CreatesNewFormattingContext()) { | |
536 child_bfc_offset = PositionNewFc(child, previous_inflow_position, | |
537 *layout_result, child_data, child_space); | |
538 if (!child_bfc_offset) | |
539 return WTF::nullopt; | |
540 } else if (layout_result->BfcOffset()) { | |
541 child_bfc_offset = | |
542 PositionWithBfcOffset(layout_result->BfcOffset().value()); | |
543 if (!child_bfc_offset) | |
544 return WTF::nullopt; | |
545 } else if (container_builder_.BfcOffset()) { | |
546 child_bfc_offset = | |
547 PositionWithParentBfc(child_space, child_data, *layout_result); | |
548 } else | |
549 DCHECK(IsEmptyFragment(ConstraintSpace().WritingMode(), *layout_result)); | |
550 | |
551 if ((layout_result->Status() == NGLayoutResult::kBfcOffsetResolved || | |
552 !layout_result->UnpositionedFloats().IsEmpty()) && | |
553 child_bfc_offset) { | |
554 RefPtr<NGConstraintSpace> new_child_space = | |
555 CreateConstraintSpaceForChild(child, child_data, child_bfc_offset); | |
556 layout_result = child.Layout(new_child_space.Get(), child_break_token); | |
557 } | |
447 | 558 |
448 NGBoxFragment fragment( | 559 NGBoxFragment fragment( |
449 ConstraintSpace().WritingMode(), | 560 ConstraintSpace().WritingMode(), |
450 ToNGPhysicalBoxFragment(layout_result->PhysicalFragment().Get())); | 561 ToNGPhysicalBoxFragment(layout_result->PhysicalFragment().Get())); |
451 | 562 |
452 // Determine the fragment's position in the parent space. | |
453 WTF::Optional<NGLogicalOffset> child_bfc_offset; | |
454 if (child.CreatesNewFormattingContext()) | |
455 child_bfc_offset = PositionNewFc(child, previous_inflow_position, fragment, | |
456 child_data, child_space); | |
457 else if (layout_result->BfcOffset()) | |
458 child_bfc_offset = | |
459 PositionWithBfcOffset(layout_result->BfcOffset().value()); | |
460 else if (container_builder_.BfcOffset()) | |
461 child_bfc_offset = | |
462 PositionWithParentBfc(child_space, child_data, *layout_result); | |
463 else | |
464 DCHECK(!fragment.BlockSize()); | |
465 | |
466 NGLogicalOffset logical_offset = | 563 NGLogicalOffset logical_offset = |
467 CalculateLogicalOffset(child_data.margins, child_bfc_offset); | 564 CalculateLogicalOffset(child_data.margins, child_bfc_offset); |
468 | 565 |
469 NGMarginStrut margin_strut = layout_result->EndMarginStrut(); | 566 NGMarginStrut margin_strut = layout_result->EndMarginStrut(); |
470 margin_strut.Append(child_data.margins.block_end); | 567 margin_strut.Append(child_data.margins.block_end); |
471 | 568 |
569 // TODO(ikilpatrick): Refactor below such that we don't have to rely on the | |
570 // if (fragment) ... checks. | |
571 | |
472 // Only modify content_size_ if the fragment's BlockSize is not empty. This is | 572 // Only modify content_size_ if the fragment's BlockSize is not empty. This is |
473 // needed to prevent the situation when logical_offset is included in | 573 // needed to prevent the situation when logical_offset is included in |
474 // content_size_ for empty blocks. Example: | 574 // content_size_ for empty blocks. Example: |
475 // <div style="overflow:hidden"> | 575 // <div style="overflow:hidden"> |
476 // <div style="margin-top: 8px"></div> | 576 // <div style="margin-top: 8px"></div> |
477 // <div style="margin-top: 10px"></div> | 577 // <div style="margin-top: 10px"></div> |
478 // </div> | 578 // </div> |
479 if (fragment.BlockSize()) | 579 if (fragment) { |
480 content_size_ = std::max( | 580 if (fragment.BlockSize()) { |
eae
2017/07/10 23:27:49
What if the blockSize > 0 but the inlineSize is ze
ikilpatrick
2017/07/11 17:20:41
Only cares about block size, "empty" is only in th
| |
481 content_size_, logical_offset.block_offset + fragment.BlockSize()); | 581 content_size_ = std::max( |
482 max_inline_size_ = std::max( | 582 content_size_, logical_offset.block_offset + fragment.BlockSize()); |
483 max_inline_size_, fragment.InlineSize() + child_data.margins.InlineSum() + | 583 } |
484 border_scrollbar_padding_.InlineSum()); | 584 max_inline_size_ = |
585 std::max(max_inline_size_, fragment.InlineSize() + | |
586 child_data.margins.InlineSum() + | |
587 border_scrollbar_padding_.InlineSum()); | |
588 } | |
485 | 589 |
486 container_builder_.AddChild(layout_result, logical_offset); | 590 if (fragment) |
591 container_builder_.AddChild(layout_result, logical_offset); | |
487 | 592 |
488 // Determine the child's end BFC block offset and logical offset, for the | 593 // Determine the child's end BFC block offset and logical offset, for the |
489 // next child to use. | 594 // next child to use. |
490 LayoutUnit child_end_bfc_block_offset; | 595 LayoutUnit child_end_bfc_block_offset; |
491 LayoutUnit logical_block_offset; | 596 LayoutUnit logical_block_offset; |
492 | 597 |
493 if (child_bfc_offset) { | 598 if (child_bfc_offset) { |
494 // TODO(crbug.com/716930): I think the layout_result->BfcOffset() condition | 599 // TODO(crbug.com/716930): I think the layout_result->BfcOffset() condition |
495 // here can be removed once we've removed inline splitting. | 600 // here can be removed once we've removed inline splitting. |
496 if (fragment.BlockSize() || layout_result->BfcOffset()) { | 601 if (fragment && (fragment.BlockSize() || layout_result->BfcOffset())) { |
497 child_end_bfc_block_offset = | 602 child_end_bfc_block_offset = |
498 child_bfc_offset.value().block_offset + fragment.BlockSize(); | 603 child_bfc_offset.value().block_offset + fragment.BlockSize(); |
499 logical_block_offset = logical_offset.block_offset + fragment.BlockSize(); | 604 logical_block_offset = logical_offset.block_offset + fragment.BlockSize(); |
500 } else { | 605 } else { |
501 DCHECK_EQ(LayoutUnit(), fragment.BlockSize()); | 606 DCHECK(IsEmptyFragment(ConstraintSpace().WritingMode(), *layout_result)); |
607 | |
502 child_end_bfc_block_offset = previous_inflow_position.bfc_block_offset; | 608 child_end_bfc_block_offset = previous_inflow_position.bfc_block_offset; |
503 logical_block_offset = previous_inflow_position.logical_block_offset; | 609 logical_block_offset = previous_inflow_position.logical_block_offset; |
504 } | 610 } |
505 } else { | 611 } else { |
506 child_end_bfc_block_offset = ConstraintSpace().BfcOffset().block_offset; | 612 child_end_bfc_block_offset = ConstraintSpace().BfcOffset().block_offset; |
507 logical_block_offset = LayoutUnit(); | 613 logical_block_offset = LayoutUnit(); |
508 } | 614 } |
509 | 615 |
510 return {child_end_bfc_block_offset, logical_block_offset, margin_strut}; | 616 return NGPreviousInflowPosition{child_end_bfc_block_offset, |
617 logical_block_offset, margin_strut}; | |
511 } | 618 } |
512 | 619 |
513 NGLogicalOffset NGBlockLayoutAlgorithm::PositionNewFc( | 620 WTF::Optional<NGLogicalOffset> NGBlockLayoutAlgorithm::PositionNewFc( |
514 const NGLayoutInputNode& child, | 621 const NGLayoutInputNode& child, |
515 const NGPreviousInflowPosition& previous_inflow_position, | 622 const NGPreviousInflowPosition& previous_inflow_position, |
516 const NGBoxFragment& fragment, | 623 const NGLayoutResult& layout_result, |
517 const NGInflowChildData& child_data, | 624 const NGInflowChildData& child_data, |
518 const NGConstraintSpace& child_space) { | 625 const NGConstraintSpace& child_space) { |
519 const ComputedStyle& child_style = child.Style(); | 626 const ComputedStyle& child_style = child.Style(); |
520 | 627 |
628 NGBoxFragment fragment( | |
629 ConstraintSpace().WritingMode(), | |
630 ToNGPhysicalBoxFragment(layout_result.PhysicalFragment().Get())); | |
631 | |
521 LayoutUnit child_bfc_offset_estimate = | 632 LayoutUnit child_bfc_offset_estimate = |
522 child_data.bfc_offset_estimate.block_offset; | 633 child_data.bfc_offset_estimate.block_offset; |
523 | 634 |
524 // 1. Position all pending floats to a temporary space. | 635 // 1. Position all pending floats to a temporary space. |
525 RefPtr<NGConstraintSpace> tmp_space = | 636 RefPtr<NGConstraintSpace> tmp_space = |
526 NGConstraintSpaceBuilder(&child_space) | 637 NGConstraintSpaceBuilder(&child_space) |
527 .SetIsNewFormattingContext(false) | 638 .SetIsNewFormattingContext(false) |
528 .ToConstraintSpace(child_space.WritingMode()); | 639 .ToConstraintSpace(child_space.WritingMode()); |
529 PositionFloats(child_bfc_offset_estimate, child_bfc_offset_estimate, | 640 PositionFloats(child_bfc_offset_estimate, child_bfc_offset_estimate, |
530 container_builder_.UnpositionedFloats(), tmp_space.Get()); | 641 unpositioned_floats_, tmp_space.Get()); |
531 | 642 |
532 NGLogicalOffset origin_offset = {ConstraintSpace().BfcOffset().inline_offset + | 643 NGLogicalOffset origin_offset = {ConstraintSpace().BfcOffset().inline_offset + |
533 border_scrollbar_padding_.inline_start, | 644 border_scrollbar_padding_.inline_start, |
534 child_bfc_offset_estimate}; | 645 child_bfc_offset_estimate}; |
535 AdjustToClearance( | 646 AdjustToClearance( |
536 GetClearanceOffset(ConstraintSpace().Exclusions(), child_style.Clear()), | 647 GetClearanceOffset(ConstraintSpace().Exclusions(), child_style.Clear()), |
537 &origin_offset); | 648 &origin_offset); |
538 | 649 |
539 // 2. Find an estimated layout opportunity for our fragment. | 650 // 2. Find an estimated layout opportunity for our fragment. |
540 NGLayoutOpportunity opportunity = FindLayoutOpportunityForFragment( | 651 NGLayoutOpportunity opportunity = FindLayoutOpportunityForFragment( |
541 tmp_space->Exclusions().get(), child_space.AvailableSize(), origin_offset, | 652 tmp_space->Exclusions().get(), child_space.AvailableSize(), origin_offset, |
542 child_data.margins, fragment.Size()); | 653 child_data.margins, fragment.Size()); |
543 | 654 |
544 NGMarginStrut margin_strut = previous_inflow_position.margin_strut; | 655 NGMarginStrut margin_strut = previous_inflow_position.margin_strut; |
545 | 656 |
546 // 3. If the found opportunity lies on the same line with our estimated | 657 // 3. If the found opportunity lies on the same line with our estimated |
547 // child's BFC offset then merge fragment's margins with the current | 658 // child's BFC offset then merge fragment's margins with the current |
548 // MarginStrut. | 659 // MarginStrut. |
549 if (opportunity.offset.block_offset == child_bfc_offset_estimate) | 660 if (opportunity.offset.block_offset == child_bfc_offset_estimate) |
550 margin_strut.Append(child_data.margins.block_start); | 661 margin_strut.Append(child_data.margins.block_start); |
551 child_bfc_offset_estimate += margin_strut.Sum(); | 662 child_bfc_offset_estimate += margin_strut.Sum(); |
552 | 663 |
553 // 4. The child's BFC block offset is known here. | 664 // 4. The child's BFC block offset is known here. |
554 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), child_bfc_offset_estimate, | 665 bool updated = MaybeUpdateFragmentBfcOffset( |
555 &container_builder_); | 666 ConstraintSpace(), child_bfc_offset_estimate, &container_builder_); |
667 | |
668 if (updated && abort_when_bfc_resolved_) | |
669 return WTF::nullopt; | |
670 | |
556 PositionPendingFloats(child_bfc_offset_estimate, &container_builder_, | 671 PositionPendingFloats(child_bfc_offset_estimate, &container_builder_, |
557 MutableConstraintSpace()); | 672 &unpositioned_floats_, MutableConstraintSpace()); |
558 | 673 |
559 origin_offset = {ConstraintSpace().BfcOffset().inline_offset + | 674 origin_offset = {ConstraintSpace().BfcOffset().inline_offset + |
560 border_scrollbar_padding_.inline_start, | 675 border_scrollbar_padding_.inline_start, |
561 child_bfc_offset_estimate}; | 676 child_bfc_offset_estimate}; |
562 AdjustToClearance( | 677 AdjustToClearance( |
563 GetClearanceOffset(ConstraintSpace().Exclusions(), child_style.Clear()), | 678 GetClearanceOffset(ConstraintSpace().Exclusions(), child_style.Clear()), |
564 &origin_offset); | 679 &origin_offset); |
565 | 680 |
566 // 5. Find the final layout opportunity for the fragment after all pending | 681 // 5. Find the final layout opportunity for the fragment after all pending |
567 // floats are positioned at the correct BFC block's offset. | 682 // floats are positioned at the correct BFC block's offset. |
568 opportunity = FindLayoutOpportunityForFragment( | 683 opportunity = FindLayoutOpportunityForFragment( |
569 MutableConstraintSpace()->Exclusions().get(), child_space.AvailableSize(), | 684 MutableConstraintSpace()->Exclusions().get(), child_space.AvailableSize(), |
570 origin_offset, child_data.margins, fragment.Size()); | 685 origin_offset, child_data.margins, fragment.Size()); |
571 | 686 |
572 return opportunity.offset; | 687 return opportunity.offset; |
573 } | 688 } |
574 | 689 |
575 NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithBfcOffset( | 690 WTF::Optional<NGLogicalOffset> NGBlockLayoutAlgorithm::PositionWithBfcOffset( |
576 const NGLogicalOffset& bfc_offset) { | 691 const NGLogicalOffset& bfc_offset) { |
577 LayoutUnit bfc_block_offset = bfc_offset.block_offset; | 692 LayoutUnit bfc_block_offset = bfc_offset.block_offset; |
578 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), bfc_block_offset, | 693 bool updated = MaybeUpdateFragmentBfcOffset( |
579 &container_builder_); | 694 ConstraintSpace(), bfc_block_offset, &container_builder_); |
695 | |
696 if (updated && abort_when_bfc_resolved_) | |
697 return WTF::nullopt; | |
698 | |
580 PositionPendingFloats(bfc_block_offset, &container_builder_, | 699 PositionPendingFloats(bfc_block_offset, &container_builder_, |
581 MutableConstraintSpace()); | 700 &unpositioned_floats_, MutableConstraintSpace()); |
582 return bfc_offset; | 701 return bfc_offset; |
583 } | 702 } |
584 | 703 |
585 NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithParentBfc( | 704 NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithParentBfc( |
586 const NGConstraintSpace& space, | 705 const NGConstraintSpace& space, |
587 const NGInflowChildData& child_data, | 706 const NGInflowChildData& child_data, |
588 const NGLayoutResult& layout_result) { | 707 const NGLayoutResult& layout_result) { |
589 // The child must be an in-flow zero-block-size fragment, use its end margin | 708 // The child must be an in-flow zero-block-size fragment, use its end margin |
590 // strut for positioning. | 709 // strut for positioning. |
591 NGFragment fragment(ConstraintSpace().WritingMode(), | 710 DCHECK(IsEmptyFragment(ConstraintSpace().WritingMode(), layout_result)); |
592 layout_result.PhysicalFragment().Get()); | |
593 DCHECK_EQ(fragment.BlockSize(), LayoutUnit()); | |
594 | 711 |
595 NGLogicalOffset child_bfc_offset = { | 712 NGLogicalOffset child_bfc_offset = { |
596 ConstraintSpace().BfcOffset().inline_offset + | 713 ConstraintSpace().BfcOffset().inline_offset + |
597 border_scrollbar_padding_.inline_start + | 714 border_scrollbar_padding_.inline_start + |
598 child_data.margins.inline_start, | 715 child_data.margins.inline_start, |
599 child_data.bfc_offset_estimate.block_offset + | 716 child_data.bfc_offset_estimate.block_offset + |
600 layout_result.EndMarginStrut().Sum()}; | 717 layout_result.EndMarginStrut().Sum()}; |
601 | 718 |
602 AdjustToClearance(space.ClearanceOffset(), &child_bfc_offset); | 719 AdjustToClearance(space.ClearanceOffset(), &child_bfc_offset); |
603 PositionPendingFloats(child_bfc_offset.block_offset, &container_builder_, | |
604 MutableConstraintSpace()); | |
605 return child_bfc_offset; | 720 return child_bfc_offset; |
606 } | 721 } |
607 | 722 |
608 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() { | 723 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() { |
609 LayoutUnit used_block_size = | 724 LayoutUnit used_block_size = |
610 BreakToken() ? BreakToken()->UsedBlockSize() : LayoutUnit(); | 725 BreakToken() ? BreakToken()->UsedBlockSize() : LayoutUnit(); |
611 LayoutUnit block_size = ComputeBlockSizeForFragment( | 726 LayoutUnit block_size = ComputeBlockSizeForFragment( |
612 ConstraintSpace(), Style(), used_block_size + content_size_); | 727 ConstraintSpace(), Style(), used_block_size + content_size_); |
613 | 728 |
614 block_size -= used_block_size; | 729 block_size -= used_block_size; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
667 | 782 |
668 LayoutUnit child_inline_size = | 783 LayoutUnit child_inline_size = |
669 ComputeInlineSizeForFragment(*space, child_style, sizes); | 784 ComputeInlineSizeForFragment(*space, child_style, sizes); |
670 ApplyAutoMargins(*space, child_style, child_inline_size, &margins); | 785 ApplyAutoMargins(*space, child_style, child_inline_size, &margins); |
671 } | 786 } |
672 return margins; | 787 return margins; |
673 } | 788 } |
674 | 789 |
675 RefPtr<NGConstraintSpace> NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild( | 790 RefPtr<NGConstraintSpace> NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild( |
676 const NGLayoutInputNode child, | 791 const NGLayoutInputNode child, |
677 const NGInflowChildData& child_data) { | 792 const NGInflowChildData& child_data, |
793 const WTF::Optional<NGLogicalOffset> floats_bfc_offset) { | |
678 NGConstraintSpaceBuilder space_builder(MutableConstraintSpace()); | 794 NGConstraintSpaceBuilder space_builder(MutableConstraintSpace()); |
679 space_builder.SetAvailableSize(child_available_size_) | 795 space_builder.SetAvailableSize(child_available_size_) |
680 .SetPercentageResolutionSize(child_percentage_size_); | 796 .SetPercentageResolutionSize(child_percentage_size_); |
681 | 797 |
682 bool is_new_fc = child.CreatesNewFormattingContext(); | 798 bool is_new_fc = child.CreatesNewFormattingContext(); |
683 space_builder.SetIsNewFormattingContext(is_new_fc) | 799 space_builder.SetIsNewFormattingContext(is_new_fc) |
684 .SetBfcOffset(child_data.bfc_offset_estimate) | 800 .SetBfcOffset(child_data.bfc_offset_estimate) |
685 .SetMarginStrut(child_data.margin_strut); | 801 .SetMarginStrut(child_data.margin_strut); |
686 | 802 |
687 if (!is_new_fc) { | 803 if (!container_builder_.BfcOffset() && ConstraintSpace().FloatsBfcOffset()) { |
688 // This clears the current layout's unpositioned floats as they may be | 804 space_builder.SetFloatsBfcOffset( |
689 // positioned by the child. | 805 NGLogicalOffset{child_data.bfc_offset_estimate.inline_offset, |
690 space_builder.SetUnpositionedFloats( | 806 ConstraintSpace().FloatsBfcOffset()->block_offset}); |
691 container_builder_.MutableUnpositionedFloats()); | 807 } |
808 | |
809 if (floats_bfc_offset) | |
810 space_builder.SetFloatsBfcOffset(floats_bfc_offset); | |
811 | |
812 if (!is_new_fc && !floats_bfc_offset) { | |
813 space_builder.SetUnpositionedFloats(unpositioned_floats_); | |
692 } | 814 } |
693 | 815 |
694 if (child.IsInline()) { | 816 if (child.IsInline()) { |
695 // TODO(kojii): Setup space_builder appropriately for inline child. | 817 // TODO(kojii): Setup space_builder appropriately for inline child. |
696 space_builder.SetClearanceOffset(ConstraintSpace().ClearanceOffset()); | 818 space_builder.SetClearanceOffset(ConstraintSpace().ClearanceOffset()); |
697 return space_builder.ToConstraintSpace( | 819 return space_builder.ToConstraintSpace( |
698 FromPlatformWritingMode(Style().GetWritingMode())); | 820 FromPlatformWritingMode(Style().GetWritingMode())); |
699 } | 821 } |
700 | 822 |
701 const ComputedStyle& child_style = child.Style(); | 823 const ComputedStyle& child_style = child.Style(); |
(...skipping 11 matching lines...) Expand all Loading... | |
713 // fragmentation line. | 835 // fragmentation line. |
714 if (is_new_fc) { | 836 if (is_new_fc) { |
715 space_available -= child_data.bfc_offset_estimate.block_offset; | 837 space_available -= child_data.bfc_offset_estimate.block_offset; |
716 } | 838 } |
717 } | 839 } |
718 space_builder.SetFragmentainerSpaceAvailable(space_available); | 840 space_builder.SetFragmentainerSpaceAvailable(space_available); |
719 | 841 |
720 return space_builder.ToConstraintSpace( | 842 return space_builder.ToConstraintSpace( |
721 FromPlatformWritingMode(child_style.GetWritingMode())); | 843 FromPlatformWritingMode(child_style.GetWritingMode())); |
722 } | 844 } |
845 | |
723 } // namespace blink | 846 } // namespace blink |
OLD | NEW |