Chromium Code Reviews| 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 f9353d41fea54f95dfc13600589115dc821e94fd..fbdd585948026f26cbbe0de22f77307e03283372 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 |
| @@ -15,7 +15,10 @@ |
| #include "core/layout/ng/ng_fragment_builder.h" |
| #include "core/layout/ng/ng_inline_node.h" |
| #include "core/layout/ng/ng_length_utils.h" |
| +#include "core/layout/ng/ng_linebox_fragment.h" |
| +#include "core/layout/ng/ng_linebox_fragment_builder.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" |
| @@ -261,19 +264,15 @@ void NGLineBuilder::BidiReorder(Vector<LineItemChunk, 32>* line_item_chunks) { |
| void NGLineBuilder::PlaceItems( |
| const Vector<LineItemChunk, 32>& line_item_chunks) { |
| const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); |
| - const unsigned fragment_start_index = container_builder_.Children().size(); |
| - NGFragmentBuilder text_builder(NGPhysicalFragment::kFragmentText, |
| - inline_box_); |
| - text_builder.SetWritingMode(ConstraintSpace().WritingMode()); |
| - line_box_data_list_.grow(line_box_data_list_.size() + 1); |
| - LineBoxData& line_box_data = line_box_data_list_.back(); |
| + NGLineboxFragmentBuilder linebox(inline_box_); |
|
ikilpatrick
2017/03/23 16:47:26
This is going to be incredibly annoying but should
|
| + NGTextFragmentBuilder text_builder(inline_box_); |
| // Accumulate a "strut"; a zero-width inline box with the element's font and |
| // line height properties. https://drafts.csswg.org/css2/visudet.html#strut |
| const ComputedStyle* block_style = inline_box_->BlockStyle(); |
| - InlineItemMetrics block_metrics(*block_style, baseline_type_); |
| - line_box_data.UpdateMaxAscentAndDescent(block_metrics); |
| + NGLineHeightMetrics block_metrics(*block_style, baseline_type_); |
| + linebox.UniteMetrics(block_metrics); |
| // Use the block style to compute the estimated baseline position because the |
| // baseline position is not known until we know the maximum ascent and leading |
| @@ -282,6 +281,7 @@ void NGLineBuilder::PlaceItems( |
| LayoutUnit estimated_baseline = |
| content_size_ + LayoutUnit(block_metrics.ascent_and_leading); |
| + LayoutUnit inline_size; |
| for (const auto& line_item_chunk : line_item_chunks) { |
| const NGLayoutInlineItem& item = items[line_item_chunk.index]; |
| // Skip bidi controls. |
| @@ -292,27 +292,24 @@ void NGLineBuilder::PlaceItems( |
| 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. |
| - InlineItemMetrics metrics(*style, baseline_type_); |
| + NGLineHeightMetrics metrics(*style, baseline_type_); |
| block_start = estimated_baseline - LayoutUnit(metrics.ascent); |
| - LayoutUnit line_height = LayoutUnit(metrics.ascent + metrics.descent); |
| - line_box_data.UpdateMaxAscentAndDescent(metrics); |
| + text_builder.SetBlockSize(metrics.LineHeight()); |
| + linebox.UniteMetrics(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); |
| + AccumulateUsedFonts(item, line_item_chunk, &linebox); |
| } else if (item.Type() == NGLayoutInlineItem::kAtomicInline) { |
| - block_start = PlaceAtomicInline(item, estimated_baseline, &line_box_data, |
| - &text_builder); |
| + block_start = |
| + PlaceAtomicInline(item, estimated_baseline, &linebox, &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 |
| @@ -340,94 +337,50 @@ void NGLineBuilder::PlaceItems( |
| line_item_chunk.end_offset); |
| NGLogicalOffset logical_offset( |
| - line_box_data.inline_size + current_opportunity_.InlineStartOffset() - |
| + inline_size + current_opportunity_.InlineStartOffset() - |
| ConstraintSpace().BfcOffset().inline_offset, |
| block_start); |
| - container_builder_.AddChild(std::move(text_fragment), logical_offset); |
| - line_box_data.inline_size += line_item_chunk.inline_size; |
| + linebox.AddChild(std::move(text_fragment), logical_offset); |
| + inline_size += line_item_chunk.inline_size; |
| } |
| - if (fragment_start_index == container_builder_.Children().size()) { |
| - // The line was empty. Remove the LineBoxData. |
| - line_box_data_list_.shrink(line_box_data_list_.size() - 1); |
| + if (linebox.Children().isEmpty()) { |
| + // The line was empty. |
| return; |
| } |
| // If the estimated baseline position was not the actual position, move all |
| // fragments in the block direction. |
| - if (block_metrics.ascent_and_leading != |
| - line_box_data.max_ascent_and_leading) { |
| - LayoutUnit adjust_top(line_box_data.max_ascent_and_leading - |
| - block_metrics.ascent_and_leading); |
| - auto& offsets = container_builder_.MutableOffsets(); |
| - for (unsigned i = fragment_start_index; i < offsets.size(); i++) |
| - offsets[i].block_offset += adjust_top; |
| - } |
| - |
| - line_box_data.fragment_end = container_builder_.Children().size(); |
| - line_box_data.top_with_leading = content_size_; |
| - max_inline_size_ = std::max(max_inline_size_, line_box_data.inline_size); |
| - content_size_ += LayoutUnit(line_box_data.max_ascent_and_leading + |
| - line_box_data.max_descent_and_leading); |
| -} |
| - |
| -NGLineBuilder::InlineItemMetrics::InlineItemMetrics( |
| - const ComputedStyle& style, |
| - FontBaseline baseline_type) { |
| - const SimpleFontData* font_data = style.font().primaryFont(); |
| - DCHECK(font_data); |
| - Initialize(font_data->getFontMetrics(), baseline_type, |
| - style.computedLineHeightInFloat()); |
| -} |
| - |
| -NGLineBuilder::InlineItemMetrics::InlineItemMetrics( |
| - const FontMetrics& font_metrics, |
| - FontBaseline baseline_type) { |
| - Initialize(font_metrics, baseline_type, font_metrics.floatLineSpacing()); |
| -} |
| - |
| -void NGLineBuilder::InlineItemMetrics::Initialize( |
| - const FontMetrics& font_metrics, |
| - FontBaseline baseline_type, |
| - float line_height) { |
| - ascent = font_metrics.floatAscent(baseline_type); |
| - descent = font_metrics.floatDescent(baseline_type); |
| - float half_leading = (line_height - (ascent + descent)) / 2; |
| - // Ensure the top and the baseline is snapped to CSS pixel. |
| - // TODO(kojii): How to handle fractional ascent isn't determined yet. Should |
| - // we snap top or baseline? If baseline, top needs fractional. If top, |
| - // baseline may not align across fonts. |
| - ascent_and_leading = ascent + floor(half_leading); |
| - descent_and_leading = line_height - ascent_and_leading; |
| -} |
| - |
| -void NGLineBuilder::LineBoxData::UpdateMaxAscentAndDescent( |
| - const NGLineBuilder::InlineItemMetrics& metrics) { |
| - max_ascent = std::max(max_ascent, metrics.ascent); |
| - max_descent = std::max(max_descent, metrics.descent); |
| - max_ascent_and_leading = |
| - std::max(max_ascent_and_leading, metrics.ascent_and_leading); |
| - max_descent_and_leading = |
| - std::max(max_descent_and_leading, metrics.descent_and_leading); |
| + LayoutUnit adjust_baseline(linebox.Metrics().ascent_and_leading - |
| + block_metrics.ascent_and_leading); |
| + if (adjust_baseline) |
| + linebox.MoveChildrenInBlockDirection(adjust_baseline); |
| + |
| + linebox.SetInlineSize(inline_size); |
| + NGLogicalOffset offset(LayoutUnit(), content_size_); |
| + container_builder_.AddChild(linebox.ToLineboxFragment(), offset); |
| + max_inline_size_ = std::max(max_inline_size_, inline_size); |
| + content_size_ += linebox.Metrics().LineHeight(); |
| } |
| void NGLineBuilder::AccumulateUsedFonts(const NGLayoutInlineItem& item, |
| const LineItemChunk& line_item_chunk, |
| - LineBoxData* line_box_data) { |
| + NGLineboxFragmentBuilder* linebox) { |
| 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) { |
| - InlineItemMetrics fallback_font_metrics(fallback_font->getFontMetrics(), |
| - baseline_type_); |
| - line_box_data->UpdateMaxAscentAndDescent(fallback_font_metrics); |
| + NGLineHeightMetrics metrics(fallback_font->getFontMetrics(), |
| + baseline_type_); |
| + linebox->UniteMetrics(metrics); |
| } |
| } |
| -LayoutUnit NGLineBuilder::PlaceAtomicInline(const NGLayoutInlineItem& item, |
| - LayoutUnit estimated_baseline, |
| - LineBoxData* line_box_data, |
| - NGFragmentBuilder* text_builder) { |
| +LayoutUnit NGLineBuilder::PlaceAtomicInline( |
| + const NGLayoutInlineItem& item, |
| + LayoutUnit estimated_baseline, |
| + NGLineboxFragmentBuilder* linebox, |
| + NGTextFragmentBuilder* text_builder) { |
| NGBoxFragment fragment( |
| ConstraintSpace().WritingMode(), |
| toNGPhysicalBoxFragment(LayoutItem(item)->PhysicalFragment().get())); |
| @@ -437,25 +390,22 @@ LayoutUnit NGLineBuilder::PlaceAtomicInline(const NGLayoutInlineItem& item, |
| // 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()); |
| + 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::HorizontalLine |
| : LineDirectionMode::VerticalLine; |
| - bool is_first_line = line_box_data_list_.size() == 1; |
| + bool is_first_line = container_builder_.Children().isEmpty(); |
| 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); |
| + NGLineHeightMetrics metrics; |
| + metrics.ascent_and_leading = baseline_offset; |
| + metrics.descent_and_leading = block_size - baseline_offset; |
| + linebox->UniteMetrics(metrics); |
| // TODO(kojii): Figure out what to do with OOF in NGLayoutResult. |
| // Floats are ok because atomic inlines are BFC? |
| @@ -498,32 +448,31 @@ void NGLineBuilder::CopyFragmentDataToLayoutBlockFlow() { |
| fragments_for_bidi_runs.reserveInitialCapacity(items.size()); |
| BidiRunList<BidiRun> bidi_runs; |
| LineInfo line_info; |
| - unsigned fragment_index = 0; |
| NGPhysicalBoxFragment* box_fragment = toNGPhysicalBoxFragment( |
| container_layout_result_->PhysicalFragment().get()); |
| - for (const auto& line_box_data : line_box_data_list_) { |
| + for (const auto& container_child : box_fragment->Children()) { |
| + NGPhysicalLineboxFragment* physical_linebox = |
| + toNGPhysicalLineboxFragment(container_child.get()); |
| // Create a BidiRunList for this line. |
| - for (; fragment_index < line_box_data.fragment_end; fragment_index++) { |
| - const NGPhysicalFragment* fragment = |
| - box_fragment->Children()[fragment_index].get(); |
| - if (!fragment->IsText()) |
| - continue; |
| - const auto* text_fragment = toNGPhysicalTextFragment(fragment); |
| + for (const auto& line_child : physical_linebox->Children()) { |
| + const auto* text_fragment = toNGPhysicalTextFragment(line_child.get()); |
| const NGLayoutInlineItem& item = items[text_fragment->ItemIndex()]; |
| - LayoutObject* layout_object = item.GetLayoutObject(); |
| - if (!layout_object) // Skip bidi controls. |
| - continue; |
| BidiRun* run; |
| - if (layout_object->isText()) { |
| + 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 { |
| + } 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); |
| @@ -535,7 +484,7 @@ void NGLineBuilder::CopyFragmentDataToLayoutBlockFlow() { |
| // RootInlineBox are set to Bidirun::m_box. |
| line_info.setEmpty(false); |
| // TODO(kojii): Implement setFirstLine, LastLine, etc. |
| - RootInlineBox* line_box = block->constructLine(bidi_runs, line_info); |
| + 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()); |
| @@ -556,17 +505,19 @@ void NGLineBuilder::CopyFragmentDataToLayoutBlockFlow() { |
| } |
| 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); |
| - line_box->setLineTopBottomPositions( |
| - baseline_position - LayoutUnit(line_box_data.max_ascent), |
| - baseline_position + LayoutUnit(line_box_data.max_descent), |
| - line_box_data.top_with_leading, |
| - baseline_position + LayoutUnit(line_box_data.max_descent_and_leading)); |
| + // Copy to RootInlineBox. |
| + NGLineboxFragment linebox(ConstraintSpace().WritingMode(), |
| + physical_linebox); |
| + root_line_box->setLogicalWidth(linebox.InlineSize()); |
| + LayoutUnit line_top_with_leading = linebox.BlockOffset(); |
| + root_line_box->setLogicalTop(line_top_with_leading); |
| + const NGLineHeightMetrics& metrics = physical_linebox->Metrics(); |
| + LayoutUnit baseline = |
| + line_top_with_leading + LayoutUnit(metrics.ascent_and_leading); |
| + root_line_box->setLineTopBottomPositions( |
| + baseline - LayoutUnit(metrics.ascent), |
| + baseline + LayoutUnit(metrics.descent), line_top_with_leading, |
| + baseline + LayoutUnit(metrics.descent_and_leading)); |
| bidi_runs.deleteRuns(); |
| fragments_for_bidi_runs.clear(); |