Chromium Code Reviews| 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_box_fragment.h" | 10 #include "core/layout/ng/ng_box_fragment.h" |
| 10 #include "core/layout/ng/ng_column_mapper.h" | 11 #include "core/layout/ng/ng_column_mapper.h" |
| 11 #include "core/layout/ng/ng_constraint_space.h" | 12 #include "core/layout/ng/ng_constraint_space.h" |
| 12 #include "core/layout/ng/ng_constraint_space_builder.h" | 13 #include "core/layout/ng/ng_constraint_space_builder.h" |
| 13 #include "core/layout/ng/ng_fragment.h" | 14 #include "core/layout/ng/ng_fragment.h" |
| 14 #include "core/layout/ng/ng_fragment_builder.h" | 15 #include "core/layout/ng/ng_fragment_builder.h" |
| 15 #include "core/layout/ng/ng_inline_node.h" | 16 #include "core/layout/ng/ng_inline_node.h" |
| 16 #include "core/layout/ng/ng_layout_opportunity_iterator.h" | 17 #include "core/layout/ng/ng_layout_opportunity_iterator.h" |
| 17 #include "core/layout/ng/ng_length_utils.h" | 18 #include "core/layout/ng/ng_length_utils.h" |
| 18 #include "core/layout/ng/ng_line_builder.h" | 19 #include "core/layout/ng/ng_line_builder.h" |
| (...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 293 if (display == EDisplay::Grid || display == EDisplay::Flex || | 294 if (display == EDisplay::Grid || display == EDisplay::Flex || |
| 294 display == EDisplay::WebkitBox) | 295 display == EDisplay::WebkitBox) |
| 295 return true; | 296 return true; |
| 296 | 297 |
| 297 if (space.WritingMode() != FromPlatformWritingMode(style.getWritingMode())) | 298 if (space.WritingMode() != FromPlatformWritingMode(style.getWritingMode())) |
| 298 return true; | 299 return true; |
| 299 | 300 |
| 300 return false; | 301 return false; |
| 301 } | 302 } |
| 302 | 303 |
| 304 // Returns the borders and padding box for the current layout. | |
| 305 NGBoxStrut ComputeBordersAndPadding(const NGConstraintSpace& space, | |
| 306 const ComputedStyle& style) { | |
| 307 // If we are producing an anonymous fragment (e.g. a column) we shouldn't | |
| 308 // have any borders or padding. | |
| 309 return space.IsAnonymous() | |
| 310 ? NGBoxStrut() | |
| 311 : ComputeBorders(style) + ComputePadding(space, style); | |
| 312 } | |
| 313 | |
| 314 // Whether we've run out of space in this flow, if so there will be no work | |
|
mstensho (USE GERRIT)
2017/02/27 13:44:36
Suggest changing punctuation and capitalization a
ikilpatrick
2017/02/27 18:50:09
Done.
| |
| 315 // left to do for this block in this fragmentainer. | |
| 316 bool IsOutOfSpace(const NGConstraintSpace& space, LayoutUnit content_size) { | |
| 317 return space.HasBlockFragmentation() && | |
| 318 content_size >= space.FragmentainerSpaceAvailable(); | |
| 319 } | |
| 320 | |
| 303 } // namespace | 321 } // namespace |
| 304 | 322 |
| 305 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm( | 323 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm( |
| 306 NGBlockNode* node, | 324 NGBlockNode* node, |
| 307 NGConstraintSpace* constraint_space, | 325 NGConstraintSpace* constraint_space, |
| 308 NGBreakToken* break_token) | 326 NGBlockBreakToken* break_token) |
| 309 : node_(node), | 327 : node_(node), |
| 310 constraint_space_(constraint_space), | 328 constraint_space_(constraint_space), |
| 311 break_token_(break_token), | 329 break_token_(break_token), |
| 312 builder_(WTF::wrapUnique( | 330 builder_(WTF::wrapUnique( |
| 313 new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox, node))) {} | 331 new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox, node))) {} |
| 314 | 332 |
| 315 Optional<MinAndMaxContentSizes> | 333 Optional<MinAndMaxContentSizes> |
| 316 NGBlockLayoutAlgorithm::ComputeMinAndMaxContentSizes() const { | 334 NGBlockLayoutAlgorithm::ComputeMinAndMaxContentSizes() const { |
| 317 MinAndMaxContentSizes sizes; | 335 MinAndMaxContentSizes sizes; |
| 318 | 336 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 354 builder_->BfcOffset().value().block_offset; | 372 builder_->BfcOffset().value().block_offset; |
| 355 } | 373 } |
| 356 return {inline_offset, block_offset}; | 374 return {inline_offset, block_offset}; |
| 357 } | 375 } |
| 358 | 376 |
| 359 RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { | 377 RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { |
| 360 WTF::Optional<MinAndMaxContentSizes> sizes; | 378 WTF::Optional<MinAndMaxContentSizes> sizes; |
| 361 if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style())) | 379 if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style())) |
| 362 sizes = ComputeMinAndMaxContentSizes(); | 380 sizes = ComputeMinAndMaxContentSizes(); |
| 363 | 381 |
| 364 border_and_padding_ = | 382 border_and_padding_ = ComputeBordersAndPadding(ConstraintSpace(), Style()); |
| 365 ComputeBorders(Style()) + ComputePadding(ConstraintSpace(), Style()); | |
| 366 | 383 |
| 367 LayoutUnit inline_size = | 384 LayoutUnit inline_size = |
| 368 ComputeInlineSizeForFragment(ConstraintSpace(), Style(), sizes); | 385 ComputeInlineSizeForFragment(ConstraintSpace(), Style(), sizes); |
| 369 LayoutUnit adjusted_inline_size = | 386 LayoutUnit adjusted_inline_size = |
| 370 inline_size - border_and_padding_.InlineSum(); | 387 inline_size - border_and_padding_.InlineSum(); |
| 371 // TODO(layout-ng): For quirks mode, should we pass blockSize instead of | 388 // TODO(layout-ng): For quirks mode, should we pass blockSize instead of |
| 372 // -1? | 389 // -1? |
| 373 LayoutUnit block_size = | 390 LayoutUnit block_size = |
| 374 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), NGSizeIndefinite); | 391 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), NGSizeIndefinite); |
| 375 LayoutUnit adjusted_block_size(block_size); | 392 LayoutUnit adjusted_block_size(block_size); |
| 376 // Our calculated block-axis size may be indefinite at this point. | 393 // Our calculated block-axis size may be indefinite at this point. |
| 377 // If so, just leave the size as NGSizeIndefinite instead of subtracting | 394 // If so, just leave the size as NGSizeIndefinite instead of subtracting |
| 378 // borders and padding. | 395 // borders and padding. |
| 379 if (adjusted_block_size != NGSizeIndefinite) | 396 if (adjusted_block_size != NGSizeIndefinite) |
| 380 adjusted_block_size -= border_and_padding_.BlockSum(); | 397 adjusted_block_size -= border_and_padding_.BlockSum(); |
| 381 | 398 |
| 382 space_builder_ = new NGConstraintSpaceBuilder(constraint_space_); | 399 space_builder_ = new NGConstraintSpaceBuilder(constraint_space_); |
| 383 if (Style().specifiesColumns()) { | 400 space_builder_ |
| 384 space_builder_->SetFragmentationType(kFragmentColumn); | 401 ->SetAvailableSize( |
| 385 adjusted_inline_size = | 402 NGLogicalSize(adjusted_inline_size, adjusted_block_size)) |
| 386 ResolveUsedColumnInlineSize(adjusted_inline_size, Style()); | 403 .SetPercentageResolutionSize( |
| 387 LayoutUnit inline_progression = | 404 NGLogicalSize(adjusted_inline_size, adjusted_block_size)); |
| 388 adjusted_inline_size + ResolveUsedColumnGap(Style()); | |
| 389 fragmentainer_mapper_ = | |
| 390 new NGColumnMapper(inline_progression, adjusted_block_size); | |
| 391 } | |
| 392 space_builder_->SetAvailableSize( | |
| 393 NGLogicalSize(adjusted_inline_size, adjusted_block_size)); | |
| 394 space_builder_->SetPercentageResolutionSize( | |
| 395 NGLogicalSize(adjusted_inline_size, adjusted_block_size)); | |
| 396 | 405 |
| 397 builder_->SetDirection(constraint_space_->Direction()); | 406 builder_->SetDirection(constraint_space_->Direction()); |
| 398 builder_->SetWritingMode(constraint_space_->WritingMode()); | 407 builder_->SetWritingMode(constraint_space_->WritingMode()); |
| 399 builder_->SetInlineSize(inline_size).SetBlockSize(block_size); | 408 builder_->SetInlineSize(inline_size).SetBlockSize(block_size); |
| 400 | 409 |
| 401 // TODO(glebl): fix multicol after the new margin collapsing/floats algorithm | 410 NGBlockChildIterator child_iterator(node_->FirstChild(), break_token_); |
| 402 // based on BFCOffset is checked in. | 411 NGBlockChildIterator::Entry entry = child_iterator.NextChild(); |
| 403 if (NGBlockBreakToken* token = CurrentBlockBreakToken()) { | 412 current_child_ = entry.node; |
| 404 // Resume after a previous break. | 413 NGBreakToken* child_break_token = entry.token; |
| 405 content_size_ = token->BreakOffset(); | 414 |
| 406 current_child_ = token->InputNode(); | 415 // If we are resuming from a break token our start border and padding is |
| 407 } else { | 416 // within a previous fragment. |
| 408 content_size_ = border_and_padding_.block_start; | 417 content_size_ = break_token_ ? LayoutUnit() : border_and_padding_.block_start; |
| 409 current_child_ = node_->FirstChild(); | |
| 410 } | |
| 411 | 418 |
| 412 curr_margin_strut_ = ConstraintSpace().MarginStrut(); | 419 curr_margin_strut_ = ConstraintSpace().MarginStrut(); |
| 413 curr_bfc_offset_ = ConstraintSpace().BfcOffset(); | 420 curr_bfc_offset_ = ConstraintSpace().BfcOffset(); |
| 414 | 421 |
| 415 // Margins collapsing: | 422 // Margins collapsing: |
| 416 // Do not collapse margins between parent and its child if there is | 423 // Do not collapse margins between parent and its child if there is |
| 417 // border/padding between them. | 424 // border/padding between them. |
| 418 if (border_and_padding_.block_start) { | 425 if (border_and_padding_.block_start) { |
| 419 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | 426 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
| 420 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); | 427 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 437 NGBlockNode* current_block_child = toNGBlockNode(current_child_); | 444 NGBlockNode* current_block_child = toNGBlockNode(current_child_); |
| 438 EPosition position = current_block_child->Style().position(); | 445 EPosition position = current_block_child->Style().position(); |
| 439 if (position == EPosition::kAbsolute || position == EPosition::kFixed) { | 446 if (position == EPosition::kAbsolute || position == EPosition::kFixed) { |
| 440 builder_->AddOutOfFlowChildCandidate(current_block_child, | 447 builder_->AddOutOfFlowChildCandidate(current_block_child, |
| 441 GetChildSpaceOffset()); | 448 GetChildSpaceOffset()); |
| 442 current_child_ = current_block_child->NextSibling(); | 449 current_child_ = current_block_child->NextSibling(); |
| 443 continue; | 450 continue; |
| 444 } | 451 } |
| 445 } | 452 } |
| 446 | 453 |
| 447 DCHECK(!ConstraintSpace().HasBlockFragmentation() || | |
| 448 SpaceAvailableForCurrentChild() > LayoutUnit()); | |
| 449 space_for_current_child_ = CreateConstraintSpaceForCurrentChild(); | 454 space_for_current_child_ = CreateConstraintSpaceForCurrentChild(); |
| 450 | 455 |
| 451 if (current_child_->Type() == NGLayoutInputNode::kLegacyInline) { | 456 if (current_child_->Type() == NGLayoutInputNode::kLegacyInline) { |
| 452 LayoutInlineChildren(toNGInlineNode(current_child_)); | 457 LayoutInlineChildren(toNGInlineNode(current_child_)); |
| 453 continue; | 458 continue; |
| 454 } | 459 } |
| 455 | 460 |
| 456 RefPtr<NGLayoutResult> layout_result = | 461 RefPtr<NGLayoutResult> layout_result = |
| 457 current_child_->Layout(space_for_current_child_); | 462 current_child_->Layout(space_for_current_child_, child_break_token); |
| 458 | 463 |
| 459 FinishCurrentChildLayout(layout_result); | 464 FinishCurrentChildLayout(layout_result); |
| 460 | 465 |
| 461 if (!ProceedToNextUnfinishedSibling( | 466 entry = child_iterator.NextChild(); |
| 462 layout_result->PhysicalFragment().get())) | 467 current_child_ = entry.node; |
| 468 child_break_token = entry.token; | |
| 469 | |
| 470 if (IsOutOfSpace(ConstraintSpace(), content_size_)) | |
| 463 break; | 471 break; |
| 464 } | 472 } |
| 465 | 473 |
| 466 // Margins collapsing: | 474 // Margins collapsing: |
| 467 // Bottom margins of an in-flow block box doesn't collapse with its last | 475 // Bottom margins of an in-flow block box doesn't collapse with its last |
| 468 // in-flow block-level child's bottom margin if the box has bottom | 476 // in-flow block-level child's bottom margin if the box has bottom |
| 469 // border/padding. | 477 // border/padding. |
| 470 content_size_ += border_and_padding_.block_end; | 478 content_size_ += border_and_padding_.block_end; |
| 471 if (border_and_padding_.block_end || | 479 if (border_and_padding_.block_end || |
| 472 ConstraintSpace().IsNewFormattingContext()) { | 480 ConstraintSpace().IsNewFormattingContext()) { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 553 PositionPendingFloats(origin_point.block_offset, ConstraintSpace(), | 561 PositionPendingFloats(origin_point.block_offset, ConstraintSpace(), |
| 554 builder_.get()); | 562 builder_.get()); |
| 555 } | 563 } |
| 556 return; | 564 return; |
| 557 } | 565 } |
| 558 | 566 |
| 559 // Determine the fragment's position in the parent space either by using | 567 // Determine the fragment's position in the parent space either by using |
| 560 // content_size_ or known fragment's BFC offset. | 568 // content_size_ or known fragment's BFC offset. |
| 561 WTF::Optional<NGLogicalOffset> bfc_offset; | 569 WTF::Optional<NGLogicalOffset> bfc_offset; |
| 562 if (CurrentChildConstraintSpace().IsNewFormattingContext()) { | 570 if (CurrentChildConstraintSpace().IsNewFormattingContext()) { |
| 571 // DO NOT SUBMIT - Do we need to move this inside | |
|
Gleb Lanbin
2017/02/25 01:12:19
do not forger to remove this before submit
ikilpatrick
2017/02/27 18:50:09
Added TODO
| |
| 572 // CreateConstraintSpaceForCurrentChild? | |
| 563 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | 573 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
| 564 bfc_offset = curr_bfc_offset_; | 574 bfc_offset = curr_bfc_offset_; |
| 565 } else if (fragment.BfcOffset()) { | 575 } else if (fragment.BfcOffset()) { |
| 566 // Fragment that knows its offset can be used to set parent's BFC position. | 576 // Fragment that knows its offset can be used to set parent's BFC position. |
| 567 curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset; | 577 curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset; |
| 568 bfc_offset = curr_bfc_offset_; | 578 bfc_offset = curr_bfc_offset_; |
| 569 } else if (builder_->BfcOffset()) { | 579 } else if (builder_->BfcOffset()) { |
| 570 // Fragment doesn't know its offset but we can still calculate its BFC | 580 // Fragment doesn't know its offset but we can still calculate its BFC |
| 571 // position because the parent fragment's BFC is known. | 581 // position because the parent fragment's BFC is known. |
| 572 // Example: | 582 // Example: |
| 573 // BFC Offset is known here because of the padding. | 583 // BFC Offset is known here because of the padding. |
| 574 // <div style="padding: 1px"> | 584 // <div style="padding: 1px"> |
| 575 // <div id="empty-div" style="margins: 1px"></div> | 585 // <div id="empty-div" style="margins: 1px"></div> |
| 576 bfc_offset = curr_bfc_offset_; | 586 bfc_offset = curr_bfc_offset_; |
| 577 bfc_offset.value().block_offset += curr_margin_strut_.Sum(); | 587 bfc_offset.value().block_offset += curr_margin_strut_.Sum(); |
| 578 } | 588 } |
| 579 if (bfc_offset) { | 589 if (bfc_offset) { |
| 580 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); | 590 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); |
| 581 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), | 591 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), |
| 582 builder_.get()); | 592 builder_.get()); |
| 583 } | 593 } |
| 584 NGLogicalOffset logical_offset = CalculateLogicalOffset(bfc_offset); | 594 NGLogicalOffset logical_offset = CalculateLogicalOffset(bfc_offset); |
| 585 | 595 |
| 586 if (fragmentainer_mapper_) | |
| 587 fragmentainer_mapper_->ToVisualOffset(logical_offset); | |
| 588 else | |
| 589 logical_offset.block_offset -= PreviousBreakOffset(); | |
| 590 | |
| 591 // Update margin strut. | 596 // Update margin strut. |
| 592 curr_margin_strut_ = fragment.EndMarginStrut(); | 597 curr_margin_strut_ = fragment.EndMarginStrut(); |
| 593 curr_margin_strut_.Append(curr_child_margins_.block_end); | 598 curr_margin_strut_.Append(curr_child_margins_.block_end); |
| 594 | 599 |
| 595 // Only modify content_size if BlockSize is not empty. It's needed to prevent | 600 // Only modify content_size if BlockSize is not empty. It's needed to prevent |
| 596 // the situation when logical_offset is included in content_size for empty | 601 // the situation when logical_offset is included in content_size for empty |
| 597 // blocks. Example: | 602 // blocks. Example: |
| 598 // <div style="overflow:hidden"> | 603 // <div style="overflow:hidden"> |
| 599 // <div style="margin-top: 8px"></div> | 604 // <div style="margin-top: 8px"></div> |
| 600 // <div style="margin-top: 10px"></div> | 605 // <div style="margin-top: 10px"></div> |
| 601 // </div> | 606 // </div> |
| 602 if (fragment.BlockSize()) | 607 if (fragment.BlockSize()) |
| 603 content_size_ = fragment.BlockSize() + logical_offset.block_offset; | 608 content_size_ = fragment.BlockSize() + logical_offset.block_offset; |
| 604 max_inline_size_ = | 609 max_inline_size_ = |
| 605 std::max(max_inline_size_, fragment.InlineSize() + | 610 std::max(max_inline_size_, fragment.InlineSize() + |
| 606 curr_child_margins_.InlineSum() + | 611 curr_child_margins_.InlineSum() + |
| 607 border_and_padding_.InlineSum()); | 612 border_and_padding_.InlineSum()); |
| 608 | 613 |
| 609 builder_->AddChild(layout_result, logical_offset); | 614 builder_->AddChild(layout_result, logical_offset); |
| 610 } | 615 } |
| 611 | 616 |
| 612 bool NGBlockLayoutAlgorithm::ProceedToNextUnfinishedSibling( | 617 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() { |
| 613 NGPhysicalFragment* child_fragment) { | 618 LayoutUnit used_block_size = |
| 614 DCHECK(current_child_); | 619 break_token_ ? break_token_->UsedBlockSize() : LayoutUnit(); |
| 615 NGBlockNode* finished_child = toNGBlockNode(current_child_); | 620 LayoutUnit block_size = ComputeBlockSizeForFragment( |
| 616 current_child_ = current_child_->NextSibling(); | 621 ConstraintSpace(), Style(), used_block_size + content_size_); |
| 617 if (!ConstraintSpace().HasBlockFragmentation() && !fragmentainer_mapper_) | |
| 618 return true; | |
| 619 // If we're resuming layout after a fragmentainer break, we need to skip | |
| 620 // siblings that we're done with. We may have been able to fully lay out some | |
| 621 // node(s) preceding a node that we had to break inside (and therefore were | |
| 622 // not able to fully lay out). This happens when we have parallel flows [1], | |
| 623 // which are caused by floats, overflow, etc. | |
| 624 // | |
| 625 // [1] https://drafts.csswg.org/css-break/#parallel-flows | |
| 626 if (CurrentBlockBreakToken()) { | |
| 627 // TODO(layout-ng): Figure out if we need a better way to determine if the | |
| 628 // node is finished. Maybe something to encode in a break token? | |
| 629 // TODO(kojii): Handle inline children. | |
| 630 while (current_child_ && | |
| 631 current_child_->Type() == NGLayoutInputNode::kLegacyBlock && | |
| 632 toNGBlockNode(current_child_)->IsLayoutFinished()) { | |
| 633 current_child_ = current_child_->NextSibling(); | |
| 634 } | |
| 635 } | |
| 636 LayoutUnit break_offset = NextBreakOffset(); | |
| 637 bool is_out_of_space = content_size_ - PreviousBreakOffset() >= break_offset; | |
| 638 if (!HasPendingBreakToken()) { | |
| 639 bool child_broke = child_fragment->BreakToken(); | |
| 640 // This block needs to break if the child broke, or if we're out of space | |
| 641 // and there's more content waiting to be laid out. Otherwise, just bail | |
| 642 // now. | |
| 643 if (!child_broke && (!is_out_of_space || !current_child_)) | |
| 644 return true; | |
| 645 // Prepare a break token for this block, so that we know where to resume | |
| 646 // when the time comes for that. We may not be able to abort layout of this | |
| 647 // block right away, due to the posibility of parallel flows. We can only | |
| 648 // abort when we're out of space, or when there are no siblings left to | |
| 649 // process. | |
| 650 NGBlockBreakToken* token; | |
| 651 if (child_broke) { | |
| 652 // The child we just laid out was the first one to break. So that is | |
| 653 // where we need to resume. | |
| 654 token = new NGBlockBreakToken(finished_child, break_offset); | |
| 655 } else { | |
| 656 // Resume layout at the next sibling that needs layout. | |
| 657 DCHECK(current_child_); | |
| 658 token = | |
| 659 new NGBlockBreakToken(toNGBlockNode(current_child_), break_offset); | |
| 660 } | |
| 661 SetPendingBreakToken(token); | |
| 662 } | |
| 663 | 622 |
| 664 if (!fragmentainer_mapper_) { | 623 block_size -= used_block_size; |
| 665 if (!is_out_of_space) | 624 DCHECK_GE(block_size, LayoutUnit()) |
| 666 return true; | 625 << "Adding and subtracting the used_block_size shouldn't leave the " |
|
mstensho (USE GERRIT)
2017/02/27 13:44:36
Isn't this going to fail when you have a block wit
ikilpatrick
2017/02/27 18:50:09
It doesn't fail is it's DCHECK_GE not DCHECK_GT.
mstensho (USE GERRIT)
2017/02/27 20:28:20
Yeah, that wasn't my problem. I was thinking that
| |
| 667 // We have run out of space in this flow, so there's no work left to do for | 626 "block_size for this fragment smaller than zero."; |
| 668 // this block in this fragmentainer. We should finalize the fragment and get | |
| 669 // back to the remaining content when laying out the next fragmentainer(s). | |
| 670 return false; | |
| 671 } | |
| 672 | 627 |
| 673 if (is_out_of_space || !current_child_) { | 628 DCHECK(builder_->BfcOffset()) << "We must have our BfcOffset by this point " |
| 674 NGBlockBreakToken* token = fragmentainer_mapper_->Advance(); | 629 "to determine the space left in the flow."; |
| 675 DCHECK(token || !is_out_of_space); | 630 LayoutUnit space_left = ConstraintSpace().FragmentainerSpaceAvailable() - |
| 676 if (token) { | 631 builder_->BfcOffset().value().block_offset; |
|
mstensho (USE GERRIT)
2017/02/27 13:44:36
What does the block formatting context offset have
ikilpatrick
2017/02/27 18:50:09
We need a bunch more documentation around this Bfc
mstensho (USE GERRIT)
2017/02/27 20:28:20
Acknowledged.
| |
| 677 break_token_ = token; | 632 DCHECK_GE(space_left, LayoutUnit()); |
| 678 content_size_ = token->BreakOffset(); | |
| 679 current_child_ = token->InputNode(); | |
| 680 } | |
| 681 } | |
| 682 return true; | |
| 683 } | |
| 684 | 633 |
| 685 void NGBlockLayoutAlgorithm::SetPendingBreakToken(NGBlockBreakToken* token) { | 634 if (builder_->DidBreak()) { |
| 686 if (fragmentainer_mapper_) | |
| 687 fragmentainer_mapper_->SetBreakToken(token); | |
| 688 else | |
| 689 builder_->SetBreakToken(token); | |
| 690 } | |
| 691 | |
| 692 bool NGBlockLayoutAlgorithm::HasPendingBreakToken() const { | |
| 693 if (fragmentainer_mapper_) | |
| 694 return fragmentainer_mapper_->HasBreakToken(); | |
| 695 return builder_->HasBreakToken(); | |
| 696 } | |
| 697 | |
| 698 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() { | |
| 699 LayoutUnit block_size = | |
| 700 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); | |
| 701 LayoutUnit previous_break_offset = PreviousBreakOffset(); | |
| 702 block_size -= previous_break_offset; | |
| 703 block_size = std::max(LayoutUnit(), block_size); | |
| 704 LayoutUnit space_left = ConstraintSpace().FragmentainerSpaceAvailable(); | |
| 705 DCHECK_GE(space_left, LayoutUnit()); | |
| 706 if (builder_->HasBreakToken()) { | |
| 707 // A break token is ready, which means that we're going to break | 635 // A break token is ready, which means that we're going to break |
|
mstensho (USE GERRIT)
2017/02/27 13:44:36
Looks like this comment now needs to be updated. T
ikilpatrick
2017/02/27 18:50:09
Done.
| |
| 708 // before or inside a block-level child. | 636 // before or inside a block-level child. |
| 637 builder_->SetUsedBlockSize(std::min(space_left, block_size) + | |
|
mstensho (USE GERRIT)
2017/02/27 20:28:20
std::min(space_left, block_size) called twice in a
| |
| 638 used_block_size); | |
| 709 builder_->SetBlockSize(std::min(space_left, block_size)); | 639 builder_->SetBlockSize(std::min(space_left, block_size)); |
| 710 builder_->SetBlockOverflow(space_left); | 640 builder_->SetBlockOverflow(space_left); |
| 711 return; | 641 return; |
| 712 } | 642 } |
| 643 | |
| 713 if (block_size > space_left) { | 644 if (block_size > space_left) { |
| 714 // Need a break inside this block. | 645 // Need a break inside this block. |
| 715 builder_->SetBreakToken(new NGBlockBreakToken(nullptr, NextBreakOffset())); | 646 builder_->SetUsedBlockSize(space_left + used_block_size); |
| 716 builder_->SetBlockSize(space_left); | 647 builder_->SetBlockSize(space_left); |
| 717 builder_->SetBlockOverflow(space_left); | 648 builder_->SetBlockOverflow(space_left); |
| 718 return; | 649 return; |
| 719 } | 650 } |
| 651 | |
| 720 // The end of the block fits in the current fragmentainer. | 652 // The end of the block fits in the current fragmentainer. |
| 721 builder_->SetBlockSize(block_size); | 653 builder_->SetBlockSize(block_size); |
| 722 builder_->SetBlockOverflow(content_size_ - previous_break_offset); | 654 builder_->SetBlockOverflow(content_size_); |
| 723 } | |
| 724 | |
| 725 NGBlockBreakToken* NGBlockLayoutAlgorithm::CurrentBlockBreakToken() const { | |
| 726 NGBreakToken* token = break_token_; | |
| 727 if (!token || token->Type() != NGBreakToken::kBlockBreakToken) | |
| 728 return nullptr; | |
| 729 return toNGBlockBreakToken(token); | |
| 730 } | |
| 731 | |
| 732 LayoutUnit NGBlockLayoutAlgorithm::PreviousBreakOffset() const { | |
| 733 const NGBlockBreakToken* token = CurrentBlockBreakToken(); | |
| 734 return token ? token->BreakOffset() : LayoutUnit(); | |
| 735 } | |
| 736 | |
| 737 LayoutUnit NGBlockLayoutAlgorithm::NextBreakOffset() const { | |
| 738 if (fragmentainer_mapper_) | |
| 739 return fragmentainer_mapper_->NextBreakOffset(); | |
| 740 DCHECK(ConstraintSpace().HasBlockFragmentation()); | |
| 741 return PreviousBreakOffset() + | |
| 742 ConstraintSpace().FragmentainerSpaceAvailable(); | |
| 743 } | |
| 744 | |
| 745 LayoutUnit NGBlockLayoutAlgorithm::SpaceAvailableForCurrentChild() const { | |
| 746 LayoutUnit space_left; | |
| 747 if (fragmentainer_mapper_) | |
| 748 space_left = fragmentainer_mapper_->BlockSize(); | |
| 749 else if (ConstraintSpace().HasBlockFragmentation()) | |
| 750 space_left = ConstraintSpace().FragmentainerSpaceAvailable(); | |
| 751 else | |
| 752 return NGSizeIndefinite; | |
| 753 space_left -= BorderEdgeForCurrentChild() - PreviousBreakOffset(); | |
| 754 return space_left; | |
| 755 } | 655 } |
| 756 | 656 |
| 757 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins( | 657 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins( |
| 758 const NGConstraintSpace& space, | 658 const NGConstraintSpace& space, |
| 759 const ComputedStyle& style) { | 659 const ComputedStyle& style) { |
| 760 WTF::Optional<MinAndMaxContentSizes> sizes; | 660 WTF::Optional<MinAndMaxContentSizes> sizes; |
| 761 if (NeedMinAndMaxContentSizes(space, style)) { | 661 if (NeedMinAndMaxContentSizes(space, style)) { |
| 762 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return | 662 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return |
| 763 // MinAndMaxContentSizes. | 663 // MinAndMaxContentSizes. |
| 764 sizes = toNGBlockNode(current_child_)->ComputeMinAndMaxContentSizes(); | 664 sizes = toNGBlockNode(current_child_)->ComputeMinAndMaxContentSizes(); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 788 CurrentChildStyle()); | 688 CurrentChildStyle()); |
| 789 | 689 |
| 790 const ComputedStyle& current_child_style = CurrentChildStyle(); | 690 const ComputedStyle& current_child_style = CurrentChildStyle(); |
| 791 | 691 |
| 792 bool is_new_bfc = IsNewFormattingContextForInFlowBlockLevelChild( | 692 bool is_new_bfc = IsNewFormattingContextForInFlowBlockLevelChild( |
| 793 ConstraintSpace(), current_child_style); | 693 ConstraintSpace(), current_child_style); |
| 794 space_builder_->SetIsNewFormattingContext(is_new_bfc) | 694 space_builder_->SetIsNewFormattingContext(is_new_bfc) |
| 795 .SetIsShrinkToFit( | 695 .SetIsShrinkToFit( |
| 796 ShouldShrinkToFit(ConstraintSpace(), CurrentChildStyle())) | 696 ShouldShrinkToFit(ConstraintSpace(), CurrentChildStyle())) |
| 797 .SetTextDirection(current_child_style.direction()); | 697 .SetTextDirection(current_child_style.direction()); |
| 798 LayoutUnit space_available = SpaceAvailableForCurrentChild(); | |
| 799 space_builder_->SetFragmentainerSpaceAvailable(space_available); | |
| 800 | 698 |
| 801 // Clearance : | 699 // Clearance : |
| 802 // - Collapse margins | 700 // - Collapse margins |
| 803 // - Update curr_bfc_offset and parent BFC offset if needed. | 701 // - Update curr_bfc_offset and parent BFC offset if needed. |
| 804 // - Position all pending floats as position is known now. | 702 // - Position all pending floats as position is known now. |
| 805 // TODO(glebl): Fix the use case with clear: left and an intruding right. | 703 // TODO(glebl): Fix the use case with clear: left and an intruding right. |
| 806 // https://software.hixie.ch/utilities/js/live-dom-viewer/saved/4847 | 704 // https://software.hixie.ch/utilities/js/live-dom-viewer/saved/4847 |
| 807 if (current_child_style.clear() != EClear::kNone) { | 705 if (current_child_style.clear() != EClear::kNone) { |
| 808 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | 706 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); |
| 809 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); | 707 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 831 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start; | 729 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start; |
| 832 // Append the current margin strut with child's block start margin. | 730 // Append the current margin strut with child's block start margin. |
| 833 // Non empty border/padding use cases are handled inside of the child's | 731 // Non empty border/padding use cases are handled inside of the child's |
| 834 // layout. | 732 // layout. |
| 835 curr_margin_strut_.Append(curr_child_margins_.block_start); | 733 curr_margin_strut_.Append(curr_child_margins_.block_start); |
| 836 space_builder_->SetMarginStrut(curr_margin_strut_); | 734 space_builder_->SetMarginStrut(curr_margin_strut_); |
| 837 } | 735 } |
| 838 | 736 |
| 839 space_builder_->SetBfcOffset(curr_bfc_offset_); | 737 space_builder_->SetBfcOffset(curr_bfc_offset_); |
| 840 | 738 |
| 739 LayoutUnit space_available; | |
| 740 if (constraint_space_->HasBlockFragmentation()) { | |
| 741 space_available = ConstraintSpace().FragmentainerSpaceAvailable(); | |
| 742 // If a block establishes a new formatting context we must know our | |
| 743 // position in the formatting context, and are able to adjust the | |
| 744 // fragmentation line. | |
| 745 if (is_new_bfc) { | |
| 746 DCHECK(builder_->BfcOffset()); | |
| 747 space_available -= curr_bfc_offset_.block_offset; | |
|
mstensho (USE GERRIT)
2017/02/27 13:44:36
Again, I don't understand the link between block f
ikilpatrick
2017/02/27 18:50:09
See above, basically the fragmentation line is alw
mstensho (USE GERRIT)
2017/02/27 20:28:20
Acknowledged.
| |
| 748 } | |
| 749 } | |
| 750 space_builder_->SetFragmentainerSpaceAvailable(space_available); | |
| 751 | |
| 841 return space_builder_->ToConstraintSpace( | 752 return space_builder_->ToConstraintSpace( |
| 842 FromPlatformWritingMode(current_child_style.getWritingMode())); | 753 FromPlatformWritingMode(current_child_style.getWritingMode())); |
| 843 } | 754 } |
| 844 | 755 |
| 845 } // namespace blink | 756 } // namespace blink |
| OLD | NEW |