Chromium Code Reviews| Index: third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc |
| diff --git a/third_party/WebKit/Source/core/layout/ng/ng_line_builder.cc b/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc |
| similarity index 83% |
| rename from third_party/WebKit/Source/core/layout/ng/ng_line_builder.cc |
| rename to third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc |
| index be639f41da13b93bc0d9f8a3458f3f0f5cd322c5..d7b22d08960f76145277b364f8e77a87a5b2f346 100644 |
| --- a/third_party/WebKit/Source/core/layout/ng/ng_line_builder.cc |
| +++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc |
| @@ -2,7 +2,7 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| -#include "core/layout/ng/ng_line_builder.h" |
| +#include "core/layout/ng/ng_inline_layout_algorithm.h" |
| #include "core/layout/BidiRun.h" |
| #include "core/layout/LayoutBlockFlow.h" |
| @@ -17,10 +17,12 @@ |
| #include "core/layout/ng/ng_floating_object.h" |
| #include "core/layout/ng/ng_floats_utils.h" |
| #include "core/layout/ng/ng_fragment_builder.h" |
| +#include "core/layout/ng/ng_inline_break_token.h" |
| #include "core/layout/ng/ng_inline_node.h" |
| #include "core/layout/ng/ng_length_utils.h" |
| #include "core/layout/ng/ng_line_box_fragment.h" |
| #include "core/layout/ng/ng_line_box_fragment_builder.h" |
| +#include "core/layout/ng/ng_line_breaker.h" |
| #include "core/layout/ng/ng_space_utils.h" |
| #include "core/layout/ng/ng_text_fragment.h" |
| #include "core/layout/ng/ng_text_fragment_builder.h" |
| @@ -65,12 +67,13 @@ void PositionPendingFloats(const NGLogicalOffset& origin_point, |
| } // namespace |
| -NGLineBuilder::NGLineBuilder(NGInlineNode* inline_box, |
| - NGConstraintSpace* constraint_space) |
| +NGInlineLayoutAlgorithm::NGInlineLayoutAlgorithm( |
| + NGInlineNode* inline_box, |
| + NGConstraintSpace* constraint_space, |
| + NGInlineBreakToken* break_token) |
| : inline_box_(inline_box), |
| constraint_space_(constraint_space), |
| container_builder_(NGPhysicalFragment::kFragmentBox, inline_box_), |
| - container_layout_result_(nullptr), |
| is_horizontal_writing_mode_( |
| blink::IsHorizontalWritingMode(constraint_space->WritingMode())), |
| space_builder_(constraint_space) |
| @@ -81,29 +84,34 @@ NGLineBuilder::NGLineBuilder(NGInlineNode* inline_box, |
| { |
| if (!is_horizontal_writing_mode_) |
| baseline_type_ = FontBaseline::IdeographicBaseline; |
| + if (break_token) |
| + Initialize(break_token->ItemIndex(), break_token->TextOffset()); |
| + else |
| + Initialize(0, 0); |
| } |
| -bool NGLineBuilder::CanFitOnLine() const { |
| +bool NGInlineLayoutAlgorithm::CanFitOnLine() const { |
| LayoutUnit available_size = current_opportunity_.InlineSize(); |
| if (available_size == NGSizeIndefinite) |
| return true; |
| return end_position_ <= available_size; |
| } |
| -bool NGLineBuilder::HasItems() const { |
| +bool NGInlineLayoutAlgorithm::HasItems() const { |
| return start_offset_ != end_offset_; |
| } |
| -bool NGLineBuilder::HasBreakOpportunity() const { |
| +bool NGInlineLayoutAlgorithm::HasBreakOpportunity() const { |
| return start_offset_ != last_break_opportunity_offset_; |
| } |
| -bool NGLineBuilder::HasItemsAfterLastBreakOpportunity() const { |
| +bool NGInlineLayoutAlgorithm::HasItemsAfterLastBreakOpportunity() const { |
| return last_break_opportunity_offset_ != end_offset_; |
| } |
| -void NGLineBuilder::SetStart(unsigned index, unsigned offset) { |
| - inline_box_->AssertOffset(index, offset); |
| +void NGInlineLayoutAlgorithm::Initialize(unsigned index, unsigned offset) { |
| + if (index || offset) |
| + inline_box_->AssertOffset(index, offset); |
| start_index_ = last_index_ = last_break_opportunity_index_ = index; |
| start_offset_ = end_offset_ = last_break_opportunity_offset_ = offset; |
| @@ -112,7 +120,7 @@ void NGLineBuilder::SetStart(unsigned index, unsigned offset) { |
| FindNextLayoutOpportunity(); |
| } |
| -void NGLineBuilder::SetEnd(unsigned new_end_offset) { |
| +void NGInlineLayoutAlgorithm::SetEnd(unsigned new_end_offset) { |
| DCHECK_GT(new_end_offset, end_offset_); |
| const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); |
| DCHECK_LE(new_end_offset, items.back().EndOffset()); |
| @@ -144,9 +152,9 @@ void NGLineBuilder::SetEnd(unsigned new_end_offset) { |
| } |
| } |
| -void NGLineBuilder::SetEnd(unsigned index, |
| - unsigned new_end_offset, |
| - LayoutUnit inline_size_since_current_end) { |
| +void NGInlineLayoutAlgorithm::SetEnd(unsigned index, |
| + unsigned new_end_offset, |
| + LayoutUnit inline_size_since_current_end) { |
| const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); |
| DCHECK_LE(new_end_offset, items.back().EndOffset()); |
| @@ -169,38 +177,39 @@ void NGLineBuilder::SetEnd(unsigned index, |
| end_position_ += inline_size_since_current_end; |
| } |
| -void NGLineBuilder::SetBreakOpportunity() { |
| +void NGInlineLayoutAlgorithm::SetBreakOpportunity() { |
| last_break_opportunity_index_ = last_index_; |
| last_break_opportunity_offset_ = end_offset_; |
| last_break_opportunity_position_ = end_position_; |
| } |
| -void NGLineBuilder::SetStartOfHangables(unsigned offset) { |
| +void NGInlineLayoutAlgorithm::SetStartOfHangables(unsigned offset) { |
| // TODO(kojii): Implement. |
| } |
| -LayoutUnit NGLineBuilder::InlineSize(const NGLayoutInlineItem& item) { |
| +LayoutUnit NGInlineLayoutAlgorithm::InlineSize(const NGLayoutInlineItem& item) { |
| if (item.Type() == NGLayoutInlineItem::kAtomicInline) |
| return InlineSizeFromLayout(item); |
| return item.InlineSize(); |
| } |
| -LayoutUnit NGLineBuilder::InlineSize(const NGLayoutInlineItem& item, |
| - unsigned start_offset, |
| - unsigned end_offset) { |
| +LayoutUnit NGInlineLayoutAlgorithm::InlineSize(const NGLayoutInlineItem& item, |
| + unsigned start_offset, |
| + unsigned end_offset) { |
| if (item.StartOffset() == start_offset && item.EndOffset() == end_offset) |
| return InlineSize(item); |
| return item.InlineSize(start_offset, end_offset); |
| } |
| -LayoutUnit NGLineBuilder::InlineSizeFromLayout(const NGLayoutInlineItem& item) { |
| +LayoutUnit NGInlineLayoutAlgorithm::InlineSizeFromLayout( |
| + const NGLayoutInlineItem& item) { |
| return NGBoxFragment(ConstraintSpace().WritingMode(), |
| toNGPhysicalBoxFragment( |
| LayoutItem(item)->PhysicalFragment().get())) |
| .InlineSize(); |
| } |
| -const NGLayoutResult* NGLineBuilder::LayoutItem( |
| +const NGLayoutResult* NGInlineLayoutAlgorithm::LayoutItem( |
| const NGLayoutInlineItem& item) { |
| // Returns the cached NGLayoutResult if available. |
| const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); |
| @@ -225,13 +234,13 @@ const NGLayoutResult* NGLineBuilder::LayoutItem( |
| return layout_result->get(); |
| } |
| -void NGLineBuilder::CreateLine() { |
| +bool NGInlineLayoutAlgorithm::CreateLine() { |
| if (HasItemsAfterLastBreakOpportunity()) |
| SetBreakOpportunity(); |
| - CreateLineUpToLastBreakOpportunity(); |
| + return CreateLineUpToLastBreakOpportunity(); |
| } |
| -void NGLineBuilder::CreateLineUpToLastBreakOpportunity() { |
| +bool NGInlineLayoutAlgorithm::CreateLineUpToLastBreakOpportunity() { |
| const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); |
| // Create a list of LineItemChunk from |start| and |last_break_opportunity|. |
| @@ -252,7 +261,8 @@ void NGLineBuilder::CreateLineUpToLastBreakOpportunity() { |
| if (inline_box_->IsBidiEnabled()) |
| BidiReorder(&line_item_chunks); |
| - PlaceItems(line_item_chunks); |
| + if (!PlaceItems(line_item_chunks)) |
| + return false; |
| // Prepare for the next line. |
| // Move |start| to |last_break_opportunity|, keeping items after |
| @@ -270,9 +280,11 @@ void NGLineBuilder::CreateLineUpToLastBreakOpportunity() { |
| GetOriginPointForFloats(ConstraintSpace(), content_size_); |
| PositionPendingFloats(origin_point, constraint_space_, &container_builder_); |
| FindNextLayoutOpportunity(); |
| + return true; |
| } |
| -void NGLineBuilder::BidiReorder(Vector<LineItemChunk, 32>* line_item_chunks) { |
| +void NGInlineLayoutAlgorithm::BidiReorder( |
| + Vector<LineItemChunk, 32>* line_item_chunks) { |
| #if DCHECK_IS_ON() |
| DCHECK(!is_bidi_reordered_); |
| is_bidi_reordered_ = true; |
| @@ -307,10 +319,10 @@ void NGLineBuilder::BidiReorder(Vector<LineItemChunk, 32>* line_item_chunks) { |
| } |
| // TODO(glebl): Add the support of clearance for inline floats. |
| -void NGLineBuilder::LayoutAndPositionFloat(LayoutUnit end_position, |
| - LayoutObject* layout_object) { |
| - LayoutNGBlockFlow* block_flow = toLayoutNGBlockFlow(layout_object); |
| - NGBlockNode* node = new NGBlockNode(block_flow); |
| +void NGInlineLayoutAlgorithm::LayoutAndPositionFloat( |
| + LayoutUnit end_position, |
| + LayoutObject* layout_object) { |
| + NGBlockNode* node = new NGBlockNode(layout_object); |
| RefPtr<NGConstraintSpace> float_space = CreateConstraintSpaceForFloat( |
| node->Style(), ConstraintSpace(), &space_builder_); |
| @@ -347,7 +359,7 @@ void NGLineBuilder::LayoutAndPositionFloat(LayoutUnit end_position, |
| } |
| } |
| -void NGLineBuilder::PlaceItems( |
| +bool NGInlineLayoutAlgorithm::PlaceItems( |
| const Vector<LineItemChunk, 32>& line_item_chunks) { |
| const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); |
| @@ -425,8 +437,15 @@ void NGLineBuilder::PlaceItems( |
| } |
| if (line_box.Children().isEmpty()) { |
| - // The line was empty. |
| - return; |
| + return true; // The line was empty. |
| + } |
| + |
| + // Check if the line fits into the constraint space in block direction. |
| + LayoutUnit block_end = content_size_ + line_box.Metrics().LineHeight(); |
| + if (!container_builder_.Children().isEmpty() && |
| + ConstraintSpace().AvailableSize().block_size != NGSizeIndefinite && |
| + block_end > ConstraintSpace().AvailableSize().block_size) { |
| + return false; |
| } |
| // If the estimated baseline position was not the actual position, move all |
| @@ -436,16 +455,27 @@ void NGLineBuilder::PlaceItems( |
| if (adjust_baseline) |
| line_box.MoveChildrenInBlockDirection(adjust_baseline); |
| + // If there are more content to consume, create an unfinished break token. |
| + if (last_break_opportunity_index_ != items.size() - 1 || |
| + last_break_opportunity_offset_ != inline_box_->Text().length()) { |
| + line_box.SetBreakToken( |
| + NGInlineBreakToken::create(inline_box_, last_break_opportunity_index_, |
| + last_break_opportunity_offset_)); |
| + } |
| + |
| line_box.SetInlineSize(inline_size); |
| - NGLogicalOffset offset(LayoutUnit(), content_size_); |
| - container_builder_.AddChild(line_box.ToLineBoxFragment(), offset); |
| + container_builder_.AddChild(line_box.ToLineBoxFragment(), |
| + {LayoutUnit(), content_size_}); |
| + |
| max_inline_size_ = std::max(max_inline_size_, inline_size); |
| - content_size_ += line_box.Metrics().LineHeight(); |
| + content_size_ = block_end; |
| + return true; |
| } |
| -void NGLineBuilder::AccumulateUsedFonts(const NGLayoutInlineItem& item, |
| - const LineItemChunk& line_item_chunk, |
| - NGLineBoxFragmentBuilder* line_box) { |
| +void NGInlineLayoutAlgorithm::AccumulateUsedFonts( |
| + const NGLayoutInlineItem& item, |
| + const LineItemChunk& line_item_chunk, |
| + NGLineBoxFragmentBuilder* line_box) { |
| HashSet<const SimpleFontData*> fallback_fonts; |
| item.GetFallbackFonts(&fallback_fonts, line_item_chunk.start_offset, |
| line_item_chunk.end_offset); |
| @@ -456,7 +486,7 @@ void NGLineBuilder::AccumulateUsedFonts(const NGLayoutInlineItem& item, |
| } |
| } |
| -LayoutUnit NGLineBuilder::PlaceAtomicInline( |
| +LayoutUnit NGInlineLayoutAlgorithm::PlaceAtomicInline( |
| const NGLayoutInlineItem& item, |
| LayoutUnit estimated_baseline, |
| NGLineBoxFragmentBuilder* line_box, |
| @@ -493,7 +523,7 @@ LayoutUnit NGLineBuilder::PlaceAtomicInline( |
| return block_start; |
| } |
| -void NGLineBuilder::FindNextLayoutOpportunity() { |
| +void NGInlineLayoutAlgorithm::FindNextLayoutOpportunity() { |
| NGLogicalOffset iter_offset = constraint_space_->BfcOffset(); |
| iter_offset.block_offset += content_size_; |
| auto* iter = constraint_space_->LayoutOpportunityIterator(iter_offset); |
| @@ -502,9 +532,7 @@ void NGLineBuilder::FindNextLayoutOpportunity() { |
| current_opportunity_ = opportunity; |
| } |
| -RefPtr<NGLayoutResult> NGLineBuilder::CreateFragments() { |
| - DCHECK(!HasItems()) << "Must call CreateLine()"; |
| - |
| +RefPtr<NGLayoutResult> NGInlineLayoutAlgorithm::CreateFragments() { |
| // TODO(kojii): Check if the line box width should be content or available. |
| // TODO(kojii): Need to take constraint_space into account. |
| container_builder_.SetInlineSize(max_inline_size_) |
| @@ -512,11 +540,33 @@ RefPtr<NGLayoutResult> NGLineBuilder::CreateFragments() { |
| .SetBlockSize(content_size_) |
| .SetBlockOverflow(content_size_); |
| - container_layout_result_ = container_builder_.ToBoxFragment(); |
| - return container_layout_result_; |
| + return container_builder_.ToBoxFragment(); |
| +} |
| + |
| +RefPtr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() { |
| + if (!inline_box_->Text().isEmpty()) |
| + NGLineBreaker().BreakLines(this, inline_box_->Text(), start_offset_); |
| + return CreateFragments(); |
|
ikilpatrick
2017/03/24 20:58:05
can just inline this function now?
|
| +} |
| + |
| +MinMaxContentSize NGInlineLayoutAlgorithm::ComputeMinMaxContentSizeByLayout() { |
| + DCHECK(ConstraintSpace().AvailableSize().inline_size == LayoutUnit() && |
| + ConstraintSpace().AvailableSize().block_size == NGSizeIndefinite); |
| + if (!inline_box_->Text().isEmpty()) |
| + NGLineBreaker().BreakLines(this, inline_box_->Text(), start_offset_); |
| + MinMaxContentSize sizes; |
| + sizes.min_content = MaxInlineSize(); |
| + |
| + // max-content is the width without any line wrapping. |
| + // TODO(kojii): Implement hard breaks (<br> etc.) to break. |
| + for (const auto& item : inline_box_->Items()) |
| + sizes.max_content += InlineSize(item); |
| + |
| + return sizes; |
| } |
| -void NGLineBuilder::CopyFragmentDataToLayoutBlockFlow() { |
| +void NGInlineLayoutAlgorithm::CopyFragmentDataToLayoutBlockFlow( |
| + NGLayoutResult* layout_result) { |
| LayoutBlockFlow* block = inline_box_->GetLayoutBlockFlow(); |
| block->deleteLineBoxTree(); |
| @@ -528,8 +578,8 @@ void NGLineBuilder::CopyFragmentDataToLayoutBlockFlow() { |
| fragments_for_bidi_runs.reserveInitialCapacity(items.size()); |
| BidiRunList<BidiRun> bidi_runs; |
| LineInfo line_info; |
| - NGPhysicalBoxFragment* box_fragment = toNGPhysicalBoxFragment( |
| - container_layout_result_->PhysicalFragment().get()); |
| + NGPhysicalBoxFragment* box_fragment = |
| + toNGPhysicalBoxFragment(layout_result->PhysicalFragment().get()); |
| for (const auto& container_child : box_fragment->Children()) { |
| NGPhysicalLineBoxFragment* physical_line_box = |
| toNGPhysicalLineBoxFragment(container_child.get()); |