Index: third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc |
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc |
index 734d6ec857e85c13d28df3e0b5aa433ef775f497..3144080646dbdd38ef3833c12314b99ea3a8762a 100644 |
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc |
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc |
@@ -33,28 +33,120 @@ namespace blink { |
namespace { |
-// Set the geometry to InlineFlowBox by computing the union of children. |
-void PlaceInlineFlowBoxes(InlineFlowBox* flow_box) { |
+struct FragmentPosition { |
+ NGLogicalOffset offset; |
+ LayoutUnit inline_size; |
+}; |
+ |
+// Create BidiRuns from a list of NGPhysicalFragment. |
+// Produce a FragmentPosition map to place InlineBoxes. |
+void CreateBidiRuns(BidiRunList<BidiRun>* bidi_runs, |
+ const Vector<RefPtr<NGPhysicalFragment>>& children, |
+ const NGConstraintSpace& constraint_space, |
+ NGLogicalOffset parent_offset, |
+ const Vector<NGInlineItem>& items, |
+ const Vector<unsigned, 32>& text_offsets, |
+ Vector<FragmentPosition, 32>* positions_for_bidi_runs_out, |
+ HashMap<LineLayoutItem, FragmentPosition>* positions_out) { |
+ for (const auto& child : children) { |
+ if (child->Type() == NGPhysicalFragment::kFragmentText) { |
+ const auto* physical_fragment = ToNGPhysicalTextFragment(child.Get()); |
+ const NGInlineItem& item = items[physical_fragment->ItemIndex()]; |
+ BidiRun* run; |
+ if (item.Type() == NGInlineItem::kText || |
+ item.Type() == NGInlineItem::kControl) { |
+ LayoutObject* layout_object = item.GetLayoutObject(); |
+ DCHECK(layout_object->IsText()); |
+ unsigned text_offset = text_offsets[physical_fragment->ItemIndex()]; |
+ run = new BidiRun(physical_fragment->StartOffset() - text_offset, |
+ physical_fragment->EndOffset() - text_offset, |
+ item.BidiLevel(), LineLayoutItem(layout_object)); |
+ layout_object->ClearNeedsLayout(); |
+ } else if (item.Type() == NGInlineItem::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); |
+ NGTextFragment fragment(constraint_space.WritingMode(), |
+ physical_fragment); |
+ // Store text fragments in a vector in the same order as BidiRunList. |
+ // One LayoutText may produce multiple text fragments that they can't |
+ // be set to a map. |
+ positions_for_bidi_runs_out->push_back(FragmentPosition{ |
+ fragment.Offset() + parent_offset, fragment.InlineSize()}); |
+ } else { |
+ DCHECK_EQ(child->Type(), NGPhysicalFragment::kFragmentBox); |
+ NGPhysicalBoxFragment* physical_fragment = |
+ ToNGPhysicalBoxFragment(child.Get()); |
+ NGBoxFragment fragment(constraint_space.WritingMode(), physical_fragment); |
+ NGLogicalOffset child_offset = fragment.Offset() + parent_offset; |
+ CreateBidiRuns(bidi_runs, physical_fragment->Children(), constraint_space, |
+ child_offset, items, text_offsets, |
+ positions_for_bidi_runs_out, positions_out); |
+ // Store box fragments in a map by LineLayoutItem. |
+ positions_out->Set(LineLayoutItem(child->GetLayoutObject()), |
+ FragmentPosition{child_offset, fragment.InlineSize()}); |
+ } |
+ } |
+} |
+ |
+// Set the geometry to InlineBoxes by using the FragmentPosition map. |
+// When the map doesn't provide positions; i.e., when InlineFlowBox doesn't have |
+// corresponding box fragment, compute the union of children. |
+unsigned PlaceInlineBoxChildren( |
+ InlineFlowBox* parent, |
+ const Vector<FragmentPosition, 32>& positions_for_bidi_runs, |
+ const HashMap<LineLayoutItem, FragmentPosition>& positions, |
+ unsigned text_index = 0, |
+ bool set_parent_position_from_children = false) { |
LayoutUnit logical_left = LayoutUnit::Max(); |
LayoutUnit logical_right = LayoutUnit::Min(); |
LayoutUnit logical_top = LayoutUnit::Max(); |
- for (InlineBox* curr = flow_box->FirstChild(); curr; |
- curr = curr->NextOnLine()) { |
- if (curr->GetLineLayoutItem().IsLayoutInline()) { |
- InlineFlowBox* flow = ToInlineFlowBox(curr); |
- PlaceInlineFlowBoxes(flow); |
+ for (InlineBox* inline_box = parent->FirstChild(); inline_box; |
+ inline_box = inline_box->NextOnLine()) { |
+ if (inline_box->IsInlineFlowBox()) { |
+ const auto& iter = positions.find(inline_box->GetLineLayoutItem()); |
+ if (iter != positions.end()) { |
+ const FragmentPosition& position = iter->value; |
+ inline_box->SetLogicalLeft(position.offset.inline_offset); |
+ inline_box->SetLogicalTop(position.offset.block_offset); |
+ inline_box->SetLogicalWidth(position.inline_size); |
+ } |
+ |
+ text_index = PlaceInlineBoxChildren(ToInlineFlowBox(inline_box), |
+ positions_for_bidi_runs, positions, |
+ text_index, iter == positions.end()); |
+ } else { |
+ const FragmentPosition& position = positions_for_bidi_runs[text_index++]; |
+ inline_box->SetLogicalLeft(position.offset.inline_offset); |
+ inline_box->SetLogicalTop(position.offset.block_offset); |
+ inline_box->SetLogicalWidth(position.inline_size); |
+ if (inline_box->GetLineLayoutItem().IsBox()) { |
+ LineLayoutBox box(inline_box->GetLineLayoutItem()); |
+ box.SetLocation(inline_box->Location()); |
+ } |
+ } |
+ |
+ if (set_parent_position_from_children) { |
+ logical_left = std::min(inline_box->LogicalLeft(), logical_left); |
+ logical_right = std::max(inline_box->LogicalRight(), logical_right); |
+ logical_top = std::min(inline_box->LogicalTop(), logical_top); |
} |
- logical_left = std::min(curr->LogicalLeft(), logical_left); |
- logical_right = std::max(curr->LogicalRight(), logical_right); |
- logical_top = std::min(curr->LogicalTop(), logical_top); |
} |
- if (logical_left == LayoutUnit::Max()) |
- return; |
- logical_left -= flow_box->MarginBorderPaddingLogicalLeft(); |
- logical_right += flow_box->MarginBorderPaddingLogicalRight(); |
- flow_box->SetLogicalLeft(logical_left); |
- flow_box->SetLogicalWidth(logical_right - logical_left); |
- flow_box->SetLogicalTop(logical_top); |
+ |
+ if (set_parent_position_from_children && logical_left != LayoutUnit::Max()) { |
+ logical_left -= parent->MarginBorderPaddingLogicalLeft(); |
+ logical_right += parent->MarginBorderPaddingLogicalRight(); |
+ parent->SetLogicalLeft(logical_left); |
+ parent->SetLogicalWidth(logical_right - logical_left); |
+ parent->SetLogicalTop(logical_top); |
+ } |
+ |
+ return text_index; |
} |
} // namespace |
@@ -324,8 +416,8 @@ void NGInlineNode::CopyFragmentDataToLayoutBox( |
? FontBaseline::kAlphabeticBaseline |
: FontBaseline::kIdeographicBaseline; |
- Vector<const NGPhysicalFragment*, 32> fragments_for_bidi_runs; |
- fragments_for_bidi_runs.ReserveInitialCapacity(items.size()); |
+ Vector<FragmentPosition, 32> positions_for_bidi_runs; |
+ HashMap<LineLayoutItem, FragmentPosition> positions; |
BidiRunList<BidiRun> bidi_runs; |
LineInfo line_info; |
NGPhysicalBoxFragment* box_fragment = |
@@ -333,31 +425,11 @@ void NGInlineNode::CopyFragmentDataToLayoutBox( |
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 NGInlineItem& item = items[text_fragment->ItemIndex()]; |
- BidiRun* run; |
- if (item.Type() == NGInlineItem::kText || |
- item.Type() == NGInlineItem::kControl) { |
- 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() == NGInlineItem::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); |
- } |
+ CreateBidiRuns(&bidi_runs, physical_line_box->Children(), constraint_space, |
+ NGLogicalOffset(), items, text_offsets, |
+ &positions_for_bidi_runs, &positions); |
// TODO(kojii): bidi needs to find the logical last run. |
bidi_runs.SetLogicallyLastRun(bidi_runs.LastRun()); |
@@ -369,27 +441,7 @@ void NGInlineNode::CopyFragmentDataToLayoutBox( |
block_flow->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(constraint_space.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); |
- |
- // InlineTextBox and InlineBox are placed, but when ConstructLine() created |
- // InlineFlowBox, they needed to be placed as well. |
- PlaceInlineFlowBoxes(root_line_box); |
+ PlaceInlineBoxChildren(root_line_box, positions_for_bidi_runs, positions); |
// Copy to RootInlineBox. |
NGLineBoxFragment line_box(constraint_space.WritingMode(), |
@@ -405,7 +457,8 @@ void NGInlineNode::CopyFragmentDataToLayoutBox( |
line_top, baseline + max_with_leading.descent); |
bidi_runs.DeleteRuns(); |
- fragments_for_bidi_runs.clear(); |
+ positions_for_bidi_runs.clear(); |
+ positions.clear(); |
} |
} |