| 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 |