| Index: third_party/WebKit/Source/core/layout/ng/ng_line_builder.cc
|
| diff --git a/third_party/WebKit/Source/core/layout/ng/ng_line_builder.cc b/third_party/WebKit/Source/core/layout/ng/ng_line_builder.cc
|
| index 7b2af9ac5792dd0fd9a33d0971e4b8a5a5d5a613..23456ec01553d3bf529eb8e5a24cca953706da55 100644
|
| --- a/third_party/WebKit/Source/core/layout/ng/ng_line_builder.cc
|
| +++ b/third_party/WebKit/Source/core/layout/ng/ng_line_builder.cc
|
| @@ -9,7 +9,9 @@
|
| #include "core/layout/line/LineInfo.h"
|
| #include "core/layout/line/RootInlineBox.h"
|
| #include "core/layout/ng/ng_bidi_paragraph.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_fragment_builder.h"
|
| #include "core/layout/ng/ng_inline_node.h"
|
| #include "core/layout/ng/ng_length_utils.h"
|
| @@ -25,17 +27,17 @@ NGLineBuilder::NGLineBuilder(NGInlineNode* inline_box,
|
| : inline_box_(inline_box),
|
| constraint_space_(constraint_space),
|
| containing_block_builder_(containing_block_builder),
|
| - baseline_type_(constraint_space->WritingMode() ==
|
| - NGWritingMode::kHorizontalTopBottom
|
| - ? FontBaseline::AlphabeticBaseline
|
| - : FontBaseline::IdeographicBaseline),
|
| container_builder_(NGPhysicalFragment::kFragmentBox, inline_box_),
|
| - container_layout_result_(nullptr)
|
| + container_layout_result_(nullptr),
|
| + is_horizontal_writing_mode_(
|
| + blink::IsHorizontalWritingMode(constraint_space->WritingMode()))
|
| #if DCHECK_IS_ON()
|
| ,
|
| is_bidi_reordered_(false)
|
| #endif
|
| {
|
| + if (!is_horizontal_writing_mode_)
|
| + baseline_type_ = FontBaseline::IdeographicBaseline;
|
| }
|
|
|
| bool NGLineBuilder::CanFitOnLine() const {
|
| @@ -78,17 +80,17 @@ void NGLineBuilder::SetEnd(unsigned new_end_offset) {
|
| if (new_end_offset > item->EndOffset()) {
|
| if (end_offset_ < item->EndOffset()) {
|
| SetEnd(item->EndOffset(),
|
| - item->InlineSize(end_offset_, item->EndOffset()));
|
| + InlineSize(*item, end_offset_, item->EndOffset()));
|
| }
|
| item = &items[++last_index];
|
|
|
| while (new_end_offset > item->EndOffset()) {
|
| - SetEnd(item->EndOffset(), item->InlineSize());
|
| + SetEnd(item->EndOffset(), InlineSize(*item));
|
| item = &items[++last_index];
|
| }
|
| }
|
|
|
| - SetEnd(new_end_offset, item->InlineSize(end_offset_, new_end_offset));
|
| + SetEnd(new_end_offset, InlineSize(*item, end_offset_, new_end_offset));
|
| }
|
|
|
| void NGLineBuilder::SetEnd(unsigned new_end_offset,
|
| @@ -127,6 +129,53 @@ void NGLineBuilder::SetStartOfHangables(unsigned offset) {
|
| // TODO(kojii): Implement.
|
| }
|
|
|
| +LayoutUnit NGLineBuilder::InlineSize(const NGLayoutInlineItem& item) {
|
| + if (item.IsAtomicInlineLevel())
|
| + return InlineSizeFromLayout(item);
|
| + return item.InlineSize();
|
| +}
|
| +
|
| +LayoutUnit NGLineBuilder::InlineSize(const NGLayoutInlineItem& item,
|
| + unsigned start_offset,
|
| + unsigned end_offset) {
|
| + if (item.StartOffset() == start_offset && item.EndOffset() == end_offset &&
|
| + item.IsAtomicInlineLevel())
|
| + return InlineSizeFromLayout(item);
|
| + return item.InlineSize(start_offset, end_offset);
|
| +}
|
| +
|
| +LayoutUnit NGLineBuilder::InlineSizeFromLayout(const NGLayoutInlineItem& item) {
|
| + return NGBoxFragment(ConstraintSpace().WritingMode(),
|
| + toNGPhysicalBoxFragment(
|
| + LayoutItem(item)->PhysicalFragment().get()))
|
| + .InlineSize();
|
| +}
|
| +
|
| +const NGLayoutResult* NGLineBuilder::LayoutItem(
|
| + const NGLayoutInlineItem& item) {
|
| + // Returns the cached NGLayoutResult if available.
|
| + const Vector<NGLayoutInlineItem>& items = inline_box_->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(item.IsAtomicInlineLevel());
|
| + 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();
|
| +}
|
| +
|
| void NGLineBuilder::CreateLine() {
|
| if (HasItemsAfterLastBreakOpportunity())
|
| SetBreakOpportunity();
|
| @@ -147,7 +196,7 @@ void NGLineBuilder::CreateLineUpToLastBreakOpportunity() {
|
| std::min(item.EndOffset(), last_break_opportunity_offset_);
|
| line_item_chunks.push_back(
|
| LineItemChunk{i, start_offset, end_offset,
|
| - item.InlineSize(start_offset, end_offset)});
|
| + InlineSize(item, start_offset, end_offset)});
|
| start_offset = end_offset;
|
| }
|
|
|
| @@ -235,19 +284,28 @@ void NGLineBuilder::PlaceItems(
|
| if (!item.GetLayoutObject())
|
| continue;
|
|
|
| - LayoutUnit top, height;
|
| + LayoutUnit block_start;
|
| const ComputedStyle* style = item.Style();
|
| if (style) {
|
| + DCHECK(item.GetLayoutObject()->isText());
|
| // |InlineTextBoxPainter| sets the baseline at |top +
|
| // ascent-of-primary-font|. Compute |top| to match.
|
| InlineItemMetrics metrics(*style, baseline_type_);
|
| - top = estimated_baseline - LayoutUnit(metrics.ascent);
|
| - height = LayoutUnit(metrics.ascent + metrics.descent);
|
| + block_start = estimated_baseline - LayoutUnit(metrics.ascent);
|
| + LayoutUnit line_height = LayoutUnit(metrics.ascent + metrics.descent);
|
| line_box_data.UpdateMaxAscentAndDescent(metrics);
|
|
|
| // Take all used fonts into account if 'line-height: normal'.
|
| if (style->lineHeight().isNegative())
|
| AccumulateUsedFonts(item, line_item_chunk, &line_box_data);
|
| +
|
| + // 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)
|
| + .SetInlineOverflow(line_item_chunk.inline_size)
|
| + .SetBlockSize(line_height)
|
| + .SetBlockOverflow(line_height);
|
| } else {
|
| LayoutObject* layout_object = item.GetLayoutObject();
|
| if (layout_object->isOutOfFlowPositioned()) {
|
| @@ -266,19 +324,10 @@ void NGLineBuilder::PlaceItems(
|
| layout_object->clearNeedsLayout();
|
| continue;
|
| }
|
| - DCHECK(layout_object->isAtomicInlineLevel());
|
| - // TODO(kojii): Implement atomic inline.
|
| - style = layout_object->style();
|
| - top = content_size_;
|
| + block_start = PlaceAtomicInline(item, estimated_baseline, &line_box_data,
|
| + &text_builder);
|
| }
|
|
|
| - // 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)
|
| - .SetInlineOverflow(line_item_chunk.inline_size)
|
| - .SetBlockSize(height)
|
| - .SetBlockOverflow(height);
|
| RefPtr<NGPhysicalTextFragment> text_fragment = text_builder.ToTextFragment(
|
| line_item_chunk.index, line_item_chunk.start_offset,
|
| line_item_chunk.end_offset);
|
| @@ -286,7 +335,7 @@ void NGLineBuilder::PlaceItems(
|
| NGLogicalOffset logical_offset(
|
| line_box_data.inline_size + current_opportunity_.InlineStartOffset() -
|
| ConstraintSpace().BfcOffset().inline_offset,
|
| - top);
|
| + block_start);
|
| container_builder_.AddChild(std::move(text_fragment), logical_offset);
|
| line_box_data.inline_size += line_item_chunk.inline_size;
|
| }
|
| @@ -368,6 +417,45 @@ void NGLineBuilder::AccumulateUsedFonts(const NGLayoutInlineItem& item,
|
| }
|
| }
|
|
|
| +LayoutUnit NGLineBuilder::PlaceAtomicInline(const NGLayoutInlineItem& item,
|
| + LayoutUnit estimated_baseline,
|
| + LineBoxData* line_box_data,
|
| + NGFragmentBuilder* 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())
|
| + .SetInlineOverflow(fragment.InlineOverflow())
|
| + .SetBlockSize(block_size)
|
| + .SetBlockOverflow(fragment.BlockOverflow());
|
| +
|
| + // TODO(kojii): Add baseline position to NGPhysicalFragment.
|
| + LayoutBox* box = toLayoutBox(item.GetLayoutObject());
|
| + LineDirectionMode line_direction_mode =
|
| + IsHorizontalWritingMode() ? LineDirectionMode::HorizontalLine
|
| + : LineDirectionMode::VerticalLine;
|
| + bool is_first_line = line_box_data_list_.size() == 1;
|
| + int baseline_offset =
|
| + box->baselinePosition(baseline_type_, is_first_line, line_direction_mode);
|
| + LayoutUnit block_start = estimated_baseline - baseline_offset;
|
| +
|
| + line_box_data->max_ascent_and_leading =
|
| + std::max<float>(baseline_offset, line_box_data->max_ascent_and_leading);
|
| + line_box_data->max_descent_and_leading = std::max<float>(
|
| + block_size - baseline_offset, line_box_data->max_descent_and_leading);
|
| +
|
| + // TODO(kojii): Figure out what to do with OOF in NGLayoutResult.
|
| + // Floats are ok because atomic inlines are BFC?
|
| +
|
| + return block_start;
|
| +}
|
| +
|
| void NGLineBuilder::FindNextLayoutOpportunity() {
|
| NGLogicalOffset iter_offset = constraint_space_->BfcOffset();
|
| iter_offset.block_offset += content_size_;
|
| @@ -429,8 +517,6 @@ void NGLineBuilder::CopyFragmentDataToLayoutBlockFlow() {
|
| DCHECK(layout_object->isAtomicInlineLevel());
|
| run =
|
| new BidiRun(0, 1, item.BidiLevel(), LineLayoutItem(layout_object));
|
| - // TODO(kojii): Temporarily clearNeedsLayout() for not to assert.
|
| - layout_object->clearNeedsLayout();
|
| }
|
| bidi_runs.addRun(run);
|
| fragments_for_bidi_runs.push_back(text_fragment);
|
| @@ -455,12 +541,17 @@ void NGLineBuilder::CopyFragmentDataToLayoutBlockFlow() {
|
| 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 LineBoxData to RootInlineBox.
|
| line_box->setLogicalWidth(line_box_data.inline_size);
|
| + line_box->setLogicalTop(line_box_data.top_with_leading);
|
| LayoutUnit baseline_position =
|
| line_box_data.top_with_leading +
|
| LayoutUnit(line_box_data.max_ascent_and_leading);
|
|
|