OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/layout/ng/ng_block_layout_algorithm.h" | 5 #include "core/layout/ng/ng_block_layout_algorithm.h" |
6 | 6 |
7 #include "core/layout/ng/ng_absolute_utils.h" | 7 #include "core/layout/ng/ng_absolute_utils.h" |
8 #include "core/layout/ng/ng_block_break_token.h" | 8 #include "core/layout/ng/ng_block_break_token.h" |
9 #include "core/layout/ng/ng_block_child_iterator.h" | |
9 #include "core/layout/ng/ng_box_fragment.h" | 10 #include "core/layout/ng/ng_box_fragment.h" |
10 #include "core/layout/ng/ng_column_mapper.h" | 11 #include "core/layout/ng/ng_column_mapper.h" |
11 #include "core/layout/ng/ng_constraint_space.h" | 12 #include "core/layout/ng/ng_constraint_space.h" |
12 #include "core/layout/ng/ng_constraint_space_builder.h" | 13 #include "core/layout/ng/ng_constraint_space_builder.h" |
13 #include "core/layout/ng/ng_fragment.h" | 14 #include "core/layout/ng/ng_fragment.h" |
14 #include "core/layout/ng/ng_fragment_builder.h" | 15 #include "core/layout/ng/ng_fragment_builder.h" |
15 #include "core/layout/ng/ng_inline_node.h" | 16 #include "core/layout/ng/ng_inline_node.h" |
16 #include "core/layout/ng/ng_layout_opportunity_iterator.h" | 17 #include "core/layout/ng/ng_layout_opportunity_iterator.h" |
17 #include "core/layout/ng/ng_length_utils.h" | 18 #include "core/layout/ng/ng_length_utils.h" |
18 #include "core/layout/ng/ng_line_builder.h" | 19 #include "core/layout/ng/ng_line_builder.h" |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |