| Index: third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc
|
| diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc
|
| deleted file mode 100644
|
| index ca96f85d032d45574cc7b44e0b4fa22661715ee8..0000000000000000000000000000000000000000
|
| --- a/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc
|
| +++ /dev/null
|
| @@ -1,666 +0,0 @@
|
| -// Copyright 2016 The Chromium Authors. All rights reserved.
|
| -// 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_inline_layout_algorithm.h"
|
| -
|
| -#include "core/layout/BidiRun.h"
|
| -#include "core/layout/LayoutBlockFlow.h"
|
| -#include "core/layout/line/LineInfo.h"
|
| -#include "core/layout/line/RootInlineBox.h"
|
| -#include "core/layout/ng/layout_ng_block_flow.h"
|
| -#include "core/layout/ng/ng_bidi_paragraph.h"
|
| -#include "core/layout/ng/ng_block_layout_algorithm.h"
|
| -#include "core/layout/ng/ng_box_fragment.h"
|
| -#include "core/layout/ng/ng_constraint_space.h"
|
| -#include "core/layout/ng/ng_constraint_space_builder.h"
|
| -#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"
|
| -#include "core/style/ComputedStyle.h"
|
| -#include "platform/text/BidiRunList.h"
|
| -
|
| -namespace blink {
|
| -namespace {
|
| -
|
| -RefPtr<NGConstraintSpace> CreateConstraintSpaceForFloat(
|
| - const ComputedStyle& parent_style,
|
| - const NGBlockNode& child,
|
| - NGConstraintSpaceBuilder* space_builder) {
|
| - DCHECK(space_builder) << "space_builder cannot be null here";
|
| - const ComputedStyle& style = child.Style();
|
| -
|
| - bool is_new_bfc =
|
| - IsNewFormattingContextForBlockLevelChild(parent_style, child);
|
| - return space_builder->SetIsNewFormattingContext(is_new_bfc)
|
| - .SetTextDirection(style.Direction())
|
| - .SetIsShrinkToFit(ShouldShrinkToFit(parent_style, style))
|
| - .ToConstraintSpace(FromPlatformWritingMode(style.GetWritingMode()));
|
| -}
|
| -
|
| -NGLogicalOffset GetOriginPointForFloats(const NGConstraintSpace& space,
|
| - LayoutUnit content_size) {
|
| - NGLogicalOffset origin_point = space.BfcOffset();
|
| - origin_point.block_offset += content_size;
|
| - return origin_point;
|
| -}
|
| -} // namespace
|
| -
|
| -NGInlineLayoutAlgorithm::NGInlineLayoutAlgorithm(
|
| - NGInlineNode* inline_node,
|
| - NGConstraintSpace* space,
|
| - NGInlineBreakToken* break_token)
|
| - : NGLayoutAlgorithm(inline_node, space, break_token),
|
| - container_builder_(NGPhysicalFragment::kFragmentBox, inline_node),
|
| - is_horizontal_writing_mode_(
|
| - blink::IsHorizontalWritingMode(space->WritingMode())),
|
| - disallow_first_line_rules_(false),
|
| - space_builder_(space)
|
| -#if DCHECK_IS_ON()
|
| - ,
|
| - is_bidi_reordered_(false)
|
| -#endif
|
| -{
|
| - if (!is_horizontal_writing_mode_)
|
| - baseline_type_ = FontBaseline::kIdeographicBaseline;
|
| - if (break_token)
|
| - Initialize(break_token->ItemIndex(), break_token->TextOffset());
|
| - else
|
| - Initialize(0, 0);
|
| -
|
| - // BFC offset is known for inline fragments.
|
| - container_builder_.SetBfcOffset(space->BfcOffset());
|
| -}
|
| -
|
| -bool NGInlineLayoutAlgorithm::IsFirstLine() const {
|
| - return !disallow_first_line_rules_ && container_builder_.Children().IsEmpty();
|
| -}
|
| -
|
| -const ComputedStyle& NGInlineLayoutAlgorithm::FirstLineStyle() const {
|
| - return Node()->GetLayoutObject()->FirstLineStyleRef();
|
| -}
|
| -
|
| -const ComputedStyle& NGInlineLayoutAlgorithm::LineStyle() const {
|
| - return IsFirstLine() ? FirstLineStyle() : Style();
|
| -}
|
| -
|
| -bool NGInlineLayoutAlgorithm::CanFitOnLine() const {
|
| - LayoutUnit available_size = current_opportunity_.InlineSize();
|
| - if (available_size == NGSizeIndefinite)
|
| - return true;
|
| - return end_position_ <= available_size;
|
| -}
|
| -
|
| -bool NGInlineLayoutAlgorithm::HasItems() const {
|
| - return start_offset_ != end_offset_;
|
| -}
|
| -
|
| -bool NGInlineLayoutAlgorithm::HasBreakOpportunity() const {
|
| - return start_offset_ != last_break_opportunity_offset_;
|
| -}
|
| -
|
| -bool NGInlineLayoutAlgorithm::HasItemsAfterLastBreakOpportunity() const {
|
| - return last_break_opportunity_offset_ != end_offset_;
|
| -}
|
| -
|
| -void NGInlineLayoutAlgorithm::Initialize(unsigned index, unsigned offset) {
|
| - if (index || offset)
|
| - Node()->AssertOffset(index, offset);
|
| -
|
| - start_index_ = last_index_ = last_break_opportunity_index_ = index;
|
| - start_offset_ = end_offset_ = last_break_opportunity_offset_ = offset;
|
| - end_position_ = last_break_opportunity_position_ = LayoutUnit();
|
| -
|
| - auto& engine = Node()->GetLayoutObject()->GetDocument().GetStyleEngine();
|
| - disallow_first_line_rules_ = index || offset || !engine.UsesFirstLineRules();
|
| -
|
| - FindNextLayoutOpportunity();
|
| -}
|
| -
|
| -void NGInlineLayoutAlgorithm::SetEnd(unsigned new_end_offset) {
|
| - DCHECK_GT(new_end_offset, end_offset_);
|
| - const Vector<NGLayoutInlineItem>& items = Node()->Items();
|
| - DCHECK_LE(new_end_offset, items.back().EndOffset());
|
| -
|
| - // SetEnd() while |new_end_offset| is beyond the current last item.
|
| - unsigned index = last_index_;
|
| - const NGLayoutInlineItem* item = &items[index];
|
| - if (new_end_offset > item->EndOffset()) {
|
| - if (end_offset_ < item->EndOffset()) {
|
| - SetEnd(index, item->EndOffset(),
|
| - InlineSize(*item, end_offset_, item->EndOffset()));
|
| - }
|
| - item = &items[++index];
|
| -
|
| - while (new_end_offset > item->EndOffset()) {
|
| - SetEnd(index, item->EndOffset(), InlineSize(*item));
|
| - item = &items[++index];
|
| - }
|
| - }
|
| -
|
| - SetEnd(index, new_end_offset, InlineSize(*item, end_offset_, new_end_offset));
|
| -
|
| - // Include closing elements.
|
| - while (new_end_offset == item->EndOffset() && index < items.size() - 1) {
|
| - item = &items[++index];
|
| - if (item->Type() != NGLayoutInlineItem::kCloseTag)
|
| - break;
|
| - SetEnd(index, new_end_offset, InlineSize(*item));
|
| - }
|
| -}
|
| -
|
| -void NGInlineLayoutAlgorithm::SetEnd(unsigned index,
|
| - unsigned new_end_offset,
|
| - LayoutUnit inline_size_since_current_end) {
|
| - const Vector<NGLayoutInlineItem>& items = Node()->Items();
|
| - DCHECK_LE(new_end_offset, items.back().EndOffset());
|
| -
|
| - // |new_end_offset| should be in the current item or next.
|
| - // TODO(kojii): Reconsider this restriction if needed.
|
| - DCHECK((index == last_index_ && new_end_offset > end_offset_) ||
|
| - (index == last_index_ + 1 && new_end_offset >= end_offset_ &&
|
| - end_offset_ == items[last_index_].EndOffset()));
|
| - const NGLayoutInlineItem& item = items[index];
|
| - item.AssertEndOffset(new_end_offset);
|
| -
|
| - if (item.Type() == NGLayoutInlineItem::kFloating) {
|
| - LayoutAndPositionFloat(
|
| - LayoutUnit(end_position_) + inline_size_since_current_end,
|
| - item.GetLayoutObject());
|
| - }
|
| -
|
| - last_index_ = index;
|
| - end_offset_ = new_end_offset;
|
| - end_position_ += inline_size_since_current_end;
|
| -}
|
| -
|
| -void NGInlineLayoutAlgorithm::SetBreakOpportunity() {
|
| - last_break_opportunity_index_ = last_index_;
|
| - last_break_opportunity_offset_ = end_offset_;
|
| - last_break_opportunity_position_ = end_position_;
|
| -}
|
| -
|
| -void NGInlineLayoutAlgorithm::SetStartOfHangables(unsigned offset) {
|
| - // TODO(kojii): Implement.
|
| -}
|
| -
|
| -LayoutUnit NGInlineLayoutAlgorithm::InlineSize(const NGLayoutInlineItem& item) {
|
| - if (item.Type() == NGLayoutInlineItem::kAtomicInline)
|
| - return InlineSizeFromLayout(item);
|
| - return item.InlineSize();
|
| -}
|
| -
|
| -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 NGInlineLayoutAlgorithm::InlineSizeFromLayout(
|
| - const NGLayoutInlineItem& item) {
|
| - return NGBoxFragment(ConstraintSpace().WritingMode(),
|
| - ToNGPhysicalBoxFragment(
|
| - LayoutItem(item)->PhysicalFragment().Get()))
|
| - .InlineSize();
|
| -}
|
| -
|
| -const NGLayoutResult* NGInlineLayoutAlgorithm::LayoutItem(
|
| - const NGLayoutInlineItem& item) {
|
| - // Returns the cached NGLayoutResult if available.
|
| - const Vector<NGLayoutInlineItem>& items = Node()->Items();
|
| - if (layout_results_.IsEmpty())
|
| - layout_results_.Resize(items.size());
|
| - unsigned index = std::distance(items.begin(), &item);
|
| - RefPtr<NGLayoutResult>* layout_result = &layout_results_[index];
|
| - if (*layout_result)
|
| - return layout_result->Get();
|
| -
|
| - DCHECK_EQ(item.Type(), NGLayoutInlineItem::kAtomicInline);
|
| - NGBlockNode* node = new NGBlockNode(item.GetLayoutObject());
|
| - // TODO(kojii): Keep node in NGLayoutInlineItem.
|
| - const ComputedStyle& style = node->Style();
|
| - NGConstraintSpaceBuilder constraint_space_builder(&ConstraintSpace());
|
| - RefPtr<NGConstraintSpace> constraint_space =
|
| - constraint_space_builder.SetIsNewFormattingContext(true)
|
| - .SetIsShrinkToFit(true)
|
| - .SetTextDirection(style.Direction())
|
| - .ToConstraintSpace(FromPlatformWritingMode(style.GetWritingMode()));
|
| - *layout_result = node->Layout(constraint_space.Get());
|
| - return layout_result->Get();
|
| -}
|
| -
|
| -bool NGInlineLayoutAlgorithm::CreateLine() {
|
| - if (HasItemsAfterLastBreakOpportunity())
|
| - SetBreakOpportunity();
|
| - return CreateLineUpToLastBreakOpportunity();
|
| -}
|
| -
|
| -bool NGInlineLayoutAlgorithm::CreateLineUpToLastBreakOpportunity() {
|
| - const Vector<NGLayoutInlineItem>& items = Node()->Items();
|
| -
|
| - // Create a list of LineItemChunk from |start| and |last_break_opportunity|.
|
| - // TODO(kojii): Consider refactoring LineItemChunk once NGLineBuilder's public
|
| - // API is more finalized. It does not fit well with the current API.
|
| - Vector<LineItemChunk, 32> line_item_chunks;
|
| - unsigned start_offset = start_offset_;
|
| - for (unsigned i = start_index_; i <= last_break_opportunity_index_; i++) {
|
| - const NGLayoutInlineItem& item = items[i];
|
| - unsigned end_offset =
|
| - std::min(item.EndOffset(), last_break_opportunity_offset_);
|
| - line_item_chunks.push_back(
|
| - LineItemChunk{i, start_offset, end_offset,
|
| - InlineSize(item, start_offset, end_offset)});
|
| - start_offset = end_offset;
|
| - }
|
| -
|
| - if (Node()->IsBidiEnabled())
|
| - BidiReorder(&line_item_chunks);
|
| -
|
| - if (!PlaceItems(line_item_chunks))
|
| - return false;
|
| -
|
| - // Prepare for the next line.
|
| - // Move |start| to |last_break_opportunity|, keeping items after
|
| - // |last_break_opportunity|.
|
| - start_index_ = last_break_opportunity_index_;
|
| - start_offset_ = last_break_opportunity_offset_;
|
| - DCHECK_GE(end_position_, last_break_opportunity_position_);
|
| - end_position_ -= last_break_opportunity_position_;
|
| - last_break_opportunity_position_ = LayoutUnit();
|
| -#if DCHECK_IS_ON()
|
| - is_bidi_reordered_ = false;
|
| -#endif
|
| -
|
| - NGLogicalOffset origin_point =
|
| - GetOriginPointForFloats(ConstraintSpace(), content_size_);
|
| - PositionPendingFloats(origin_point.block_offset, MutableConstraintSpace(),
|
| - &container_builder_);
|
| - FindNextLayoutOpportunity();
|
| - return true;
|
| -}
|
| -
|
| -void NGInlineLayoutAlgorithm::BidiReorder(
|
| - Vector<LineItemChunk, 32>* line_item_chunks) {
|
| -#if DCHECK_IS_ON()
|
| - DCHECK(!is_bidi_reordered_);
|
| - is_bidi_reordered_ = true;
|
| -#endif
|
| -
|
| - // TODO(kojii): UAX#9 L1 is not supported yet. Supporting L1 may change
|
| - // embedding levels of parts of runs, which requires to split items.
|
| - // http://unicode.org/reports/tr9/#L1
|
| - // BidiResolver does not support L1 crbug.com/316409.
|
| -
|
| - // Create a list of chunk indices in the visual order.
|
| - // ICU |ubidi_getVisualMap()| works for a run of characters. Since we can
|
| - // handle the direction of each run, we use |ubidi_reorderVisual()| to reorder
|
| - // runs instead of characters.
|
| - Vector<UBiDiLevel, 32> levels;
|
| - levels.ReserveInitialCapacity(line_item_chunks->size());
|
| - for (const auto& chunk : *line_item_chunks)
|
| - levels.push_back(Node()->Items()[chunk.index].BidiLevel());
|
| - Vector<int32_t, 32> indices_in_visual_order(line_item_chunks->size());
|
| - NGBidiParagraph::IndicesInVisualOrder(levels, &indices_in_visual_order);
|
| -
|
| - // Reorder |line_item_chunks| in visual order.
|
| - Vector<LineItemChunk, 32> line_item_chunks_in_visual_order(
|
| - line_item_chunks->size());
|
| - for (unsigned visual_index = 0; visual_index < indices_in_visual_order.size();
|
| - visual_index++) {
|
| - unsigned logical_index = indices_in_visual_order[visual_index];
|
| - line_item_chunks_in_visual_order[visual_index] =
|
| - (*line_item_chunks)[logical_index];
|
| - }
|
| - line_item_chunks->Swap(line_item_chunks_in_visual_order);
|
| -}
|
| -
|
| -// TODO(glebl): Add the support of clearance for inline floats.
|
| -void NGInlineLayoutAlgorithm::LayoutAndPositionFloat(
|
| - LayoutUnit end_position,
|
| - LayoutObject* layout_object) {
|
| - NGBlockNode* node = new NGBlockNode(layout_object);
|
| -
|
| - RefPtr<NGConstraintSpace> float_space =
|
| - CreateConstraintSpaceForFloat(Node()->Style(), *node, &space_builder_);
|
| - // TODO(glebl): add the fragmentation support:
|
| - // same writing mode - get the inline size ComputeInlineSizeForFragment to
|
| - // determine if it fits on this line, then perform layout with the correct
|
| - // fragmentation line.
|
| - // diff writing mode - get the inline size from performing layout.
|
| - RefPtr<NGLayoutResult> layout_result = node->Layout(float_space.Get());
|
| -
|
| - NGBoxFragment float_fragment(
|
| - float_space->WritingMode(),
|
| - ToNGPhysicalBoxFragment(layout_result->PhysicalFragment().Get()));
|
| -
|
| - NGLogicalOffset origin_offset =
|
| - GetOriginPointForFloats(ConstraintSpace(), content_size_);
|
| - NGLogicalOffset from_offset = ConstraintSpace().BfcOffset();
|
| - const ComputedStyle& float_style = node->Style();
|
| - NGBoxStrut margins = ComputeMargins(ConstraintSpace(), float_style,
|
| - ConstraintSpace().WritingMode(),
|
| - ConstraintSpace().Direction());
|
| - RefPtr<NGFloatingObject> floating_object = NGFloatingObject::Create(
|
| - float_style, float_space->WritingMode(), current_opportunity_.size,
|
| - origin_offset, from_offset, margins,
|
| - layout_result->PhysicalFragment().Get());
|
| -
|
| - bool float_does_not_fit = end_position + float_fragment.InlineSize() >
|
| - current_opportunity_.InlineSize();
|
| - // Check if we already have a pending float. That's because a float cannot be
|
| - // higher than any block or floated box generated before.
|
| - if (!container_builder_.UnpositionedFloats().IsEmpty() ||
|
| - float_does_not_fit) {
|
| - container_builder_.AddUnpositionedFloat(floating_object);
|
| - } else {
|
| - NGLogicalOffset offset =
|
| - PositionFloat(floating_object.Get(), MutableConstraintSpace());
|
| - container_builder_.AddFloatingObject(floating_object, offset);
|
| - FindNextLayoutOpportunity();
|
| - }
|
| -}
|
| -
|
| -bool NGInlineLayoutAlgorithm::PlaceItems(
|
| - const Vector<LineItemChunk, 32>& line_item_chunks) {
|
| - const Vector<NGLayoutInlineItem>& items = Node()->Items();
|
| -
|
| - // Use a "strut" (a zero-width inline box with the element's font and
|
| - // line height properties) as the initial metrics for the line box.
|
| - // https://drafts.csswg.org/css2/visudet.html#strut
|
| - const ComputedStyle& line_style = LineStyle();
|
| - NGLineHeightMetrics line_metrics(line_style, baseline_type_);
|
| - NGLineHeightMetrics line_metrics_with_leading = line_metrics;
|
| - line_metrics_with_leading.AddLeading(line_style.ComputedLineHeightAsFixed());
|
| - NGLineBoxFragmentBuilder line_box(Node(), line_metrics_with_leading);
|
| -
|
| - // Compute heights of all inline items by placing the dominant baseline at 0.
|
| - // The baseline is adjusted after the height of the line box is computed.
|
| - NGTextFragmentBuilder text_builder(Node());
|
| - LayoutUnit inline_size;
|
| - for (const auto& line_item_chunk : line_item_chunks) {
|
| - const NGLayoutInlineItem& item = items[line_item_chunk.index];
|
| - // Skip bidi controls.
|
| - if (!item.GetLayoutObject())
|
| - continue;
|
| -
|
| - LayoutUnit block_start;
|
| - if (item.Type() == NGLayoutInlineItem::kText) {
|
| - DCHECK(item.GetLayoutObject()->IsText());
|
| - const ComputedStyle* style = item.Style();
|
| - // The direction of a fragment is the CSS direction to resolve logical
|
| - // properties, not the resolved bidi direction.
|
| - text_builder.SetDirection(style->Direction())
|
| - .SetInlineSize(line_item_chunk.inline_size);
|
| -
|
| - // |InlineTextBoxPainter| sets the baseline at |top +
|
| - // ascent-of-primary-font|. Compute |top| to match.
|
| - NGLineHeightMetrics metrics(*style, baseline_type_);
|
| - block_start = -metrics.ascent;
|
| - metrics.AddLeading(style->ComputedLineHeightAsFixed());
|
| - text_builder.SetBlockSize(metrics.LineHeight());
|
| - line_box.UniteMetrics(metrics);
|
| -
|
| - // Take all used fonts into account if 'line-height: normal'.
|
| - if (style->LineHeight().IsNegative())
|
| - AccumulateUsedFonts(item, line_item_chunk, &line_box);
|
| - } else if (item.Type() == NGLayoutInlineItem::kAtomicInline) {
|
| - block_start = PlaceAtomicInline(item, &line_box, &text_builder);
|
| - } else if (item.Type() == NGLayoutInlineItem::kOutOfFlowPositioned) {
|
| - // TODO(layout-dev): Report the correct static position for the out of
|
| - // flow descendant. We can't do this here yet as it doesn't know the
|
| - // size of the line box.
|
| - container_builder_.AddOutOfFlowDescendant(
|
| - // Absolute positioning blockifies the box's display type.
|
| - // https://drafts.csswg.org/css-display/#transformations
|
| - new NGBlockNode(item.GetLayoutObject()),
|
| - NGStaticPosition::Create(ConstraintSpace().WritingMode(),
|
| - ConstraintSpace().Direction(),
|
| - NGPhysicalOffset()));
|
| - continue;
|
| - } else {
|
| - continue;
|
| - }
|
| -
|
| - RefPtr<NGPhysicalTextFragment> text_fragment = text_builder.ToTextFragment(
|
| - line_item_chunk.index, line_item_chunk.start_offset,
|
| - line_item_chunk.end_offset);
|
| -
|
| - NGLogicalOffset logical_offset(
|
| - inline_size + current_opportunity_.InlineStartOffset() -
|
| - ConstraintSpace().BfcOffset().inline_offset,
|
| - block_start);
|
| - line_box.AddChild(std::move(text_fragment), logical_offset);
|
| - inline_size += line_item_chunk.inline_size;
|
| - }
|
| -
|
| - if (line_box.Children().IsEmpty()) {
|
| - return true; // The line was empty.
|
| - }
|
| -
|
| - // The baselines are always placed at pixel boundaries. Not doing so results
|
| - // in incorrect layout of text decorations, most notably underlines.
|
| - LayoutUnit baseline = content_size_ + line_box.Metrics().ascent;
|
| - baseline = LayoutUnit(baseline.Round());
|
| -
|
| - // Check if the line fits into the constraint space in block direction.
|
| - LayoutUnit line_bottom = baseline + line_box.Metrics().descent;
|
| - if (!container_builder_.Children().IsEmpty() &&
|
| - ConstraintSpace().AvailableSize().block_size != NGSizeIndefinite &&
|
| - line_bottom > ConstraintSpace().AvailableSize().block_size) {
|
| - return false;
|
| - }
|
| -
|
| - // If there are more content to consume, create an unfinished break token.
|
| - if (last_break_opportunity_index_ != items.size() - 1 ||
|
| - last_break_opportunity_offset_ != Node()->Text().length()) {
|
| - line_box.SetBreakToken(NGInlineBreakToken::Create(
|
| - Node(), last_break_opportunity_index_, last_break_opportunity_offset_));
|
| - }
|
| -
|
| - // TODO(kojii): Implement flipped line (vertical-lr). In this case, line_top
|
| - // and block_start do not match.
|
| -
|
| - // Up until this point, children are placed so that the dominant baseline is
|
| - // at 0. Move them to the final baseline position, and set the logical top of
|
| - // the line box to the line top.
|
| - line_box.MoveChildrenInBlockDirection(baseline);
|
| - line_box.SetInlineSize(inline_size);
|
| - container_builder_.AddChild(line_box.ToLineBoxFragment(),
|
| - {LayoutUnit(), baseline - line_metrics.ascent});
|
| -
|
| - max_inline_size_ = std::max(max_inline_size_, inline_size);
|
| - content_size_ = line_bottom;
|
| - return true;
|
| -}
|
| -
|
| -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);
|
| - for (const auto& fallback_font : fallback_fonts) {
|
| - NGLineHeightMetrics metrics(fallback_font->GetFontMetrics(),
|
| - baseline_type_);
|
| - metrics.AddLeading(fallback_font->GetFontMetrics().FixedLineSpacing());
|
| - line_box->UniteMetrics(metrics);
|
| - }
|
| -}
|
| -
|
| -LayoutUnit NGInlineLayoutAlgorithm::PlaceAtomicInline(
|
| - const NGLayoutInlineItem& item,
|
| - NGLineBoxFragmentBuilder* line_box,
|
| - NGTextFragmentBuilder* text_builder) {
|
| - NGBoxFragment fragment(
|
| - ConstraintSpace().WritingMode(),
|
| - ToNGPhysicalBoxFragment(LayoutItem(item)->PhysicalFragment().Get()));
|
| - // TODO(kojii): Margin and border in block progression not implemented yet.
|
| - LayoutUnit block_size = fragment.BlockSize();
|
| -
|
| - // TODO(kojii): Try to eliminate the wrapping text fragment and use the
|
| - // |fragment| directly. Currently |CopyFragmentDataToLayoutBlockFlow|
|
| - // requires a text fragment.
|
| - text_builder->SetInlineSize(fragment.InlineSize()).SetBlockSize(block_size);
|
| -
|
| - // TODO(kojii): Add baseline position to NGPhysicalFragment.
|
| - LayoutBox* box = ToLayoutBox(item.GetLayoutObject());
|
| - LineDirectionMode line_direction_mode =
|
| - IsHorizontalWritingMode() ? LineDirectionMode::kHorizontalLine
|
| - : LineDirectionMode::kVerticalLine;
|
| - LayoutUnit baseline_offset(box->BaselinePosition(
|
| - baseline_type_, IsFirstLine(), line_direction_mode));
|
| - line_box->UniteMetrics({baseline_offset, block_size - baseline_offset});
|
| -
|
| - // TODO(kojii): Figure out what to do with OOF in NGLayoutResult.
|
| - // Floats are ok because atomic inlines are BFC?
|
| -
|
| - return -baseline_offset;
|
| -}
|
| -
|
| -void NGInlineLayoutAlgorithm::FindNextLayoutOpportunity() {
|
| - NGLogicalOffset iter_offset = ConstraintSpace().BfcOffset();
|
| - iter_offset.block_offset += content_size_;
|
| - auto* iter = MutableConstraintSpace()->LayoutOpportunityIterator(iter_offset);
|
| - NGLayoutOpportunity opportunity = iter->Next();
|
| - if (!opportunity.IsEmpty())
|
| - current_opportunity_ = opportunity;
|
| -}
|
| -
|
| -RefPtr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
|
| - // TODO(koji): The relationship of NGInlineLayoutAlgorithm and NGLineBreaker
|
| - // should be inverted.
|
| - if (!Node()->Text().IsEmpty()) {
|
| - // TODO(eae): Does this need the LayoutText::LocaleForLineBreakIterator
|
| - // logic to switch the locale based on breaking mode?
|
| - NGLineBreaker line_breaker(Node()->Style().Locale());
|
| - line_breaker.BreakLines(this, Node()->Text(), start_offset_);
|
| - }
|
| -
|
| - // TODO(kojii): Check if the line box width should be content or available.
|
| - container_builder_.SetInlineSize(max_inline_size_)
|
| - .SetInlineOverflow(max_inline_size_)
|
| - .SetBlockSize(content_size_)
|
| - .SetBlockOverflow(content_size_);
|
| -
|
| - return container_builder_.ToBoxFragment();
|
| -}
|
| -
|
| -MinMaxContentSize NGInlineLayoutAlgorithm::ComputeMinMaxContentSizeByLayout() {
|
| - DCHECK_EQ(ConstraintSpace().AvailableSize().inline_size, LayoutUnit());
|
| - DCHECK_EQ(ConstraintSpace().AvailableSize().block_size, NGSizeIndefinite);
|
| - if (!Node()->Text().IsEmpty()) {
|
| - NGLineBreaker line_breaker(Node()->Style().Locale());
|
| - line_breaker.BreakLines(this, Node()->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 : Node()->Items())
|
| - sizes.max_content += InlineSize(item);
|
| -
|
| - return sizes;
|
| -}
|
| -
|
| -void NGInlineLayoutAlgorithm::CopyFragmentDataToLayoutBlockFlow(
|
| - NGLayoutResult* layout_result) {
|
| - LayoutBlockFlow* block = Node()->GetLayoutBlockFlow();
|
| - block->DeleteLineBoxTree();
|
| -
|
| - Vector<NGLayoutInlineItem>& items = Node()->Items();
|
| - Vector<unsigned, 32> text_offsets(items.size());
|
| - Node()->GetLayoutTextOffsets(&text_offsets);
|
| -
|
| - Vector<const NGPhysicalFragment*, 32> fragments_for_bidi_runs;
|
| - fragments_for_bidi_runs.ReserveInitialCapacity(items.size());
|
| - BidiRunList<BidiRun> bidi_runs;
|
| - LineInfo line_info;
|
| - NGPhysicalBoxFragment* box_fragment =
|
| - ToNGPhysicalBoxFragment(layout_result->PhysicalFragment().Get());
|
| - for (const auto& container_child : box_fragment->Children()) {
|
| - NGPhysicalLineBoxFragment* physical_line_box =
|
| - ToNGPhysicalLineBoxFragment(container_child.Get());
|
| - // Create a BidiRunList for this line.
|
| - for (const auto& line_child : physical_line_box->Children()) {
|
| - const auto* text_fragment = ToNGPhysicalTextFragment(line_child.Get());
|
| - const NGLayoutInlineItem& item = items[text_fragment->ItemIndex()];
|
| - BidiRun* run;
|
| - if (item.Type() == NGLayoutInlineItem::kText) {
|
| - LayoutObject* layout_object = item.GetLayoutObject();
|
| - DCHECK(layout_object->IsText());
|
| - unsigned text_offset = text_offsets[text_fragment->ItemIndex()];
|
| - run = new BidiRun(text_fragment->StartOffset() - text_offset,
|
| - text_fragment->EndOffset() - text_offset,
|
| - item.BidiLevel(), LineLayoutItem(layout_object));
|
| - layout_object->ClearNeedsLayout();
|
| - } else if (item.Type() == NGLayoutInlineItem::kAtomicInline) {
|
| - LayoutObject* layout_object = item.GetLayoutObject();
|
| - DCHECK(layout_object->IsAtomicInlineLevel());
|
| - run =
|
| - new BidiRun(0, 1, item.BidiLevel(), LineLayoutItem(layout_object));
|
| - } else {
|
| - continue;
|
| - }
|
| - bidi_runs.AddRun(run);
|
| - fragments_for_bidi_runs.push_back(text_fragment);
|
| - }
|
| - // TODO(kojii): bidi needs to find the logical last run.
|
| - bidi_runs.SetLogicallyLastRun(bidi_runs.LastRun());
|
| -
|
| - // Create a RootInlineBox from BidiRunList. InlineBoxes created for the
|
| - // RootInlineBox are set to Bidirun::m_box.
|
| - line_info.SetEmpty(false);
|
| - // TODO(kojii): Implement setFirstLine, LastLine, etc.
|
| - RootInlineBox* root_line_box = block->ConstructLine(bidi_runs, line_info);
|
| -
|
| - // Copy fragments data to InlineBoxes.
|
| - DCHECK_EQ(fragments_for_bidi_runs.size(), bidi_runs.RunCount());
|
| - BidiRun* run = bidi_runs.FirstRun();
|
| - for (auto* physical_fragment : fragments_for_bidi_runs) {
|
| - DCHECK(run);
|
| - NGTextFragment fragment(ConstraintSpace().WritingMode(),
|
| - ToNGPhysicalTextFragment(physical_fragment));
|
| - InlineBox* inline_box = run->box_;
|
| - inline_box->SetLogicalWidth(fragment.InlineSize());
|
| - inline_box->SetLogicalLeft(fragment.InlineOffset());
|
| - inline_box->SetLogicalTop(fragment.BlockOffset());
|
| - if (inline_box->GetLineLayoutItem().IsBox()) {
|
| - LineLayoutBox box(inline_box->GetLineLayoutItem());
|
| - box.SetLocation(inline_box->Location());
|
| - }
|
| - run = run->Next();
|
| - }
|
| - DCHECK(!run);
|
| -
|
| - // Copy to RootInlineBox.
|
| - NGLineBoxFragment line_box(ConstraintSpace().WritingMode(),
|
| - physical_line_box);
|
| - root_line_box->SetLogicalWidth(line_box.InlineSize());
|
| - LayoutUnit line_top = line_box.BlockOffset();
|
| - root_line_box->SetLogicalTop(line_top);
|
| - NGLineHeightMetrics line_metrics(Style(), baseline_type_);
|
| - const NGLineHeightMetrics& max_with_leading = physical_line_box->Metrics();
|
| - LayoutUnit baseline = line_top + line_metrics.ascent;
|
| - root_line_box->SetLineTopBottomPositions(
|
| - line_top, baseline + line_metrics.descent,
|
| - baseline - max_with_leading.ascent,
|
| - baseline + max_with_leading.descent);
|
| -
|
| - bidi_runs.DeleteRuns();
|
| - fragments_for_bidi_runs.Clear();
|
| - }
|
| -}
|
| -} // namespace blink
|
|
|