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); |
| 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 PropagateBaselinesFromChildren(); | 402 PropagateBaselinesFromChildren(); |
341 | 403 |
342 return container_builder_.ToBoxFragment(); | 404 return container_builder_.ToBoxFragment(); |
343 } | 405 } |
344 | 406 |
345 void NGBlockLayoutAlgorithm::HandleOutOfFlowPositioned( | 407 void NGBlockLayoutAlgorithm::HandleOutOfFlowPositioned( |
346 const NGPreviousInflowPosition& previous_inflow_position, | 408 const NGPreviousInflowPosition& previous_inflow_position, |
347 NGBlockNode child) { | 409 NGBlockNode child) { |
348 // TODO(ikilpatrick): Determine which of the child's margins need to be | 410 // TODO(ikilpatrick): Determine which of the child's margins need to be |
349 // included for the static position. | 411 // included for the static position. |
(...skipping 15 matching lines...) Expand all Loading... |
365 // Calculate margins in the BFC's writing mode. | 427 // Calculate margins in the BFC's writing mode. |
366 NGBoxStrut margins = CalculateMargins(child); | 428 NGBoxStrut margins = CalculateMargins(child); |
367 | 429 |
368 LayoutUnit origin_inline_offset = | 430 LayoutUnit origin_inline_offset = |
369 constraint_space_->BfcOffset().inline_offset + | 431 constraint_space_->BfcOffset().inline_offset + |
370 border_scrollbar_padding_.inline_start; | 432 border_scrollbar_padding_.inline_start; |
371 | 433 |
372 RefPtr<NGUnpositionedFloat> unpositioned_float = NGUnpositionedFloat::Create( | 434 RefPtr<NGUnpositionedFloat> unpositioned_float = NGUnpositionedFloat::Create( |
373 child_available_size_, child_percentage_size_, origin_inline_offset, | 435 child_available_size_, child_percentage_size_, origin_inline_offset, |
374 constraint_space_->BfcOffset().inline_offset, margins, child, token); | 436 constraint_space_->BfcOffset().inline_offset, margins, child, token); |
375 container_builder_.AddUnpositionedFloat(unpositioned_float); | 437 unpositioned_floats_.push_back(std::move(unpositioned_float)); |
376 | 438 |
377 // If there is a break token for a float we must be resuming layout, we must | 439 // If there is a break token for a float we must be resuming layout, we must |
378 // always know our position in the BFC. | 440 // always know our position in the BFC. |
379 DCHECK(!token || container_builder_.BfcOffset()); | 441 DCHECK(!token || container_builder_.BfcOffset()); |
380 | 442 |
381 // No need to postpone the positioning if we know the correct offset. | 443 // No need to postpone the positioning if we know the correct offset. |
382 if (container_builder_.BfcOffset()) { | 444 if (container_builder_.BfcOffset() || ConstraintSpace().FloatsBfcOffset()) { |
383 // Adjust origin point to the margins of the last child. | 445 // Adjust origin point to the margins of the last child. |
384 // Example: <div style="margin-bottom: 20px"><float></div> | 446 // Example: <div style="margin-bottom: 20px"><float></div> |
385 // <div style="margin-bottom: 30px"></div> | 447 // <div style="margin-bottom: 30px"></div> |
386 LayoutUnit origin_block_offset = | 448 LayoutUnit origin_block_offset = |
387 previous_inflow_position.bfc_block_offset + | 449 container_builder_.BfcOffset() |
388 previous_inflow_position.margin_strut.Sum(); | 450 ? previous_inflow_position.bfc_block_offset + |
| 451 previous_inflow_position.margin_strut.Sum() |
| 452 : ConstraintSpace().FloatsBfcOffset().value().block_offset; |
389 PositionPendingFloats(origin_block_offset, &container_builder_, | 453 PositionPendingFloats(origin_block_offset, &container_builder_, |
390 MutableConstraintSpace()); | 454 &unpositioned_floats_, MutableConstraintSpace()); |
391 } | 455 } |
392 } | 456 } |
393 | 457 |
394 NGInflowChildData NGBlockLayoutAlgorithm::PrepareChildLayout( | 458 WTF::Optional<NGInflowChildData> NGBlockLayoutAlgorithm::PrepareChildLayout( |
395 const NGPreviousInflowPosition& previous_inflow_position, | 459 const NGPreviousInflowPosition& previous_inflow_position, |
396 NGLayoutInputNode child) { | 460 NGLayoutInputNode child) { |
397 DCHECK(child); | 461 DCHECK(child); |
398 DCHECK(!child.IsFloating()); | 462 DCHECK(!child.IsFloating()); |
399 | 463 |
400 LayoutUnit bfc_block_offset = previous_inflow_position.bfc_block_offset; | 464 LayoutUnit bfc_block_offset = previous_inflow_position.bfc_block_offset; |
401 | 465 |
402 // Calculate margins in parent's writing mode. | 466 // Calculate margins in parent's writing mode. |
403 NGBoxStrut margins = CalculateMargins(child); | 467 NGBoxStrut margins = CalculateMargins(child); |
404 NGMarginStrut margin_strut = previous_inflow_position.margin_strut; | 468 NGMarginStrut margin_strut = previous_inflow_position.margin_strut; |
405 | 469 |
406 bool should_position_pending_floats = | 470 bool should_position_pending_floats = |
407 !child.CreatesNewFormattingContext() && | 471 !child.CreatesNewFormattingContext() && |
408 ClearanceMayAffectLayout(ConstraintSpace(), | 472 ClearanceMayAffectLayout(ConstraintSpace(), unpositioned_floats_, |
409 container_builder_.UnpositionedFloats(), | |
410 child.Style()); | 473 child.Style()); |
411 | 474 |
412 // Children which may clear a float need to force all the pending floats to | 475 // Children which may clear a float need to force all the pending floats to |
413 // be positioned before layout. This also resolves the fragment's bfc offset. | 476 // be positioned before layout. This also resolves the fragment's bfc offset. |
414 if (should_position_pending_floats) { | 477 if (should_position_pending_floats) { |
415 LayoutUnit origin_point_block_offset = | 478 LayoutUnit origin_point_block_offset = |
416 bfc_block_offset + margin_strut.Sum(); | 479 bfc_block_offset + margin_strut.Sum(); |
417 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), origin_point_block_offset, | 480 bool updated = MaybeUpdateFragmentBfcOffset( |
418 &container_builder_); | 481 ConstraintSpace(), origin_point_block_offset, &container_builder_); |
| 482 |
| 483 if (updated && abort_when_bfc_resolved_) |
| 484 return WTF::nullopt; |
| 485 |
419 // TODO(ikilpatrick): Check if origin_point_block_offset is correct - | 486 // TODO(ikilpatrick): Check if origin_point_block_offset is correct - |
420 // MaybeUpdateFragmentBfcOffset might have changed it due to clearance. | 487 // MaybeUpdateFragmentBfcOffset might have changed it due to clearance. |
421 PositionPendingFloats(origin_point_block_offset, &container_builder_, | 488 PositionPendingFloats(origin_point_block_offset, &container_builder_, |
422 MutableConstraintSpace()); | 489 &unpositioned_floats_, MutableConstraintSpace()); |
423 } | 490 } |
424 | 491 |
425 NGLogicalOffset child_bfc_offset = { | 492 NGLogicalOffset child_bfc_offset = { |
426 ConstraintSpace().BfcOffset().inline_offset + | 493 ConstraintSpace().BfcOffset().inline_offset + |
427 border_scrollbar_padding_.inline_start + margins.inline_start, | 494 border_scrollbar_padding_.inline_start + margins.inline_start, |
428 bfc_block_offset}; | 495 bfc_block_offset}; |
429 | 496 |
430 // Append the current margin strut with child's block start margin. | 497 // Append the current margin strut with child's block start margin. |
431 // Non empty border/padding, and new FC use cases are handled inside of the | 498 // Non empty border/padding, and new FC use cases are handled inside of the |
432 // child's layout. | 499 // child's layout |
433 margin_strut.Append(margins.block_start); | 500 margin_strut.Append(margins.block_start); |
434 | 501 |
435 return {child_bfc_offset, margin_strut, margins}; | 502 return NGInflowChildData{child_bfc_offset, margin_strut, margins}; |
436 } | 503 } |
437 | 504 |
438 NGPreviousInflowPosition NGBlockLayoutAlgorithm::FinishChildLayout( | 505 WTF::Optional<NGPreviousInflowPosition> |
| 506 NGBlockLayoutAlgorithm::FinishChildLayout( |
439 const NGConstraintSpace& child_space, | 507 const NGConstraintSpace& child_space, |
440 const NGPreviousInflowPosition& previous_inflow_position, | 508 const NGPreviousInflowPosition& previous_inflow_position, |
441 const NGInflowChildData& child_data, | 509 const NGInflowChildData& child_data, |
442 const NGLayoutInputNode child, | 510 NGLayoutInputNode child, |
443 NGLayoutResult* layout_result) { | 511 NGBreakToken* child_break_token, |
444 // Pull out unpositioned floats to the current fragment. This may needed if | 512 RefPtr<NGLayoutResult> layout_result) { |
445 // for example the child fragment could not position its floats because it's | 513 // TODO(ikilpatrick): Split this function into two - one for positioning, and |
446 // empty and therefore couldn't determine its position in space. | 514 // the other for producing NGPreviousInflowPosition. |
447 container_builder_.MutableUnpositionedFloats().AppendVector( | 515 |
448 layout_result->UnpositionedFloats()); | 516 // If we don't know our BFC offset yet, we need to copy the list of |
| 517 // unpositioned floats from the child's layout result. |
| 518 // |
| 519 // If the child had any unpositioned floats, we need to abort our layout if |
| 520 // we resolve our BFC offset. |
| 521 // |
| 522 // If we are a new formatting context, the child will get re-laid out once it |
| 523 // has been positioned. |
| 524 // |
| 525 // TODO(ikilpatrick): a more optimal version of this is to set |
| 526 // abort_when_bfc_resolved_, if the child tree _added_ any floats. |
| 527 if (!container_builder_.BfcOffset() && |
| 528 !child_space.IsNewFormattingContext()) { |
| 529 unpositioned_floats_ = layout_result->UnpositionedFloats(); |
| 530 abort_when_bfc_resolved_ |= !layout_result->UnpositionedFloats().IsEmpty(); |
| 531 if (child_space.FloatsBfcOffset()) |
| 532 DCHECK(layout_result->UnpositionedFloats().IsEmpty()); |
| 533 } |
| 534 |
| 535 // Determine the fragment's position in the parent space. |
| 536 WTF::Optional<NGLogicalOffset> child_bfc_offset; |
| 537 if (child.CreatesNewFormattingContext()) { |
| 538 if (!PositionNewFc(child, previous_inflow_position, *layout_result, |
| 539 child_data, child_space, &child_bfc_offset)) |
| 540 return WTF::nullopt; |
| 541 } else if (layout_result->BfcOffset()) { |
| 542 if (!PositionWithBfcOffset(layout_result->BfcOffset().value(), |
| 543 &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 } |
449 | 558 |
450 NGBoxFragment fragment( | 559 NGBoxFragment fragment( |
451 ConstraintSpace().WritingMode(), | 560 ConstraintSpace().WritingMode(), |
452 ToNGPhysicalBoxFragment(layout_result->PhysicalFragment().Get())); | 561 ToNGPhysicalBoxFragment(layout_result->PhysicalFragment().Get())); |
453 | 562 |
454 // Determine the fragment's position in the parent space. | |
455 WTF::Optional<NGLogicalOffset> child_bfc_offset; | |
456 if (child.CreatesNewFormattingContext()) | |
457 child_bfc_offset = PositionNewFc(child, previous_inflow_position, fragment, | |
458 child_data, child_space); | |
459 else if (layout_result->BfcOffset()) | |
460 child_bfc_offset = | |
461 PositionWithBfcOffset(layout_result->BfcOffset().value()); | |
462 else if (container_builder_.BfcOffset()) | |
463 child_bfc_offset = | |
464 PositionWithParentBfc(child_space, child_data, *layout_result); | |
465 else | |
466 DCHECK(!fragment.BlockSize()); | |
467 | |
468 NGLogicalOffset logical_offset = | 563 NGLogicalOffset logical_offset = |
469 CalculateLogicalOffset(child_data.margins, child_bfc_offset); | 564 CalculateLogicalOffset(child_data.margins, child_bfc_offset); |
470 | 565 |
471 NGMarginStrut margin_strut = layout_result->EndMarginStrut(); | 566 NGMarginStrut margin_strut = layout_result->EndMarginStrut(); |
472 margin_strut.Append(child_data.margins.block_end); | 567 margin_strut.Append(child_data.margins.block_end); |
473 | 568 |
| 569 // TODO(ikilpatrick): Refactor below such that we don't have to rely on the |
| 570 // if (fragment) ... checks. |
| 571 |
474 // 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 |
475 // needed to prevent the situation when logical_offset is included in | 573 // needed to prevent the situation when logical_offset is included in |
476 // content_size_ for empty blocks. Example: | 574 // content_size_ for empty blocks. Example: |
477 // <div style="overflow:hidden"> | 575 // <div style="overflow:hidden"> |
478 // <div style="margin-top: 8px"></div> | 576 // <div style="margin-top: 8px"></div> |
479 // <div style="margin-top: 10px"></div> | 577 // <div style="margin-top: 10px"></div> |
480 // </div> | 578 // </div> |
481 if (fragment.BlockSize()) | 579 if (fragment) { |
482 content_size_ = std::max( | 580 if (fragment.BlockSize()) { |
483 content_size_, logical_offset.block_offset + fragment.BlockSize()); | 581 content_size_ = std::max( |
484 max_inline_size_ = std::max( | 582 content_size_, logical_offset.block_offset + fragment.BlockSize()); |
485 max_inline_size_, fragment.InlineSize() + child_data.margins.InlineSum() + | 583 } |
486 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 } |
487 | 589 |
488 container_builder_.AddChild(layout_result, logical_offset); | 590 if (fragment) |
| 591 container_builder_.AddChild(layout_result, logical_offset); |
489 | 592 |
490 // 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 |
491 // next child to use. | 594 // next child to use. |
492 LayoutUnit child_end_bfc_block_offset; | 595 LayoutUnit child_end_bfc_block_offset; |
493 LayoutUnit logical_block_offset; | 596 LayoutUnit logical_block_offset; |
494 | 597 |
495 if (child_bfc_offset) { | 598 if (child_bfc_offset) { |
496 // TODO(crbug.com/716930): I think the layout_result->BfcOffset() condition | 599 // TODO(crbug.com/716930): I think the layout_result->BfcOffset() condition |
497 // here can be removed once we've removed inline splitting. | 600 // here can be removed once we've removed inline splitting. |
498 if (fragment.BlockSize() || layout_result->BfcOffset()) { | 601 if (fragment && (fragment.BlockSize() || layout_result->BfcOffset())) { |
499 child_end_bfc_block_offset = | 602 child_end_bfc_block_offset = |
500 child_bfc_offset.value().block_offset + fragment.BlockSize(); | 603 child_bfc_offset.value().block_offset + fragment.BlockSize(); |
501 logical_block_offset = logical_offset.block_offset + fragment.BlockSize(); | 604 logical_block_offset = logical_offset.block_offset + fragment.BlockSize(); |
502 } else { | 605 } else { |
503 DCHECK_EQ(LayoutUnit(), fragment.BlockSize()); | 606 DCHECK(IsEmptyFragment(ConstraintSpace().WritingMode(), *layout_result)); |
| 607 |
504 child_end_bfc_block_offset = previous_inflow_position.bfc_block_offset; | 608 child_end_bfc_block_offset = previous_inflow_position.bfc_block_offset; |
505 logical_block_offset = previous_inflow_position.logical_block_offset; | 609 logical_block_offset = previous_inflow_position.logical_block_offset; |
506 } | 610 } |
507 } else { | 611 } else { |
508 child_end_bfc_block_offset = ConstraintSpace().BfcOffset().block_offset; | 612 child_end_bfc_block_offset = ConstraintSpace().BfcOffset().block_offset; |
509 logical_block_offset = LayoutUnit(); | 613 logical_block_offset = LayoutUnit(); |
510 } | 614 } |
511 | 615 |
512 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}; |
513 } | 618 } |
514 | 619 |
515 NGLogicalOffset NGBlockLayoutAlgorithm::PositionNewFc( | 620 bool NGBlockLayoutAlgorithm::PositionNewFc( |
516 const NGLayoutInputNode& child, | 621 const NGLayoutInputNode& child, |
517 const NGPreviousInflowPosition& previous_inflow_position, | 622 const NGPreviousInflowPosition& previous_inflow_position, |
518 const NGBoxFragment& fragment, | 623 const NGLayoutResult& layout_result, |
519 const NGInflowChildData& child_data, | 624 const NGInflowChildData& child_data, |
520 const NGConstraintSpace& child_space) { | 625 const NGConstraintSpace& child_space, |
| 626 WTF::Optional<NGLogicalOffset>* child_bfc_offset) { |
521 const ComputedStyle& child_style = child.Style(); | 627 const ComputedStyle& child_style = child.Style(); |
522 | 628 |
| 629 NGBoxFragment fragment( |
| 630 ConstraintSpace().WritingMode(), |
| 631 ToNGPhysicalBoxFragment(layout_result.PhysicalFragment().Get())); |
| 632 |
523 LayoutUnit child_bfc_offset_estimate = | 633 LayoutUnit child_bfc_offset_estimate = |
524 child_data.bfc_offset_estimate.block_offset; | 634 child_data.bfc_offset_estimate.block_offset; |
525 | 635 |
526 // 1. Position all pending floats to a temporary space. | 636 // 1. Position all pending floats to a temporary space. |
527 RefPtr<NGConstraintSpace> tmp_space = | 637 RefPtr<NGConstraintSpace> tmp_space = |
528 NGConstraintSpaceBuilder(&child_space) | 638 NGConstraintSpaceBuilder(&child_space) |
529 .SetIsNewFormattingContext(false) | 639 .SetIsNewFormattingContext(false) |
530 .ToConstraintSpace(child_space.WritingMode()); | 640 .ToConstraintSpace(child_space.WritingMode()); |
531 PositionFloats(child_bfc_offset_estimate, child_bfc_offset_estimate, | 641 PositionFloats(child_bfc_offset_estimate, child_bfc_offset_estimate, |
532 container_builder_.UnpositionedFloats(), tmp_space.Get()); | 642 unpositioned_floats_, tmp_space.Get()); |
533 | 643 |
534 NGLogicalOffset origin_offset = {ConstraintSpace().BfcOffset().inline_offset + | 644 NGLogicalOffset origin_offset = {ConstraintSpace().BfcOffset().inline_offset + |
535 border_scrollbar_padding_.inline_start, | 645 border_scrollbar_padding_.inline_start, |
536 child_bfc_offset_estimate}; | 646 child_bfc_offset_estimate}; |
537 AdjustToClearance( | 647 AdjustToClearance( |
538 GetClearanceOffset(ConstraintSpace().Exclusions(), child_style.Clear()), | 648 GetClearanceOffset(ConstraintSpace().Exclusions(), child_style.Clear()), |
539 &origin_offset); | 649 &origin_offset); |
540 | 650 |
541 // 2. Find an estimated layout opportunity for our fragment. | 651 // 2. Find an estimated layout opportunity for our fragment. |
542 NGLayoutOpportunity opportunity = FindLayoutOpportunityForFragment( | 652 NGLayoutOpportunity opportunity = FindLayoutOpportunityForFragment( |
543 tmp_space->Exclusions().get(), child_space.AvailableSize(), origin_offset, | 653 tmp_space->Exclusions().get(), child_space.AvailableSize(), origin_offset, |
544 child_data.margins, fragment.Size()); | 654 child_data.margins, fragment.Size()); |
545 | 655 |
546 NGMarginStrut margin_strut = previous_inflow_position.margin_strut; | 656 NGMarginStrut margin_strut = previous_inflow_position.margin_strut; |
547 | 657 |
548 // 3. If the found opportunity lies on the same line with our estimated | 658 // 3. If the found opportunity lies on the same line with our estimated |
549 // child's BFC offset then merge fragment's margins with the current | 659 // child's BFC offset then merge fragment's margins with the current |
550 // MarginStrut. | 660 // MarginStrut. |
551 if (opportunity.offset.block_offset == child_bfc_offset_estimate) | 661 if (opportunity.offset.block_offset == child_bfc_offset_estimate) |
552 margin_strut.Append(child_data.margins.block_start); | 662 margin_strut.Append(child_data.margins.block_start); |
553 child_bfc_offset_estimate += margin_strut.Sum(); | 663 child_bfc_offset_estimate += margin_strut.Sum(); |
554 | 664 |
555 // 4. The child's BFC block offset is known here. | 665 // 4. The child's BFC block offset is known here. |
556 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), child_bfc_offset_estimate, | 666 bool updated = MaybeUpdateFragmentBfcOffset( |
557 &container_builder_); | 667 ConstraintSpace(), child_bfc_offset_estimate, &container_builder_); |
| 668 |
| 669 if (updated && abort_when_bfc_resolved_) |
| 670 return false; |
| 671 |
558 PositionPendingFloats(child_bfc_offset_estimate, &container_builder_, | 672 PositionPendingFloats(child_bfc_offset_estimate, &container_builder_, |
559 MutableConstraintSpace()); | 673 &unpositioned_floats_, MutableConstraintSpace()); |
560 | 674 |
561 origin_offset = {ConstraintSpace().BfcOffset().inline_offset + | 675 origin_offset = {ConstraintSpace().BfcOffset().inline_offset + |
562 border_scrollbar_padding_.inline_start, | 676 border_scrollbar_padding_.inline_start, |
563 child_bfc_offset_estimate}; | 677 child_bfc_offset_estimate}; |
564 AdjustToClearance( | 678 AdjustToClearance( |
565 GetClearanceOffset(ConstraintSpace().Exclusions(), child_style.Clear()), | 679 GetClearanceOffset(ConstraintSpace().Exclusions(), child_style.Clear()), |
566 &origin_offset); | 680 &origin_offset); |
567 | 681 |
568 // 5. Find the final layout opportunity for the fragment after all pending | 682 // 5. Find the final layout opportunity for the fragment after all pending |
569 // floats are positioned at the correct BFC block's offset. | 683 // floats are positioned at the correct BFC block's offset. |
570 opportunity = FindLayoutOpportunityForFragment( | 684 opportunity = FindLayoutOpportunityForFragment( |
571 MutableConstraintSpace()->Exclusions().get(), child_space.AvailableSize(), | 685 MutableConstraintSpace()->Exclusions().get(), child_space.AvailableSize(), |
572 origin_offset, child_data.margins, fragment.Size()); | 686 origin_offset, child_data.margins, fragment.Size()); |
573 | 687 |
574 return opportunity.offset; | 688 *child_bfc_offset = opportunity.offset; |
| 689 return true; |
575 } | 690 } |
576 | 691 |
577 NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithBfcOffset( | 692 bool NGBlockLayoutAlgorithm::PositionWithBfcOffset( |
578 const NGLogicalOffset& bfc_offset) { | 693 const NGLogicalOffset& bfc_offset, |
| 694 WTF::Optional<NGLogicalOffset>* child_bfc_offset) { |
579 LayoutUnit bfc_block_offset = bfc_offset.block_offset; | 695 LayoutUnit bfc_block_offset = bfc_offset.block_offset; |
580 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), bfc_block_offset, | 696 bool updated = MaybeUpdateFragmentBfcOffset( |
581 &container_builder_); | 697 ConstraintSpace(), bfc_block_offset, &container_builder_); |
| 698 |
| 699 if (updated && abort_when_bfc_resolved_) |
| 700 return false; |
| 701 |
582 PositionPendingFloats(bfc_block_offset, &container_builder_, | 702 PositionPendingFloats(bfc_block_offset, &container_builder_, |
583 MutableConstraintSpace()); | 703 &unpositioned_floats_, MutableConstraintSpace()); |
584 return bfc_offset; | 704 |
| 705 *child_bfc_offset = bfc_offset; |
| 706 return true; |
585 } | 707 } |
586 | 708 |
587 NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithParentBfc( | 709 NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithParentBfc( |
588 const NGConstraintSpace& space, | 710 const NGConstraintSpace& space, |
589 const NGInflowChildData& child_data, | 711 const NGInflowChildData& child_data, |
590 const NGLayoutResult& layout_result) { | 712 const NGLayoutResult& layout_result) { |
591 // The child must be an in-flow zero-block-size fragment, use its end margin | 713 // The child must be an in-flow zero-block-size fragment, use its end margin |
592 // strut for positioning. | 714 // strut for positioning. |
593 NGFragment fragment(ConstraintSpace().WritingMode(), | 715 DCHECK(IsEmptyFragment(ConstraintSpace().WritingMode(), layout_result)); |
594 layout_result.PhysicalFragment().Get()); | |
595 DCHECK_EQ(fragment.BlockSize(), LayoutUnit()); | |
596 | 716 |
597 NGLogicalOffset child_bfc_offset = { | 717 NGLogicalOffset child_bfc_offset = { |
598 ConstraintSpace().BfcOffset().inline_offset + | 718 ConstraintSpace().BfcOffset().inline_offset + |
599 border_scrollbar_padding_.inline_start + | 719 border_scrollbar_padding_.inline_start + |
600 child_data.margins.inline_start, | 720 child_data.margins.inline_start, |
601 child_data.bfc_offset_estimate.block_offset + | 721 child_data.bfc_offset_estimate.block_offset + |
602 layout_result.EndMarginStrut().Sum()}; | 722 layout_result.EndMarginStrut().Sum()}; |
603 | 723 |
604 AdjustToClearance(space.ClearanceOffset(), &child_bfc_offset); | 724 AdjustToClearance(space.ClearanceOffset(), &child_bfc_offset); |
605 PositionPendingFloats(child_bfc_offset.block_offset, &container_builder_, | |
606 MutableConstraintSpace()); | |
607 return child_bfc_offset; | 725 return child_bfc_offset; |
608 } | 726 } |
609 | 727 |
610 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() { | 728 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() { |
611 LayoutUnit used_block_size = | 729 LayoutUnit used_block_size = |
612 BreakToken() ? BreakToken()->UsedBlockSize() : LayoutUnit(); | 730 BreakToken() ? BreakToken()->UsedBlockSize() : LayoutUnit(); |
613 LayoutUnit block_size = ComputeBlockSizeForFragment( | 731 LayoutUnit block_size = ComputeBlockSizeForFragment( |
614 ConstraintSpace(), Style(), used_block_size + content_size_); | 732 ConstraintSpace(), Style(), used_block_size + content_size_); |
615 | 733 |
616 block_size -= used_block_size; | 734 block_size -= used_block_size; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
669 | 787 |
670 LayoutUnit child_inline_size = | 788 LayoutUnit child_inline_size = |
671 ComputeInlineSizeForFragment(*space, child_style, sizes); | 789 ComputeInlineSizeForFragment(*space, child_style, sizes); |
672 ApplyAutoMargins(*space, child_style, child_inline_size, &margins); | 790 ApplyAutoMargins(*space, child_style, child_inline_size, &margins); |
673 } | 791 } |
674 return margins; | 792 return margins; |
675 } | 793 } |
676 | 794 |
677 RefPtr<NGConstraintSpace> NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild( | 795 RefPtr<NGConstraintSpace> NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild( |
678 const NGLayoutInputNode child, | 796 const NGLayoutInputNode child, |
679 const NGInflowChildData& child_data) { | 797 const NGInflowChildData& child_data, |
| 798 const WTF::Optional<NGLogicalOffset> floats_bfc_offset) { |
680 NGConstraintSpaceBuilder space_builder(MutableConstraintSpace()); | 799 NGConstraintSpaceBuilder space_builder(MutableConstraintSpace()); |
681 space_builder.SetAvailableSize(child_available_size_) | 800 space_builder.SetAvailableSize(child_available_size_) |
682 .SetPercentageResolutionSize(child_percentage_size_); | 801 .SetPercentageResolutionSize(child_percentage_size_); |
683 | 802 |
684 if (NGBaseline::ShouldPropagateBaselines(child)) | 803 if (NGBaseline::ShouldPropagateBaselines(child)) |
685 space_builder.AddBaselineRequests(ConstraintSpace().BaselineRequests()); | 804 space_builder.AddBaselineRequests(ConstraintSpace().BaselineRequests()); |
686 | 805 |
687 bool is_new_fc = child.CreatesNewFormattingContext(); | 806 bool is_new_fc = child.CreatesNewFormattingContext(); |
688 space_builder.SetIsNewFormattingContext(is_new_fc) | 807 space_builder.SetIsNewFormattingContext(is_new_fc) |
689 .SetBfcOffset(child_data.bfc_offset_estimate) | 808 .SetBfcOffset(child_data.bfc_offset_estimate) |
690 .SetMarginStrut(child_data.margin_strut); | 809 .SetMarginStrut(child_data.margin_strut); |
691 | 810 |
692 if (!is_new_fc) { | 811 if (!container_builder_.BfcOffset() && ConstraintSpace().FloatsBfcOffset()) { |
693 // This clears the current layout's unpositioned floats as they may be | 812 space_builder.SetFloatsBfcOffset( |
694 // positioned by the child. | 813 NGLogicalOffset{child_data.bfc_offset_estimate.inline_offset, |
695 space_builder.SetUnpositionedFloats( | 814 ConstraintSpace().FloatsBfcOffset()->block_offset}); |
696 container_builder_.MutableUnpositionedFloats()); | 815 } |
| 816 |
| 817 if (floats_bfc_offset) |
| 818 space_builder.SetFloatsBfcOffset(floats_bfc_offset); |
| 819 |
| 820 if (!is_new_fc && !floats_bfc_offset) { |
| 821 space_builder.SetUnpositionedFloats(unpositioned_floats_); |
697 } | 822 } |
698 | 823 |
699 if (child.IsInline()) { | 824 if (child.IsInline()) { |
700 // TODO(kojii): Setup space_builder appropriately for inline child. | 825 // TODO(kojii): Setup space_builder appropriately for inline child. |
701 space_builder.SetClearanceOffset(ConstraintSpace().ClearanceOffset()); | 826 space_builder.SetClearanceOffset(ConstraintSpace().ClearanceOffset()); |
702 return space_builder.ToConstraintSpace( | 827 return space_builder.ToConstraintSpace( |
703 FromPlatformWritingMode(Style().GetWritingMode())); | 828 FromPlatformWritingMode(Style().GetWritingMode())); |
704 } | 829 } |
705 | 830 |
706 const ComputedStyle& child_style = child.Style(); | 831 const ComputedStyle& child_style = child.Style(); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
766 break; | 891 break; |
767 case NGBaselineAlgorithmType::kFirstLine: | 892 case NGBaselineAlgorithmType::kFirstLine: |
768 for (unsigned i = 0; i < container_builder_.Children().size(); i++) { | 893 for (unsigned i = 0; i < container_builder_.Children().size(); i++) { |
769 if (AddBaseline(request, i)) | 894 if (AddBaseline(request, i)) |
770 break; | 895 break; |
771 } | 896 } |
772 break; | 897 break; |
773 } | 898 } |
774 } | 899 } |
775 } | 900 } |
| 901 |
776 } // namespace blink | 902 } // namespace blink |
OLD | NEW |