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 @@ ...@@ -6,6 +6,7 @@
#include "third_party/blink/renderer/core/editing/position_with_affinity.h" #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_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_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/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
...@@ -357,6 +358,45 @@ TextDirection NGInlineCursor::CurrentBaseDirection() const { ...@@ -357,6 +358,45 @@ TextDirection NGInlineCursor::CurrentBaseDirection() const {
return TextDirection::kLtr; 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 { const NGPhysicalBoxFragment* NGInlineCursor::CurrentBoxFragment() const {
if (current_paint_fragment_) { if (current_paint_fragment_) {
return DynamicTo<NGPhysicalBoxFragment>( return DynamicTo<NGPhysicalBoxFragment>(
...@@ -441,6 +481,16 @@ const ComputedStyle& NGInlineCursor::CurrentStyle() const { ...@@ -441,6 +481,16 @@ const ComputedStyle& NGInlineCursor::CurrentStyle() const {
return current_item_->Style(); 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 { unsigned NGInlineCursor::CurrentTextStartOffset() const {
if (current_paint_fragment_) { if (current_paint_fragment_) {
return To<NGPhysicalTextFragment>( return To<NGPhysicalTextFragment>(
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_CURSOR_H_ #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_ #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_CURSOR_H_
#include <unicode/ubidi.h>
#include "base/containers/span.h" #include "base/containers/span.h"
#include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/editing/forward.h" #include "third_party/blink/renderer/core/editing/forward.h"
...@@ -23,6 +25,7 @@ class NGFragmentItems; ...@@ -23,6 +25,7 @@ class NGFragmentItems;
class NGInlineBreakToken; class NGInlineBreakToken;
class NGPaintFragment; class NGPaintFragment;
class NGPhysicalBoxFragment; class NGPhysicalBoxFragment;
enum class NGStyleVariant;
class Node; class Node;
struct PhysicalOffset; struct PhysicalOffset;
struct PhysicalRect; struct PhysicalRect;
...@@ -156,6 +159,11 @@ class CORE_EXPORT NGInlineCursor { ...@@ -156,6 +159,11 @@ class CORE_EXPORT NGInlineCursor {
const NGPhysicalBoxFragment* CurrentBoxFragment() const; const NGPhysicalBoxFragment* CurrentBoxFragment() const;
const LayoutObject* CurrentLayoutObject() const; const LayoutObject* CurrentLayoutObject() const;
Node* CurrentNode() 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 // 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 // call at other than text or atomic inline. Note: <span> doesn't have
// reserved direction. // reserved direction.
...@@ -274,6 +282,10 @@ class CORE_EXPORT NGInlineCursor { ...@@ -274,6 +282,10 @@ class CORE_EXPORT NGInlineCursor {
// Returns break token for line box. It is error to call other than line box. // Returns break token for line box. It is error to call other than line box.
const NGInlineBreakToken& CurrentInlineBreakToken() const; 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|. // True if current position is descendant or self of |layout_object|.
// Note: This function is used for moving cursor in culled inline boxes. // Note: This function is used for moving cursor in culled inline boxes.
bool IsInclusiveDescendantOf(const LayoutObject& layout_object) const; bool IsInclusiveDescendantOf(const LayoutObject& layout_object) const;
...@@ -307,9 +319,9 @@ class CORE_EXPORT NGInlineCursor { ...@@ -307,9 +319,9 @@ class CORE_EXPORT NGInlineCursor {
void MoveToNextPaintFragment(); void MoveToNextPaintFragment();
void MoveToNextSiblingPaintFragment(); void MoveToNextSiblingPaintFragment();
void MoveToNextPaintFragmentSkippingChildren(); void MoveToNextPaintFragmentSkippingChildren();
void MoveToPreviousPaintFragment(); void MoveToPreviousPaintFragment();
void MoveToPreviousSiblingPaintFragment(); void MoveToPreviousSiblingPaintFragment();
ItemsSpan items_; ItemsSpan items_;
ItemsSpan::iterator item_iter_; ItemsSpan::iterator item_iter_;
const NGFragmentItem* current_item_ = nullptr; const NGFragmentItem* current_item_ = nullptr;
......
...@@ -43,11 +43,12 @@ class NGInlineCursorTest : public NGLayoutTest, ...@@ -43,11 +43,12 @@ class NGInlineCursorTest : public NGLayoutTest,
cursor.GetLayoutBlockFlow()->GetNGInlineNodeData()->text_content; cursor.GetLayoutBlockFlow()->GetNGInlineNodeData()->text_content;
if (const LayoutObject* layout_object = cursor.CurrentLayoutObject()) { if (const LayoutObject* layout_object = cursor.CurrentLayoutObject()) {
if (layout_object->IsText()) { if (layout_object->IsText()) {
return text_content String result = text_content
.Substring( .Substring(cursor.CurrentTextStartOffset(),
cursor.CurrentTextStartOffset(), cursor.CurrentTextEndOffset() -
cursor.CurrentTextEndOffset() - cursor.CurrentTextStartOffset()) cursor.CurrentTextStartOffset())
.StripWhiteSpace(); .StripWhiteSpace();
return result;
} }
if (const Element* element = if (const Element* element =
DynamicTo<Element>(layout_object->GetNode())) { DynamicTo<Element>(layout_object->GetNode())) {
...@@ -60,12 +61,70 @@ class NGInlineCursorTest : public NGLayoutTest, ...@@ -60,12 +61,70 @@ class NGInlineCursorTest : public NGLayoutTest,
return "#null"; 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, INSTANTIATE_TEST_SUITE_P(NGInlineCursorTest,
NGInlineCursorTest, NGInlineCursorTest,
testing::Bool()); 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) { TEST_P(NGInlineCursorTest, GetLayoutBlockFlowWithScopedCursor) {
NGInlineCursor line = SetupCursor("<div id=root>line1<br>line2</div>"); NGInlineCursor line = SetupCursor("<div id=root>line1<br>line2</div>");
ASSERT_TRUE(line.IsLineBox()) << line; ASSERT_TRUE(line.IsLineBox()) << line;
......
...@@ -23,12 +23,13 @@ struct CORE_EXPORT NGInlineNodeData : NGInlineItemsData { ...@@ -23,12 +23,13 @@ struct CORE_EXPORT NGInlineNodeData : NGInlineItemsData {
bool IsBlockLevel() const { return is_block_level_; } bool IsBlockLevel() const { return is_block_level_; }
private:
const NGInlineItemsData& ItemsData(bool is_first_line) const { const NGInlineItemsData& ItemsData(bool is_first_line) const {
return !is_first_line || !first_line_items_ return !is_first_line || !first_line_items_
? (const NGInlineItemsData&)*this ? (const NGInlineItemsData&)*this
: *first_line_items_; : *first_line_items_;
} }
private:
void SetBaseDirection(TextDirection direction) { void SetBaseDirection(TextDirection direction) {
base_direction_ = static_cast<unsigned>(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