| Index: third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc
|
| diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc
|
| index 4d27613e7d9b0ff58deac025b3e974eaa468241a..64cdfd1c7d16995848abbe47921e0aee80b733df 100644
|
| --- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc
|
| +++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc
|
| @@ -7,6 +7,8 @@
|
| #include "core/layout/ng/inline/ng_inline_node.h"
|
| #include "core/layout/ng/inline/ng_line_box_fragment_builder.h"
|
| #include "core/layout/ng/inline/ng_text_fragment_builder.h"
|
| +#include "core/layout/ng/ng_fragment_builder.h"
|
| +#include "core/layout/ng/ng_layout_result.h"
|
| #include "core/style/ComputedStyle.h"
|
|
|
| namespace blink {
|
| @@ -36,6 +38,16 @@ void NGInlineBoxState::AccumulateUsedFonts(const NGInlineItem& item,
|
| }
|
| }
|
|
|
| +void NGInlineBoxState::SetNeedsBoxFragment(
|
| + LayoutUnit position,
|
| + LayoutUnit borders_paddings_block_start,
|
| + LayoutUnit borders_paddings_block_height) {
|
| + needs_box_fragment = true;
|
| + line_left_position = position;
|
| + this->borders_paddings_block_start = borders_paddings_block_start;
|
| + this->borders_paddings_block_height = borders_paddings_block_height;
|
| +}
|
| +
|
| NGInlineBoxState* NGInlineLayoutStateStack::OnBeginPlaceItems(
|
| const ComputedStyle* line_style,
|
| FontBaseline baseline_type) {
|
| @@ -67,13 +79,12 @@ NGInlineBoxState* NGInlineLayoutStateStack::OnBeginPlaceItems(
|
|
|
| NGInlineBoxState* NGInlineLayoutStateStack::OnOpenTag(
|
| const NGInlineItem& item,
|
| - NGLineBoxFragmentBuilder* line_box,
|
| - NGTextFragmentBuilder* text_builder) {
|
| + NGLineBoxFragmentBuilder* line_box) {
|
| stack_.resize(stack_.size() + 1);
|
| NGInlineBoxState* box = &stack_.back();
|
| box->fragment_start = line_box->Children().size();
|
| + box->item = &item;
|
| box->style = item.Style();
|
| - text_builder->SetDirection(box->style->Direction());
|
| return box;
|
| }
|
|
|
| @@ -81,8 +92,9 @@ NGInlineBoxState* NGInlineLayoutStateStack::OnCloseTag(
|
| const NGInlineItem& item,
|
| NGLineBoxFragmentBuilder* line_box,
|
| NGInlineBoxState* box,
|
| - FontBaseline baseline_type) {
|
| - EndBoxState(box, line_box, baseline_type);
|
| + FontBaseline baseline_type,
|
| + LayoutUnit position) {
|
| + EndBoxState(box, line_box, baseline_type, position);
|
| // TODO(kojii): When the algorithm restarts from a break token, the stack may
|
| // underflow. We need either synthesize a missing box state, or push all
|
| // parents on initialize.
|
| @@ -92,19 +104,27 @@ NGInlineBoxState* NGInlineLayoutStateStack::OnCloseTag(
|
|
|
| void NGInlineLayoutStateStack::OnEndPlaceItems(
|
| NGLineBoxFragmentBuilder* line_box,
|
| - FontBaseline baseline_type) {
|
| + FontBaseline baseline_type,
|
| + LayoutUnit position) {
|
| for (auto it = stack_.rbegin(); it != stack_.rend(); ++it) {
|
| NGInlineBoxState* box = &(*it);
|
| - EndBoxState(box, line_box, baseline_type);
|
| + EndBoxState(box, line_box, baseline_type, position);
|
| }
|
|
|
| + if (!box_placeholders_.IsEmpty())
|
| + CreateBoxFragments(line_box);
|
| +
|
| DCHECK(!LineBoxState().metrics.IsEmpty());
|
| line_box->SetMetrics(LineBoxState().metrics);
|
| }
|
|
|
| void NGInlineLayoutStateStack::EndBoxState(NGInlineBoxState* box,
|
| NGLineBoxFragmentBuilder* line_box,
|
| - FontBaseline baseline_type) {
|
| + FontBaseline baseline_type,
|
| + LayoutUnit position) {
|
| + if (box->needs_box_fragment)
|
| + AddBoxFragmentPlaceholder(box, line_box, baseline_type, position);
|
| +
|
| PositionPending position_pending =
|
| ApplyBaselineShift(box, line_box, baseline_type);
|
|
|
| @@ -114,6 +134,106 @@ void NGInlineLayoutStateStack::EndBoxState(NGInlineBoxState* box,
|
| }
|
| }
|
|
|
| +// Crete a placeholder for a box fragment.
|
| +// We keep a flat list of fragments because it is more suitable for operations
|
| +// such as ApplyBaselineShift. Later, CreateBoxFragments() creates box fragments
|
| +// from placeholders.
|
| +void NGInlineLayoutStateStack::AddBoxFragmentPlaceholder(
|
| + NGInlineBoxState* box,
|
| + NGLineBoxFragmentBuilder* line_box,
|
| + FontBaseline baseline_type,
|
| + LayoutUnit position) {
|
| + if (box->fragment_start == line_box->Children().size()) {
|
| + // Don't create a placeholder if the inline box is empty.
|
| + // Whether to create this box or not affects layout when the line contains
|
| + // only this box, since this box participates the line height.
|
| + // TODO(kojii): Testing indicates that we should create a box if it has
|
| + // borders, but not for backgrounds. But creating such a RootInlineBox needs
|
| + // additional code. The plan is to enable such line box when NG paint is
|
| + // enabled.
|
| + return;
|
| + }
|
| +
|
| + // The inline box should have the height of the font metrics without the
|
| + // line-height property. Compute from style because |box->metrics| includes
|
| + // the line-height property.
|
| + DCHECK(box->style);
|
| + const ComputedStyle& style = *box->style;
|
| + NGLineHeightMetrics metrics(style, baseline_type);
|
| +
|
| + // Extend the block direction of the box by borders and paddings. Inline
|
| + // direction is already included into positions in NGLineBreaker.
|
| + NGLogicalRect bounds(
|
| + box->line_left_position,
|
| + -metrics.ascent - box->borders_paddings_block_start,
|
| + position - box->line_left_position,
|
| + metrics.LineHeight() + box->borders_paddings_block_height);
|
| +
|
| + // The start is marked only in BoxFragmentPlaceholder, while end is marked
|
| + // in both BoxFragmentPlaceholder and the list itself.
|
| + // With a list of 4 text fragments:
|
| + // | 0 | 1 | 2 | 3 |
|
| + // |text0|text1|text2|text3|
|
| + // By adding a BoxFragmentPlaceholder(2,4) (end is exclusive), it becomes:
|
| + // | 0 | 1 | 2 | 3 | 4 |
|
| + // |text0|text1|text2|text3|null |
|
| + // The "null" is added to the list to compute baseline shift of the box
|
| + // separately from text fragments.
|
| + unsigned fragment_end = line_box->Children().size();
|
| + box_placeholders_.push_back(BoxFragmentPlaceholder{
|
| + box->fragment_start, fragment_end, box->item, bounds.size});
|
| + line_box->AddChild(nullptr, bounds.offset);
|
| +}
|
| +
|
| +// Create box fragments and construct a tree from the placeholders.
|
| +void NGInlineLayoutStateStack::CreateBoxFragments(
|
| + NGLineBoxFragmentBuilder* line_box) {
|
| + DCHECK(!box_placeholders_.IsEmpty());
|
| +
|
| + Vector<RefPtr<NGPhysicalFragment>> children =
|
| + std::move(line_box->MutableChildren());
|
| + Vector<NGLogicalOffset> offsets = std::move(line_box->MutableOffsets());
|
| + DCHECK(line_box->Children().IsEmpty() && line_box->Offsets().IsEmpty());
|
| +
|
| + // At this point, children is a list of text fragments and box placeholders.
|
| + // | 0 | 1 | 2 | 3 | 4 | 5 |
|
| + // |text0|text1|text2|text3|null1|text5|
|
| + // When there is a BoxFragmentPlaceholder(2,4), this loop creates a box
|
| + // fragment with text2 and text3 as its children and changes the list to:
|
| + // | 0 | 1 | 2 | 3 | 4 | 5 |
|
| + // |text0|text1|null |null | box |text5|
|
| + for (const BoxFragmentPlaceholder& placeholder : box_placeholders_) {
|
| + NGFragmentBuilder box(NGPhysicalFragment::kFragmentBox,
|
| + placeholder.item->GetLayoutObject());
|
| + const NGLogicalOffset& box_offset = offsets[placeholder.fragment_end];
|
| + for (unsigned i = placeholder.fragment_start; i < placeholder.fragment_end;
|
| + i++) {
|
| + if (RefPtr<NGPhysicalFragment>& child = children[i]) {
|
| + box.AddChild(std::move(child), offsets[i] - box_offset);
|
| + DCHECK(!children[i]);
|
| + }
|
| + }
|
| +
|
| + box.SetWritingMode(line_box->WritingMode());
|
| + box.SetDirection(placeholder.item->Direction());
|
| + box.SetSize(placeholder.size);
|
| + // TODO(kojii): Overflow size should be computed from children.
|
| + box.SetOverflowSize(placeholder.size);
|
| + RefPtr<NGLayoutResult> layout_result = box.ToBoxFragment();
|
| + DCHECK(!children[placeholder.fragment_end]);
|
| + children[placeholder.fragment_end] =
|
| + std::move(layout_result->MutablePhysicalFragment());
|
| + }
|
| + box_placeholders_.clear();
|
| +
|
| + // Add the list to line_box by skipping null fragments; i.e., fragments added
|
| + // to box children.
|
| + for (unsigned i = 0; i < children.size(); i++) {
|
| + if (children[i])
|
| + line_box->AddChild(children[i], offsets[i]);
|
| + }
|
| +}
|
| +
|
| NGInlineLayoutStateStack::PositionPending
|
| NGInlineLayoutStateStack::ApplyBaselineShift(NGInlineBoxState* box,
|
| NGLineBoxFragmentBuilder* line_box,
|
|
|