Index: third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder_test.cc |
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder_test.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder_test.cc |
index dac3a1292c250aea7eaedbb1cb1efebf5e7e4b75..757b56eaa913d8023eb16f4bd40d16ad72bb7104 100644 |
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder_test.cc |
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder_test.cc |
@@ -5,6 +5,7 @@ |
#include "core/layout/ng/inline/ng_inline_items_builder.h" |
#include "core/layout/LayoutInline.h" |
+#include "core/layout/ng/api/ng_offset_mapping_builder.h" |
#include "core/layout/ng/inline/ng_inline_node.h" |
#include "core/style/ComputedStyle.h" |
#include "testing/gtest/include/gtest/gtest.h" |
@@ -19,6 +20,52 @@ static PassRefPtr<ComputedStyle> CreateWhitespaceStyle(EWhiteSpace whitespace) { |
return style.Release(); |
} |
+static unsigned MaskForCollapsedIndexes(const Vector<unsigned>& indexes) { |
+ unsigned mask = 0; |
+ for (unsigned index : indexes) |
+ mask ^= 1u << index; |
+ return mask; |
+} |
+ |
+class MockOffsetMappingBuilder final : public NGOffsetMappingBuilder { |
+ STACK_ALLOCATED(); |
+ |
+ public: |
+ MockOffsetMappingBuilder() = default; |
+ ~MockOffsetMappingBuilder() final = default; |
+ |
+ void AppendBijection(unsigned length) final { |
+ ASSERT_LT(0u, length); |
+ ASSERT_GE(32u, total_length_ + length); |
+ total_length_ += length; |
+ } |
+ |
+ void AppendCollapsed(unsigned length) final { |
+ ASSERT_LT(0u, length); |
+ ASSERT_GE(32u, total_length_ + length); |
+ mask_ |= ((1u << length) - 1) << total_length_; |
+ total_length_ += length; |
+ } |
+ |
+ void CollapseLastCharacter() final { |
+ ASSERT_NE((1u << total_length_) - 1, mask_); |
+ for (unsigned i = (1u << total_length_); i >>= 1;) { |
+ if (!(mask_ & i)) { |
+ mask_ ^= i; |
+ return; |
+ } |
+ } |
+ } |
+ |
+ unsigned GetMask() const { return mask_; } |
+ |
+ private: |
+ unsigned total_length_ = 0; |
+ unsigned mask_ = 0; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(MockOffsetMappingBuilder); |
+}; |
+ |
class NGInlineItemsBuilderTest : public ::testing::Test { |
protected: |
void SetUp() override { style_ = ComputedStyle::Create(); } |
@@ -29,11 +76,13 @@ class NGInlineItemsBuilderTest : public ::testing::Test { |
const String& TestAppend(const String inputs[], int size) { |
items_.clear(); |
- NGInlineItemsBuilder builder(&items_); |
+ MockOffsetMappingBuilder mapping_builder; |
+ NGInlineItemsBuilder builder(&items_, &mapping_builder); |
for (int i = 0; i < size; i++) |
builder.Append(inputs[i], style_.Get()); |
text_ = builder.ToString(); |
ValidateItems(); |
+ mask_ = mapping_builder.GetMask(); |
return text_; |
} |
@@ -67,169 +116,229 @@ class NGInlineItemsBuilderTest : public ::testing::Test { |
Vector<NGInlineItem> items_; |
String text_; |
+ unsigned mask_; |
RefPtr<ComputedStyle> style_; |
}; |
-#define TestWhitespaceValue(expected, input, whitespace) \ |
- SetWhiteSpace(whitespace); \ |
- EXPECT_EQ(expected, TestAppend(input)) << "white-space: " #whitespace; |
+#define TestWhitespaceValue(expected_text, expected_mask, input, whitespace) \ |
+ SetWhiteSpace(whitespace); \ |
+ EXPECT_EQ(expected_text, TestAppend(input)) << "white-space: " #whitespace; \ |
+ EXPECT_EQ(expected_mask, mask_); |
TEST_F(NGInlineItemsBuilderTest, CollapseSpaces) { |
String input("text text text text"); |
String collapsed("text text text text"); |
- TestWhitespaceValue(collapsed, input, EWhiteSpace::kNormal); |
- TestWhitespaceValue(collapsed, input, EWhiteSpace::kNowrap); |
- TestWhitespaceValue(collapsed, input, EWhiteSpace::kWebkitNowrap); |
- TestWhitespaceValue(collapsed, input, EWhiteSpace::kPreLine); |
- TestWhitespaceValue(input, input, EWhiteSpace::kPre); |
- TestWhitespaceValue(input, input, EWhiteSpace::kPreWrap); |
+ unsigned collapsed_mask = MaskForCollapsedIndexes({10, 16, 17}); |
+ TestWhitespaceValue(collapsed, collapsed_mask, input, EWhiteSpace::kNormal); |
+ TestWhitespaceValue(collapsed, collapsed_mask, input, EWhiteSpace::kNowrap); |
+ TestWhitespaceValue(collapsed, collapsed_mask, input, |
+ EWhiteSpace::kWebkitNowrap); |
+ TestWhitespaceValue(collapsed, collapsed_mask, input, EWhiteSpace::kPreLine); |
+ TestWhitespaceValue(input, 0u, input, EWhiteSpace::kPre); |
+ TestWhitespaceValue(input, 0u, input, EWhiteSpace::kPreWrap); |
} |
TEST_F(NGInlineItemsBuilderTest, CollapseTabs) { |
String input("text\ttext\t text \t text"); |
String collapsed("text text text text"); |
- TestWhitespaceValue(collapsed, input, EWhiteSpace::kNormal); |
- TestWhitespaceValue(collapsed, input, EWhiteSpace::kNowrap); |
- TestWhitespaceValue(collapsed, input, EWhiteSpace::kWebkitNowrap); |
- TestWhitespaceValue(collapsed, input, EWhiteSpace::kPreLine); |
- TestWhitespaceValue(input, input, EWhiteSpace::kPre); |
- TestWhitespaceValue(input, input, EWhiteSpace::kPreWrap); |
+ unsigned collapsed_mask = MaskForCollapsedIndexes({10, 16, 17}); |
+ TestWhitespaceValue(collapsed, collapsed_mask, input, EWhiteSpace::kNormal); |
+ TestWhitespaceValue(collapsed, collapsed_mask, input, EWhiteSpace::kNowrap); |
+ TestWhitespaceValue(collapsed, collapsed_mask, input, |
+ EWhiteSpace::kWebkitNowrap); |
+ TestWhitespaceValue(collapsed, collapsed_mask, input, EWhiteSpace::kPreLine); |
+ TestWhitespaceValue(input, 0u, input, EWhiteSpace::kPre); |
+ TestWhitespaceValue(input, 0u, input, EWhiteSpace::kPreWrap); |
} |
TEST_F(NGInlineItemsBuilderTest, CollapseNewLines) { |
String input("text\ntext \n text\n\ntext"); |
String collapsed("text text text text"); |
- TestWhitespaceValue(collapsed, input, EWhiteSpace::kNormal); |
- TestWhitespaceValue(collapsed, input, EWhiteSpace::kNowrap); |
- TestWhitespaceValue("text\ntext\ntext\n\ntext", input, EWhiteSpace::kPreLine); |
- TestWhitespaceValue(input, input, EWhiteSpace::kPre); |
- TestWhitespaceValue(input, input, EWhiteSpace::kPreWrap); |
+ unsigned collapsed_mask = MaskForCollapsedIndexes({10, 11, 17}); |
+ TestWhitespaceValue(collapsed, collapsed_mask, input, EWhiteSpace::kNormal); |
+ TestWhitespaceValue(collapsed, collapsed_mask, input, EWhiteSpace::kNowrap); |
+ TestWhitespaceValue("text\ntext\ntext\n\ntext", |
+ MaskForCollapsedIndexes({9, 11}), input, |
+ EWhiteSpace::kPreLine); |
+ TestWhitespaceValue(input, 0u, input, EWhiteSpace::kPre); |
+ TestWhitespaceValue(input, 0u, input, EWhiteSpace::kPreWrap); |
} |
TEST_F(NGInlineItemsBuilderTest, CollapseNewlinesAsSpaces) { |
EXPECT_EQ("text text", TestAppend("text\ntext")); |
+ EXPECT_EQ(0u, mask_); |
EXPECT_EQ("text text", TestAppend("text\n\ntext")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({5}), mask_); |
EXPECT_EQ("text text", TestAppend("text \n\n text")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({5, 6, 7}), mask_); |
EXPECT_EQ("text text", TestAppend("text \n \n text")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({5, 6, 7, 8}), mask_); |
} |
TEST_F(NGInlineItemsBuilderTest, CollapseAcrossElements) { |
EXPECT_EQ("text text", TestAppend("text ", " text")) |
<< "Spaces are collapsed even when across elements."; |
+ EXPECT_EQ(MaskForCollapsedIndexes({5}), mask_); |
} |
TEST_F(NGInlineItemsBuilderTest, CollapseLeadingSpaces) { |
EXPECT_EQ("text", TestAppend(" text")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0, 1}), mask_); |
EXPECT_EQ("text", TestAppend(" ", "text")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0}), mask_); |
EXPECT_EQ("text", TestAppend(" ", " text")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0, 1}), mask_); |
} |
TEST_F(NGInlineItemsBuilderTest, CollapseTrailingSpaces) { |
EXPECT_EQ("text", TestAppend("text ")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({4, 5}), mask_); |
EXPECT_EQ("text", TestAppend("text", " ")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({4}), mask_); |
EXPECT_EQ("text", TestAppend("text ", " ")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({4, 5}), mask_); |
} |
TEST_F(NGInlineItemsBuilderTest, CollapseAllSpaces) { |
EXPECT_EQ("", TestAppend(" ")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0, 1}), mask_); |
EXPECT_EQ("", TestAppend(" ", " ")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0, 1, 2, 3}), mask_); |
EXPECT_EQ("", TestAppend(" ", "\n")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0, 1, 2}), mask_); |
EXPECT_EQ("", TestAppend("\n", " ")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0, 1, 2}), mask_); |
} |
TEST_F(NGInlineItemsBuilderTest, CollapseLeadingNewlines) { |
EXPECT_EQ("text", TestAppend("\ntext")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0}), mask_); |
EXPECT_EQ("text", TestAppend("\n\ntext")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0, 1}), mask_); |
EXPECT_EQ("text", TestAppend("\n", "text")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0}), mask_); |
EXPECT_EQ("text", TestAppend("\n\n", "text")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0, 1}), mask_); |
EXPECT_EQ("text", TestAppend(" \n", "text")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0, 1}), mask_); |
EXPECT_EQ("text", TestAppend("\n", " text")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0, 1}), mask_); |
EXPECT_EQ("text", TestAppend("\n\n", " text")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0, 1, 2}), mask_); |
EXPECT_EQ("text", TestAppend(" \n", " text")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0, 1, 2}), mask_); |
EXPECT_EQ("text", TestAppend("\n", "\ntext")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0, 1}), mask_); |
EXPECT_EQ("text", TestAppend("\n\n", "\ntext")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0, 1, 2}), mask_); |
EXPECT_EQ("text", TestAppend(" \n", "\ntext")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({0, 1, 2}), mask_); |
} |
TEST_F(NGInlineItemsBuilderTest, CollapseTrailingNewlines) { |
EXPECT_EQ("text", TestAppend("text\n")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({4}), mask_); |
EXPECT_EQ("text", TestAppend("text", "\n")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({4}), mask_); |
EXPECT_EQ("text", TestAppend("text\n", "\n")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({4, 5}), mask_); |
EXPECT_EQ("text", TestAppend("text\n", " ")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({4, 5}), mask_); |
EXPECT_EQ("text", TestAppend("text ", "\n")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({4, 5}), mask_); |
} |
TEST_F(NGInlineItemsBuilderTest, CollapseBeforeNewlineAcrossElements) { |
EXPECT_EQ("text text", TestAppend("text ", "\ntext")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({5}), mask_); |
EXPECT_EQ("text text", TestAppend("text", " ", "\ntext")); |
+ EXPECT_EQ(MaskForCollapsedIndexes({5}), mask_); |
} |
TEST_F(NGInlineItemsBuilderTest, CollapseBeforeAndAfterNewline) { |
SetWhiteSpace(EWhiteSpace::kPreLine); |
EXPECT_EQ("text\ntext", TestAppend("text \n text")) |
<< "Spaces before and after newline are removed."; |
+ EXPECT_EQ(MaskForCollapsedIndexes({4, 5, 7, 8}), mask_); |
} |
TEST_F(NGInlineItemsBuilderTest, |
CollapsibleSpaceAfterNonCollapsibleSpaceAcrossElements) { |
- NGInlineItemsBuilder builder(&items_); |
+ MockOffsetMappingBuilder mapping_builder; |
+ NGInlineItemsBuilder builder(&items_, &mapping_builder); |
RefPtr<ComputedStyle> pre_wrap(CreateWhitespaceStyle(EWhiteSpace::kPreWrap)); |
builder.Append("text ", pre_wrap.Get()); |
builder.Append(" text", style_.Get()); |
EXPECT_EQ("text text", builder.ToString()) |
<< "The whitespace in constructions like '<span style=\"white-space: " |
"pre-wrap\">text <span><span> text</span>' does not collapse."; |
+ EXPECT_EQ(0u, mapping_builder.GetMask()); |
} |
TEST_F(NGInlineItemsBuilderTest, CollapseZeroWidthSpaces) { |
EXPECT_EQ(String(u"text\u200Btext"), TestAppend(u"text\u200B\ntext")) |
<< "Newline is removed if the character before is ZWS."; |
+ EXPECT_EQ(MaskForCollapsedIndexes({5}), mask_); |
EXPECT_EQ(String(u"text\u200Btext"), TestAppend(u"text\n\u200Btext")) |
<< "Newline is removed if the character after is ZWS."; |
+ EXPECT_EQ(MaskForCollapsedIndexes({4}), mask_); |
EXPECT_EQ(String(u"text\u200B\u200Btext"), |
TestAppend(u"text\u200B\n\u200Btext")) |
<< "Newline is removed if the character before/after is ZWS."; |
+ EXPECT_EQ(MaskForCollapsedIndexes({5}), mask_); |
EXPECT_EQ(String(u"text\u200Btext"), TestAppend(u"text\n", u"\u200Btext")) |
<< "Newline is removed if the character after across elements is ZWS."; |
+ EXPECT_EQ(MaskForCollapsedIndexes({4}), mask_); |
EXPECT_EQ(String(u"text\u200Btext"), TestAppend(u"text\u200B", u"\ntext")) |
<< "Newline is removed if the character before is ZWS even across " |
"elements."; |
+ EXPECT_EQ(MaskForCollapsedIndexes({5}), mask_); |
EXPECT_EQ(String(u"text\u200Btext"), TestAppend(u"text \n", u"\u200Btext")) |
<< "Collapsible space before newline does not affect the result."; |
+ EXPECT_EQ(MaskForCollapsedIndexes({4, 5}), mask_); |
EXPECT_EQ(String(u"text\u200Btext"), TestAppend(u"text\u200B\n", u" text")) |
<< "Collapsible space after newline is removed even when the " |
"newline was removed."; |
+ EXPECT_EQ(MaskForCollapsedIndexes({5, 6}), mask_); |
} |
TEST_F(NGInlineItemsBuilderTest, CollapseEastAsianWidth) { |
EXPECT_EQ(String(u"\u4E00\u4E00"), TestAppend(u"\u4E00\n\u4E00")) |
<< "Newline is removed when both sides are Wide."; |
+ EXPECT_EQ(MaskForCollapsedIndexes({1}), mask_); |
EXPECT_EQ(String(u"\u4E00 A"), TestAppend(u"\u4E00\nA")) |
<< "Newline is not removed when after is Narrow."; |
+ EXPECT_EQ(0u, mask_); |
EXPECT_EQ(String(u"A \u4E00"), TestAppend(u"A\n\u4E00")) |
<< "Newline is not removed when before is Narrow."; |
+ EXPECT_EQ(0u, mask_); |
EXPECT_EQ(String(u"\u4E00\u4E00"), TestAppend(u"\u4E00\n", u"\u4E00")) |
<< "Newline at the end of elements is removed when both sides are Wide."; |
+ EXPECT_EQ(MaskForCollapsedIndexes({1}), mask_); |
EXPECT_EQ(String(u"\u4E00\u4E00"), TestAppend(u"\u4E00", u"\n\u4E00")) |
<< "Newline at the beginning of elements is removed " |
"when both sides are Wide."; |
+ EXPECT_EQ(MaskForCollapsedIndexes({1}), mask_); |
} |
TEST_F(NGInlineItemsBuilderTest, CollapseAroundReplacedElement) { |
- NGInlineItemsBuilder builder(&items_); |
+ MockOffsetMappingBuilder mapping_builder; |
+ NGInlineItemsBuilder builder(&items_, &mapping_builder); |
builder.Append("Hello ", style_.Get()); |
builder.Append(NGInlineItem::kAtomicInline, kObjectReplacementCharacter); |
builder.Append(" World", style_.Get()); |
EXPECT_EQ(String(u"Hello \uFFFC World"), builder.ToString()); |
+ EXPECT_EQ(0u, mapping_builder.GetMask()); |
} |
TEST_F(NGInlineItemsBuilderTest, CollapseNewlineAfterObject) { |
- NGInlineItemsBuilder builder(&items_); |
+ MockOffsetMappingBuilder mapping_builder; |
+ NGInlineItemsBuilder builder(&items_, &mapping_builder); |
builder.Append(NGInlineItem::kAtomicInline, kObjectReplacementCharacter); |
builder.Append("\n", style_.Get()); |
builder.Append(NGInlineItem::kAtomicInline, kObjectReplacementCharacter); |
@@ -238,16 +347,19 @@ TEST_F(NGInlineItemsBuilderTest, CollapseNewlineAfterObject) { |
EXPECT_EQ(nullptr, items_[0].Style()); |
EXPECT_EQ(style_.Get(), items_[1].Style()); |
EXPECT_EQ(nullptr, items_[2].Style()); |
+ EXPECT_EQ(0u, mapping_builder.GetMask()); |
} |
TEST_F(NGInlineItemsBuilderTest, AppendEmptyString) { |
EXPECT_EQ("", TestAppend("")); |
+ EXPECT_EQ(0u, mask_); |
EXPECT_EQ(0u, items_.size()); |
} |
TEST_F(NGInlineItemsBuilderTest, NewLines) { |
SetWhiteSpace(EWhiteSpace::kPre); |
EXPECT_EQ("apple\norange\ngrape\n", TestAppend("apple\norange\ngrape\n")); |
+ EXPECT_EQ(0u, mask_); |
EXPECT_EQ(6u, items_.size()); |
EXPECT_EQ(NGInlineItem::kText, items_[0].Type()); |
EXPECT_EQ(NGInlineItem::kControl, items_[1].Type()); |
@@ -259,12 +371,14 @@ TEST_F(NGInlineItemsBuilderTest, NewLines) { |
TEST_F(NGInlineItemsBuilderTest, Empty) { |
Vector<NGInlineItem> items; |
- NGInlineItemsBuilder builder(&items); |
+ MockOffsetMappingBuilder mapping_builder; |
+ NGInlineItemsBuilder builder(&items, &mapping_builder); |
RefPtr<ComputedStyle> block_style(ComputedStyle::Create()); |
builder.EnterBlock(block_style.Get()); |
builder.ExitBlock(); |
EXPECT_EQ("", builder.ToString()); |
+ EXPECT_EQ(0u, mapping_builder.GetMask()); |
} |
TEST_F(NGInlineItemsBuilderTest, BidiBlockOverride) { |