| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/layout/ng/ng_block_layout_algorithm.h" | 5 #include "core/layout/ng/ng_block_layout_algorithm.h" |
| 6 | 6 |
| 7 #include "core/layout/ng/ng_absolute_utils.h" | 7 #include "core/layout/ng/ng_absolute_utils.h" |
| 8 #include "core/layout/ng/ng_block_break_token.h" | 8 #include "core/layout/ng/ng_block_break_token.h" |
| 9 #include "core/layout/ng/ng_block_child_iterator.h" | 9 #include "core/layout/ng/ng_block_child_iterator.h" |
| 10 #include "core/layout/ng/ng_box_fragment.h" | 10 #include "core/layout/ng/ng_box_fragment.h" |
| (...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 | 303 |
| 304 } // namespace | 304 } // namespace |
| 305 | 305 |
| 306 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm( | 306 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm( |
| 307 NGBlockNode* node, | 307 NGBlockNode* node, |
| 308 NGConstraintSpace* constraint_space, | 308 NGConstraintSpace* constraint_space, |
| 309 NGBlockBreakToken* break_token) | 309 NGBlockBreakToken* break_token) |
| 310 : node_(node), | 310 : node_(node), |
| 311 constraint_space_(constraint_space), | 311 constraint_space_(constraint_space), |
| 312 break_token_(break_token), | 312 break_token_(break_token), |
| 313 builder_(WTF::wrapUnique( | 313 builder_(NGPhysicalFragment::kFragmentBox, node), |
| 314 new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox, node))) {} | 314 space_builder_(constraint_space_) {} |
| 315 | 315 |
| 316 Optional<MinAndMaxContentSizes> | 316 Optional<MinAndMaxContentSizes> |
| 317 NGBlockLayoutAlgorithm::ComputeMinAndMaxContentSizes() const { | 317 NGBlockLayoutAlgorithm::ComputeMinAndMaxContentSizes() const { |
| 318 MinAndMaxContentSizes sizes; | 318 MinAndMaxContentSizes sizes; |
| 319 | 319 |
| 320 // Size-contained elements don't consider their contents for intrinsic sizing. | 320 // Size-contained elements don't consider their contents for intrinsic sizing. |
| 321 if (Style().containsSize()) | 321 if (Style().containsSize()) |
| 322 return sizes; | 322 return sizes; |
| 323 | 323 |
| 324 // TODO: handle floats & orthogonal children. | 324 // TODO: handle floats & orthogonal children. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 353 return sizes; | 353 return sizes; |
| 354 } | 354 } |
| 355 | 355 |
| 356 NGLogicalOffset NGBlockLayoutAlgorithm::CalculateLogicalOffset( | 356 NGLogicalOffset NGBlockLayoutAlgorithm::CalculateLogicalOffset( |
| 357 const WTF::Optional<NGLogicalOffset>& known_fragment_offset) { | 357 const WTF::Optional<NGLogicalOffset>& known_fragment_offset) { |
| 358 LayoutUnit inline_offset = | 358 LayoutUnit inline_offset = |
| 359 border_and_padding_.inline_start + curr_child_margins_.inline_start; | 359 border_and_padding_.inline_start + curr_child_margins_.inline_start; |
| 360 LayoutUnit block_offset = content_size_; | 360 LayoutUnit block_offset = content_size_; |
| 361 if (known_fragment_offset) { | 361 if (known_fragment_offset) { |
| 362 block_offset = known_fragment_offset.value().block_offset - | 362 block_offset = known_fragment_offset.value().block_offset - |
| 363 builder_->BfcOffset().value().block_offset; | 363 builder_.BfcOffset().value().block_offset; |
| 364 } | 364 } |
| 365 return {inline_offset, block_offset}; | 365 return {inline_offset, block_offset}; |
| 366 } | 366 } |
| 367 | 367 |
| 368 void NGBlockLayoutAlgorithm::UpdateFragmentBfcOffset( | 368 void NGBlockLayoutAlgorithm::UpdateFragmentBfcOffset( |
| 369 const NGLogicalOffset& offset) { | 369 const NGLogicalOffset& offset) { |
| 370 if (!builder_->BfcOffset()) { | 370 if (!builder_.BfcOffset()) { |
| 371 NGLogicalOffset bfc_offset = offset; | 371 NGLogicalOffset bfc_offset = offset; |
| 372 if (ConstraintSpace().ClearanceOffset()) { | 372 if (ConstraintSpace().ClearanceOffset()) { |
| 373 bfc_offset.block_offset = std::max( | 373 bfc_offset.block_offset = std::max( |
| 374 ConstraintSpace().ClearanceOffset().value(), offset.block_offset); | 374 ConstraintSpace().ClearanceOffset().value(), offset.block_offset); |
| 375 } | 375 } |
| 376 builder_->SetBfcOffset(bfc_offset); | 376 builder_.SetBfcOffset(bfc_offset); |
| 377 } | 377 } |
| 378 } | 378 } |
| 379 | 379 |
| 380 RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { | 380 RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { |
| 381 WTF::Optional<MinAndMaxContentSizes> sizes; | 381 WTF::Optional<MinAndMaxContentSizes> sizes; |
| 382 if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style())) | 382 if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style())) |
| 383 sizes = ComputeMinAndMaxContentSizes(); | 383 sizes = ComputeMinAndMaxContentSizes(); |
| 384 | 384 |
| 385 border_and_padding_ = ComputeBorders(ConstraintSpace(), Style()) + | 385 border_and_padding_ = ComputeBorders(ConstraintSpace(), Style()) + |
| 386 ComputePadding(ConstraintSpace(), Style()); | 386 ComputePadding(ConstraintSpace(), Style()); |
| 387 | 387 |
| 388 LayoutUnit inline_size = | 388 LayoutUnit inline_size = |
| 389 ComputeInlineSizeForFragment(ConstraintSpace(), Style(), sizes); | 389 ComputeInlineSizeForFragment(ConstraintSpace(), Style(), sizes); |
| 390 LayoutUnit adjusted_inline_size = | 390 LayoutUnit adjusted_inline_size = |
| 391 inline_size - border_and_padding_.InlineSum(); | 391 inline_size - border_and_padding_.InlineSum(); |
| 392 // TODO(layout-ng): For quirks mode, should we pass blockSize instead of | 392 // TODO(layout-ng): For quirks mode, should we pass blockSize instead of |
| 393 // -1? | 393 // -1? |
| 394 LayoutUnit block_size = | 394 LayoutUnit block_size = |
| 395 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), NGSizeIndefinite); | 395 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), NGSizeIndefinite); |
| 396 LayoutUnit adjusted_block_size(block_size); | 396 LayoutUnit adjusted_block_size(block_size); |
| 397 // Our calculated block-axis size may be indefinite at this point. | 397 // Our calculated block-axis size may be indefinite at this point. |
| 398 // If so, just leave the size as NGSizeIndefinite instead of subtracting | 398 // If so, just leave the size as NGSizeIndefinite instead of subtracting |
| 399 // borders and padding. | 399 // borders and padding. |
| 400 if (adjusted_block_size != NGSizeIndefinite) | 400 if (adjusted_block_size != NGSizeIndefinite) |
| 401 adjusted_block_size -= border_and_padding_.BlockSum(); | 401 adjusted_block_size -= border_and_padding_.BlockSum(); |
| 402 | 402 |
| 403 space_builder_ = new NGConstraintSpaceBuilder(constraint_space_); | |
| 404 space_builder_ | 403 space_builder_ |
| 405 ->SetAvailableSize( | 404 .SetAvailableSize( |
| 406 NGLogicalSize(adjusted_inline_size, adjusted_block_size)) | 405 NGLogicalSize(adjusted_inline_size, adjusted_block_size)) |
| 407 .SetPercentageResolutionSize( | 406 .SetPercentageResolutionSize( |
| 408 NGLogicalSize(adjusted_inline_size, adjusted_block_size)); | 407 NGLogicalSize(adjusted_inline_size, adjusted_block_size)); |
| 409 | 408 |
| 410 builder_->SetDirection(constraint_space_->Direction()); | 409 builder_.SetDirection(constraint_space_->Direction()); |
| 411 builder_->SetWritingMode(constraint_space_->WritingMode()); | 410 builder_.SetWritingMode(constraint_space_->WritingMode()); |
| 412 builder_->SetInlineSize(inline_size).SetBlockSize(block_size); | 411 builder_.SetInlineSize(inline_size).SetBlockSize(block_size); |
| 413 | 412 |
| 414 NGBlockChildIterator child_iterator(node_->FirstChild(), break_token_); | 413 NGBlockChildIterator child_iterator(node_->FirstChild(), break_token_); |
| 415 NGBlockChildIterator::Entry entry = child_iterator.NextChild(); | 414 NGBlockChildIterator::Entry entry = child_iterator.NextChild(); |
| 416 NGLayoutInputNode* child = entry.node; | 415 NGLayoutInputNode* child = entry.node; |
| 417 NGBreakToken* child_break_token = entry.token; | 416 NGBreakToken* child_break_token = entry.token; |
| 418 | 417 |
| 419 // If we are resuming from a break token our start border and padding is | 418 // If we are resuming from a break token our start border and padding is |
| 420 // within a previous fragment. | 419 // within a previous fragment. |
| 421 content_size_ = break_token_ ? LayoutUnit() : border_and_padding_.block_start; | 420 content_size_ = break_token_ ? LayoutUnit() : border_and_padding_.block_start; |
| 422 | 421 |
| 423 curr_margin_strut_ = ConstraintSpace().MarginStrut(); | 422 curr_margin_strut_ = ConstraintSpace().MarginStrut(); |
| 424 curr_bfc_offset_ = ConstraintSpace().BfcOffset(); | 423 curr_bfc_offset_ = ConstraintSpace().BfcOffset(); |
| 425 | 424 |
| 426 // Margins collapsing: | 425 // Margins collapsing: |
| 427 // Do not collapse margins between parent and its child if there is | 426 // Do not collapse margins between parent and its child if there is |
| 428 // border/padding between them. | 427 // border/padding between them. |
| 429 if (border_and_padding_.block_start) { | 428 if (border_and_padding_.block_start) { |
| 430 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | 429 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
| 431 UpdateFragmentBfcOffset(curr_bfc_offset_); | 430 UpdateFragmentBfcOffset(curr_bfc_offset_); |
| 432 curr_margin_strut_ = NGMarginStrut(); | 431 curr_margin_strut_ = NGMarginStrut(); |
| 433 } | 432 } |
| 434 | 433 |
| 435 // Block that establishes a new BFC knows its BFC offset == {} | 434 // Block that establishes a new BFC knows its BFC offset == {} |
| 436 // If a new formatting context hits the if branch above then the BFC offset is | 435 // If a new formatting context hits the if branch above then the BFC offset is |
| 437 // still {} as the margin strut from the constraint space must also be empty. | 436 // still {} as the margin strut from the constraint space must also be empty. |
| 438 if (ConstraintSpace().IsNewFormattingContext()) { | 437 if (ConstraintSpace().IsNewFormattingContext()) { |
| 439 UpdateFragmentBfcOffset(curr_bfc_offset_); | 438 UpdateFragmentBfcOffset(curr_bfc_offset_); |
| 440 DCHECK_EQ(builder_->BfcOffset().value(), NGLogicalOffset()); | 439 DCHECK_EQ(builder_.BfcOffset().value(), NGLogicalOffset()); |
| 441 DCHECK_EQ(curr_margin_strut_, NGMarginStrut()); | 440 DCHECK_EQ(curr_margin_strut_, NGMarginStrut()); |
| 442 } | 441 } |
| 443 | 442 |
| 444 curr_bfc_offset_.block_offset += content_size_; | 443 curr_bfc_offset_.block_offset += content_size_; |
| 445 | 444 |
| 446 while (child) { | 445 while (child) { |
| 447 if (child->Type() == NGLayoutInputNode::kLegacyBlock) { | 446 if (child->Type() == NGLayoutInputNode::kLegacyBlock) { |
| 448 NGBlockNode* current_block_child = toNGBlockNode(child); | 447 NGBlockNode* current_block_child = toNGBlockNode(child); |
| 449 EPosition position = current_block_child->Style().position(); | 448 EPosition position = current_block_child->Style().position(); |
| 450 if (position == EPosition::kAbsolute || position == EPosition::kFixed) { | 449 if (position == EPosition::kAbsolute || position == EPosition::kFixed) { |
| 451 builder_->AddOutOfFlowChildCandidate(current_block_child, | 450 builder_.AddOutOfFlowChildCandidate(current_block_child, |
| 452 GetChildSpaceOffset()); | 451 GetChildSpaceOffset()); |
| 453 NGBlockChildIterator::Entry entry = child_iterator.NextChild(); | 452 NGBlockChildIterator::Entry entry = child_iterator.NextChild(); |
| 454 child = entry.node; | 453 child = entry.node; |
| 455 child_break_token = entry.token; | 454 child_break_token = entry.token; |
| 456 continue; | 455 continue; |
| 457 } | 456 } |
| 458 } | 457 } |
| 459 | 458 |
| 460 NGConstraintSpace* child_space = CreateConstraintSpaceForChild(child); | 459 NGConstraintSpace* child_space = CreateConstraintSpaceForChild(child); |
| 461 | 460 |
| 462 if (child->Type() == NGLayoutInputNode::kLegacyInline) { | 461 if (child->Type() == NGLayoutInputNode::kLegacyInline) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 484 content_size_ += border_and_padding_.block_end; | 483 content_size_ += border_and_padding_.block_end; |
| 485 if (border_and_padding_.block_end || | 484 if (border_and_padding_.block_end || |
| 486 ConstraintSpace().IsNewFormattingContext()) { | 485 ConstraintSpace().IsNewFormattingContext()) { |
| 487 content_size_ += curr_margin_strut_.Sum(); | 486 content_size_ += curr_margin_strut_.Sum(); |
| 488 curr_margin_strut_ = NGMarginStrut(); | 487 curr_margin_strut_ = NGMarginStrut(); |
| 489 } | 488 } |
| 490 | 489 |
| 491 // Recompute the block-axis size now that we know our content size. | 490 // Recompute the block-axis size now that we know our content size. |
| 492 block_size = | 491 block_size = |
| 493 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); | 492 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); |
| 494 builder_->SetBlockSize(block_size); | 493 builder_.SetBlockSize(block_size); |
| 495 | 494 |
| 496 // Layout our absolute and fixed positioned children. | 495 // Layout our absolute and fixed positioned children. |
| 497 NGOutOfFlowLayoutPart(ConstraintSpace(), Style(), builder_.get()).Run(); | 496 NGOutOfFlowLayoutPart(ConstraintSpace(), Style(), &builder_).Run(); |
| 498 | 497 |
| 499 // Non-empty blocks always know their position in space: | 498 // Non-empty blocks always know their position in space: |
| 500 if (block_size) { | 499 if (block_size) { |
| 501 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | 500 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
| 502 UpdateFragmentBfcOffset(curr_bfc_offset_); | 501 UpdateFragmentBfcOffset(curr_bfc_offset_); |
| 503 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), | 502 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), |
| 504 builder_.get()); | 503 &builder_); |
| 505 } | 504 } |
| 506 | 505 |
| 507 // Margins collapsing: | 506 // Margins collapsing: |
| 508 // Do not collapse margins between the last in-flow child and bottom margin | 507 // Do not collapse margins between the last in-flow child and bottom margin |
| 509 // of its parent if the parent has height != auto() | 508 // of its parent if the parent has height != auto() |
| 510 if (!Style().logicalHeight().isAuto()) { | 509 if (!Style().logicalHeight().isAuto()) { |
| 511 // TODO(glebl): handle minLogicalHeight, maxLogicalHeight. | 510 // TODO(glebl): handle minLogicalHeight, maxLogicalHeight. |
| 512 curr_margin_strut_ = NGMarginStrut(); | 511 curr_margin_strut_ = NGMarginStrut(); |
| 513 } | 512 } |
| 514 builder_->SetEndMarginStrut(curr_margin_strut_); | 513 builder_.SetEndMarginStrut(curr_margin_strut_); |
| 515 | 514 |
| 516 builder_->SetInlineOverflow(max_inline_size_).SetBlockOverflow(content_size_); | 515 builder_.SetInlineOverflow(max_inline_size_).SetBlockOverflow(content_size_); |
| 517 | 516 |
| 518 if (ConstraintSpace().HasBlockFragmentation()) | 517 if (ConstraintSpace().HasBlockFragmentation()) |
| 519 FinalizeForFragmentation(); | 518 FinalizeForFragmentation(); |
| 520 | 519 |
| 521 return builder_->ToBoxFragment(); | 520 return builder_.ToBoxFragment(); |
| 522 } | 521 } |
| 523 | 522 |
| 524 void NGBlockLayoutAlgorithm::LayoutInlineChildren( | 523 void NGBlockLayoutAlgorithm::LayoutInlineChildren( |
| 525 NGInlineNode* inline_child, | 524 NGInlineNode* inline_child, |
| 526 NGConstraintSpace* child_space) { | 525 NGConstraintSpace* child_space) { |
| 527 // TODO(kojii): This logic does not handle when children are mix of | 526 // TODO(kojii): This logic does not handle when children are mix of |
| 528 // inline/block. We need to detect the case and setup appropriately; e.g., | 527 // inline/block. We need to detect the case and setup appropriately; e.g., |
| 529 // constraint space, margin collapsing, next siblings, etc. | 528 // constraint space, margin collapsing, next siblings, etc. |
| 530 NGLineBuilder line_builder(inline_child, child_space); | 529 NGLineBuilder line_builder(inline_child, child_space); |
| 531 // TODO(kojii): Need to determine when to invalidate PrepareLayout() more | 530 // TODO(kojii): Need to determine when to invalidate PrepareLayout() more |
| (...skipping 14 matching lines...) Expand all Loading... |
| 546 NGLayoutInputNode* child, | 545 NGLayoutInputNode* child, |
| 547 NGConstraintSpace* child_space, | 546 NGConstraintSpace* child_space, |
| 548 RefPtr<NGLayoutResult> layout_result) { | 547 RefPtr<NGLayoutResult> layout_result) { |
| 549 NGBoxFragment fragment( | 548 NGBoxFragment fragment( |
| 550 ConstraintSpace().WritingMode(), | 549 ConstraintSpace().WritingMode(), |
| 551 toNGPhysicalBoxFragment(layout_result->PhysicalFragment().get())); | 550 toNGPhysicalBoxFragment(layout_result->PhysicalFragment().get())); |
| 552 | 551 |
| 553 // Pull out unpositioned floats to the current fragment. This may needed if | 552 // Pull out unpositioned floats to the current fragment. This may needed if |
| 554 // for example the child fragment could not position its floats because it's | 553 // for example the child fragment could not position its floats because it's |
| 555 // empty and therefore couldn't determine its position in space. | 554 // empty and therefore couldn't determine its position in space. |
| 556 builder_->MutableUnpositionedFloats().appendVector( | 555 builder_.MutableUnpositionedFloats().appendVector( |
| 557 layout_result->UnpositionedFloats()); | 556 layout_result->UnpositionedFloats()); |
| 558 | 557 |
| 559 if (child->Type() == NGLayoutInputNode::kLegacyBlock && | 558 if (child->Type() == NGLayoutInputNode::kLegacyBlock && |
| 560 toNGBlockNode(child)->Style().isFloating()) { | 559 toNGBlockNode(child)->Style().isFloating()) { |
| 561 NGFloatingObject* floating_object = new NGFloatingObject( | 560 NGFloatingObject* floating_object = new NGFloatingObject( |
| 562 layout_result->PhysicalFragment().get(), child_space, constraint_space_, | 561 layout_result->PhysicalFragment().get(), child_space, constraint_space_, |
| 563 toNGBlockNode(child), toNGBlockNode(child)->Style(), | 562 toNGBlockNode(child), toNGBlockNode(child)->Style(), |
| 564 curr_child_margins_); | 563 curr_child_margins_); |
| 565 builder_->AddUnpositionedFloat(floating_object); | 564 builder_.AddUnpositionedFloat(floating_object); |
| 566 // No need to postpone the positioning if we know the correct offset. | 565 // No need to postpone the positioning if we know the correct offset. |
| 567 if (builder_->BfcOffset()) { | 566 if (builder_.BfcOffset()) { |
| 568 NGLogicalOffset origin_point = curr_bfc_offset_; | 567 NGLogicalOffset origin_point = curr_bfc_offset_; |
| 569 // Adjust origin point to the margins of the last child. | 568 // Adjust origin point to the margins of the last child. |
| 570 // Example: <div style="margin-bottom: 20px"><float></div> | 569 // Example: <div style="margin-bottom: 20px"><float></div> |
| 571 // <div style="margin-bottom: 30px"></div> | 570 // <div style="margin-bottom: 30px"></div> |
| 572 origin_point.block_offset += curr_margin_strut_.Sum(); | 571 origin_point.block_offset += curr_margin_strut_.Sum(); |
| 573 PositionPendingFloats(origin_point.block_offset, ConstraintSpace(), | 572 PositionPendingFloats(origin_point.block_offset, ConstraintSpace(), |
| 574 builder_.get()); | 573 &builder_); |
| 575 } | 574 } |
| 576 return; | 575 return; |
| 577 } | 576 } |
| 578 | 577 |
| 579 // Determine the fragment's position in the parent space either by using | 578 // Determine the fragment's position in the parent space either by using |
| 580 // content_size_ or known fragment's BFC offset. | 579 // content_size_ or known fragment's BFC offset. |
| 581 WTF::Optional<NGLogicalOffset> bfc_offset; | 580 WTF::Optional<NGLogicalOffset> bfc_offset; |
| 582 if (child_space->IsNewFormattingContext()) { | 581 if (child_space->IsNewFormattingContext()) { |
| 583 // TODO(ikilpatrick): We may need to place ourself within the BFC | 582 // TODO(ikilpatrick): We may need to place ourself within the BFC |
| 584 // before a new formatting context child is laid out. (Not after layout as | 583 // before a new formatting context child is laid out. (Not after layout as |
| 585 // is done here). | 584 // is done here). |
| 586 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | 585 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
| 587 bfc_offset = curr_bfc_offset_; | 586 bfc_offset = curr_bfc_offset_; |
| 588 } else if (fragment.BfcOffset()) { | 587 } else if (fragment.BfcOffset()) { |
| 589 // Fragment that knows its offset can be used to set parent's BFC position. | 588 // Fragment that knows its offset can be used to set parent's BFC position. |
| 590 curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset; | 589 curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset; |
| 591 bfc_offset = curr_bfc_offset_; | 590 bfc_offset = curr_bfc_offset_; |
| 592 } else if (builder_->BfcOffset()) { | 591 } else if (builder_.BfcOffset()) { |
| 593 // Fragment doesn't know its offset but we can still calculate its BFC | 592 // Fragment doesn't know its offset but we can still calculate its BFC |
| 594 // position because the parent fragment's BFC is known. | 593 // position because the parent fragment's BFC is known. |
| 595 // Example: | 594 // Example: |
| 596 // BFC Offset is known here because of the padding. | 595 // BFC Offset is known here because of the padding. |
| 597 // <div style="padding: 1px"> | 596 // <div style="padding: 1px"> |
| 598 // <div id="empty-div" style="margins: 1px"></div> | 597 // <div id="empty-div" style="margins: 1px"></div> |
| 599 bfc_offset = curr_bfc_offset_; | 598 bfc_offset = curr_bfc_offset_; |
| 600 bfc_offset.value().block_offset += curr_margin_strut_.Sum(); | 599 bfc_offset.value().block_offset += curr_margin_strut_.Sum(); |
| 601 } | 600 } |
| 602 if (bfc_offset) { | 601 if (bfc_offset) { |
| 603 UpdateFragmentBfcOffset(curr_bfc_offset_); | 602 UpdateFragmentBfcOffset(curr_bfc_offset_); |
| 604 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), | 603 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), |
| 605 builder_.get()); | 604 &builder_); |
| 606 } | 605 } |
| 607 NGLogicalOffset logical_offset = CalculateLogicalOffset(bfc_offset); | 606 NGLogicalOffset logical_offset = CalculateLogicalOffset(bfc_offset); |
| 608 | 607 |
| 609 // Update margin strut. | 608 // Update margin strut. |
| 610 curr_margin_strut_ = fragment.EndMarginStrut(); | 609 curr_margin_strut_ = fragment.EndMarginStrut(); |
| 611 curr_margin_strut_.Append(curr_child_margins_.block_end); | 610 curr_margin_strut_.Append(curr_child_margins_.block_end); |
| 612 | 611 |
| 613 // Only modify content_size if BlockSize is not empty. It's needed to prevent | 612 // Only modify content_size if BlockSize is not empty. It's needed to prevent |
| 614 // the situation when logical_offset is included in content_size for empty | 613 // the situation when logical_offset is included in content_size for empty |
| 615 // blocks. Example: | 614 // blocks. Example: |
| 616 // <div style="overflow:hidden"> | 615 // <div style="overflow:hidden"> |
| 617 // <div style="margin-top: 8px"></div> | 616 // <div style="margin-top: 8px"></div> |
| 618 // <div style="margin-top: 10px"></div> | 617 // <div style="margin-top: 10px"></div> |
| 619 // </div> | 618 // </div> |
| 620 if (fragment.BlockSize()) | 619 if (fragment.BlockSize()) |
| 621 content_size_ = fragment.BlockSize() + logical_offset.block_offset; | 620 content_size_ = fragment.BlockSize() + logical_offset.block_offset; |
| 622 max_inline_size_ = | 621 max_inline_size_ = |
| 623 std::max(max_inline_size_, fragment.InlineSize() + | 622 std::max(max_inline_size_, fragment.InlineSize() + |
| 624 curr_child_margins_.InlineSum() + | 623 curr_child_margins_.InlineSum() + |
| 625 border_and_padding_.InlineSum()); | 624 border_and_padding_.InlineSum()); |
| 626 | 625 |
| 627 builder_->AddChild(layout_result, logical_offset); | 626 builder_.AddChild(layout_result, logical_offset); |
| 628 } | 627 } |
| 629 | 628 |
| 630 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() { | 629 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() { |
| 631 LayoutUnit used_block_size = | 630 LayoutUnit used_block_size = |
| 632 break_token_ ? break_token_->UsedBlockSize() : LayoutUnit(); | 631 break_token_ ? break_token_->UsedBlockSize() : LayoutUnit(); |
| 633 LayoutUnit block_size = ComputeBlockSizeForFragment( | 632 LayoutUnit block_size = ComputeBlockSizeForFragment( |
| 634 ConstraintSpace(), Style(), used_block_size + content_size_); | 633 ConstraintSpace(), Style(), used_block_size + content_size_); |
| 635 | 634 |
| 636 block_size -= used_block_size; | 635 block_size -= used_block_size; |
| 637 DCHECK_GE(block_size, LayoutUnit()) | 636 DCHECK_GE(block_size, LayoutUnit()) |
| 638 << "Adding and subtracting the used_block_size shouldn't leave the " | 637 << "Adding and subtracting the used_block_size shouldn't leave the " |
| 639 "block_size for this fragment smaller than zero."; | 638 "block_size for this fragment smaller than zero."; |
| 640 | 639 |
| 641 DCHECK(builder_->BfcOffset()) << "We must have our BfcOffset by this point " | 640 DCHECK(builder_.BfcOffset()) << "We must have our BfcOffset by this point " |
| 642 "to determine the space left in the flow."; | 641 "to determine the space left in the flow."; |
| 643 LayoutUnit space_left = ConstraintSpace().FragmentainerSpaceAvailable() - | 642 LayoutUnit space_left = ConstraintSpace().FragmentainerSpaceAvailable() - |
| 644 builder_->BfcOffset().value().block_offset; | 643 builder_.BfcOffset().value().block_offset; |
| 645 DCHECK_GE(space_left, LayoutUnit()); | 644 DCHECK_GE(space_left, LayoutUnit()); |
| 646 | 645 |
| 647 if (builder_->DidBreak()) { | 646 if (builder_.DidBreak()) { |
| 648 // One of our children broke. Even if we fit within the remaining space we | 647 // One of our children broke. Even if we fit within the remaining space we |
| 649 // need to prepare a break token. | 648 // need to prepare a break token. |
| 650 builder_->SetUsedBlockSize(std::min(space_left, block_size) + | 649 builder_.SetUsedBlockSize(std::min(space_left, block_size) + |
| 651 used_block_size); | 650 used_block_size); |
| 652 builder_->SetBlockSize(std::min(space_left, block_size)); | 651 builder_.SetBlockSize(std::min(space_left, block_size)); |
| 653 builder_->SetBlockOverflow(space_left); | 652 builder_.SetBlockOverflow(space_left); |
| 654 return; | 653 return; |
| 655 } | 654 } |
| 656 | 655 |
| 657 if (block_size > space_left) { | 656 if (block_size > space_left) { |
| 658 // Need a break inside this block. | 657 // Need a break inside this block. |
| 659 builder_->SetUsedBlockSize(space_left + used_block_size); | 658 builder_.SetUsedBlockSize(space_left + used_block_size); |
| 660 builder_->SetBlockSize(space_left); | 659 builder_.SetBlockSize(space_left); |
| 661 builder_->SetBlockOverflow(space_left); | 660 builder_.SetBlockOverflow(space_left); |
| 662 return; | 661 return; |
| 663 } | 662 } |
| 664 | 663 |
| 665 // The end of the block fits in the current fragmentainer. | 664 // The end of the block fits in the current fragmentainer. |
| 666 builder_->SetBlockSize(block_size); | 665 builder_.SetBlockSize(block_size); |
| 667 builder_->SetBlockOverflow(content_size_); | 666 builder_.SetBlockOverflow(content_size_); |
| 668 } | 667 } |
| 669 | 668 |
| 670 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins( | 669 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins( |
| 671 NGBlockNode* child, | 670 NGBlockNode* child, |
| 672 const NGConstraintSpace& space) { | 671 const NGConstraintSpace& space) { |
| 673 DCHECK(child); | 672 DCHECK(child); |
| 674 const ComputedStyle& child_style = child->Style(); | 673 const ComputedStyle& child_style = child->Style(); |
| 675 | 674 |
| 676 WTF::Optional<MinAndMaxContentSizes> sizes; | 675 WTF::Optional<MinAndMaxContentSizes> sizes; |
| 677 if (NeedMinAndMaxContentSizes(space, child_style)) | 676 if (NeedMinAndMaxContentSizes(space, child_style)) |
| (...skipping 13 matching lines...) Expand all Loading... |
| 691 NGLayoutInputNode* child) { | 690 NGLayoutInputNode* child) { |
| 692 DCHECK(child); | 691 DCHECK(child); |
| 693 | 692 |
| 694 if (child->Type() == NGLayoutInputNode::kLegacyInline) { | 693 if (child->Type() == NGLayoutInputNode::kLegacyInline) { |
| 695 // TODO(kojii): Setup space_builder_ appropriately for inline child. | 694 // TODO(kojii): Setup space_builder_ appropriately for inline child. |
| 696 | 695 |
| 697 // Margins collapsing: Inline block. | 696 // Margins collapsing: Inline block. |
| 698 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | 697 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
| 699 UpdateFragmentBfcOffset(curr_bfc_offset_); | 698 UpdateFragmentBfcOffset(curr_bfc_offset_); |
| 700 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), | 699 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), |
| 701 builder_.get()); | 700 &builder_); |
| 702 curr_margin_strut_ = {}; | 701 curr_margin_strut_ = {}; |
| 703 | 702 |
| 704 return space_builder_->ToConstraintSpace( | 703 return space_builder_.ToConstraintSpace( |
| 705 FromPlatformWritingMode(Style().getWritingMode())); | 704 FromPlatformWritingMode(Style().getWritingMode())); |
| 706 } | 705 } |
| 707 | 706 |
| 708 NGBlockNode* block_child = toNGBlockNode(child); | 707 NGBlockNode* block_child = toNGBlockNode(child); |
| 709 const ComputedStyle& child_style = block_child->Style(); | 708 const ComputedStyle& child_style = block_child->Style(); |
| 710 | 709 |
| 711 // Calculate margins in parent's writing mode. | 710 // Calculate margins in parent's writing mode. |
| 712 curr_child_margins_ = CalculateMargins( | 711 curr_child_margins_ = CalculateMargins( |
| 713 block_child, *space_builder_->ToConstraintSpace( | 712 block_child, *space_builder_.ToConstraintSpace( |
| 714 FromPlatformWritingMode(Style().getWritingMode()))); | 713 FromPlatformWritingMode(Style().getWritingMode()))); |
| 715 | 714 |
| 716 bool is_new_bfc = IsNewFormattingContextForInFlowBlockLevelChild( | 715 bool is_new_bfc = IsNewFormattingContextForInFlowBlockLevelChild( |
| 717 ConstraintSpace(), child_style); | 716 ConstraintSpace(), child_style); |
| 718 space_builder_->SetIsNewFormattingContext(is_new_bfc) | 717 space_builder_.SetIsNewFormattingContext(is_new_bfc) |
| 719 .SetIsShrinkToFit(ShouldShrinkToFit(ConstraintSpace(), child_style)) | 718 .SetIsShrinkToFit(ShouldShrinkToFit(ConstraintSpace(), child_style)) |
| 720 .SetTextDirection(child_style.direction()); | 719 .SetTextDirection(child_style.direction()); |
| 721 | 720 |
| 722 // Clearance : | 721 // Clearance : |
| 723 // - *Always* collapse margins and update *container*'s BFC offset. | 722 // - *Always* collapse margins and update *container*'s BFC offset. |
| 724 // - Position all pending floats since the fragment's BFC offset is known. | 723 // - Position all pending floats since the fragment's BFC offset is known. |
| 725 // - Set the clearance offset on the constraint space's builder. | 724 // - Set the clearance offset on the constraint space's builder. |
| 726 if (child_style.clear() != EClear::kNone) { | 725 if (child_style.clear() != EClear::kNone) { |
| 727 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | 726 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
| 728 UpdateFragmentBfcOffset(curr_bfc_offset_); | 727 UpdateFragmentBfcOffset(curr_bfc_offset_); |
| 729 // Only collapse margins if it's an adjoining block with clearance. | 728 // Only collapse margins if it's an adjoining block with clearance. |
| 730 if (!content_size_) { | 729 if (!content_size_) { |
| 731 curr_margin_strut_ = NGMarginStrut(); | 730 curr_margin_strut_ = NGMarginStrut(); |
| 732 curr_child_margins_.block_start = LayoutUnit(); | 731 curr_child_margins_.block_start = LayoutUnit(); |
| 733 } | 732 } |
| 734 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), | 733 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), |
| 735 builder_.get()); | 734 &builder_); |
| 736 WTF::Optional<LayoutUnit> clearance_offset = | 735 WTF::Optional<LayoutUnit> clearance_offset = |
| 737 GetClearanceOffset(constraint_space_->Exclusions(), child_style); | 736 GetClearanceOffset(constraint_space_->Exclusions(), child_style); |
| 738 space_builder_->SetClearanceOffset(clearance_offset); | 737 space_builder_.SetClearanceOffset(clearance_offset); |
| 739 } | 738 } |
| 740 | 739 |
| 741 // Set estimated BFC offset to the next child's constraint space. | 740 // Set estimated BFC offset to the next child's constraint space. |
| 742 curr_bfc_offset_ = builder_->BfcOffset() ? builder_->BfcOffset().value() | 741 curr_bfc_offset_ = builder_.BfcOffset() ? builder_.BfcOffset().value() |
| 743 : ConstraintSpace().BfcOffset(); | 742 : ConstraintSpace().BfcOffset(); |
| 744 curr_bfc_offset_.block_offset += content_size_; | 743 curr_bfc_offset_.block_offset += content_size_; |
| 745 curr_bfc_offset_.inline_offset += border_and_padding_.inline_start; | 744 curr_bfc_offset_.inline_offset += border_and_padding_.inline_start; |
| 746 | 745 |
| 747 // Floats margins are not included in child's CS because | 746 // Floats margins are not included in child's CS because |
| 748 // 1) Floats do not participate in margins collapsing | 747 // 1) Floats do not participate in margins collapsing |
| 749 // 2) Floats margins are used separately to calculate floating exclusions. | 748 // 2) Floats margins are used separately to calculate floating exclusions. |
| 750 if (!child_style.isFloating()) { | 749 if (!child_style.isFloating()) { |
| 751 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start; | 750 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start; |
| 752 // Append the current margin strut with child's block start margin. | 751 // Append the current margin strut with child's block start margin. |
| 753 // Non empty border/padding use cases are handled inside of the child's | 752 // Non empty border/padding use cases are handled inside of the child's |
| 754 // layout. | 753 // layout. |
| 755 curr_margin_strut_.Append(curr_child_margins_.block_start); | 754 curr_margin_strut_.Append(curr_child_margins_.block_start); |
| 756 space_builder_->SetMarginStrut(curr_margin_strut_); | 755 space_builder_.SetMarginStrut(curr_margin_strut_); |
| 757 } | 756 } |
| 758 | 757 |
| 759 space_builder_->SetBfcOffset(curr_bfc_offset_); | 758 space_builder_.SetBfcOffset(curr_bfc_offset_); |
| 760 | 759 |
| 761 LayoutUnit space_available; | 760 LayoutUnit space_available; |
| 762 if (constraint_space_->HasBlockFragmentation()) { | 761 if (constraint_space_->HasBlockFragmentation()) { |
| 763 space_available = ConstraintSpace().FragmentainerSpaceAvailable(); | 762 space_available = ConstraintSpace().FragmentainerSpaceAvailable(); |
| 764 // If a block establishes a new formatting context we must know our | 763 // If a block establishes a new formatting context we must know our |
| 765 // position in the formatting context, and are able to adjust the | 764 // position in the formatting context, and are able to adjust the |
| 766 // fragmentation line. | 765 // fragmentation line. |
| 767 if (is_new_bfc) { | 766 if (is_new_bfc) { |
| 768 DCHECK(builder_->BfcOffset()); | 767 DCHECK(builder_.BfcOffset()); |
| 769 space_available -= curr_bfc_offset_.block_offset; | 768 space_available -= curr_bfc_offset_.block_offset; |
| 770 } | 769 } |
| 771 } | 770 } |
| 772 space_builder_->SetFragmentainerSpaceAvailable(space_available); | 771 space_builder_.SetFragmentainerSpaceAvailable(space_available); |
| 773 | 772 |
| 774 return space_builder_->ToConstraintSpace( | 773 return space_builder_.ToConstraintSpace( |
| 775 FromPlatformWritingMode(child_style.getWritingMode())); | 774 FromPlatformWritingMode(child_style.getWritingMode())); |
| 776 } | 775 } |
| 777 } // namespace blink | 776 } // namespace blink |
| OLD | NEW |