Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(164)

Side by Side Diff: third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc

Issue 2714803002: [LayoutNG] Allow block-flow layout to be fragmented using new approach. (Closed)
Patch Set: address comments. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 268 matching lines...) Expand 10 before | Expand all | Expand 10 after
287 if (display == EDisplay::Grid || display == EDisplay::Flex || 288 if (display == EDisplay::Grid || display == EDisplay::Flex ||
288 display == EDisplay::WebkitBox) 289 display == EDisplay::WebkitBox)
289 return true; 290 return true;
290 291
291 if (space.WritingMode() != FromPlatformWritingMode(style.getWritingMode())) 292 if (space.WritingMode() != FromPlatformWritingMode(style.getWritingMode()))
292 return true; 293 return true;
293 294
294 return false; 295 return false;
295 } 296 }
296 297
298 // Returns the borders and padding box for the current layout.
299 NGBoxStrut ComputeBordersAndPadding(const NGConstraintSpace& space,
300 const ComputedStyle& style) {
301 // If we are producing an anonymous fragment (e.g. a column) we shouldn't
302 // have any borders or padding.
303 return space.IsAnonymous()
cbiesinger 2017/02/27 19:09:37 It worries me a bit to have this check only here.
ikilpatrick 2017/02/27 19:29:34 Yeah, thoughts on moving this into ComputeBorders
cbiesinger 2017/02/27 19:32:03 Yes I think that would be good. ComputeBorders wil
ikilpatrick 2017/02/27 20:44:55 Done. PTAL
304 ? NGBoxStrut()
305 : ComputeBorders(style) + ComputePadding(space, style);
306 }
307
308 // Whether we've run out of space in this flow. If so, there will be no work
309 // left to do for this block in this fragmentainer.
310 bool IsOutOfSpace(const NGConstraintSpace& space, LayoutUnit content_size) {
311 return space.HasBlockFragmentation() &&
312 content_size >= space.FragmentainerSpaceAvailable();
313 }
314
297 } // namespace 315 } // namespace
298 316
299 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm( 317 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm(
300 NGBlockNode* node, 318 NGBlockNode* node,
301 NGConstraintSpace* constraint_space, 319 NGConstraintSpace* constraint_space,
302 NGBreakToken* break_token) 320 NGBlockBreakToken* break_token)
303 : node_(node), 321 : node_(node),
304 constraint_space_(constraint_space), 322 constraint_space_(constraint_space),
305 break_token_(break_token), 323 break_token_(break_token),
306 builder_(WTF::wrapUnique( 324 builder_(WTF::wrapUnique(
307 new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox, node))) {} 325 new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox, node))) {}
308 326
309 Optional<MinAndMaxContentSizes> 327 Optional<MinAndMaxContentSizes>
310 NGBlockLayoutAlgorithm::ComputeMinAndMaxContentSizes() const { 328 NGBlockLayoutAlgorithm::ComputeMinAndMaxContentSizes() const {
311 MinAndMaxContentSizes sizes; 329 MinAndMaxContentSizes sizes;
312 330
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 } 378 }
361 builder_->SetBfcOffset(bfc_offset); 379 builder_->SetBfcOffset(bfc_offset);
362 } 380 }
363 } 381 }
364 382
365 RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { 383 RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
366 WTF::Optional<MinAndMaxContentSizes> sizes; 384 WTF::Optional<MinAndMaxContentSizes> sizes;
367 if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style())) 385 if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style()))
368 sizes = ComputeMinAndMaxContentSizes(); 386 sizes = ComputeMinAndMaxContentSizes();
369 387
370 border_and_padding_ = 388 border_and_padding_ = ComputeBordersAndPadding(ConstraintSpace(), Style());
371 ComputeBorders(Style()) + ComputePadding(ConstraintSpace(), Style());
372 389
373 LayoutUnit inline_size = 390 LayoutUnit inline_size =
374 ComputeInlineSizeForFragment(ConstraintSpace(), Style(), sizes); 391 ComputeInlineSizeForFragment(ConstraintSpace(), Style(), sizes);
375 LayoutUnit adjusted_inline_size = 392 LayoutUnit adjusted_inline_size =
376 inline_size - border_and_padding_.InlineSum(); 393 inline_size - border_and_padding_.InlineSum();
377 // TODO(layout-ng): For quirks mode, should we pass blockSize instead of 394 // TODO(layout-ng): For quirks mode, should we pass blockSize instead of
378 // -1? 395 // -1?
379 LayoutUnit block_size = 396 LayoutUnit block_size =
380 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), NGSizeIndefinite); 397 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), NGSizeIndefinite);
381 LayoutUnit adjusted_block_size(block_size); 398 LayoutUnit adjusted_block_size(block_size);
382 // Our calculated block-axis size may be indefinite at this point. 399 // Our calculated block-axis size may be indefinite at this point.
383 // If so, just leave the size as NGSizeIndefinite instead of subtracting 400 // If so, just leave the size as NGSizeIndefinite instead of subtracting
384 // borders and padding. 401 // borders and padding.
385 if (adjusted_block_size != NGSizeIndefinite) 402 if (adjusted_block_size != NGSizeIndefinite)
386 adjusted_block_size -= border_and_padding_.BlockSum(); 403 adjusted_block_size -= border_and_padding_.BlockSum();
387 404
388 space_builder_ = new NGConstraintSpaceBuilder(constraint_space_); 405 space_builder_ = new NGConstraintSpaceBuilder(constraint_space_);
389 if (Style().specifiesColumns()) { 406 space_builder_
390 space_builder_->SetFragmentationType(kFragmentColumn); 407 ->SetAvailableSize(
391 adjusted_inline_size = 408 NGLogicalSize(adjusted_inline_size, adjusted_block_size))
392 ResolveUsedColumnInlineSize(adjusted_inline_size, Style()); 409 .SetPercentageResolutionSize(
393 LayoutUnit inline_progression = 410 NGLogicalSize(adjusted_inline_size, adjusted_block_size));
394 adjusted_inline_size + ResolveUsedColumnGap(Style());
395 fragmentainer_mapper_ =
396 new NGColumnMapper(inline_progression, adjusted_block_size);
397 }
398 space_builder_->SetAvailableSize(
399 NGLogicalSize(adjusted_inline_size, adjusted_block_size));
400 space_builder_->SetPercentageResolutionSize(
401 NGLogicalSize(adjusted_inline_size, adjusted_block_size));
402 411
403 builder_->SetDirection(constraint_space_->Direction()); 412 builder_->SetDirection(constraint_space_->Direction());
404 builder_->SetWritingMode(constraint_space_->WritingMode()); 413 builder_->SetWritingMode(constraint_space_->WritingMode());
405 builder_->SetInlineSize(inline_size).SetBlockSize(block_size); 414 builder_->SetInlineSize(inline_size).SetBlockSize(block_size);
406 415
407 // TODO(glebl): fix multicol after the new margin collapsing/floats algorithm 416 NGBlockChildIterator child_iterator(node_->FirstChild(), break_token_);
408 // based on BFCOffset is checked in. 417 NGBlockChildIterator::Entry entry = child_iterator.NextChild();
409 if (NGBlockBreakToken* token = CurrentBlockBreakToken()) { 418 current_child_ = entry.node;
410 // Resume after a previous break. 419 NGBreakToken* child_break_token = entry.token;
411 content_size_ = token->BreakOffset(); 420
412 current_child_ = token->InputNode(); 421 // If we are resuming from a break token our start border and padding is
413 } else { 422 // within a previous fragment.
414 content_size_ = border_and_padding_.block_start; 423 content_size_ = break_token_ ? LayoutUnit() : border_and_padding_.block_start;
415 current_child_ = node_->FirstChild();
416 }
417 424
418 curr_margin_strut_ = ConstraintSpace().MarginStrut(); 425 curr_margin_strut_ = ConstraintSpace().MarginStrut();
419 curr_bfc_offset_ = ConstraintSpace().BfcOffset(); 426 curr_bfc_offset_ = ConstraintSpace().BfcOffset();
420 427
421 // Margins collapsing: 428 // Margins collapsing:
422 // Do not collapse margins between parent and its child if there is 429 // Do not collapse margins between parent and its child if there is
423 // border/padding between them. 430 // border/padding between them.
424 if (border_and_padding_.block_start) { 431 if (border_and_padding_.block_start) {
425 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); 432 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
426 UpdateFragmentBfcOffset(curr_bfc_offset_); 433 UpdateFragmentBfcOffset(curr_bfc_offset_);
(...skipping 16 matching lines...) Expand all
443 NGBlockNode* current_block_child = toNGBlockNode(current_child_); 450 NGBlockNode* current_block_child = toNGBlockNode(current_child_);
444 EPosition position = current_block_child->Style().position(); 451 EPosition position = current_block_child->Style().position();
445 if (position == EPosition::kAbsolute || position == EPosition::kFixed) { 452 if (position == EPosition::kAbsolute || position == EPosition::kFixed) {
446 builder_->AddOutOfFlowChildCandidate(current_block_child, 453 builder_->AddOutOfFlowChildCandidate(current_block_child,
447 GetChildSpaceOffset()); 454 GetChildSpaceOffset());
448 current_child_ = current_block_child->NextSibling(); 455 current_child_ = current_block_child->NextSibling();
449 continue; 456 continue;
450 } 457 }
451 } 458 }
452 459
453 DCHECK(!ConstraintSpace().HasBlockFragmentation() ||
454 SpaceAvailableForCurrentChild() > LayoutUnit());
455 space_for_current_child_ = CreateConstraintSpaceForCurrentChild(); 460 space_for_current_child_ = CreateConstraintSpaceForCurrentChild();
456 461
457 if (current_child_->Type() == NGLayoutInputNode::kLegacyInline) { 462 if (current_child_->Type() == NGLayoutInputNode::kLegacyInline) {
458 LayoutInlineChildren(toNGInlineNode(current_child_)); 463 LayoutInlineChildren(toNGInlineNode(current_child_));
459 continue; 464 continue;
460 } 465 }
461 466
462 RefPtr<NGLayoutResult> layout_result = 467 RefPtr<NGLayoutResult> layout_result =
463 current_child_->Layout(space_for_current_child_); 468 current_child_->Layout(space_for_current_child_, child_break_token);
464 469
465 FinishCurrentChildLayout(layout_result); 470 FinishCurrentChildLayout(layout_result);
466 471
467 if (!ProceedToNextUnfinishedSibling( 472 entry = child_iterator.NextChild();
468 layout_result->PhysicalFragment().get())) 473 current_child_ = entry.node;
474 child_break_token = entry.token;
475
476 if (IsOutOfSpace(ConstraintSpace(), content_size_))
469 break; 477 break;
470 } 478 }
471 479
472 // Margins collapsing: 480 // Margins collapsing:
473 // Bottom margins of an in-flow block box doesn't collapse with its last 481 // Bottom margins of an in-flow block box doesn't collapse with its last
474 // in-flow block-level child's bottom margin if the box has bottom 482 // in-flow block-level child's bottom margin if the box has bottom
475 // border/padding. 483 // border/padding.
476 content_size_ += border_and_padding_.block_end; 484 content_size_ += border_and_padding_.block_end;
477 if (border_and_padding_.block_end || 485 if (border_and_padding_.block_end ||
478 ConstraintSpace().IsNewFormattingContext()) { 486 ConstraintSpace().IsNewFormattingContext()) {
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
559 PositionPendingFloats(origin_point.block_offset, ConstraintSpace(), 567 PositionPendingFloats(origin_point.block_offset, ConstraintSpace(),
560 builder_.get()); 568 builder_.get());
561 } 569 }
562 return; 570 return;
563 } 571 }
564 572
565 // Determine the fragment's position in the parent space either by using 573 // Determine the fragment's position in the parent space either by using
566 // content_size_ or known fragment's BFC offset. 574 // content_size_ or known fragment's BFC offset.
567 WTF::Optional<NGLogicalOffset> bfc_offset; 575 WTF::Optional<NGLogicalOffset> bfc_offset;
568 if (CurrentChildConstraintSpace().IsNewFormattingContext()) { 576 if (CurrentChildConstraintSpace().IsNewFormattingContext()) {
577 // TODO(ikilpatrick): We may need to place ourself within the BFC
578 // before a new formatting context child is laid out. (Not after layout as
579 // is done here).
569 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); 580 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
570 bfc_offset = curr_bfc_offset_; 581 bfc_offset = curr_bfc_offset_;
571 } else if (fragment.BfcOffset()) { 582 } else if (fragment.BfcOffset()) {
572 // Fragment that knows its offset can be used to set parent's BFC position. 583 // Fragment that knows its offset can be used to set parent's BFC position.
573 curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset; 584 curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset;
574 bfc_offset = curr_bfc_offset_; 585 bfc_offset = curr_bfc_offset_;
575 } else if (builder_->BfcOffset()) { 586 } else if (builder_->BfcOffset()) {
576 // Fragment doesn't know its offset but we can still calculate its BFC 587 // Fragment doesn't know its offset but we can still calculate its BFC
577 // position because the parent fragment's BFC is known. 588 // position because the parent fragment's BFC is known.
578 // Example: 589 // Example:
579 // BFC Offset is known here because of the padding. 590 // BFC Offset is known here because of the padding.
580 // <div style="padding: 1px"> 591 // <div style="padding: 1px">
581 // <div id="empty-div" style="margins: 1px"></div> 592 // <div id="empty-div" style="margins: 1px"></div>
582 bfc_offset = curr_bfc_offset_; 593 bfc_offset = curr_bfc_offset_;
583 bfc_offset.value().block_offset += curr_margin_strut_.Sum(); 594 bfc_offset.value().block_offset += curr_margin_strut_.Sum();
584 } 595 }
585 if (bfc_offset) { 596 if (bfc_offset) {
586 UpdateFragmentBfcOffset(curr_bfc_offset_); 597 UpdateFragmentBfcOffset(curr_bfc_offset_);
587 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), 598 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(),
588 builder_.get()); 599 builder_.get());
589 } 600 }
590 NGLogicalOffset logical_offset = CalculateLogicalOffset(bfc_offset); 601 NGLogicalOffset logical_offset = CalculateLogicalOffset(bfc_offset);
591 602
592 if (fragmentainer_mapper_)
593 fragmentainer_mapper_->ToVisualOffset(logical_offset);
594 else
595 logical_offset.block_offset -= PreviousBreakOffset();
596
597 // Update margin strut. 603 // Update margin strut.
598 curr_margin_strut_ = fragment.EndMarginStrut(); 604 curr_margin_strut_ = fragment.EndMarginStrut();
599 curr_margin_strut_.Append(curr_child_margins_.block_end); 605 curr_margin_strut_.Append(curr_child_margins_.block_end);
600 606
601 // Only modify content_size if BlockSize is not empty. It's needed to prevent 607 // Only modify content_size if BlockSize is not empty. It's needed to prevent
602 // the situation when logical_offset is included in content_size for empty 608 // the situation when logical_offset is included in content_size for empty
603 // blocks. Example: 609 // blocks. Example:
604 // <div style="overflow:hidden"> 610 // <div style="overflow:hidden">
605 // <div style="margin-top: 8px"></div> 611 // <div style="margin-top: 8px"></div>
606 // <div style="margin-top: 10px"></div> 612 // <div style="margin-top: 10px"></div>
607 // </div> 613 // </div>
608 if (fragment.BlockSize()) 614 if (fragment.BlockSize())
609 content_size_ = fragment.BlockSize() + logical_offset.block_offset; 615 content_size_ = fragment.BlockSize() + logical_offset.block_offset;
610 max_inline_size_ = 616 max_inline_size_ =
611 std::max(max_inline_size_, fragment.InlineSize() + 617 std::max(max_inline_size_, fragment.InlineSize() +
612 curr_child_margins_.InlineSum() + 618 curr_child_margins_.InlineSum() +
613 border_and_padding_.InlineSum()); 619 border_and_padding_.InlineSum());
614 620
615 builder_->AddChild(layout_result, logical_offset); 621 builder_->AddChild(layout_result, logical_offset);
616 } 622 }
617 623
618 bool NGBlockLayoutAlgorithm::ProceedToNextUnfinishedSibling( 624 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() {
619 NGPhysicalFragment* child_fragment) { 625 LayoutUnit used_block_size =
620 DCHECK(current_child_); 626 break_token_ ? break_token_->UsedBlockSize() : LayoutUnit();
621 NGBlockNode* finished_child = toNGBlockNode(current_child_); 627 LayoutUnit block_size = ComputeBlockSizeForFragment(
622 current_child_ = current_child_->NextSibling(); 628 ConstraintSpace(), Style(), used_block_size + content_size_);
623 if (!ConstraintSpace().HasBlockFragmentation() && !fragmentainer_mapper_)
624 return true;
625 // If we're resuming layout after a fragmentainer break, we need to skip
626 // siblings that we're done with. We may have been able to fully lay out some
627 // node(s) preceding a node that we had to break inside (and therefore were
628 // not able to fully lay out). This happens when we have parallel flows [1],
629 // which are caused by floats, overflow, etc.
630 //
631 // [1] https://drafts.csswg.org/css-break/#parallel-flows
632 if (CurrentBlockBreakToken()) {
633 // TODO(layout-ng): Figure out if we need a better way to determine if the
634 // node is finished. Maybe something to encode in a break token?
635 // TODO(kojii): Handle inline children.
636 while (current_child_ &&
637 current_child_->Type() == NGLayoutInputNode::kLegacyBlock &&
638 toNGBlockNode(current_child_)->IsLayoutFinished()) {
639 current_child_ = current_child_->NextSibling();
640 }
641 }
642 LayoutUnit break_offset = NextBreakOffset();
643 bool is_out_of_space = content_size_ - PreviousBreakOffset() >= break_offset;
644 if (!HasPendingBreakToken()) {
645 bool child_broke = child_fragment->BreakToken();
646 // This block needs to break if the child broke, or if we're out of space
647 // and there's more content waiting to be laid out. Otherwise, just bail
648 // now.
649 if (!child_broke && (!is_out_of_space || !current_child_))
650 return true;
651 // Prepare a break token for this block, so that we know where to resume
652 // when the time comes for that. We may not be able to abort layout of this
653 // block right away, due to the posibility of parallel flows. We can only
654 // abort when we're out of space, or when there are no siblings left to
655 // process.
656 NGBlockBreakToken* token;
657 if (child_broke) {
658 // The child we just laid out was the first one to break. So that is
659 // where we need to resume.
660 token = new NGBlockBreakToken(finished_child, break_offset);
661 } else {
662 // Resume layout at the next sibling that needs layout.
663 DCHECK(current_child_);
664 token =
665 new NGBlockBreakToken(toNGBlockNode(current_child_), break_offset);
666 }
667 SetPendingBreakToken(token);
668 }
669 629
670 if (!fragmentainer_mapper_) { 630 block_size -= used_block_size;
671 if (!is_out_of_space) 631 DCHECK_GE(block_size, LayoutUnit())
672 return true; 632 << "Adding and subtracting the used_block_size shouldn't leave the "
673 // We have run out of space in this flow, so there's no work left to do for 633 "block_size for this fragment smaller than zero.";
674 // this block in this fragmentainer. We should finalize the fragment and get
675 // back to the remaining content when laying out the next fragmentainer(s).
676 return false;
677 }
678 634
679 if (is_out_of_space || !current_child_) { 635 DCHECK(builder_->BfcOffset()) << "We must have our BfcOffset by this point "
680 NGBlockBreakToken* token = fragmentainer_mapper_->Advance(); 636 "to determine the space left in the flow.";
681 DCHECK(token || !is_out_of_space); 637 LayoutUnit space_left = ConstraintSpace().FragmentainerSpaceAvailable() -
682 if (token) { 638 builder_->BfcOffset().value().block_offset;
683 break_token_ = token; 639 DCHECK_GE(space_left, LayoutUnit());
684 content_size_ = token->BreakOffset();
685 current_child_ = token->InputNode();
686 }
687 }
688 return true;
689 }
690 640
691 void NGBlockLayoutAlgorithm::SetPendingBreakToken(NGBlockBreakToken* token) { 641 if (builder_->DidBreak()) {
692 if (fragmentainer_mapper_) 642 // One of our children broke. Even if we fit within the remaining space we
693 fragmentainer_mapper_->SetBreakToken(token); 643 // need to prepare a break token.
694 else 644 builder_->SetUsedBlockSize(std::min(space_left, block_size) +
695 builder_->SetBreakToken(token); 645 used_block_size);
696 }
697
698 bool NGBlockLayoutAlgorithm::HasPendingBreakToken() const {
699 if (fragmentainer_mapper_)
700 return fragmentainer_mapper_->HasBreakToken();
701 return builder_->HasBreakToken();
702 }
703
704 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() {
705 LayoutUnit block_size =
706 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_);
707 LayoutUnit previous_break_offset = PreviousBreakOffset();
708 block_size -= previous_break_offset;
709 block_size = std::max(LayoutUnit(), block_size);
710 LayoutUnit space_left = ConstraintSpace().FragmentainerSpaceAvailable();
711 DCHECK_GE(space_left, LayoutUnit());
712 if (builder_->HasBreakToken()) {
713 // A break token is ready, which means that we're going to break
714 // before or inside a block-level child.
715 builder_->SetBlockSize(std::min(space_left, block_size)); 646 builder_->SetBlockSize(std::min(space_left, block_size));
716 builder_->SetBlockOverflow(space_left); 647 builder_->SetBlockOverflow(space_left);
717 return; 648 return;
718 } 649 }
650
719 if (block_size > space_left) { 651 if (block_size > space_left) {
720 // Need a break inside this block. 652 // Need a break inside this block.
721 builder_->SetBreakToken(new NGBlockBreakToken(nullptr, NextBreakOffset())); 653 builder_->SetUsedBlockSize(space_left + used_block_size);
722 builder_->SetBlockSize(space_left); 654 builder_->SetBlockSize(space_left);
723 builder_->SetBlockOverflow(space_left); 655 builder_->SetBlockOverflow(space_left);
724 return; 656 return;
725 } 657 }
658
726 // The end of the block fits in the current fragmentainer. 659 // The end of the block fits in the current fragmentainer.
727 builder_->SetBlockSize(block_size); 660 builder_->SetBlockSize(block_size);
728 builder_->SetBlockOverflow(content_size_ - previous_break_offset); 661 builder_->SetBlockOverflow(content_size_);
729 }
730
731 NGBlockBreakToken* NGBlockLayoutAlgorithm::CurrentBlockBreakToken() const {
732 NGBreakToken* token = break_token_;
733 if (!token || token->Type() != NGBreakToken::kBlockBreakToken)
734 return nullptr;
735 return toNGBlockBreakToken(token);
736 }
737
738 LayoutUnit NGBlockLayoutAlgorithm::PreviousBreakOffset() const {
739 const NGBlockBreakToken* token = CurrentBlockBreakToken();
740 return token ? token->BreakOffset() : LayoutUnit();
741 }
742
743 LayoutUnit NGBlockLayoutAlgorithm::NextBreakOffset() const {
744 if (fragmentainer_mapper_)
745 return fragmentainer_mapper_->NextBreakOffset();
746 DCHECK(ConstraintSpace().HasBlockFragmentation());
747 return PreviousBreakOffset() +
748 ConstraintSpace().FragmentainerSpaceAvailable();
749 }
750
751 LayoutUnit NGBlockLayoutAlgorithm::SpaceAvailableForCurrentChild() const {
752 LayoutUnit space_left;
753 if (fragmentainer_mapper_)
754 space_left = fragmentainer_mapper_->BlockSize();
755 else if (ConstraintSpace().HasBlockFragmentation())
756 space_left = ConstraintSpace().FragmentainerSpaceAvailable();
757 else
758 return NGSizeIndefinite;
759 space_left -= BorderEdgeForCurrentChild() - PreviousBreakOffset();
760 return space_left;
761 } 662 }
762 663
763 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins( 664 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins(
764 const NGConstraintSpace& space, 665 const NGConstraintSpace& space,
765 const ComputedStyle& style) { 666 const ComputedStyle& style) {
766 WTF::Optional<MinAndMaxContentSizes> sizes; 667 WTF::Optional<MinAndMaxContentSizes> sizes;
767 if (NeedMinAndMaxContentSizes(space, style)) { 668 if (NeedMinAndMaxContentSizes(space, style)) {
768 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return 669 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return
769 // MinAndMaxContentSizes. 670 // MinAndMaxContentSizes.
770 sizes = toNGBlockNode(current_child_)->ComputeMinAndMaxContentSizes(); 671 sizes = toNGBlockNode(current_child_)->ComputeMinAndMaxContentSizes();
(...skipping 23 matching lines...) Expand all
794 CurrentChildStyle()); 695 CurrentChildStyle());
795 696
796 const ComputedStyle& current_child_style = CurrentChildStyle(); 697 const ComputedStyle& current_child_style = CurrentChildStyle();
797 698
798 bool is_new_bfc = IsNewFormattingContextForInFlowBlockLevelChild( 699 bool is_new_bfc = IsNewFormattingContextForInFlowBlockLevelChild(
799 ConstraintSpace(), current_child_style); 700 ConstraintSpace(), current_child_style);
800 space_builder_->SetIsNewFormattingContext(is_new_bfc) 701 space_builder_->SetIsNewFormattingContext(is_new_bfc)
801 .SetIsShrinkToFit( 702 .SetIsShrinkToFit(
802 ShouldShrinkToFit(ConstraintSpace(), CurrentChildStyle())) 703 ShouldShrinkToFit(ConstraintSpace(), CurrentChildStyle()))
803 .SetTextDirection(current_child_style.direction()); 704 .SetTextDirection(current_child_style.direction());
804 LayoutUnit space_available = SpaceAvailableForCurrentChild();
805 space_builder_->SetFragmentainerSpaceAvailable(space_available);
806 705
807 // Clearance : 706 // Clearance :
808 // - *Always* collapse margins and update *container*'s BFC offset. 707 // - *Always* collapse margins and update *container*'s BFC offset.
809 // - Position all pending floats since the fragment's BFC offset is known. 708 // - Position all pending floats since the fragment's BFC offset is known.
810 // - Set the clearance offset on the constraint space's builder. 709 // - Set the clearance offset on the constraint space's builder.
811 if (current_child_style.clear() != EClear::kNone) { 710 if (current_child_style.clear() != EClear::kNone) {
812 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); 711 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
813 UpdateFragmentBfcOffset(curr_bfc_offset_); 712 UpdateFragmentBfcOffset(curr_bfc_offset_);
814 // Only collapse margins if it's an adjoining block with clearance. 713 // Only collapse margins if it's an adjoining block with clearance.
815 if (!content_size_) { 714 if (!content_size_) {
(...skipping 20 matching lines...) Expand all
836 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start; 735 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start;
837 // Append the current margin strut with child's block start margin. 736 // Append the current margin strut with child's block start margin.
838 // Non empty border/padding use cases are handled inside of the child's 737 // Non empty border/padding use cases are handled inside of the child's
839 // layout. 738 // layout.
840 curr_margin_strut_.Append(curr_child_margins_.block_start); 739 curr_margin_strut_.Append(curr_child_margins_.block_start);
841 space_builder_->SetMarginStrut(curr_margin_strut_); 740 space_builder_->SetMarginStrut(curr_margin_strut_);
842 } 741 }
843 742
844 space_builder_->SetBfcOffset(curr_bfc_offset_); 743 space_builder_->SetBfcOffset(curr_bfc_offset_);
845 744
745 LayoutUnit space_available;
746 if (constraint_space_->HasBlockFragmentation()) {
747 space_available = ConstraintSpace().FragmentainerSpaceAvailable();
748 // If a block establishes a new formatting context we must know our
749 // position in the formatting context, and are able to adjust the
750 // fragmentation line.
751 if (is_new_bfc) {
752 DCHECK(builder_->BfcOffset());
753 space_available -= curr_bfc_offset_.block_offset;
754 }
755 }
756 space_builder_->SetFragmentainerSpaceAvailable(space_available);
757
846 return space_builder_->ToConstraintSpace( 758 return space_builder_->ToConstraintSpace(
847 FromPlatformWritingMode(current_child_style.getWritingMode())); 759 FromPlatformWritingMode(current_child_style.getWritingMode()));
848 } 760 }
849 } // namespace blink 761 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698