Index: third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc |
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc |
index 0d92903cecd8964f77c6475e0d1b1b696c4b49fb..181a529cd99deb47fc1e85b3e968b5271a925f99 100644 |
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc |
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc |
@@ -300,18 +300,17 @@ bool IsNewFormattingContextForInFlowBlockLevelChild( |
} // namespace |
NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm( |
- LayoutObject* layout_object, |
- PassRefPtr<const ComputedStyle> style, |
- NGLayoutInputNode* first_child, |
+ NGBlockNode* node, |
NGConstraintSpace* constraint_space, |
- NGBreakToken* break_token) |
- : style_(style), |
- first_child_(first_child), |
+ NGBlockBreakToken* break_token) |
+ : style_(node->Style()), |
+ first_child_(node->FirstChild()), |
constraint_space_(constraint_space), |
break_token_(break_token), |
builder_(WTF::wrapUnique( |
- new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox, |
- layout_object))) { |
+ new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox, node))), |
+ child_iterator_(WTF::wrapUnique( |
+ new NGBlockLayoutChildIterator(first_child_, break_token))) { |
DCHECK(style_); |
} |
@@ -364,6 +363,7 @@ RefPtr<NGPhysicalFragment> NGBlockLayoutAlgorithm::Layout() { |
if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style())) |
sizes = ComputeMinAndMaxContentSizes(); |
+ // TODO(ikilpatrick): should be no borders or padding if anon. |
border_and_padding_ = |
ComputeBorders(Style()) + ComputePadding(ConstraintSpace(), Style()); |
@@ -383,34 +383,21 @@ RefPtr<NGPhysicalFragment> NGBlockLayoutAlgorithm::Layout() { |
adjusted_block_size -= border_and_padding_.BlockSum(); |
space_builder_ = new NGConstraintSpaceBuilder(constraint_space_); |
- if (Style().specifiesColumns()) { |
- space_builder_->SetFragmentationType(kFragmentColumn); |
- adjusted_inline_size = |
- ResolveUsedColumnInlineSize(adjusted_inline_size, Style()); |
- LayoutUnit inline_progression = |
- adjusted_inline_size + ResolveUsedColumnGap(Style()); |
- fragmentainer_mapper_ = |
- new NGColumnMapper(inline_progression, adjusted_block_size); |
- } |
- space_builder_->SetAvailableSize( |
- NGLogicalSize(adjusted_inline_size, adjusted_block_size)); |
- space_builder_->SetPercentageResolutionSize( |
- NGLogicalSize(adjusted_inline_size, adjusted_block_size)); |
+ space_builder_ |
+ ->SetAvailableSize( |
+ NGLogicalSize(adjusted_inline_size, adjusted_block_size)) |
+ .SetPercentageResolutionSize( |
+ NGLogicalSize(adjusted_inline_size, adjusted_block_size)); |
builder_->SetDirection(constraint_space_->Direction()); |
builder_->SetWritingMode(constraint_space_->WritingMode()); |
builder_->SetInlineSize(inline_size).SetBlockSize(block_size); |
- // TODO(glebl): fix multicol after the new margin collapsing/floats algorithm |
- // based on BFCOffset is checked in. |
- if (NGBlockBreakToken* token = CurrentBlockBreakToken()) { |
- // Resume after a previous break. |
- content_size_ = token->BreakOffset(); |
- current_child_ = token->InputNode(); |
- } else { |
- content_size_ = border_and_padding_.block_start; |
- current_child_ = first_child_; |
- } |
+ std::tie(current_child_, current_child_break_token_) = |
+ child_iterator_->NextChild(); |
+ |
+ content_size_ = |
+ break_token_ ? LayoutUnit(0) : border_and_padding_.block_start; |
mstensho (USE GERRIT)
2017/02/15 21:12:22
Should use LayoutUnit() instead of LayoutUnit(0),
|
curr_margin_strut_ = ConstraintSpace().MarginStrut(); |
curr_bfc_offset_ = ConstraintSpace().BfcOffset(); |
@@ -438,8 +425,6 @@ RefPtr<NGPhysicalFragment> NGBlockLayoutAlgorithm::Layout() { |
} |
} |
- DCHECK(!ConstraintSpace().HasBlockFragmentation() || |
- SpaceAvailableForCurrentChild() > LayoutUnit()); |
space_for_current_child_ = CreateConstraintSpaceForCurrentChild(); |
if (current_child_->Type() == NGLayoutInputNode::kLegacyInline) { |
@@ -508,7 +493,7 @@ void NGBlockLayoutAlgorithm::LayoutInlineChildren(NGInlineNode* current_child) { |
current_child->LayoutInline(space_for_current_child_, &line_builder); |
// TODO(kojii): The wrapper fragment should not be needed. |
NGFragmentBuilder wrapper_fragment_builder(NGPhysicalFragment::kFragmentBox, |
- current_child->GetLayoutObject()); |
+ current_child); |
line_builder.CreateFragments(&wrapper_fragment_builder); |
RefPtr<NGPhysicalBoxFragment> child_fragment = |
wrapper_fragment_builder.ToBoxFragment(); |
@@ -568,11 +553,6 @@ void NGBlockLayoutAlgorithm::FinishCurrentChildLayout( |
} |
NGLogicalOffset logical_offset = CalculateLogicalOffset(bfc_offset); |
- if (fragmentainer_mapper_) |
- fragmentainer_mapper_->ToVisualOffset(logical_offset); |
mstensho (USE GERRIT)
2017/02/15 21:12:22
Is the plan to replace the fragmentainer mapper wi
ikilpatrick
2017/02/16 16:48:31
Yeah i think most of the logic inside the fragment
|
- else |
- logical_offset.block_offset -= PreviousBreakOffset(); |
- |
// Update margin strut. |
curr_margin_strut_ = fragment.EndMarginStrut(); |
curr_margin_strut_.Append(curr_child_margins_.block_end); |
@@ -589,146 +569,63 @@ void NGBlockLayoutAlgorithm::FinishCurrentChildLayout( |
bool NGBlockLayoutAlgorithm::ProceedToNextUnfinishedSibling( |
NGPhysicalFragment* child_fragment) { |
DCHECK(current_child_); |
- NGBlockNode* finished_child = toNGBlockNode(current_child_); |
- current_child_ = current_child_->NextSibling(); |
- if (!ConstraintSpace().HasBlockFragmentation() && !fragmentainer_mapper_) |
- return true; |
- // If we're resuming layout after a fragmentainer break, we need to skip |
- // siblings that we're done with. We may have been able to fully lay out some |
- // node(s) preceding a node that we had to break inside (and therefore were |
- // not able to fully lay out). This happens when we have parallel flows [1], |
- // which are caused by floats, overflow, etc. |
- // |
- // [1] https://drafts.csswg.org/css-break/#parallel-flows |
- if (CurrentBlockBreakToken()) { |
- // TODO(layout-ng): Figure out if we need a better way to determine if the |
- // node is finished. Maybe something to encode in a break token? |
- // TODO(kojii): Handle inline children. |
- while (current_child_ && |
- current_child_->Type() == NGLayoutInputNode::kLegacyBlock && |
- toNGBlockNode(current_child_)->IsLayoutFinished()) { |
- current_child_ = current_child_->NextSibling(); |
- } |
- } |
- LayoutUnit break_offset = NextBreakOffset(); |
- bool is_out_of_space = content_size_ - PreviousBreakOffset() >= break_offset; |
- if (!HasPendingBreakToken()) { |
- bool child_broke = child_fragment->BreakToken(); |
- // This block needs to break if the child broke, or if we're out of space |
- // and there's more content waiting to be laid out. Otherwise, just bail |
- // now. |
- if (!child_broke && (!is_out_of_space || !current_child_)) |
- return true; |
- // Prepare a break token for this block, so that we know where to resume |
- // when the time comes for that. We may not be able to abort layout of this |
- // block right away, due to the posibility of parallel flows. We can only |
- // abort when we're out of space, or when there are no siblings left to |
- // process. |
- NGBlockBreakToken* token; |
- if (child_broke) { |
- // The child we just laid out was the first one to break. So that is |
- // where we need to resume. |
- token = new NGBlockBreakToken(finished_child, break_offset); |
- } else { |
- // Resume layout at the next sibling that needs layout. |
- DCHECK(current_child_); |
- token = |
- new NGBlockBreakToken(toNGBlockNode(current_child_), break_offset); |
- } |
- SetPendingBreakToken(token); |
- } |
- |
- if (!fragmentainer_mapper_) { |
- if (!is_out_of_space) |
- return true; |
- // We have run out of space in this flow, so there's no work left to do for |
- // this block in this fragmentainer. We should finalize the fragment and get |
- // back to the remaining content when laying out the next fragmentainer(s). |
+ std::tie(current_child_, current_child_break_token_) = |
+ child_iterator_->NextChild(); |
+ |
+ bool is_out_of_space = |
+ constraint_space_->HasBlockFragmentation() |
+ ? content_size_ >= constraint_space_->FragmentainerSpaceAvailable() |
mstensho (USE GERRIT)
2017/02/15 21:12:22
All you need is: constraint_space_->HasBlockFragme
|
+ : false; |
+ |
+ // We have run out of space in this flow, so there's no work left to do for |
+ // this block in this fragmentainer. We should finalize the fragment and get |
+ // back to the remaining content when laying out the next fragmentainer(s). |
+ if (is_out_of_space) |
return false; |
- } |
- if (is_out_of_space || !current_child_) { |
- NGBlockBreakToken* token = fragmentainer_mapper_->Advance(); |
- DCHECK(token || !is_out_of_space); |
- if (token) { |
- break_token_ = token; |
- content_size_ = token->BreakOffset(); |
- current_child_ = token->InputNode(); |
- } |
- } |
- return true; |
+ return current_child_; |
} |
-void NGBlockLayoutAlgorithm::SetPendingBreakToken(NGBlockBreakToken* token) { |
- if (fragmentainer_mapper_) |
- fragmentainer_mapper_->SetBreakToken(token); |
- else |
- builder_->SetBreakToken(token); |
-} |
+void NGBlockLayoutAlgorithm::FinalizeForFragmentation() { |
+ LayoutUnit used_block_size = |
+ break_token_ ? break_token_->UsedBlockSize() : LayoutUnit(); |
+ LayoutUnit block_size = ComputeBlockSizeForFragment( |
+ ConstraintSpace(), Style(), used_block_size + content_size_); |
-bool NGBlockLayoutAlgorithm::HasPendingBreakToken() const { |
- if (fragmentainer_mapper_) |
- return fragmentainer_mapper_->HasBreakToken(); |
- return builder_->HasBreakToken(); |
-} |
+ if (!block_size) |
+ return; |
-void NGBlockLayoutAlgorithm::FinalizeForFragmentation() { |
- LayoutUnit block_size = |
- ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); |
- LayoutUnit previous_break_offset = PreviousBreakOffset(); |
- block_size -= previous_break_offset; |
- block_size = std::max(LayoutUnit(), block_size); |
- LayoutUnit space_left = ConstraintSpace().FragmentainerSpaceAvailable(); |
+ block_size -= used_block_size; |
+ DCHECK_GE(block_size, LayoutUnit()); |
+ |
+ // This is relative to the bfc offset, we should have this if non-zero block |
+ // size. |
+ DCHECK(builder_->BfcOffset()); |
+ LayoutUnit space_left = ConstraintSpace().FragmentainerSpaceAvailable() - |
+ builder_->BfcOffset().value().block_offset; |
DCHECK_GE(space_left, LayoutUnit()); |
- if (builder_->HasBreakToken()) { |
+ |
+ if (builder_->DidBreak()) { |
// A break token is ready, which means that we're going to break |
// before or inside a block-level child. |
+ builder_->SetUsedBlockSize(std::min(space_left, block_size) + |
+ used_block_size); |
builder_->SetBlockSize(std::min(space_left, block_size)); |
builder_->SetBlockOverflow(space_left); |
return; |
} |
+ |
if (block_size > space_left) { |
// Need a break inside this block. |
- builder_->SetBreakToken(new NGBlockBreakToken(nullptr, NextBreakOffset())); |
+ builder_->SetUsedBlockSize(space_left + used_block_size); |
builder_->SetBlockSize(space_left); |
builder_->SetBlockOverflow(space_left); |
return; |
} |
+ |
// The end of the block fits in the current fragmentainer. |
builder_->SetBlockSize(block_size); |
- builder_->SetBlockOverflow(content_size_ - previous_break_offset); |
-} |
- |
-NGBlockBreakToken* NGBlockLayoutAlgorithm::CurrentBlockBreakToken() const { |
- NGBreakToken* token = break_token_; |
- if (!token || token->Type() != NGBreakToken::kBlockBreakToken) |
- return nullptr; |
- return toNGBlockBreakToken(token); |
-} |
- |
-LayoutUnit NGBlockLayoutAlgorithm::PreviousBreakOffset() const { |
- const NGBlockBreakToken* token = CurrentBlockBreakToken(); |
- return token ? token->BreakOffset() : LayoutUnit(); |
-} |
- |
-LayoutUnit NGBlockLayoutAlgorithm::NextBreakOffset() const { |
- if (fragmentainer_mapper_) |
- return fragmentainer_mapper_->NextBreakOffset(); |
- DCHECK(ConstraintSpace().HasBlockFragmentation()); |
- return PreviousBreakOffset() + |
- ConstraintSpace().FragmentainerSpaceAvailable(); |
-} |
- |
-LayoutUnit NGBlockLayoutAlgorithm::SpaceAvailableForCurrentChild() const { |
- LayoutUnit space_left; |
- if (fragmentainer_mapper_) |
- space_left = fragmentainer_mapper_->BlockSize(); |
- else if (ConstraintSpace().HasBlockFragmentation()) |
- space_left = ConstraintSpace().FragmentainerSpaceAvailable(); |
- else |
- return NGSizeIndefinite; |
- space_left -= BorderEdgeForCurrentChild() - PreviousBreakOffset(); |
- return space_left; |
+ builder_->SetBlockOverflow(content_size_); |
} |
NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins( |
@@ -770,8 +667,6 @@ NGBlockLayoutAlgorithm::CreateConstraintSpaceForCurrentChild() { |
.SetWritingMode( |
FromPlatformWritingMode(current_child_style.getWritingMode())) |
.SetTextDirection(current_child_style.direction()); |
- LayoutUnit space_available = SpaceAvailableForCurrentChild(); |
- space_builder_->SetFragmentainerSpaceAvailable(space_available); |
// Clearance : |
// - Collapse margins |
@@ -813,6 +708,18 @@ NGBlockLayoutAlgorithm::CreateConstraintSpaceForCurrentChild() { |
space_builder_->SetBfcOffset(curr_bfc_offset_); |
+ if (constraint_space_->HasBlockFragmentation()) { |
+ LayoutUnit space_available = |
+ ConstraintSpace().FragmentainerSpaceAvailable(); |
+ if (builder_->BfcOffset()) { |
+ // TODO(ikilpatrick): this should be true for new FC's. |
+ space_available -= builder_->BfcOffset().value().block_offset; |
mstensho (USE GERRIT)
2017/02/15 21:12:22
I don't understand how this is supposed to work. W
ikilpatrick
2017/02/16 16:48:31
Ah yeah this is wrong, we need a IsNewFormattingCo
mstensho (USE GERRIT)
2017/02/16 21:14:47
Not sure if I misunderstand what you mean here, bu
|
+ } |
+ space_builder_->SetFragmentainerSpaceAvailable(space_available); |
+ } else { |
+ space_builder_->SetFragmentainerSpaceAvailable(LayoutUnit(0)); |
mstensho (USE GERRIT)
2017/02/15 21:12:22
Just LayoutUnit().
|
+ } |
+ |
return space_builder_->ToConstraintSpace(); |
} |