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

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: rebase. 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_constraint_space.h" 11 #include "core/layout/ng/ng_constraint_space.h"
12 #include "core/layout/ng/ng_constraint_space_builder.h" 12 #include "core/layout/ng/ng_constraint_space_builder.h"
13 #include "core/layout/ng/ng_fragment.h" 13 #include "core/layout/ng/ng_fragment.h"
14 #include "core/layout/ng/ng_fragment_builder.h" 14 #include "core/layout/ng/ng_fragment_builder.h"
15 #include "core/layout/ng/ng_inline_node.h" 15 #include "core/layout/ng/ng_inline_node.h"
16 #include "core/layout/ng/ng_layout_opportunity_iterator.h" 16 #include "core/layout/ng/ng_layout_opportunity_iterator.h"
17 #include "core/layout/ng/ng_length_utils.h" 17 #include "core/layout/ng/ng_length_utils.h"
18 #include "core/layout/ng/ng_line_builder.h" 18 #include "core/layout/ng/ng_line_builder.h"
19 #include "core/layout/ng/ng_out_of_flow_layout_part.h" 19 #include "core/layout/ng/ng_out_of_flow_layout_part.h"
20 #include "core/layout/ng/ng_units.h" 20 #include "core/layout/ng/ng_units.h"
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after
287 if (display == EDisplay::Grid || display == EDisplay::Flex || 287 if (display == EDisplay::Grid || display == EDisplay::Flex ||
288 display == EDisplay::WebkitBox) 288 display == EDisplay::WebkitBox)
289 return true; 289 return true;
290 290
291 if (space.WritingMode() != FromPlatformWritingMode(style.getWritingMode())) 291 if (space.WritingMode() != FromPlatformWritingMode(style.getWritingMode()))
292 return true; 292 return true;
293 293
294 return false; 294 return false;
295 } 295 }
296 296
297 // Whether we've run out of space in this flow. If so, there will be no work
298 // left to do for this block in this fragmentainer.
299 bool IsOutOfSpace(const NGConstraintSpace& space, LayoutUnit content_size) {
300 return space.HasBlockFragmentation() &&
301 content_size >= space.FragmentainerSpaceAvailable();
302 }
303
297 } // namespace 304 } // namespace
298 305
299 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm( 306 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm(
300 NGBlockNode* node, 307 NGBlockNode* node,
301 NGConstraintSpace* constraint_space, 308 NGConstraintSpace* constraint_space,
302 NGBreakToken* break_token) 309 NGBlockBreakToken* break_token)
303 : node_(node), 310 : node_(node),
304 constraint_space_(constraint_space), 311 constraint_space_(constraint_space),
305 break_token_(break_token), 312 break_token_(break_token),
306 builder_(WTF::wrapUnique( 313 builder_(WTF::wrapUnique(
307 new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox, node))) {} 314 new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox, node))) {}
308 315
309 Optional<MinAndMaxContentSizes> 316 Optional<MinAndMaxContentSizes>
310 NGBlockLayoutAlgorithm::ComputeMinAndMaxContentSizes() const { 317 NGBlockLayoutAlgorithm::ComputeMinAndMaxContentSizes() const {
311 MinAndMaxContentSizes sizes; 318 MinAndMaxContentSizes sizes;
312 319
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 } 367 }
361 builder_->SetBfcOffset(bfc_offset); 368 builder_->SetBfcOffset(bfc_offset);
362 } 369 }
363 } 370 }
364 371
365 RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { 372 RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
366 WTF::Optional<MinAndMaxContentSizes> sizes; 373 WTF::Optional<MinAndMaxContentSizes> sizes;
367 if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style())) 374 if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style()))
368 sizes = ComputeMinAndMaxContentSizes(); 375 sizes = ComputeMinAndMaxContentSizes();
369 376
370 border_and_padding_ = 377 border_and_padding_ = ComputeBorders(ConstraintSpace(), Style()) +
371 ComputeBorders(Style()) + ComputePadding(ConstraintSpace(), Style()); 378 ComputePadding(ConstraintSpace(), Style());
372 379
373 LayoutUnit inline_size = 380 LayoutUnit inline_size =
374 ComputeInlineSizeForFragment(ConstraintSpace(), Style(), sizes); 381 ComputeInlineSizeForFragment(ConstraintSpace(), Style(), sizes);
375 LayoutUnit adjusted_inline_size = 382 LayoutUnit adjusted_inline_size =
376 inline_size - border_and_padding_.InlineSum(); 383 inline_size - border_and_padding_.InlineSum();
377 // TODO(layout-ng): For quirks mode, should we pass blockSize instead of 384 // TODO(layout-ng): For quirks mode, should we pass blockSize instead of
378 // -1? 385 // -1?
379 LayoutUnit block_size = 386 LayoutUnit block_size =
380 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), NGSizeIndefinite); 387 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), NGSizeIndefinite);
381 LayoutUnit adjusted_block_size(block_size); 388 LayoutUnit adjusted_block_size(block_size);
382 // Our calculated block-axis size may be indefinite at this point. 389 // Our calculated block-axis size may be indefinite at this point.
383 // If so, just leave the size as NGSizeIndefinite instead of subtracting 390 // If so, just leave the size as NGSizeIndefinite instead of subtracting
384 // borders and padding. 391 // borders and padding.
385 if (adjusted_block_size != NGSizeIndefinite) 392 if (adjusted_block_size != NGSizeIndefinite)
386 adjusted_block_size -= border_and_padding_.BlockSum(); 393 adjusted_block_size -= border_and_padding_.BlockSum();
387 394
388 space_builder_ = new NGConstraintSpaceBuilder(constraint_space_); 395 space_builder_ = new NGConstraintSpaceBuilder(constraint_space_);
389 if (Style().specifiesColumns()) { 396 space_builder_
390 space_builder_->SetFragmentationType(kFragmentColumn); 397 ->SetAvailableSize(
391 adjusted_inline_size = 398 NGLogicalSize(adjusted_inline_size, adjusted_block_size))
392 ResolveUsedColumnInlineSize(adjusted_inline_size, Style()); 399 .SetPercentageResolutionSize(
393 LayoutUnit inline_progression = 400 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 401
403 builder_->SetDirection(constraint_space_->Direction()); 402 builder_->SetDirection(constraint_space_->Direction());
404 builder_->SetWritingMode(constraint_space_->WritingMode()); 403 builder_->SetWritingMode(constraint_space_->WritingMode());
405 builder_->SetInlineSize(inline_size).SetBlockSize(block_size); 404 builder_->SetInlineSize(inline_size).SetBlockSize(block_size);
406 405
407 // TODO(glebl): fix multicol after the new margin collapsing/floats algorithm 406 NGBlockChildIterator child_iterator(node_->FirstChild(), break_token_);
408 // based on BFCOffset is checked in. 407 NGBlockChildIterator::Entry entry = child_iterator.NextChild();
409 if (NGBlockBreakToken* token = CurrentBlockBreakToken()) { 408 current_child_ = entry.node;
410 // Resume after a previous break. 409 NGBreakToken* child_break_token = entry.token;
411 content_size_ = token->BreakOffset(); 410
412 current_child_ = token->InputNode(); 411 // If we are resuming from a break token our start border and padding is
413 } else { 412 // within a previous fragment.
414 content_size_ = border_and_padding_.block_start; 413 content_size_ = break_token_ ? LayoutUnit() : border_and_padding_.block_start;
415 current_child_ = node_->FirstChild();
416 }
417 414
418 curr_margin_strut_ = ConstraintSpace().MarginStrut(); 415 curr_margin_strut_ = ConstraintSpace().MarginStrut();
419 curr_bfc_offset_ = ConstraintSpace().BfcOffset(); 416 curr_bfc_offset_ = ConstraintSpace().BfcOffset();
420 417
421 // Margins collapsing: 418 // Margins collapsing:
422 // Do not collapse margins between parent and its child if there is 419 // Do not collapse margins between parent and its child if there is
423 // border/padding between them. 420 // border/padding between them.
424 if (border_and_padding_.block_start) { 421 if (border_and_padding_.block_start) {
425 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); 422 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
426 UpdateFragmentBfcOffset(curr_bfc_offset_); 423 UpdateFragmentBfcOffset(curr_bfc_offset_);
(...skipping 11 matching lines...) Expand all
438 435
439 curr_bfc_offset_.block_offset += content_size_; 436 curr_bfc_offset_.block_offset += content_size_;
440 437
441 while (current_child_) { 438 while (current_child_) {
442 if (current_child_->Type() == NGLayoutInputNode::kLegacyBlock) { 439 if (current_child_->Type() == NGLayoutInputNode::kLegacyBlock) {
443 NGBlockNode* current_block_child = toNGBlockNode(current_child_); 440 NGBlockNode* current_block_child = toNGBlockNode(current_child_);
444 EPosition position = current_block_child->Style().position(); 441 EPosition position = current_block_child->Style().position();
445 if (position == EPosition::kAbsolute || position == EPosition::kFixed) { 442 if (position == EPosition::kAbsolute || position == EPosition::kFixed) {
446 builder_->AddOutOfFlowChildCandidate(current_block_child, 443 builder_->AddOutOfFlowChildCandidate(current_block_child,
447 GetChildSpaceOffset()); 444 GetChildSpaceOffset());
448 current_child_ = current_block_child->NextSibling(); 445 NGBlockChildIterator::Entry entry = child_iterator.NextChild();
446 current_child_ = entry.node;
447 child_break_token = entry.token;
449 continue; 448 continue;
450 } 449 }
451 } 450 }
452 451
453 DCHECK(!ConstraintSpace().HasBlockFragmentation() ||
454 SpaceAvailableForCurrentChild() > LayoutUnit());
455 space_for_current_child_ = CreateConstraintSpaceForCurrentChild(); 452 space_for_current_child_ = CreateConstraintSpaceForCurrentChild();
456 453
457 if (current_child_->Type() == NGLayoutInputNode::kLegacyInline) { 454 if (current_child_->Type() == NGLayoutInputNode::kLegacyInline) {
458 LayoutInlineChildren(toNGInlineNode(current_child_)); 455 LayoutInlineChildren(toNGInlineNode(current_child_));
459 continue; 456 continue;
460 } 457 }
461 458
462 RefPtr<NGLayoutResult> layout_result = 459 RefPtr<NGLayoutResult> layout_result =
463 current_child_->Layout(space_for_current_child_); 460 current_child_->Layout(space_for_current_child_, child_break_token);
464 461
465 FinishCurrentChildLayout(layout_result); 462 FinishCurrentChildLayout(layout_result);
466 463
467 if (!ProceedToNextUnfinishedSibling( 464 entry = child_iterator.NextChild();
468 layout_result->PhysicalFragment().get())) 465 current_child_ = entry.node;
466 child_break_token = entry.token;
467
468 if (IsOutOfSpace(ConstraintSpace(), content_size_))
469 break; 469 break;
470 } 470 }
471 471
472 // Margins collapsing: 472 // Margins collapsing:
473 // Bottom margins of an in-flow block box doesn't collapse with its last 473 // 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 474 // in-flow block-level child's bottom margin if the box has bottom
475 // border/padding. 475 // border/padding.
476 content_size_ += border_and_padding_.block_end; 476 content_size_ += border_and_padding_.block_end;
477 if (border_and_padding_.block_end || 477 if (border_and_padding_.block_end ||
478 ConstraintSpace().IsNewFormattingContext()) { 478 ConstraintSpace().IsNewFormattingContext()) {
479 content_size_ += curr_margin_strut_.Sum(); 479 content_size_ += curr_margin_strut_.Sum();
480 curr_margin_strut_ = NGMarginStrut(); 480 curr_margin_strut_ = NGMarginStrut();
481 } 481 }
482 482
483 // Recompute the block-axis size now that we know our content size. 483 // Recompute the block-axis size now that we know our content size.
484 block_size = 484 block_size =
485 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); 485 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_);
486 builder_->SetBlockSize(block_size); 486 builder_->SetBlockSize(block_size);
487 487
488 // Layout our absolute and fixed positioned children. 488 // Layout our absolute and fixed positioned children.
489 NGOutOfFlowLayoutPart(Style(), builder_.get()).Run(); 489 NGOutOfFlowLayoutPart(ConstraintSpace(), Style(), builder_.get()).Run();
490 490
491 // Non-empty blocks always know their position in space: 491 // Non-empty blocks always know their position in space:
492 if (block_size) { 492 if (block_size) {
493 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); 493 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
494 UpdateFragmentBfcOffset(curr_bfc_offset_); 494 UpdateFragmentBfcOffset(curr_bfc_offset_);
495 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), 495 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(),
496 builder_.get()); 496 builder_.get());
497 } 497 }
498 498
499 // Margins collapsing: 499 // Margins collapsing:
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
559 PositionPendingFloats(origin_point.block_offset, ConstraintSpace(), 559 PositionPendingFloats(origin_point.block_offset, ConstraintSpace(),
560 builder_.get()); 560 builder_.get());
561 } 561 }
562 return; 562 return;
563 } 563 }
564 564
565 // Determine the fragment's position in the parent space either by using 565 // Determine the fragment's position in the parent space either by using
566 // content_size_ or known fragment's BFC offset. 566 // content_size_ or known fragment's BFC offset.
567 WTF::Optional<NGLogicalOffset> bfc_offset; 567 WTF::Optional<NGLogicalOffset> bfc_offset;
568 if (CurrentChildConstraintSpace().IsNewFormattingContext()) { 568 if (CurrentChildConstraintSpace().IsNewFormattingContext()) {
569 // TODO(ikilpatrick): We may need to place ourself within the BFC
570 // before a new formatting context child is laid out. (Not after layout as
571 // is done here).
569 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); 572 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
570 bfc_offset = curr_bfc_offset_; 573 bfc_offset = curr_bfc_offset_;
571 } else if (fragment.BfcOffset()) { 574 } else if (fragment.BfcOffset()) {
572 // Fragment that knows its offset can be used to set parent's BFC position. 575 // 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; 576 curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset;
574 bfc_offset = curr_bfc_offset_; 577 bfc_offset = curr_bfc_offset_;
575 } else if (builder_->BfcOffset()) { 578 } else if (builder_->BfcOffset()) {
576 // Fragment doesn't know its offset but we can still calculate its BFC 579 // Fragment doesn't know its offset but we can still calculate its BFC
577 // position because the parent fragment's BFC is known. 580 // position because the parent fragment's BFC is known.
578 // Example: 581 // Example:
579 // BFC Offset is known here because of the padding. 582 // BFC Offset is known here because of the padding.
580 // <div style="padding: 1px"> 583 // <div style="padding: 1px">
581 // <div id="empty-div" style="margins: 1px"></div> 584 // <div id="empty-div" style="margins: 1px"></div>
582 bfc_offset = curr_bfc_offset_; 585 bfc_offset = curr_bfc_offset_;
583 bfc_offset.value().block_offset += curr_margin_strut_.Sum(); 586 bfc_offset.value().block_offset += curr_margin_strut_.Sum();
584 } 587 }
585 if (bfc_offset) { 588 if (bfc_offset) {
586 UpdateFragmentBfcOffset(curr_bfc_offset_); 589 UpdateFragmentBfcOffset(curr_bfc_offset_);
587 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), 590 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(),
588 builder_.get()); 591 builder_.get());
589 } 592 }
590 NGLogicalOffset logical_offset = CalculateLogicalOffset(bfc_offset); 593 NGLogicalOffset logical_offset = CalculateLogicalOffset(bfc_offset);
591 594
592 if (fragmentainer_mapper_)
593 fragmentainer_mapper_->ToVisualOffset(logical_offset);
594 else
595 logical_offset.block_offset -= PreviousBreakOffset();
596
597 // Update margin strut. 595 // Update margin strut.
598 curr_margin_strut_ = fragment.EndMarginStrut(); 596 curr_margin_strut_ = fragment.EndMarginStrut();
599 curr_margin_strut_.Append(curr_child_margins_.block_end); 597 curr_margin_strut_.Append(curr_child_margins_.block_end);
600 598
601 // Only modify content_size if BlockSize is not empty. It's needed to prevent 599 // 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 600 // the situation when logical_offset is included in content_size for empty
603 // blocks. Example: 601 // blocks. Example:
604 // <div style="overflow:hidden"> 602 // <div style="overflow:hidden">
605 // <div style="margin-top: 8px"></div> 603 // <div style="margin-top: 8px"></div>
606 // <div style="margin-top: 10px"></div> 604 // <div style="margin-top: 10px"></div>
607 // </div> 605 // </div>
608 if (fragment.BlockSize()) 606 if (fragment.BlockSize())
609 content_size_ = fragment.BlockSize() + logical_offset.block_offset; 607 content_size_ = fragment.BlockSize() + logical_offset.block_offset;
610 max_inline_size_ = 608 max_inline_size_ =
611 std::max(max_inline_size_, fragment.InlineSize() + 609 std::max(max_inline_size_, fragment.InlineSize() +
612 curr_child_margins_.InlineSum() + 610 curr_child_margins_.InlineSum() +
613 border_and_padding_.InlineSum()); 611 border_and_padding_.InlineSum());
614 612
615 builder_->AddChild(layout_result, logical_offset); 613 builder_->AddChild(layout_result, logical_offset);
616 } 614 }
617 615
618 bool NGBlockLayoutAlgorithm::ProceedToNextUnfinishedSibling( 616 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() {
619 NGPhysicalFragment* child_fragment) { 617 LayoutUnit used_block_size =
620 DCHECK(current_child_); 618 break_token_ ? break_token_->UsedBlockSize() : LayoutUnit();
621 NGBlockNode* finished_child = toNGBlockNode(current_child_); 619 LayoutUnit block_size = ComputeBlockSizeForFragment(
622 current_child_ = current_child_->NextSibling(); 620 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 621
670 if (!fragmentainer_mapper_) { 622 block_size -= used_block_size;
671 if (!is_out_of_space) 623 DCHECK_GE(block_size, LayoutUnit())
672 return true; 624 << "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 625 "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 626
679 if (is_out_of_space || !current_child_) { 627 DCHECK(builder_->BfcOffset()) << "We must have our BfcOffset by this point "
680 NGBlockBreakToken* token = fragmentainer_mapper_->Advance(); 628 "to determine the space left in the flow.";
681 DCHECK(token || !is_out_of_space); 629 LayoutUnit space_left = ConstraintSpace().FragmentainerSpaceAvailable() -
682 if (token) { 630 builder_->BfcOffset().value().block_offset;
683 break_token_ = token; 631 DCHECK_GE(space_left, LayoutUnit());
684 content_size_ = token->BreakOffset();
685 current_child_ = token->InputNode();
686 }
687 }
688 return true;
689 }
690 632
691 void NGBlockLayoutAlgorithm::SetPendingBreakToken(NGBlockBreakToken* token) { 633 if (builder_->DidBreak()) {
692 if (fragmentainer_mapper_) 634 // One of our children broke. Even if we fit within the remaining space we
693 fragmentainer_mapper_->SetBreakToken(token); 635 // need to prepare a break token.
694 else 636 builder_->SetUsedBlockSize(std::min(space_left, block_size) +
695 builder_->SetBreakToken(token); 637 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)); 638 builder_->SetBlockSize(std::min(space_left, block_size));
716 builder_->SetBlockOverflow(space_left); 639 builder_->SetBlockOverflow(space_left);
717 return; 640 return;
718 } 641 }
642
719 if (block_size > space_left) { 643 if (block_size > space_left) {
720 // Need a break inside this block. 644 // Need a break inside this block.
721 builder_->SetBreakToken(new NGBlockBreakToken(nullptr, NextBreakOffset())); 645 builder_->SetUsedBlockSize(space_left + used_block_size);
722 builder_->SetBlockSize(space_left); 646 builder_->SetBlockSize(space_left);
723 builder_->SetBlockOverflow(space_left); 647 builder_->SetBlockOverflow(space_left);
724 return; 648 return;
725 } 649 }
650
726 // The end of the block fits in the current fragmentainer. 651 // The end of the block fits in the current fragmentainer.
727 builder_->SetBlockSize(block_size); 652 builder_->SetBlockSize(block_size);
728 builder_->SetBlockOverflow(content_size_ - previous_break_offset); 653 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 } 654 }
762 655
763 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins( 656 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins(
764 const NGConstraintSpace& space, 657 const NGConstraintSpace& space,
765 const ComputedStyle& style) { 658 const ComputedStyle& style) {
766 WTF::Optional<MinAndMaxContentSizes> sizes; 659 WTF::Optional<MinAndMaxContentSizes> sizes;
767 if (NeedMinAndMaxContentSizes(space, style)) { 660 if (NeedMinAndMaxContentSizes(space, style)) {
768 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return 661 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return
769 // MinAndMaxContentSizes. 662 // MinAndMaxContentSizes.
770 sizes = toNGBlockNode(current_child_)->ComputeMinAndMaxContentSizes(); 663 sizes = toNGBlockNode(current_child_)->ComputeMinAndMaxContentSizes();
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
802 CurrentChildStyle()); 695 CurrentChildStyle());
803 696
804 const ComputedStyle& current_child_style = CurrentChildStyle(); 697 const ComputedStyle& current_child_style = CurrentChildStyle();
805 698
806 bool is_new_bfc = IsNewFormattingContextForInFlowBlockLevelChild( 699 bool is_new_bfc = IsNewFormattingContextForInFlowBlockLevelChild(
807 ConstraintSpace(), current_child_style); 700 ConstraintSpace(), current_child_style);
808 space_builder_->SetIsNewFormattingContext(is_new_bfc) 701 space_builder_->SetIsNewFormattingContext(is_new_bfc)
809 .SetIsShrinkToFit( 702 .SetIsShrinkToFit(
810 ShouldShrinkToFit(ConstraintSpace(), CurrentChildStyle())) 703 ShouldShrinkToFit(ConstraintSpace(), CurrentChildStyle()))
811 .SetTextDirection(current_child_style.direction()); 704 .SetTextDirection(current_child_style.direction());
812 LayoutUnit space_available = SpaceAvailableForCurrentChild();
813 space_builder_->SetFragmentainerSpaceAvailable(space_available);
814 705
815 // Clearance : 706 // Clearance :
816 // - *Always* collapse margins and update *container*'s BFC offset. 707 // - *Always* collapse margins and update *container*'s BFC offset.
817 // - 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.
818 // - Set the clearance offset on the constraint space's builder. 709 // - Set the clearance offset on the constraint space's builder.
819 if (current_child_style.clear() != EClear::kNone) { 710 if (current_child_style.clear() != EClear::kNone) {
820 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); 711 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
821 UpdateFragmentBfcOffset(curr_bfc_offset_); 712 UpdateFragmentBfcOffset(curr_bfc_offset_);
822 // Only collapse margins if it's an adjoining block with clearance. 713 // Only collapse margins if it's an adjoining block with clearance.
823 if (!content_size_) { 714 if (!content_size_) {
(...skipping 20 matching lines...) Expand all
844 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start; 735 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start;
845 // Append the current margin strut with child's block start margin. 736 // Append the current margin strut with child's block start margin.
846 // 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
847 // layout. 738 // layout.
848 curr_margin_strut_.Append(curr_child_margins_.block_start); 739 curr_margin_strut_.Append(curr_child_margins_.block_start);
849 space_builder_->SetMarginStrut(curr_margin_strut_); 740 space_builder_->SetMarginStrut(curr_margin_strut_);
850 } 741 }
851 742
852 space_builder_->SetBfcOffset(curr_bfc_offset_); 743 space_builder_->SetBfcOffset(curr_bfc_offset_);
853 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
854 return space_builder_->ToConstraintSpace( 758 return space_builder_->ToConstraintSpace(
855 FromPlatformWritingMode(current_child_style.getWritingMode())); 759 FromPlatformWritingMode(current_child_style.getWritingMode()));
856 } 760 }
857 } // namespace blink 761 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698