| 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_box_fragment.h" | |
| 11 #include "core/layout/ng/ng_constraint_space.h" | 10 #include "core/layout/ng/ng_constraint_space.h" |
| 12 #include "core/layout/ng/ng_constraint_space_builder.h" | 11 #include "core/layout/ng/ng_constraint_space_builder.h" |
| 13 #include "core/layout/ng/ng_floats_utils.h" | 12 #include "core/layout/ng/ng_floats_utils.h" |
| 14 #include "core/layout/ng/ng_fragment.h" | 13 #include "core/layout/ng/ng_fragment.h" |
| 15 #include "core/layout/ng/ng_fragment_builder.h" | 14 #include "core/layout/ng/ng_fragment_builder.h" |
| 16 #include "core/layout/ng/ng_layout_opportunity_iterator.h" | 15 #include "core/layout/ng/ng_layout_opportunity_iterator.h" |
| 17 #include "core/layout/ng/ng_length_utils.h" | 16 #include "core/layout/ng/ng_length_utils.h" |
| 18 #include "core/layout/ng/ng_out_of_flow_layout_part.h" | 17 #include "core/layout/ng/ng_out_of_flow_layout_part.h" |
| 19 #include "core/layout/ng/ng_space_utils.h" | 18 #include "core/layout/ng/ng_space_utils.h" |
| 20 #include "core/style/ComputedStyle.h" | 19 #include "core/style/ComputedStyle.h" |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 const NGLogicalOffset& offset, | 76 const NGLogicalOffset& offset, |
| 78 NGFragmentBuilder* builder) { | 77 NGFragmentBuilder* builder) { |
| 79 DCHECK(builder); | 78 DCHECK(builder); |
| 80 if (!builder->BfcOffset()) { | 79 if (!builder->BfcOffset()) { |
| 81 NGLogicalOffset mutable_offset(offset); | 80 NGLogicalOffset mutable_offset(offset); |
| 82 AdjustToClearance(space.ClearanceOffset(), &mutable_offset); | 81 AdjustToClearance(space.ClearanceOffset(), &mutable_offset); |
| 83 builder->SetBfcOffset(mutable_offset); | 82 builder->SetBfcOffset(mutable_offset); |
| 84 } | 83 } |
| 85 } | 84 } |
| 86 | 85 |
| 86 void PositionPendingFloats(LayoutUnit origin_block_offset, |
| 87 NGFragmentBuilder* container_builder, |
| 88 NGConstraintSpace* space) { |
| 89 DCHECK(container_builder->BfcOffset()) |
| 90 << "Parent BFC offset should be known here"; |
| 91 const auto& floating_objects = container_builder->UnpositionedFloats(); |
| 92 PositionFloats(origin_block_offset, |
| 93 container_builder->BfcOffset().value().block_offset, |
| 94 floating_objects, space); |
| 95 container_builder->MutablePositionedFloats().AppendVector(floating_objects); |
| 96 container_builder->MutableUnpositionedFloats().clear(); |
| 97 } |
| 98 |
| 87 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm(NGBlockNode* node, | 99 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm(NGBlockNode* node, |
| 88 NGConstraintSpace* space, | 100 NGConstraintSpace* space, |
| 89 NGBlockBreakToken* break_token) | 101 NGBlockBreakToken* break_token) |
| 90 : NGLayoutAlgorithm(node, space, break_token), | 102 : NGLayoutAlgorithm(node, space, break_token), |
| 91 space_builder_(constraint_space_) {} | 103 space_builder_(constraint_space_) {} |
| 92 | 104 |
| 93 Optional<MinMaxContentSize> NGBlockLayoutAlgorithm::ComputeMinMaxContentSize() | 105 Optional<MinMaxContentSize> NGBlockLayoutAlgorithm::ComputeMinMaxContentSize() |
| 94 const { | 106 const { |
| 95 MinMaxContentSize sizes; | 107 MinMaxContentSize sizes; |
| 96 | 108 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 123 sizes.min_content = std::max(sizes.min_content, child_sizes.min_content); | 135 sizes.min_content = std::max(sizes.min_content, child_sizes.min_content); |
| 124 sizes.max_content = std::max(sizes.max_content, child_sizes.max_content); | 136 sizes.max_content = std::max(sizes.max_content, child_sizes.max_content); |
| 125 } | 137 } |
| 126 | 138 |
| 127 sizes.max_content = std::max(sizes.min_content, sizes.max_content); | 139 sizes.max_content = std::max(sizes.min_content, sizes.max_content); |
| 128 return sizes; | 140 return sizes; |
| 129 } | 141 } |
| 130 | 142 |
| 131 NGLogicalOffset NGBlockLayoutAlgorithm::CalculateLogicalOffset( | 143 NGLogicalOffset NGBlockLayoutAlgorithm::CalculateLogicalOffset( |
| 132 const WTF::Optional<NGLogicalOffset>& known_fragment_offset) { | 144 const WTF::Optional<NGLogicalOffset>& known_fragment_offset) { |
| 145 if (known_fragment_offset) |
| 146 return known_fragment_offset.value() - ContainerBfcOffset(); |
| 133 LayoutUnit inline_offset = | 147 LayoutUnit inline_offset = |
| 134 border_and_padding_.inline_start + curr_child_margins_.inline_start; | 148 border_and_padding_.inline_start + curr_child_margins_.inline_start; |
| 135 LayoutUnit block_offset = content_size_; | 149 return {inline_offset, content_size_}; |
| 136 if (known_fragment_offset) { | |
| 137 block_offset = known_fragment_offset.value().block_offset - | |
| 138 ContainerBfcOffset().block_offset; | |
| 139 } | |
| 140 return {inline_offset, block_offset}; | |
| 141 } | 150 } |
| 142 | 151 |
| 143 RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { | 152 RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { |
| 144 WTF::Optional<MinMaxContentSize> min_max_size; | 153 WTF::Optional<MinMaxContentSize> min_max_size; |
| 145 if (NeedMinMaxContentSize(ConstraintSpace(), Style())) | 154 if (NeedMinMaxContentSize(ConstraintSpace(), Style())) |
| 146 min_max_size = ComputeMinMaxContentSize(); | 155 min_max_size = ComputeMinMaxContentSize(); |
| 147 | 156 |
| 148 border_and_padding_ = ComputeBorders(ConstraintSpace(), Style()) + | 157 border_and_padding_ = ComputeBorders(ConstraintSpace(), Style()) + |
| 149 ComputePadding(ConstraintSpace(), Style()); | 158 ComputePadding(ConstraintSpace(), Style()); |
| 150 | 159 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 214 content_size_ + curr_margin_strut_.Sum()}; | 223 content_size_ + curr_margin_strut_.Sum()}; |
| 215 container_builder_.AddOutOfFlowChildCandidate(ToNGBlockNode(child), | 224 container_builder_.AddOutOfFlowChildCandidate(ToNGBlockNode(child), |
| 216 offset); | 225 offset); |
| 217 NGBlockChildIterator::Entry entry = child_iterator.NextChild(); | 226 NGBlockChildIterator::Entry entry = child_iterator.NextChild(); |
| 218 child = entry.node; | 227 child = entry.node; |
| 219 child_break_token = entry.token; | 228 child_break_token = entry.token; |
| 220 continue; | 229 continue; |
| 221 } | 230 } |
| 222 } | 231 } |
| 223 | 232 |
| 224 PrepareChildLayout(child); | 233 NGLogicalOffset child_bfc_offset = PrepareChildLayout(child); |
| 225 RefPtr<NGConstraintSpace> child_space = | 234 RefPtr<NGConstraintSpace> child_space = |
| 226 CreateConstraintSpaceForChild(child); | 235 CreateConstraintSpaceForChild(child_bfc_offset, child); |
| 227 RefPtr<NGLayoutResult> layout_result = | 236 RefPtr<NGLayoutResult> layout_result = |
| 228 child->Layout(child_space.Get(), child_break_token); | 237 child->Layout(child_space.Get(), child_break_token); |
| 229 | 238 |
| 230 FinishChildLayout(child, child_space.Get(), layout_result); | 239 if (child->IsFloating()) |
| 240 FinishFloatChildLayout(child->Style(), *child_space, layout_result.Get()); |
| 241 else |
| 242 FinishChildLayout(child_space.Get(), layout_result.Get()); |
| 231 | 243 |
| 232 entry = child_iterator.NextChild(); | 244 entry = child_iterator.NextChild(); |
| 233 child = entry.node; | 245 child = entry.node; |
| 234 child_break_token = entry.token; | 246 child_break_token = entry.token; |
| 235 | 247 |
| 236 if (IsOutOfSpace(ConstraintSpace(), content_size_)) | 248 if (IsOutOfSpace(ConstraintSpace(), content_size_)) |
| 237 break; | 249 break; |
| 238 } | 250 } |
| 239 | 251 |
| 240 // Margins collapsing: | 252 // Margins collapsing: |
| (...skipping 13 matching lines...) Expand all Loading... |
| 254 container_builder_.SetBlockSize(size.block_size); | 266 container_builder_.SetBlockSize(size.block_size); |
| 255 | 267 |
| 256 // Layout our absolute and fixed positioned children. | 268 // Layout our absolute and fixed positioned children. |
| 257 NGOutOfFlowLayoutPart(ConstraintSpace(), Style(), &container_builder_).Run(); | 269 NGOutOfFlowLayoutPart(ConstraintSpace(), Style(), &container_builder_).Run(); |
| 258 | 270 |
| 259 // Non-empty blocks always know their position in space: | 271 // Non-empty blocks always know their position in space: |
| 260 if (size.block_size) { | 272 if (size.block_size) { |
| 261 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | 273 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
| 262 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, | 274 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, |
| 263 &container_builder_); | 275 &container_builder_); |
| 264 PositionPendingFloats(curr_bfc_offset_.block_offset, | 276 PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_, |
| 265 MutableConstraintSpace(), &container_builder_); | 277 MutableConstraintSpace()); |
| 266 } | 278 } |
| 267 | 279 |
| 268 // Margins collapsing: | 280 // Margins collapsing: |
| 269 // Do not collapse margins between the last in-flow child and bottom margin | 281 // Do not collapse margins between the last in-flow child and bottom margin |
| 270 // of its parent if the parent has height != auto() | 282 // of its parent if the parent has height != auto() |
| 271 if (!Style().LogicalHeight().IsAuto()) { | 283 if (!Style().LogicalHeight().IsAuto()) { |
| 272 // TODO(glebl): handle minLogicalHeight, maxLogicalHeight. | 284 // TODO(glebl): handle minLogicalHeight, maxLogicalHeight. |
| 273 curr_margin_strut_ = NGMarginStrut(); | 285 curr_margin_strut_ = NGMarginStrut(); |
| 274 } | 286 } |
| 275 container_builder_.SetEndMarginStrut(curr_margin_strut_); | 287 container_builder_.SetEndMarginStrut(curr_margin_strut_); |
| 276 | 288 |
| 277 container_builder_.SetOverflowSize( | 289 container_builder_.SetOverflowSize( |
| 278 NGLogicalSize(max_inline_size_, content_size_)); | 290 NGLogicalSize(max_inline_size_, content_size_)); |
| 279 | 291 |
| 280 if (ConstraintSpace().HasBlockFragmentation()) | 292 if (ConstraintSpace().HasBlockFragmentation()) |
| 281 FinalizeForFragmentation(); | 293 FinalizeForFragmentation(); |
| 282 | 294 |
| 283 return container_builder_.ToBoxFragment(); | 295 return container_builder_.ToBoxFragment(); |
| 284 } | 296 } |
| 285 | 297 |
| 286 void NGBlockLayoutAlgorithm::PrepareChildLayout(NGLayoutInputNode* child) { | 298 NGLogicalOffset NGBlockLayoutAlgorithm::PrepareChildLayout( |
| 299 NGLayoutInputNode* child) { |
| 287 DCHECK(child); | 300 DCHECK(child); |
| 288 | 301 |
| 302 curr_bfc_offset_ = container_builder_.BfcOffset() |
| 303 ? container_builder_.BfcOffset().value() |
| 304 : ConstraintSpace().BfcOffset(); |
| 305 curr_bfc_offset_.block_offset += content_size_; |
| 306 |
| 289 // Calculate margins in parent's writing mode. | 307 // Calculate margins in parent's writing mode. |
| 290 curr_child_margins_ = CalculateMargins( | 308 curr_child_margins_ = CalculateMargins( |
| 291 child, *space_builder_.ToConstraintSpace( | 309 child, *space_builder_.ToConstraintSpace( |
| 292 FromPlatformWritingMode(Style().GetWritingMode()))); | 310 FromPlatformWritingMode(Style().GetWritingMode()))); |
| 293 | 311 |
| 294 // Set estimated BFC offset to the next child's constraint space. | |
| 295 curr_bfc_offset_ = container_builder_.BfcOffset() | |
| 296 ? container_builder_.BfcOffset().value() | |
| 297 : ConstraintSpace().BfcOffset(); | |
| 298 curr_bfc_offset_.block_offset += content_size_; | |
| 299 curr_bfc_offset_.inline_offset += border_and_padding_.inline_start; | |
| 300 | |
| 301 bool is_floating = child->IsBlock() && child->Style().IsFloating(); | |
| 302 | |
| 303 bool should_position_pending_floats = | 312 bool should_position_pending_floats = |
| 304 child->IsBlock() && !is_floating && | 313 !child->IsFloating() && |
| 305 !IsNewFormattingContextForBlockLevelChild(Style(), *child) && | 314 !IsNewFormattingContextForBlockLevelChild(Style(), *child) && |
| 306 ClearanceMayAffectLayout(ConstraintSpace(), | 315 ClearanceMayAffectLayout(ConstraintSpace(), |
| 307 container_builder_.UnpositionedFloats(), | 316 container_builder_.UnpositionedFloats(), |
| 308 child->Style()); | 317 child->Style()); |
| 309 | 318 |
| 310 // Children which may clear a float need to force all the pending floats to | 319 // Children which may clear a float need to force all the pending floats to |
| 311 // be positioned before layout. This also resolves the fragment's bfc offset. | 320 // be positioned before layout. This also resolves the fragment's bfc offset. |
| 312 if (should_position_pending_floats) { | 321 if (should_position_pending_floats) { |
| 313 LayoutUnit origin_point_block_offset = | 322 LayoutUnit origin_point_block_offset = |
| 314 curr_bfc_offset_.block_offset + curr_margin_strut_.Sum(); | 323 curr_bfc_offset_.block_offset + curr_margin_strut_.Sum(); |
| 315 MaybeUpdateFragmentBfcOffset( | 324 MaybeUpdateFragmentBfcOffset( |
| 316 ConstraintSpace(), | 325 ConstraintSpace(), |
| 317 {curr_bfc_offset_.inline_offset, origin_point_block_offset}, | 326 {curr_bfc_offset_.inline_offset, origin_point_block_offset}, |
| 318 &container_builder_); | 327 &container_builder_); |
| 319 PositionPendingFloats(origin_point_block_offset, MutableConstraintSpace(), | 328 PositionPendingFloats(origin_point_block_offset, &container_builder_, |
| 320 &container_builder_); | 329 MutableConstraintSpace()); |
| 321 } | 330 } |
| 322 | 331 |
| 323 bool is_inflow = child->IsInline() || !is_floating; | 332 bool is_inflow = child->IsInline() || !child->IsFloating(); |
| 324 | 333 |
| 334 NGLogicalOffset child_bfc_offset = curr_bfc_offset_; |
| 335 child_bfc_offset.inline_offset += border_and_padding_.inline_start; |
| 325 // Only inflow children (e.g. not floats) are included in the child's margin | 336 // Only inflow children (e.g. not floats) are included in the child's margin |
| 326 // strut as they do not participate in margin collapsing. | 337 // strut as they do not participate in margin collapsing. |
| 327 if (is_inflow) { | 338 if (is_inflow) { |
| 328 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start; | 339 child_bfc_offset.inline_offset += curr_child_margins_.inline_start; |
| 329 // Append the current margin strut with child's block start margin. | 340 // Append the current margin strut with child's block start margin. |
| 330 // Non empty border/padding use cases are handled inside of the child's | 341 // Non empty border/padding, and new FC use cases are handled inside of the |
| 331 // layout. | 342 // child's layout. |
| 332 curr_margin_strut_.Append(curr_child_margins_.block_start); | 343 if (!IsNewFormattingContextForBlockLevelChild(Style(), *child)) |
| 344 curr_margin_strut_.Append(curr_child_margins_.block_start); |
| 333 } | 345 } |
| 334 | 346 |
| 335 // TODO(ikilpatrick): Children which establish new formatting contexts need | 347 // Should collapse margins if inline. |
| 336 // to be placed using the opportunity iterator before we can collapse margins. | 348 if (child->IsInline()) { |
| 337 // If the child is placed at the block_start of this fragment, then its | |
| 338 // margins do impact the position of its parent, if not (its placed below a | |
| 339 // float for example) it doesn't. \o/ | |
| 340 | |
| 341 bool should_collapse_margins = | |
| 342 child->IsInline() || | |
| 343 (!is_floating && | |
| 344 IsNewFormattingContextForBlockLevelChild(Style(), *child)); | |
| 345 | |
| 346 // Inline children or children which establish a block formatting context | |
| 347 // collapse margins and position themselves immediately as they need to know | |
| 348 // their BFC offset for fragmentation purposes. | |
| 349 if (should_collapse_margins) { | |
| 350 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | 349 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
| 351 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, | 350 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, |
| 352 &container_builder_); | 351 &container_builder_); |
| 353 PositionPendingFloats(curr_bfc_offset_.block_offset, | 352 PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_, |
| 354 MutableConstraintSpace(), &container_builder_); | 353 MutableConstraintSpace()); |
| 355 curr_margin_strut_ = {}; | 354 curr_margin_strut_ = {}; |
| 356 } | 355 } |
| 356 child_bfc_offset.block_offset = curr_bfc_offset_.block_offset; |
| 357 return child_bfc_offset; |
| 357 } | 358 } |
| 358 | 359 |
| 359 void NGBlockLayoutAlgorithm::FinishChildLayout( | 360 void NGBlockLayoutAlgorithm::FinishChildLayout( |
| 360 NGLayoutInputNode* child, | 361 const NGConstraintSpace* child_space, |
| 361 NGConstraintSpace* child_space, | 362 NGLayoutResult* layout_result) { |
| 362 RefPtr<NGLayoutResult> layout_result) { | |
| 363 NGBoxFragment fragment( | |
| 364 ConstraintSpace().WritingMode(), | |
| 365 ToNGPhysicalBoxFragment(layout_result->PhysicalFragment().Get())); | |
| 366 | |
| 367 // Pull out unpositioned floats to the current fragment. This may needed if | 363 // Pull out unpositioned floats to the current fragment. This may needed if |
| 368 // for example the child fragment could not position its floats because it's | 364 // for example the child fragment could not position its floats because it's |
| 369 // empty and therefore couldn't determine its position in space. | 365 // empty and therefore couldn't determine its position in space. |
| 370 container_builder_.MutableUnpositionedFloats().AppendVector( | 366 container_builder_.MutableUnpositionedFloats().AppendVector( |
| 371 layout_result->UnpositionedFloats()); | 367 layout_result->UnpositionedFloats()); |
| 372 | 368 |
| 373 if (child->IsBlock() && child->Style().IsFloating()) { | 369 NGBoxFragment fragment( |
| 374 NGLogicalOffset origin_offset = constraint_space_->BfcOffset(); | 370 ConstraintSpace().WritingMode(), |
| 375 origin_offset.inline_offset += border_and_padding_.inline_start; | 371 ToNGPhysicalBoxFragment(layout_result->PhysicalFragment().Get())); |
| 376 RefPtr<NGFloatingObject> floating_object = NGFloatingObject::Create( | |
| 377 child->Style(), child_space->WritingMode(), | |
| 378 child_space->AvailableSize(), origin_offset, | |
| 379 constraint_space_->BfcOffset(), curr_child_margins_, | |
| 380 layout_result->PhysicalFragment().Get()); | |
| 381 container_builder_.AddUnpositionedFloat(floating_object); | |
| 382 // No need to postpone the positioning if we know the correct offset. | |
| 383 if (container_builder_.BfcOffset()) { | |
| 384 NGLogicalOffset origin_point = curr_bfc_offset_; | |
| 385 // Adjust origin point to the margins of the last child. | |
| 386 // Example: <div style="margin-bottom: 20px"><float></div> | |
| 387 // <div style="margin-bottom: 30px"></div> | |
| 388 origin_point.block_offset += curr_margin_strut_.Sum(); | |
| 389 PositionPendingFloats(origin_point.block_offset, MutableConstraintSpace(), | |
| 390 &container_builder_); | |
| 391 } | |
| 392 return; | |
| 393 } | |
| 394 | 372 |
| 395 // Determine the fragment's position in the parent space either by using | 373 // Determine the fragment's position in the parent space. |
| 396 // content_size_ or known fragment's BFC offset. | 374 WTF::Optional<NGLogicalOffset> child_bfc_offset; |
| 397 WTF::Optional<NGLogicalOffset> bfc_offset; | 375 if (child_space->IsNewFormattingContext()) |
| 398 if (child_space->IsNewFormattingContext()) { | 376 child_bfc_offset = PositionNewFc(fragment, *child_space); |
| 399 bfc_offset = curr_bfc_offset_; | 377 else if (fragment.BfcOffset()) |
| 400 } else if (fragment.BfcOffset()) { | 378 child_bfc_offset = PositionWithBfcOffset(fragment); |
| 401 // Fragment that knows its offset can be used to set parent's BFC position. | 379 else if (container_builder_.BfcOffset()) |
| 402 curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset; | 380 child_bfc_offset = PositionWithParentBfc(); |
| 403 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, | 381 |
| 404 &container_builder_); | 382 NGLogicalOffset logical_offset = CalculateLogicalOffset(child_bfc_offset); |
| 405 PositionPendingFloats(curr_bfc_offset_.block_offset, | |
| 406 MutableConstraintSpace(), &container_builder_); | |
| 407 bfc_offset = curr_bfc_offset_; | |
| 408 } else if (container_builder_.BfcOffset()) { | |
| 409 // Fragment doesn't know its offset but we can still calculate its BFC | |
| 410 // position because the parent fragment's BFC is known. | |
| 411 // Example: | |
| 412 // BFC Offset is known here because of the padding. | |
| 413 // <div style="padding: 1px"> | |
| 414 // <div id="empty-div" style="margins: 1px"></div> | |
| 415 bfc_offset = curr_bfc_offset_; | |
| 416 bfc_offset.value().block_offset += curr_margin_strut_.Sum(); | |
| 417 } | |
| 418 NGLogicalOffset logical_offset = CalculateLogicalOffset(bfc_offset); | |
| 419 | 383 |
| 420 // Update margin strut. | 384 // Update margin strut. |
| 421 curr_margin_strut_ = fragment.EndMarginStrut(); | 385 curr_margin_strut_ = fragment.EndMarginStrut(); |
| 422 curr_margin_strut_.Append(curr_child_margins_.block_end); | 386 curr_margin_strut_.Append(curr_child_margins_.block_end); |
| 423 | 387 |
| 424 // Only modify content_size if BlockSize is not empty. It's needed to prevent | 388 // Only modify content_size if BlockSize is not empty. It's needed to prevent |
| 425 // the situation when logical_offset is included in content_size for empty | 389 // the situation when logical_offset is included in content_size for empty |
| 426 // blocks. Example: | 390 // blocks. Example: |
| 427 // <div style="overflow:hidden"> | 391 // <div style="overflow:hidden"> |
| 428 // <div style="margin-top: 8px"></div> | 392 // <div style="margin-top: 8px"></div> |
| 429 // <div style="margin-top: 10px"></div> | 393 // <div style="margin-top: 10px"></div> |
| 430 // </div> | 394 // </div> |
| 431 if (fragment.BlockSize()) | 395 if (fragment.BlockSize()) |
| 432 content_size_ = fragment.BlockSize() + logical_offset.block_offset; | 396 content_size_ = fragment.BlockSize() + logical_offset.block_offset; |
| 433 max_inline_size_ = | 397 max_inline_size_ = |
| 434 std::max(max_inline_size_, fragment.InlineSize() + | 398 std::max(max_inline_size_, fragment.InlineSize() + |
| 435 curr_child_margins_.InlineSum() + | 399 curr_child_margins_.InlineSum() + |
| 436 border_and_padding_.InlineSum()); | 400 border_and_padding_.InlineSum()); |
| 437 | 401 |
| 438 container_builder_.AddChild(layout_result, logical_offset); | 402 container_builder_.AddChild(layout_result, logical_offset); |
| 439 } | 403 } |
| 440 | 404 |
| 405 NGLogicalOffset NGBlockLayoutAlgorithm::PositionNewFc( |
| 406 const NGBoxFragment& fragment, |
| 407 const NGConstraintSpace& child_space) { |
| 408 // 1. Position all pending floats to a temporary space. |
| 409 RefPtr<NGConstraintSpace> tmp_space = |
| 410 NGConstraintSpaceBuilder(&child_space) |
| 411 .SetIsNewFormattingContext(false) |
| 412 .ToConstraintSpace(child_space.WritingMode()); |
| 413 PositionFloats(curr_bfc_offset_.block_offset, curr_bfc_offset_.block_offset, |
| 414 container_builder_.UnpositionedFloats(), tmp_space.Get()); |
| 415 |
| 416 // 2. Find an estimated layout opportunity for our fragment. |
| 417 NGLayoutOpportunity opportunity = FindLayoutOpportunityForFragment( |
| 418 tmp_space->Exclusions().get(), child_space.AvailableSize(), |
| 419 curr_bfc_offset_, curr_child_margins_, fragment); |
| 420 |
| 421 // 3. If the found opportunity lies on the same line with our estimated |
| 422 // child's BFC offset then merge fragment's margins with the current |
| 423 // MarginStrut. |
| 424 if (opportunity.offset.block_offset == curr_bfc_offset_.block_offset) |
| 425 curr_margin_strut_.Append(curr_child_margins_.block_start); |
| 426 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
| 427 curr_margin_strut_ = {}; |
| 428 |
| 429 // 4. The child's BFC block offset is known here. |
| 430 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, |
| 431 &container_builder_); |
| 432 PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_, |
| 433 MutableConstraintSpace()); |
| 434 |
| 435 // 5. Find the final layout opportunity for the fragment after all pending |
| 436 // floats are positioned at the correct BFC block's offset. |
| 437 opportunity = FindLayoutOpportunityForFragment( |
| 438 MutableConstraintSpace()->Exclusions().get(), child_space.AvailableSize(), |
| 439 curr_bfc_offset_, curr_child_margins_, fragment); |
| 440 |
| 441 curr_bfc_offset_ = opportunity.offset; |
| 442 return curr_bfc_offset_; |
| 443 } |
| 444 |
| 445 NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithBfcOffset( |
| 446 const NGBoxFragment& fragment) { |
| 447 DCHECK(fragment.BfcOffset()); |
| 448 curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset; |
| 449 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_, |
| 450 &container_builder_); |
| 451 PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_, |
| 452 MutableConstraintSpace()); |
| 453 return fragment.BfcOffset().value(); |
| 454 } |
| 455 |
| 456 NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithParentBfc() { |
| 457 curr_bfc_offset_ += |
| 458 {border_and_padding_.inline_start + curr_child_margins_.inline_start, |
| 459 curr_margin_strut_.Sum()}; |
| 460 return curr_bfc_offset_; |
| 461 } |
| 462 |
| 463 void NGBlockLayoutAlgorithm::FinishFloatChildLayout( |
| 464 const ComputedStyle& child_style, |
| 465 const NGConstraintSpace& child_space, |
| 466 const NGLayoutResult* layout_result) { |
| 467 NGLogicalOffset origin_offset = constraint_space_->BfcOffset(); |
| 468 origin_offset.inline_offset += border_and_padding_.inline_start; |
| 469 RefPtr<NGFloatingObject> floating_object = NGFloatingObject::Create( |
| 470 child_style, child_space.WritingMode(), child_space.AvailableSize(), |
| 471 origin_offset, constraint_space_->BfcOffset(), curr_child_margins_, |
| 472 layout_result->PhysicalFragment().Get()); |
| 473 container_builder_.AddUnpositionedFloat(floating_object); |
| 474 |
| 475 // No need to postpone the positioning if we know the correct offset. |
| 476 if (container_builder_.BfcOffset()) { |
| 477 NGLogicalOffset origin_point = curr_bfc_offset_; |
| 478 // Adjust origin point to the margins of the last child. |
| 479 // Example: <div style="margin-bottom: 20px"><float></div> |
| 480 // <div style="margin-bottom: 30px"></div> |
| 481 origin_point.block_offset += curr_margin_strut_.Sum(); |
| 482 PositionPendingFloats(origin_point.block_offset, &container_builder_, |
| 483 MutableConstraintSpace()); |
| 484 } |
| 485 } |
| 486 |
| 441 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() { | 487 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() { |
| 442 LayoutUnit used_block_size = | 488 LayoutUnit used_block_size = |
| 443 BreakToken() ? BreakToken()->UsedBlockSize() : LayoutUnit(); | 489 BreakToken() ? BreakToken()->UsedBlockSize() : LayoutUnit(); |
| 444 LayoutUnit block_size = ComputeBlockSizeForFragment( | 490 LayoutUnit block_size = ComputeBlockSizeForFragment( |
| 445 ConstraintSpace(), Style(), used_block_size + content_size_); | 491 ConstraintSpace(), Style(), used_block_size + content_size_); |
| 446 | 492 |
| 447 block_size -= used_block_size; | 493 block_size -= used_block_size; |
| 448 DCHECK_GE(block_size, LayoutUnit()) | 494 DCHECK_GE(block_size, LayoutUnit()) |
| 449 << "Adding and subtracting the used_block_size shouldn't leave the " | 495 << "Adding and subtracting the used_block_size shouldn't leave the " |
| 450 "block_size for this fragment smaller than zero."; | 496 "block_size for this fragment smaller than zero."; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 473 | 519 |
| 474 // The end of the block fits in the current fragmentainer. | 520 // The end of the block fits in the current fragmentainer. |
| 475 container_builder_.SetBlockSize(block_size); | 521 container_builder_.SetBlockSize(block_size); |
| 476 container_builder_.SetBlockOverflow(content_size_); | 522 container_builder_.SetBlockOverflow(content_size_); |
| 477 } | 523 } |
| 478 | 524 |
| 479 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins( | 525 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins( |
| 480 NGLayoutInputNode* child, | 526 NGLayoutInputNode* child, |
| 481 const NGConstraintSpace& space) { | 527 const NGConstraintSpace& space) { |
| 482 DCHECK(child); | 528 DCHECK(child); |
| 529 if (child->IsInline()) |
| 530 return {}; |
| 483 const ComputedStyle& child_style = child->Style(); | 531 const ComputedStyle& child_style = child->Style(); |
| 484 | 532 |
| 485 WTF::Optional<MinMaxContentSize> sizes; | 533 WTF::Optional<MinMaxContentSize> sizes; |
| 486 if (NeedMinMaxContentSize(space, child_style)) | 534 if (NeedMinMaxContentSize(space, child_style)) |
| 487 sizes = child->ComputeMinMaxContentSize(); | 535 sizes = child->ComputeMinMaxContentSize(); |
| 488 | 536 |
| 489 LayoutUnit child_inline_size = | 537 LayoutUnit child_inline_size = |
| 490 ComputeInlineSizeForFragment(space, child_style, sizes); | 538 ComputeInlineSizeForFragment(space, child_style, sizes); |
| 491 NGBoxStrut margins = ComputeMargins(space, child_style, space.WritingMode(), | 539 NGBoxStrut margins = ComputeMargins(space, child_style, space.WritingMode(), |
| 492 space.Direction()); | 540 space.Direction()); |
| 493 if (!child_style.IsFloating()) { | 541 if (!child->IsFloating()) { |
| 494 ApplyAutoMargins(space, child_style, child_inline_size, &margins); | 542 ApplyAutoMargins(space, child_style, child_inline_size, &margins); |
| 495 } | 543 } |
| 496 return margins; | 544 return margins; |
| 497 } | 545 } |
| 498 | 546 |
| 499 RefPtr<NGConstraintSpace> NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild( | 547 RefPtr<NGConstraintSpace> NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild( |
| 548 const NGLogicalOffset& child_bfc_offset, |
| 500 NGLayoutInputNode* child) { | 549 NGLayoutInputNode* child) { |
| 501 DCHECK(child); | 550 DCHECK(child); |
| 502 | 551 |
| 503 const ComputedStyle& child_style = child->Style(); | 552 const ComputedStyle& child_style = child->Style(); |
| 504 bool is_new_bfc = IsNewFormattingContextForBlockLevelChild(Style(), *child); | 553 bool is_new_bfc = IsNewFormattingContextForBlockLevelChild(Style(), *child); |
| 505 space_builder_.SetIsNewFormattingContext(is_new_bfc) | 554 space_builder_.SetIsNewFormattingContext(is_new_bfc) |
| 506 .SetBfcOffset(curr_bfc_offset_); | 555 .SetBfcOffset(child_bfc_offset); |
| 507 | 556 |
| 508 if (child->IsInline()) { | 557 if (child->IsInline()) { |
| 509 // TODO(kojii): Setup space_builder_ appropriately for inline child. | 558 // TODO(kojii): Setup space_builder_ appropriately for inline child. |
| 510 space_builder_.SetBfcOffset(curr_bfc_offset_) | 559 space_builder_.SetClearanceOffset(ConstraintSpace().ClearanceOffset()); |
| 511 .SetClearanceOffset(ConstraintSpace().ClearanceOffset()); | |
| 512 return space_builder_.ToConstraintSpace( | 560 return space_builder_.ToConstraintSpace( |
| 513 FromPlatformWritingMode(Style().GetWritingMode())); | 561 FromPlatformWritingMode(Style().GetWritingMode())); |
| 514 } | 562 } |
| 515 | 563 |
| 516 space_builder_ | 564 space_builder_ |
| 517 .SetClearanceOffset( | 565 .SetClearanceOffset( |
| 518 GetClearanceOffset(constraint_space_->Exclusions(), child_style)) | 566 GetClearanceOffset(constraint_space_->Exclusions(), child_style)) |
| 519 .SetIsShrinkToFit(ShouldShrinkToFit(Style(), child_style)) | 567 .SetIsShrinkToFit(ShouldShrinkToFit(Style(), child_style)) |
| 520 .SetTextDirection(child_style.Direction()); | 568 .SetTextDirection(child_style.Direction()); |
| 521 | 569 |
| 522 // Float's margins are not included in child's space because: | 570 // Float's margins are not included in child's space because: |
| 523 // 1) Floats do not participate in margins collapsing. | 571 // 1) Floats do not participate in margins collapsing. |
| 524 // 2) Floats margins are used separately to calculate floating exclusions. | 572 // 2) Floats margins are used separately to calculate floating exclusions. |
| 525 space_builder_.SetMarginStrut(child_style.IsFloating() ? NGMarginStrut() | 573 space_builder_.SetMarginStrut(child->IsFloating() ? NGMarginStrut() |
| 526 : curr_margin_strut_); | 574 : curr_margin_strut_); |
| 527 | 575 |
| 528 LayoutUnit space_available; | 576 LayoutUnit space_available; |
| 529 if (constraint_space_->HasBlockFragmentation()) { | 577 if (constraint_space_->HasBlockFragmentation()) { |
| 530 space_available = ConstraintSpace().FragmentainerSpaceAvailable(); | 578 space_available = ConstraintSpace().FragmentainerSpaceAvailable(); |
| 531 // If a block establishes a new formatting context we must know our | 579 // If a block establishes a new formatting context we must know our |
| 532 // position in the formatting context, and are able to adjust the | 580 // position in the formatting context, and are able to adjust the |
| 533 // fragmentation line. | 581 // fragmentation line. |
| 534 if (is_new_bfc) { | 582 if (is_new_bfc) { |
| 535 space_available -= curr_bfc_offset_.block_offset; | 583 space_available -= child_bfc_offset.block_offset; |
| 536 } | 584 } |
| 537 } | 585 } |
| 538 space_builder_.SetFragmentainerSpaceAvailable(space_available); | 586 space_builder_.SetFragmentainerSpaceAvailable(space_available); |
| 539 | 587 |
| 540 return space_builder_.ToConstraintSpace( | 588 return space_builder_.ToConstraintSpace( |
| 541 FromPlatformWritingMode(child_style.GetWritingMode())); | 589 FromPlatformWritingMode(child_style.GetWritingMode())); |
| 542 } | 590 } |
| 543 } // namespace blink | 591 } // namespace blink |
| OLD | NEW |