| Index: third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.cc
|
| diff --git a/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.cc
|
| index 291c18eebcdd5cbce5eec3fdd5b7ac3a4cdf0089..0a2be7d7f485e59bd865b400118add3204272777 100644
|
| --- a/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.cc
|
| +++ b/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.cc
|
| @@ -4,11 +4,14 @@
|
|
|
| #include "core/layout/ng/ng_text_layout_algorithm.h"
|
|
|
| +#include "core/layout/ng/ng_bidi_paragraph.h"
|
| #include "core/layout/ng/ng_break_token.h"
|
| #include "core/layout/ng/ng_constraint_space.h"
|
| #include "core/layout/ng/ng_fragment.h"
|
| #include "core/layout/ng/ng_fragment_builder.h"
|
| +#include "core/layout/ng/ng_text_fragment.h"
|
| #include "core/layout/ng/ng_inline_node.h"
|
| +#include "core/style/ComputedStyle.h"
|
|
|
| namespace blink {
|
|
|
| @@ -27,26 +30,124 @@ NGLayoutStatus NGTextLayoutAlgorithm::Layout(
|
| NGPhysicalFragmentBase*,
|
| NGPhysicalFragmentBase** fragment_out,
|
| NGLayoutAlgorithm**) {
|
| - // TODO(kojii): What kind of fragment tree do we want for line boxes/root line
|
| - // boxes? Just text, box, or new type of fragment?
|
| - NGFragmentBuilder root_line_box_builder(NGPhysicalFragmentBase::kFragmentBox);
|
| - root_line_box_builder.SetWritingMode(constraint_space_->WritingMode());
|
| - root_line_box_builder.SetDirection(constraint_space_->Direction());
|
| + HeapVector<Member<NGFragmentBase>> fragments;
|
| + // TODO(kojii): Make this tickable. Each line is easy. Needs more thoughts
|
| + // for each fragment in a line. Bidi reordering is probably atomic.
|
| + Vector<NGLogicalOffset> logical_offsets;
|
| unsigned start = 0;
|
| do {
|
| - NGFragmentBuilder line_box_builder(NGPhysicalFragmentBase::kFragmentBox);
|
| - start =
|
| - inline_box_->CreateLine(start, constraint_space_, &line_box_builder);
|
| - root_line_box_builder.AddChild(
|
| - new NGFragment(constraint_space_->WritingMode(),
|
| - constraint_space_->Direction(),
|
| - line_box_builder.ToFragment()),
|
| - NGLogicalOffset());
|
| + start = CreateLine(start, *constraint_space_, &fragments, &logical_offsets);
|
| + DCHECK_EQ(fragments.size(), logical_offsets.size());
|
| } while (start);
|
| - *fragment_out = root_line_box_builder.ToFragment();
|
| +
|
| + // TODO(kojii): Put all TextFragments into children of a kFragmentBox since
|
| + // this function can return only one fragment. Change the signature to return
|
| + // a list of NGTextFragment, only for NGTextLayoutAlgorithm.
|
| + NGFragmentBuilder container_builder(NGPhysicalFragmentBase::kFragmentBox);
|
| + container_builder.SetWritingMode(constraint_space_->WritingMode());
|
| + container_builder.SetDirection(constraint_space_->Direction());
|
| + for (unsigned i = 0; i < fragments.size(); i++) {
|
| + container_builder.AddChild(fragments[i], logical_offsets[i]);
|
| + }
|
| + *fragment_out = container_builder.ToFragment();
|
| return kNewFragment;
|
| }
|
|
|
| +// Compute the line break for the line starting at |start_index|.
|
| +// @return the index after the line break, or 0 if no more lines.
|
| +unsigned NGTextLayoutAlgorithm::CreateLine(
|
| + unsigned start_index,
|
| + const NGConstraintSpace& constraint_space,
|
| + HeapVector<Member<NGFragmentBase>>* fragments_out,
|
| + Vector<NGLogicalOffset>* logical_offsets_out) {
|
| + // TODO(kojii): |unsigned start| should be BreakToken.
|
| + // TODO(kojii): implement line breaker.
|
| + CreateLine(inline_box_->Items(start_index, inline_box_->Items().size()),
|
| + constraint_space, fragments_out, logical_offsets_out);
|
| + return 0; // All items are consumed.
|
| +}
|
| +
|
| +// Create text fragments for a line from the specified |items|.
|
| +// Bidi reordering is applied if necessary.
|
| +void NGTextLayoutAlgorithm::CreateLine(
|
| + const NGLayoutInlineItemRange& items,
|
| + const NGConstraintSpace& constraint_space,
|
| + HeapVector<Member<NGFragmentBase>>* fragments_out,
|
| + Vector<NGLogicalOffset>* logical_offsets_out) {
|
| + NGFragmentBuilder text_builder(NGPhysicalFragmentBase::kFragmentText);
|
| + text_builder.SetWritingMode(constraint_space.WritingMode());
|
| +
|
| + // TODO(kojii): atomic inline is not well-thought yet.
|
| + // TODO(kojii): oof is not well-thought yet. The bottom static position may be
|
| + // in the next line, https://github.com/w3c/csswg-drafts/issues/609
|
| + // TODO(kojii): need to split TextFragment if:
|
| + // * oof static position is needed.
|
| + // * nested borders?
|
| +
|
| + if (!inline_box_->IsBidiEnabled()) {
|
| + // If no bidi reordering, the logical order is the visual order.
|
| + DCHECK_EQ(constraint_space.Direction(), LTR);
|
| + DCHECK_EQ(items[0].Style()->direction(), LTR);
|
| + fragments_out->append(new NGTextFragment(
|
| + constraint_space.WritingMode(), constraint_space.Direction(),
|
| + text_builder.ToTextFragment(inline_box_, items.StartIndex(),
|
| + items.EndIndex())));
|
| + logical_offsets_out->append(NGLogicalOffset());
|
| + return;
|
| + }
|
| +
|
| + // TODO(kojii): UAX#9 L1 is not supported yet. Supporting L1 may change
|
| + // embedding levels of parts of runs, which requires to split items.
|
| + // http://unicode.org/reports/tr9/#L1
|
| + // BidiResolver does not support L1 crbug.com/316409.
|
| +
|
| + // Create a list of item indicies in the visual order.
|
| + Vector<int32_t, 32> item_indicies_in_visual_order(items.Size());
|
| + NGBidiParagraph::IndiciesInVisualOrder(items, &item_indicies_in_visual_order);
|
| +
|
| + // Create a TextFragment for each bidi level.
|
| + // Bidi controls inserted in |CollectInlines()| are excluded.
|
| + for (unsigned visual_start = 0; visual_start < items.Size();) {
|
| + int32_t logical_start = item_indicies_in_visual_order[visual_start];
|
| + const NGLayoutInlineItem& start_item = items[logical_start];
|
| + if (!start_item.Style()) { // Skip bidi controls.
|
| + visual_start++;
|
| + continue;
|
| + }
|
| + UBiDiLevel level = start_item.BidiLevel();
|
| + unsigned visual_end = visual_start + 1;
|
| + for (; visual_end < items.Size(); visual_end++) {
|
| + int32_t logical_next = item_indicies_in_visual_order[visual_end];
|
| + const NGLayoutInlineItem& next_item = items[logical_next];
|
| + if (!next_item.Style()) // Stop before bidi controls.
|
| + break;
|
| + if (next_item.BidiLevel() != level)
|
| + break;
|
| + DCHECK_EQ(logical_next, item_indicies_in_visual_order[visual_end - 1] +
|
| + (level & 1 ? -1 : 1));
|
| + }
|
| + int32_t logical_end;
|
| + if (level & 1) {
|
| + // start/end are in the logical order, see NGPhysicalTextFragment.
|
| + logical_end = logical_start + 1;
|
| + logical_start = logical_end - (visual_end - visual_start);
|
| + } else {
|
| + logical_end = logical_start + (visual_end - visual_start);
|
| + }
|
| + // The direction of a fragment is the CSS direction to resolve logical
|
| + // properties, not the resolved bidi direction.
|
| + TextDirection css_direction = start_item.Style()->direction();
|
| + text_builder.SetDirection(css_direction);
|
| + fragments_out->append(new NGTextFragment(
|
| + constraint_space.WritingMode(), css_direction,
|
| + text_builder.ToTextFragment(inline_box_,
|
| + logical_start + items.StartIndex(),
|
| + logical_end + items.StartIndex())));
|
| + logical_offsets_out->append(NGLogicalOffset());
|
| + visual_start = visual_end;
|
| + }
|
| +}
|
| +
|
| DEFINE_TRACE(NGTextLayoutAlgorithm) {
|
| NGLayoutAlgorithm::trace(visitor);
|
| visitor->trace(inline_box_);
|
|
|