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

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: silly me... Created 3 years, 10 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 274 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698