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 4bb239f596d26b44643673aa8a265a8fd07e6ed0..be639f41da13b93bc0d9f8a3458f3f0f5cd322c5 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 |
@@ -19,8 +19,11 @@ |
#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_line_box_fragment.h" |
+#include "core/layout/ng/ng_line_box_fragment_builder.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" |
@@ -347,19 +350,15 @@ void NGLineBuilder::LayoutAndPositionFloat(LayoutUnit end_position, |
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 line_box(inline_box_); |
+ 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_); |
+ line_box.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 |
@@ -368,6 +367,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. |
@@ -378,27 +378,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()); |
+ 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_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, &line_box); |
} else if (item.Type() == NGLayoutInlineItem::kAtomicInline) { |
- block_start = PlaceAtomicInline(item, estimated_baseline, &line_box_data, |
- &text_builder); |
+ block_start = |
+ PlaceAtomicInline(item, estimated_baseline, &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 |
@@ -420,94 +417,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; |
+ line_box.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 (line_box.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(line_box.Metrics().ascent_and_leading - |
+ block_metrics.ascent_and_leading); |
+ if (adjust_baseline) |
+ line_box.MoveChildrenInBlockDirection(adjust_baseline); |
+ |
+ line_box.SetInlineSize(inline_size); |
+ NGLogicalOffset offset(LayoutUnit(), content_size_); |
+ container_builder_.AddChild(line_box.ToLineBoxFragment(), offset); |
+ max_inline_size_ = std::max(max_inline_size_, inline_size); |
+ content_size_ += line_box.Metrics().LineHeight(); |
} |
void NGLineBuilder::AccumulateUsedFonts(const NGLayoutInlineItem& item, |
const LineItemChunk& line_item_chunk, |
- LineBoxData* line_box_data) { |
+ 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) { |
- InlineItemMetrics fallback_font_metrics(fallback_font->getFontMetrics(), |
- baseline_type_); |
- line_box_data->UpdateMaxAscentAndDescent(fallback_font_metrics); |
+ NGLineHeightMetrics metrics(fallback_font->getFontMetrics(), |
+ baseline_type_); |
+ line_box->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* line_box, |
+ NGTextFragmentBuilder* text_builder) { |
NGBoxFragment fragment( |
ConstraintSpace().WritingMode(), |
toNGPhysicalBoxFragment(LayoutItem(item)->PhysicalFragment().get())); |
@@ -517,25 +470,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; |
+ line_box->UniteMetrics(metrics); |
// TODO(kojii): Figure out what to do with OOF in NGLayoutResult. |
// Floats are ok because atomic inlines are BFC? |
@@ -578,32 +528,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_line_box = |
+ 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_line_box->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); |
@@ -615,7 +564,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()); |
@@ -636,17 +585,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 line_box(ConstraintSpace().WritingMode(), |
+ physical_line_box); |
+ root_line_box->setLogicalWidth(line_box.InlineSize()); |
+ LayoutUnit line_top_with_leading = line_box.BlockOffset(); |
+ root_line_box->setLogicalTop(line_top_with_leading); |
+ const NGLineHeightMetrics& metrics = physical_line_box->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(); |