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

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_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 279 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 return true; 299 return true;
299 300
300 return false; 301 return false;
301 } 302 }
302 303
303 } // namespace 304 } // namespace
304 305
305 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm( 306 NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm(
306 NGBlockNode* node, 307 NGBlockNode* node,
307 NGConstraintSpace* constraint_space, 308 NGConstraintSpace* constraint_space,
308 NGBreakToken* break_token) 309 NGBlockBreakToken* break_token)
309 : node_(node), 310 : node_(node),
310 constraint_space_(constraint_space), 311 constraint_space_(constraint_space),
311 break_token_(break_token), 312 break_token_(break_token),
312 builder_(WTF::wrapUnique( 313 builder_(WTF::wrapUnique(
313 new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox, node))) {} 314 new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox, node))) {}
314 315
315 Optional<MinAndMaxContentSizes> 316 Optional<MinAndMaxContentSizes>
316 NGBlockLayoutAlgorithm::ComputeMinAndMaxContentSizes() const { 317 NGBlockLayoutAlgorithm::ComputeMinAndMaxContentSizes() const {
317 MinAndMaxContentSizes sizes; 318 MinAndMaxContentSizes sizes;
318 319
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
354 builder_->BfcOffset().value().block_offset; 355 builder_->BfcOffset().value().block_offset;
355 } 356 }
356 return {inline_offset, block_offset}; 357 return {inline_offset, block_offset};
357 } 358 }
358 359
359 RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() { 360 RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
360 WTF::Optional<MinAndMaxContentSizes> sizes; 361 WTF::Optional<MinAndMaxContentSizes> sizes;
361 if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style())) 362 if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style()))
362 sizes = ComputeMinAndMaxContentSizes(); 363 sizes = ComputeMinAndMaxContentSizes();
363 364
364 border_and_padding_ = 365 // If we are producing an anonymous fragment (e.g. a column) we shouldn't
365 ComputeBorders(Style()) + ComputePadding(ConstraintSpace(), Style()); 366 // have any borders or padding.
367 border_and_padding_ = ConstraintSpace().IsAnonymous()
Gleb Lanbin 2017/02/24 21:51:27 may be introduce a helper function GetBorderPaddin
ikilpatrick 2017/02/25 00:57:22 Done.
368 ? NGBoxStrut()
369 : ComputeBorders(Style()) +
370 ComputePadding(ConstraintSpace(), Style());
366 371
367 LayoutUnit inline_size = 372 LayoutUnit inline_size =
368 ComputeInlineSizeForFragment(ConstraintSpace(), Style(), sizes); 373 ComputeInlineSizeForFragment(ConstraintSpace(), Style(), sizes);
369 LayoutUnit adjusted_inline_size = 374 LayoutUnit adjusted_inline_size =
370 inline_size - border_and_padding_.InlineSum(); 375 inline_size - border_and_padding_.InlineSum();
371 // TODO(layout-ng): For quirks mode, should we pass blockSize instead of 376 // TODO(layout-ng): For quirks mode, should we pass blockSize instead of
372 // -1? 377 // -1?
373 LayoutUnit block_size = 378 LayoutUnit block_size =
374 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), NGSizeIndefinite); 379 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), NGSizeIndefinite);
375 LayoutUnit adjusted_block_size(block_size); 380 LayoutUnit adjusted_block_size(block_size);
376 // Our calculated block-axis size may be indefinite at this point. 381 // Our calculated block-axis size may be indefinite at this point.
377 // If so, just leave the size as NGSizeIndefinite instead of subtracting 382 // If so, just leave the size as NGSizeIndefinite instead of subtracting
378 // borders and padding. 383 // borders and padding.
379 if (adjusted_block_size != NGSizeIndefinite) 384 if (adjusted_block_size != NGSizeIndefinite)
380 adjusted_block_size -= border_and_padding_.BlockSum(); 385 adjusted_block_size -= border_and_padding_.BlockSum();
381 386
382 space_builder_ = new NGConstraintSpaceBuilder(constraint_space_); 387 space_builder_ = new NGConstraintSpaceBuilder(constraint_space_);
383 if (Style().specifiesColumns()) { 388 space_builder_
384 space_builder_->SetFragmentationType(kFragmentColumn); 389 ->SetAvailableSize(
385 adjusted_inline_size = 390 NGLogicalSize(adjusted_inline_size, adjusted_block_size))
386 ResolveUsedColumnInlineSize(adjusted_inline_size, Style()); 391 .SetPercentageResolutionSize(
387 LayoutUnit inline_progression = 392 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 393
397 builder_->SetDirection(constraint_space_->Direction()); 394 builder_->SetDirection(constraint_space_->Direction());
398 builder_->SetWritingMode(constraint_space_->WritingMode()); 395 builder_->SetWritingMode(constraint_space_->WritingMode());
399 builder_->SetInlineSize(inline_size).SetBlockSize(block_size); 396 builder_->SetInlineSize(inline_size).SetBlockSize(block_size);
400 397
401 // TODO(glebl): fix multicol after the new margin collapsing/floats algorithm 398 NGBlockChildIterator child_iterator(node_->FirstChild(), break_token_);
402 // based on BFCOffset is checked in. 399 NGBlockChildIterator::Entry entry = child_iterator.NextChild();
403 if (NGBlockBreakToken* token = CurrentBlockBreakToken()) { 400 current_child_ = entry.node;
Gleb Lanbin 2017/02/24 21:51:27 .nit current_child_ = child_iterator.NextChild()
ikilpatrick 2017/02/25 00:57:22 Do you mind if I clean this up in a later patch? I
404 // Resume after a previous break. 401 NGBreakToken* child_break_token = entry.token;
405 content_size_ = token->BreakOffset(); 402
406 current_child_ = token->InputNode(); 403 // If we are resuming from a break token our start border and padding is
407 } else { 404 // within a previous fragment.
408 content_size_ = border_and_padding_.block_start; 405 content_size_ = break_token_ ? LayoutUnit() : border_and_padding_.block_start;
409 current_child_ = node_->FirstChild();
410 }
411 406
412 curr_margin_strut_ = ConstraintSpace().MarginStrut(); 407 curr_margin_strut_ = ConstraintSpace().MarginStrut();
413 curr_bfc_offset_ = ConstraintSpace().BfcOffset(); 408 curr_bfc_offset_ = ConstraintSpace().BfcOffset();
414 409
415 // Margins collapsing: 410 // Margins collapsing:
416 // Do not collapse margins between parent and its child if there is 411 // Do not collapse margins between parent and its child if there is
417 // border/padding between them. 412 // border/padding between them.
418 if (border_and_padding_.block_start) { 413 if (border_and_padding_.block_start) {
419 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); 414 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
420 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); 415 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get());
(...skipping 16 matching lines...) Expand all
437 NGBlockNode* current_block_child = toNGBlockNode(current_child_); 432 NGBlockNode* current_block_child = toNGBlockNode(current_child_);
438 EPosition position = current_block_child->Style().position(); 433 EPosition position = current_block_child->Style().position();
439 if (position == EPosition::kAbsolute || position == EPosition::kFixed) { 434 if (position == EPosition::kAbsolute || position == EPosition::kFixed) {
440 builder_->AddOutOfFlowChildCandidate(current_block_child, 435 builder_->AddOutOfFlowChildCandidate(current_block_child,
441 GetChildSpaceOffset()); 436 GetChildSpaceOffset());
442 current_child_ = current_block_child->NextSibling(); 437 current_child_ = current_block_child->NextSibling();
443 continue; 438 continue;
444 } 439 }
445 } 440 }
446 441
447 DCHECK(!ConstraintSpace().HasBlockFragmentation() ||
448 SpaceAvailableForCurrentChild() > LayoutUnit());
449 space_for_current_child_ = CreateConstraintSpaceForCurrentChild(); 442 space_for_current_child_ = CreateConstraintSpaceForCurrentChild();
450 443
451 if (current_child_->Type() == NGLayoutInputNode::kLegacyInline) { 444 if (current_child_->Type() == NGLayoutInputNode::kLegacyInline) {
452 LayoutInlineChildren(toNGInlineNode(current_child_)); 445 LayoutInlineChildren(toNGInlineNode(current_child_));
453 continue; 446 continue;
454 } 447 }
455 448
456 RefPtr<NGLayoutResult> layout_result = 449 RefPtr<NGLayoutResult> layout_result =
457 current_child_->Layout(space_for_current_child_); 450 current_child_->Layout(space_for_current_child_, child_break_token);
458 451
459 FinishCurrentChildLayout(layout_result); 452 FinishCurrentChildLayout(layout_result);
460 453
461 if (!ProceedToNextUnfinishedSibling( 454 entry = child_iterator.NextChild();
462 layout_result->PhysicalFragment().get())) 455 current_child_ = entry.node;
456 child_break_token = entry.token;
457
458 bool is_out_of_space =
Gleb Lanbin 2017/02/24 21:51:27 move the code and documentation to a helper functi
ikilpatrick 2017/02/25 00:57:22 Done.
459 constraint_space_->HasBlockFragmentation() &&
460 content_size_ >= constraint_space_->FragmentainerSpaceAvailable();
461
462 // We have run out of space in this flow, so there's no work left to do for
463 // this block in this fragmentainer. We should finalize the fragment and get
464 // back to the remaining content when laying out the next fragmentainer(s).
465 if (is_out_of_space)
463 break; 466 break;
464 } 467 }
465 468
466 // Margins collapsing: 469 // Margins collapsing:
467 // Bottom margins of an in-flow block box doesn't collapse with its last 470 // 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 471 // in-flow block-level child's bottom margin if the box has bottom
469 // border/padding. 472 // border/padding.
470 content_size_ += border_and_padding_.block_end; 473 content_size_ += border_and_padding_.block_end;
471 if (border_and_padding_.block_end || 474 if (border_and_padding_.block_end ||
472 ConstraintSpace().IsNewFormattingContext()) { 475 ConstraintSpace().IsNewFormattingContext()) {
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
553 PositionPendingFloats(origin_point.block_offset, ConstraintSpace(), 556 PositionPendingFloats(origin_point.block_offset, ConstraintSpace(),
554 builder_.get()); 557 builder_.get());
555 } 558 }
556 return; 559 return;
557 } 560 }
558 561
559 // Determine the fragment's position in the parent space either by using 562 // Determine the fragment's position in the parent space either by using
560 // content_size_ or known fragment's BFC offset. 563 // content_size_ or known fragment's BFC offset.
561 WTF::Optional<NGLogicalOffset> bfc_offset; 564 WTF::Optional<NGLogicalOffset> bfc_offset;
562 if (CurrentChildConstraintSpace().IsNewFormattingContext()) { 565 if (CurrentChildConstraintSpace().IsNewFormattingContext()) {
566 // DO NOT SUBMIT - Do we need to move this inside
567 // CreateConstraintSpaceForCurrentChild?
563 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); 568 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
564 bfc_offset = curr_bfc_offset_; 569 bfc_offset = curr_bfc_offset_;
565 } else if (fragment.BfcOffset()) { 570 } else if (fragment.BfcOffset()) {
566 // Fragment that knows its offset can be used to set parent's BFC position. 571 // 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; 572 curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset;
568 bfc_offset = curr_bfc_offset_; 573 bfc_offset = curr_bfc_offset_;
569 } else if (builder_->BfcOffset()) { 574 } else if (builder_->BfcOffset()) {
570 // Fragment doesn't know its offset but we can still calculate its BFC 575 // Fragment doesn't know its offset but we can still calculate its BFC
571 // position because the parent fragment's BFC is known. 576 // position because the parent fragment's BFC is known.
572 // Example: 577 // Example:
573 // BFC Offset is known here because of the padding. 578 // BFC Offset is known here because of the padding.
574 // <div style="padding: 1px"> 579 // <div style="padding: 1px">
575 // <div id="empty-div" style="margins: 1px"></div> 580 // <div id="empty-div" style="margins: 1px"></div>
576 bfc_offset = curr_bfc_offset_; 581 bfc_offset = curr_bfc_offset_;
577 bfc_offset.value().block_offset += curr_margin_strut_.Sum(); 582 bfc_offset.value().block_offset += curr_margin_strut_.Sum();
578 } 583 }
579 if (bfc_offset) { 584 if (bfc_offset) {
580 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); 585 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get());
581 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(), 586 PositionPendingFloats(curr_bfc_offset_.block_offset, ConstraintSpace(),
582 builder_.get()); 587 builder_.get());
583 } 588 }
584 NGLogicalOffset logical_offset = CalculateLogicalOffset(bfc_offset); 589 NGLogicalOffset logical_offset = CalculateLogicalOffset(bfc_offset);
585 590
586 if (fragmentainer_mapper_)
587 fragmentainer_mapper_->ToVisualOffset(logical_offset);
588 else
589 logical_offset.block_offset -= PreviousBreakOffset();
590
591 // Update margin strut. 591 // Update margin strut.
592 curr_margin_strut_ = fragment.EndMarginStrut(); 592 curr_margin_strut_ = fragment.EndMarginStrut();
593 curr_margin_strut_.Append(curr_child_margins_.block_end); 593 curr_margin_strut_.Append(curr_child_margins_.block_end);
594 594
595 // Only modify content_size if BlockSize is not empty. It's needed to prevent 595 // 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 596 // the situation when logical_offset is included in content_size for empty
597 // blocks. Example: 597 // blocks. Example:
598 // <div style="overflow:hidden"> 598 // <div style="overflow:hidden">
599 // <div style="margin-top: 8px"></div> 599 // <div style="margin-top: 8px"></div>
600 // <div style="margin-top: 10px"></div> 600 // <div style="margin-top: 10px"></div>
601 // </div> 601 // </div>
602 if (fragment.BlockSize()) 602 if (fragment.BlockSize())
603 content_size_ = fragment.BlockSize() + logical_offset.block_offset; 603 content_size_ = fragment.BlockSize() + logical_offset.block_offset;
604 max_inline_size_ = 604 max_inline_size_ =
605 std::max(max_inline_size_, fragment.InlineSize() + 605 std::max(max_inline_size_, fragment.InlineSize() +
606 curr_child_margins_.InlineSum() + 606 curr_child_margins_.InlineSum() +
607 border_and_padding_.InlineSum()); 607 border_and_padding_.InlineSum());
608 608
609 builder_->AddChild(layout_result, logical_offset); 609 builder_->AddChild(layout_result, logical_offset);
610 } 610 }
611 611
612 bool NGBlockLayoutAlgorithm::ProceedToNextUnfinishedSibling( 612 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() {
613 NGPhysicalFragment* child_fragment) { 613 LayoutUnit used_block_size =
614 DCHECK(current_child_); 614 break_token_ ? break_token_->UsedBlockSize() : LayoutUnit();
615 NGBlockNode* finished_child = toNGBlockNode(current_child_); 615 LayoutUnit block_size = ComputeBlockSizeForFragment(
616 current_child_ = current_child_->NextSibling(); 616 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 617
664 if (!fragmentainer_mapper_) { 618 block_size -= used_block_size;
665 if (!is_out_of_space) 619 DCHECK_GE(block_size, LayoutUnit());
Gleb Lanbin 2017/02/24 21:51:27 DCHECK_GE(block_size, LayoutUnit()) << "Brief expl
ikilpatrick 2017/02/25 00:57:22 Done.
666 return true;
667 // We have run out of space in this flow, so there's no work left to do for
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 620
673 if (is_out_of_space || !current_child_) { 621 // This is relative to the bfc offset, we should have this if non-zero block
674 NGBlockBreakToken* token = fragmentainer_mapper_->Advance(); 622 // size.
675 DCHECK(token || !is_out_of_space); 623 DCHECK(builder_->BfcOffset());
Gleb Lanbin 2017/02/24 21:51:27 may be rephrase the comment a bit from the line 62
ikilpatrick 2017/02/25 00:57:22 Done.
676 if (token) { 624 LayoutUnit space_left = ConstraintSpace().FragmentainerSpaceAvailable() -
677 break_token_ = token; 625 builder_->BfcOffset().value().block_offset;
678 content_size_ = token->BreakOffset(); 626 DCHECK_GE(space_left, LayoutUnit());
679 current_child_ = token->InputNode();
680 }
681 }
682 return true;
683 }
684 627
685 void NGBlockLayoutAlgorithm::SetPendingBreakToken(NGBlockBreakToken* token) { 628 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 629 // A break token is ready, which means that we're going to break
708 // before or inside a block-level child. 630 // before or inside a block-level child.
631 builder_->SetUsedBlockSize(std::min(space_left, block_size) +
632 used_block_size);
709 builder_->SetBlockSize(std::min(space_left, block_size)); 633 builder_->SetBlockSize(std::min(space_left, block_size));
710 builder_->SetBlockOverflow(space_left); 634 builder_->SetBlockOverflow(space_left);
711 return; 635 return;
712 } 636 }
637
713 if (block_size > space_left) { 638 if (block_size > space_left) {
714 // Need a break inside this block. 639 // Need a break inside this block.
715 builder_->SetBreakToken(new NGBlockBreakToken(nullptr, NextBreakOffset())); 640 builder_->SetUsedBlockSize(space_left + used_block_size);
716 builder_->SetBlockSize(space_left); 641 builder_->SetBlockSize(space_left);
717 builder_->SetBlockOverflow(space_left); 642 builder_->SetBlockOverflow(space_left);
718 return; 643 return;
719 } 644 }
645
720 // The end of the block fits in the current fragmentainer. 646 // The end of the block fits in the current fragmentainer.
721 builder_->SetBlockSize(block_size); 647 builder_->SetBlockSize(block_size);
722 builder_->SetBlockOverflow(content_size_ - previous_break_offset); 648 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 } 649 }
756 650
757 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins( 651 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins(
758 const NGConstraintSpace& space, 652 const NGConstraintSpace& space,
759 const ComputedStyle& style) { 653 const ComputedStyle& style) {
760 WTF::Optional<MinAndMaxContentSizes> sizes; 654 WTF::Optional<MinAndMaxContentSizes> sizes;
761 if (NeedMinAndMaxContentSizes(space, style)) { 655 if (NeedMinAndMaxContentSizes(space, style)) {
762 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return 656 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return
763 // MinAndMaxContentSizes. 657 // MinAndMaxContentSizes.
764 sizes = toNGBlockNode(current_child_)->ComputeMinAndMaxContentSizes(); 658 sizes = toNGBlockNode(current_child_)->ComputeMinAndMaxContentSizes();
(...skipping 23 matching lines...) Expand all
788 CurrentChildStyle()); 682 CurrentChildStyle());
789 683
790 const ComputedStyle& current_child_style = CurrentChildStyle(); 684 const ComputedStyle& current_child_style = CurrentChildStyle();
791 685
792 bool is_new_bfc = IsNewFormattingContextForInFlowBlockLevelChild( 686 bool is_new_bfc = IsNewFormattingContextForInFlowBlockLevelChild(
793 ConstraintSpace(), current_child_style); 687 ConstraintSpace(), current_child_style);
794 space_builder_->SetIsNewFormattingContext(is_new_bfc) 688 space_builder_->SetIsNewFormattingContext(is_new_bfc)
795 .SetIsShrinkToFit( 689 .SetIsShrinkToFit(
796 ShouldShrinkToFit(ConstraintSpace(), CurrentChildStyle())) 690 ShouldShrinkToFit(ConstraintSpace(), CurrentChildStyle()))
797 .SetTextDirection(current_child_style.direction()); 691 .SetTextDirection(current_child_style.direction());
798 LayoutUnit space_available = SpaceAvailableForCurrentChild();
799 space_builder_->SetFragmentainerSpaceAvailable(space_available);
800 692
801 // Clearance : 693 // Clearance :
802 // - Collapse margins 694 // - Collapse margins
803 // - Update curr_bfc_offset and parent BFC offset if needed. 695 // - Update curr_bfc_offset and parent BFC offset if needed.
804 // - Position all pending floats as position is known now. 696 // - Position all pending floats as position is known now.
805 // TODO(glebl): Fix the use case with clear: left and an intruding right. 697 // 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 698 // https://software.hixie.ch/utilities/js/live-dom-viewer/saved/4847
807 if (current_child_style.clear() != EClear::kNone) { 699 if (current_child_style.clear() != EClear::kNone) {
808 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); 700 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
809 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get()); 701 UpdateFragmentBfcOffset(curr_bfc_offset_, builder_.get());
(...skipping 21 matching lines...) Expand all
831 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start; 723 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start;
832 // Append the current margin strut with child's block start margin. 724 // 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 725 // Non empty border/padding use cases are handled inside of the child's
834 // layout. 726 // layout.
835 curr_margin_strut_.Append(curr_child_margins_.block_start); 727 curr_margin_strut_.Append(curr_child_margins_.block_start);
836 space_builder_->SetMarginStrut(curr_margin_strut_); 728 space_builder_->SetMarginStrut(curr_margin_strut_);
837 } 729 }
838 730
839 space_builder_->SetBfcOffset(curr_bfc_offset_); 731 space_builder_->SetBfcOffset(curr_bfc_offset_);
840 732
733 if (constraint_space_->HasBlockFragmentation()) {
Gleb Lanbin 2017/02/24 21:51:27 .nit LayoutUnit space_available; if (constraint_sp
ikilpatrick 2017/02/25 00:57:22 Done.
734 LayoutUnit space_available =
735 ConstraintSpace().FragmentainerSpaceAvailable();
736 // If a block establishes a new formatting context we must know our
737 // position in the formatting context, and are able to adjust the
738 // fragmentation line.
739 if (is_new_bfc) {
740 DCHECK(builder_->BfcOffset());
741 space_available -= curr_bfc_offset_.block_offset;
742 }
743 space_builder_->SetFragmentainerSpaceAvailable(space_available);
744 } else {
745 space_builder_->SetFragmentainerSpaceAvailable(LayoutUnit());
746 }
747
841 return space_builder_->ToConstraintSpace( 748 return space_builder_->ToConstraintSpace(
842 FromPlatformWritingMode(current_child_style.getWritingMode())); 749 FromPlatformWritingMode(current_child_style.getWritingMode()));
843 } 750 }
844 751
845 } // namespace blink 752 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698