Commit 8ac86664 authored by Yoshifumi Inoue's avatar Yoshifumi Inoue Committed by Commit Bot

Introduce NGInlineCursor::CurrentBidiLevel()

This patch introduces |NGInlineCursor::CurrentBidiLevel()| with helper functions
for prepration of utilizing |NGInlineCursor| to |AbstractInlineTextBox|[1].

[1] http://crrev.com/c/1888242 Utilize NGInlineCursor for inline box traversal

Bug: 982194
Change-Id: I92f5aa918f27274cfd97dd2726bf95086d0b9ea8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1899240
Commit-Queue: Yoshifumi Inoue <yosin@chromium.org>
Auto-Submit: Yoshifumi Inoue <yosin@chromium.org>
Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#712909}
parent 277947cc
......@@ -6,6 +6,7 @@
#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/layout_text.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
......@@ -357,6 +358,45 @@ TextDirection NGInlineCursor::CurrentBaseDirection() const {
return TextDirection::kLtr;
}
UBiDiLevel NGInlineCursor::CurrentBidiLevel() const {
if (IsText()) {
const LayoutText& layout_text = *ToLayoutText(CurrentLayoutObject());
DCHECK(!layout_text.NeedsLayout()) << this;
const auto* const items = layout_text.GetNGInlineItems();
if (!items || items->size() == 0) {
// In case of <br>, <wbr>, text-combine-upright, etc.
return 0;
}
const auto& item = std::find_if(
items->begin(), items->end(), [this](const NGInlineItem& item) {
return item.StartOffset() <= CurrentTextStartOffset() &&
item.EndOffset() >= CurrentTextEndOffset();
});
DCHECK(item != items->end()) << this;
return item->BidiLevel();
}
if (IsAtomicInline()) {
const NGPhysicalBoxFragment* fragmentainer =
CurrentLayoutObject()->ContainingBlockFlowFragment();
DCHECK(fragmentainer);
const LayoutBlockFlow& block_flow =
*To<LayoutBlockFlow>(fragmentainer->GetLayoutObject());
const Vector<NGInlineItem> items =
block_flow.GetNGInlineNodeData()->ItemsData(UsesFirstLineStyle()).items;
const LayoutObject* const layout_object = CurrentLayoutObject();
const auto* const item = std::find_if(
items.begin(), items.end(), [layout_object](const NGInlineItem& item) {
return item.GetLayoutObject() == layout_object;
});
DCHECK(item != items.end()) << this;
return item->BidiLevel();
}
NOTREACHED();
return 0;
}
const NGPhysicalBoxFragment* NGInlineCursor::CurrentBoxFragment() const {
if (current_paint_fragment_) {
return DynamicTo<NGPhysicalBoxFragment>(
......@@ -441,6 +481,16 @@ const ComputedStyle& NGInlineCursor::CurrentStyle() const {
return current_item_->Style();
}
NGStyleVariant NGInlineCursor::CurrentStyleVariant() const {
if (current_paint_fragment_)
return current_paint_fragment_->PhysicalFragment().StyleVariant();
return current_item_->StyleVariant();
}
bool NGInlineCursor::UsesFirstLineStyle() const {
return CurrentStyleVariant() == NGStyleVariant::kFirstLine;
}
unsigned NGInlineCursor::CurrentTextStartOffset() const {
if (current_paint_fragment_) {
return To<NGPhysicalTextFragment>(
......
......@@ -5,6 +5,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_CURSOR_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_CURSOR_H_
#include <unicode/ubidi.h>
#include "base/containers/span.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/editing/forward.h"
......@@ -23,6 +25,7 @@ class NGFragmentItems;
class NGInlineBreakToken;
class NGPaintFragment;
class NGPhysicalBoxFragment;
enum class NGStyleVariant;
class Node;
struct PhysicalOffset;
struct PhysicalRect;
......@@ -156,6 +159,11 @@ class CORE_EXPORT NGInlineCursor {
const NGPhysicalBoxFragment* CurrentBoxFragment() const;
const LayoutObject* CurrentLayoutObject() const;
Node* CurrentNode() const;
// Returns bidi level of current position. It is error to call other than
// text and atomic inline.
UBiDiLevel CurrentBidiLevel() const;
// Returns text direction of current text or atomic inline. It is error to
// call at other than text or atomic inline. Note: <span> doesn't have
// reserved direction.
......@@ -274,6 +282,10 @@ class CORE_EXPORT NGInlineCursor {
// Returns break token for line box. It is error to call other than line box.
const NGInlineBreakToken& CurrentInlineBreakToken() const;
// Returns style variant of the current position.
NGStyleVariant CurrentStyleVariant() const;
bool UsesFirstLineStyle() const;
// True if current position is descendant or self of |layout_object|.
// Note: This function is used for moving cursor in culled inline boxes.
bool IsInclusiveDescendantOf(const LayoutObject& layout_object) const;
......@@ -307,9 +319,9 @@ class CORE_EXPORT NGInlineCursor {
void MoveToNextPaintFragment();
void MoveToNextSiblingPaintFragment();
void MoveToNextPaintFragmentSkippingChildren();
void MoveToPreviousPaintFragment();
void MoveToPreviousSiblingPaintFragment();
ItemsSpan items_;
ItemsSpan::iterator item_iter_;
const NGFragmentItem* current_item_ = nullptr;
......
......@@ -43,11 +43,12 @@ class NGInlineCursorTest : public NGLayoutTest,
cursor.GetLayoutBlockFlow()->GetNGInlineNodeData()->text_content;
if (const LayoutObject* layout_object = cursor.CurrentLayoutObject()) {
if (layout_object->IsText()) {
return text_content
.Substring(
cursor.CurrentTextStartOffset(),
cursor.CurrentTextEndOffset() - cursor.CurrentTextStartOffset())
.StripWhiteSpace();
String result = text_content
.Substring(cursor.CurrentTextStartOffset(),
cursor.CurrentTextEndOffset() -
cursor.CurrentTextStartOffset())
.StripWhiteSpace();
return result;
}
if (const Element* element =
DynamicTo<Element>(layout_object->GetNode())) {
......@@ -60,12 +61,70 @@ class NGInlineCursorTest : public NGLayoutTest,
return "#null";
}
Vector<String> ToDebugStringListWithBidiLevel(const NGInlineCursor& start) {
Vector<String> list;
for (NGInlineCursor cursor(start); cursor; cursor.MoveToNext())
list.push_back(ToDebugStringWithBidiLevel(cursor));
return list;
}
String ToDebugStringWithBidiLevel(const NGInlineCursor& cursor) {
if (!cursor.IsText() && !cursor.IsAtomicInline())
return ToDebugString(cursor);
StringBuilder result;
result.Append(ToDebugString(cursor));
result.Append(':');
result.AppendNumber(cursor.CurrentBidiLevel());
return result.ToString();
}
};
INSTANTIATE_TEST_SUITE_P(NGInlineCursorTest,
NGInlineCursorTest,
testing::Bool());
TEST_P(NGInlineCursorTest, BidiLevelInlineBoxLTR) {
InsertStyleElement("b { display: inline-block; }");
NGInlineCursor cursor = SetupCursor(
"<div id=root dir=ltr>"
"abc<b id=def>def</b><bdo dir=rtl><b id=ghi>GHI</b></bdo>jkl</div>");
Vector<String> list = ToDebugStringListWithBidiLevel(cursor);
EXPECT_THAT(list, ElementsAre("#linebox", "abc:0", "#def:0",
"LayoutInline BDO", "#ghi:1", "jkl:0"));
}
TEST_P(NGInlineCursorTest, BidiLevelInlineBoxRTL) {
InsertStyleElement("b { display: inline-block; }");
NGInlineCursor cursor = SetupCursor(
"<div id=root dir=rtl>"
"abc<b id=def>def</b><bdo dir=rtl><b id=ghi>GHI</b></bdo>jkl</div>");
Vector<String> list = ToDebugStringListWithBidiLevel(cursor);
EXPECT_THAT(list, ElementsAre("#linebox", "LayoutInline BDO", "#ghi:3",
"jkl:2", "#def:1", "abc:2"));
}
TEST_P(NGInlineCursorTest, BidiLevelSimpleLTR) {
NGInlineCursor cursor = SetupCursor(
"<div id=root dir=ltr>"
"<bdo dir=rtl>GHI<bdo dir=ltr>abc</bdo>DEF</bdo><br>"
"123, jkl <bdo dir=rtl>MNO</bdo></div>");
Vector<String> list = ToDebugStringListWithBidiLevel(cursor);
EXPECT_THAT(list, ElementsAre("#linebox", "DEF:1", "abc:2", "GHI:1", ":0",
"#linebox", "123, jkl:0", "MNO:1"));
}
TEST_P(NGInlineCursorTest, BidiLevelSimpleRTL) {
NGInlineCursor cursor = SetupCursor(
"<div id=root dir=rtl>"
"<bdo dir=rtl>GHI<bdo dir=ltr>abc</bdo>DEF</bdo><br>"
"123, jkl <bdo dir=rtl>MNO</bdo></div>");
Vector<String> list = ToDebugStringListWithBidiLevel(cursor);
EXPECT_THAT(
list, ElementsAre("#linebox", ":0", "DEF:3", "abc:4", "GHI:3", "#linebox",
"MNO:3", ":1", "jkl:2", ",:1", "123:2"));
}
TEST_P(NGInlineCursorTest, GetLayoutBlockFlowWithScopedCursor) {
NGInlineCursor line = SetupCursor("<div id=root>line1<br>line2</div>");
ASSERT_TRUE(line.IsLineBox()) << line;
......
......@@ -23,12 +23,13 @@ struct CORE_EXPORT NGInlineNodeData : NGInlineItemsData {
bool IsBlockLevel() const { return is_block_level_; }
private:
const NGInlineItemsData& ItemsData(bool is_first_line) const {
return !is_first_line || !first_line_items_
? (const NGInlineItemsData&)*this
: *first_line_items_;
}
private:
void SetBaseDirection(TextDirection direction) {
base_direction_ = static_cast<unsigned>(direction);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment