blob: 5ae44d718f89bad2cb9cf2badc452ce62b56592b [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/editing/VisibleUnits.h"
#include <ostream> // NOLINT
#include "bindings/core/v8/V8BindingForTesting.h"
#include "core/dom/Text.h"
#include "core/editing/EditingTestBase.h"
#include "core/editing/VisiblePosition.h"
#include "core/html/TextControlElement.h"
#include "core/layout/LayoutTextFragment.h"
#include "core/layout/line/InlineTextBox.h"
namespace blink {
namespace {
PositionWithAffinity PositionWithAffinityInDOMTree(
Node& anchor,
int offset,
TextAffinity affinity = TextAffinity::kDownstream) {
return PositionWithAffinity(CanonicalPositionOf(Position(&anchor, offset)),
affinity);
}
VisiblePosition CreateVisiblePositionInDOMTree(
Node& anchor,
int offset,
TextAffinity affinity = TextAffinity::kDownstream) {
return CreateVisiblePosition(Position(&anchor, offset), affinity);
}
PositionInFlatTreeWithAffinity PositionWithAffinityInFlatTree(
Node& anchor,
int offset,
TextAffinity affinity = TextAffinity::kDownstream) {
return PositionInFlatTreeWithAffinity(
CanonicalPositionOf(PositionInFlatTree(&anchor, offset)), affinity);
}
VisiblePositionInFlatTree CreateVisiblePositionInFlatTree(
Node& anchor,
int offset,
TextAffinity affinity = TextAffinity::kDownstream) {
return CreateVisiblePosition(PositionInFlatTree(&anchor, offset), affinity);
}
} // namespace
std::ostream& operator<<(std::ostream& ostream,
const InlineBoxPosition& inline_box_position) {
if (!inline_box_position.inline_box)
return ostream << "null";
return ostream
<< inline_box_position.inline_box->GetLineLayoutItem().GetNode() << "@"
<< inline_box_position.offset_in_box;
}
class VisibleUnitsTest : public EditingTestBase {};
TEST_F(VisibleUnitsTest, absoluteCaretBoundsOf) {
const char* body_content =
"<p id='host'><b id='one'>11</b><b id='two'>22</b></p>";
const char* shadow_content =
"<div><content select=#two></content><content "
"select=#one></content></div>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Element* body = GetDocument().body();
Element* one = body->QuerySelector("#one");
IntRect bounds_in_dom_tree =
AbsoluteCaretBoundsOf(CreateVisiblePosition(Position(one, 0)));
IntRect bounds_in_flat_tree =
AbsoluteCaretBoundsOf(CreateVisiblePosition(PositionInFlatTree(one, 0)));
EXPECT_FALSE(bounds_in_dom_tree.IsEmpty());
EXPECT_EQ(bounds_in_dom_tree, bounds_in_flat_tree);
}
TEST_F(VisibleUnitsTest, caretMinOffset) {
const char* body_content = "<p id=one>one</p>";
SetBodyContent(body_content);
Element* one = GetDocument().getElementById("one");
EXPECT_EQ(0, CaretMinOffset(one->firstChild()));
}
TEST_F(VisibleUnitsTest, caretMinOffsetWithFirstLetter) {
const char* body_content =
"<style>#one:first-letter { font-size: 200%; }</style><p id=one>one</p>";
SetBodyContent(body_content);
Element* one = GetDocument().getElementById("one");
EXPECT_EQ(0, CaretMinOffset(one->firstChild()));
}
TEST_F(VisibleUnitsTest, characterAfter) {
const char* body_content =
"<p id='host'><b id='one'>1</b><b id='two'>22</b></p><b "
"id='three'>333</b>";
const char* shadow_content =
"<b id='four'>4444</b><content select=#two></content><content "
"select=#one></content><b id='five'>5555</b>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Element* one = GetDocument().getElementById("one");
Element* two = GetDocument().getElementById("two");
EXPECT_EQ('2', CharacterAfter(
CreateVisiblePositionInDOMTree(*one->firstChild(), 1)));
EXPECT_EQ('5', CharacterAfter(
CreateVisiblePositionInFlatTree(*one->firstChild(), 1)));
EXPECT_EQ(
0, CharacterAfter(CreateVisiblePositionInDOMTree(*two->firstChild(), 2)));
EXPECT_EQ('1', CharacterAfter(
CreateVisiblePositionInFlatTree(*two->firstChild(), 2)));
}
TEST_F(VisibleUnitsTest, canonicalPositionOfWithHTMLHtmlElement) {
const char* body_content =
"<html><div id=one contenteditable>1</div><span id=two "
"contenteditable=false>22</span><span id=three "
"contenteditable=false>333</span><span id=four "
"contenteditable=false>333</span></html>";
SetBodyContent(body_content);
Node* one = GetDocument().QuerySelector("#one");
Node* two = GetDocument().QuerySelector("#two");
Node* three = GetDocument().QuerySelector("#three");
Node* four = GetDocument().QuerySelector("#four");
Element* html = GetDocument().createElement("html");
// Move two, three and four into second html element.
html->AppendChild(two);
html->AppendChild(three);
html->AppendChild(four);
one->appendChild(html);
UpdateAllLifecyclePhases();
EXPECT_EQ(Position(),
CanonicalPositionOf(Position(GetDocument().documentElement(), 0)));
EXPECT_EQ(Position(one->firstChild(), 0),
CanonicalPositionOf(Position(one, 0)));
EXPECT_EQ(Position(one->firstChild(), 1),
CanonicalPositionOf(Position(one, 1)));
EXPECT_EQ(Position(one->firstChild(), 0),
CanonicalPositionOf(Position(one->firstChild(), 0)));
EXPECT_EQ(Position(one->firstChild(), 1),
CanonicalPositionOf(Position(one->firstChild(), 1)));
EXPECT_EQ(Position(html, 0), CanonicalPositionOf(Position(html, 0)));
EXPECT_EQ(Position(html, 1), CanonicalPositionOf(Position(html, 1)));
EXPECT_EQ(Position(html, 2), CanonicalPositionOf(Position(html, 2)));
EXPECT_EQ(Position(two->firstChild(), 0),
CanonicalPositionOf(Position(two, 0)));
EXPECT_EQ(Position(two->firstChild(), 2),
CanonicalPositionOf(Position(two, 1)));
}
// For http://crbug.com/695317
TEST_F(VisibleUnitsTest, canonicalPositionOfWithInputElement) {
SetBodyContent("<input>123");
Element* const input = GetDocument().QuerySelector("input");
EXPECT_EQ(Position::BeforeNode(*input),
CanonicalPositionOf(Position::FirstPositionInNode(
*GetDocument().documentElement())));
EXPECT_EQ(PositionInFlatTree::BeforeNode(*input),
CanonicalPositionOf(PositionInFlatTree::FirstPositionInNode(
*GetDocument().documentElement())));
}
TEST_F(VisibleUnitsTest, characterBefore) {
const char* body_content =
"<p id=host><b id=one>1</b><b id=two>22</b></p><b id=three>333</b>";
const char* shadow_content =
"<b id=four>4444</b><content select=#two></content><content "
"select=#one></content><b id=five>5555</b>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Node* one = GetDocument().getElementById("one")->firstChild();
Node* two = GetDocument().getElementById("two")->firstChild();
Node* five = shadow_root->getElementById("five")->firstChild();
EXPECT_EQ(0, CharacterBefore(CreateVisiblePositionInDOMTree(*one, 0)));
EXPECT_EQ('2', CharacterBefore(CreateVisiblePositionInFlatTree(*one, 0)));
EXPECT_EQ('1', CharacterBefore(CreateVisiblePositionInDOMTree(*one, 1)));
EXPECT_EQ('1', CharacterBefore(CreateVisiblePositionInFlatTree(*one, 1)));
EXPECT_EQ('1', CharacterBefore(CreateVisiblePositionInDOMTree(*two, 0)));
EXPECT_EQ('4', CharacterBefore(CreateVisiblePositionInFlatTree(*two, 0)));
EXPECT_EQ('4', CharacterBefore(CreateVisiblePositionInDOMTree(*five, 0)));
EXPECT_EQ('1', CharacterBefore(CreateVisiblePositionInFlatTree(*five, 0)));
}
TEST_F(VisibleUnitsTest, computeInlineBoxPositionBidiIsolate) {
// "|" is bidi-level 0, and "foo" and "bar" are bidi-level 2
SetBodyContent(
"|<span id=sample style='unicode-bidi: isolate;'>foo<br>bar</span>|");
Element* sample = GetDocument().getElementById("sample");
Node* text = sample->firstChild();
const InlineBoxPosition& actual =
ComputeInlineBoxPosition(Position(text, 0), TextAffinity::kDownstream);
EXPECT_EQ(ToLayoutText(text->GetLayoutObject())->FirstTextBox(),
actual.inline_box);
}
// http://crbug.com/716093
TEST_F(VisibleUnitsTest, ComputeInlineBoxPositionMixedEditable) {
SetBodyContent(
"<div contenteditable id=sample>abc<input contenteditable=false></div>");
Element* const sample = GetDocument().getElementById("sample");
const InlineBoxPosition& actual = ComputeInlineBoxPosition(
Position::LastPositionInNode(*sample), TextAffinity::kDownstream);
// Should not be in infinite-loop
EXPECT_EQ(nullptr, actual.inline_box);
EXPECT_EQ(0, actual.offset_in_box);
}
TEST_F(VisibleUnitsTest, endOfDocument) {
const char* body_content = "<a id=host><b id=one>1</b><b id=two>22</b></a>";
const char* shadow_content =
"<p><content select=#two></content></p><p><content "
"select=#one></content></p>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Element* one = GetDocument().getElementById("one");
Element* two = GetDocument().getElementById("two");
EXPECT_EQ(Position(two->firstChild(), 2),
EndOfDocument(CreateVisiblePositionInDOMTree(*one->firstChild(), 0))
.DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(one->firstChild(), 1),
EndOfDocument(CreateVisiblePositionInFlatTree(*one->firstChild(), 0))
.DeepEquivalent());
EXPECT_EQ(Position(two->firstChild(), 2),
EndOfDocument(CreateVisiblePositionInDOMTree(*two->firstChild(), 1))
.DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(one->firstChild(), 1),
EndOfDocument(CreateVisiblePositionInFlatTree(*two->firstChild(), 1))
.DeepEquivalent());
}
TEST_F(VisibleUnitsTest, endOfLine) {
const char* body_content =
"<a id=host><b id=one>11</b><b id=two>22</b></a><i id=three>333</i><i "
"id=four>4444</i><br>";
const char* shadow_content =
"<div><u id=five>55555</u><content select=#two></content><br><u "
"id=six>666666</u><br><content select=#one></content><u "
"id=seven>7777777</u></div>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Node* one = GetDocument().getElementById("one")->firstChild();
Node* two = GetDocument().getElementById("two")->firstChild();
Node* three = GetDocument().getElementById("three")->firstChild();
Node* four = GetDocument().getElementById("four")->firstChild();
Node* five = shadow_root->getElementById("five")->firstChild();
Node* six = shadow_root->getElementById("six")->firstChild();
Node* seven = shadow_root->getElementById("seven")->firstChild();
EXPECT_EQ(
Position(seven, 7),
EndOfLine(CreateVisiblePositionInDOMTree(*one, 0)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(seven, 7),
EndOfLine(CreateVisiblePositionInFlatTree(*one, 0)).DeepEquivalent());
EXPECT_EQ(
Position(seven, 7),
EndOfLine(CreateVisiblePositionInDOMTree(*one, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(seven, 7),
EndOfLine(CreateVisiblePositionInFlatTree(*one, 1)).DeepEquivalent());
EXPECT_EQ(
Position(seven, 7),
EndOfLine(CreateVisiblePositionInDOMTree(*two, 0)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(two, 2),
EndOfLine(CreateVisiblePositionInFlatTree(*two, 0)).DeepEquivalent());
// TODO(yosin) endOfLine(two, 1) -> (five, 5) is a broken result. We keep
// it as a marker for future change.
EXPECT_EQ(
Position(five, 5),
EndOfLine(CreateVisiblePositionInDOMTree(*two, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(two, 2),
EndOfLine(CreateVisiblePositionInFlatTree(*two, 1)).DeepEquivalent());
EXPECT_EQ(
Position(five, 5),
EndOfLine(CreateVisiblePositionInDOMTree(*three, 0)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(four, 4),
EndOfLine(CreateVisiblePositionInFlatTree(*three, 1)).DeepEquivalent());
EXPECT_EQ(
Position(four, 4),
EndOfLine(CreateVisiblePositionInDOMTree(*four, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(four, 4),
EndOfLine(CreateVisiblePositionInFlatTree(*four, 1)).DeepEquivalent());
EXPECT_EQ(
Position(five, 5),
EndOfLine(CreateVisiblePositionInDOMTree(*five, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(two, 2),
EndOfLine(CreateVisiblePositionInFlatTree(*five, 1)).DeepEquivalent());
EXPECT_EQ(
Position(six, 6),
EndOfLine(CreateVisiblePositionInDOMTree(*six, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(six, 6),
EndOfLine(CreateVisiblePositionInFlatTree(*six, 1)).DeepEquivalent());
EXPECT_EQ(
Position(seven, 7),
EndOfLine(CreateVisiblePositionInDOMTree(*seven, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(seven, 7),
EndOfLine(CreateVisiblePositionInFlatTree(*seven, 1)).DeepEquivalent());
}
TEST_F(VisibleUnitsTest, endOfParagraphFirstLetter) {
SetBodyContent(
"<style>div::first-letter { color: red }</style><div "
"id=sample>1ab\nde</div>");
Node* sample = GetDocument().getElementById("sample");
Node* text = sample->firstChild();
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 0))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 1))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 2))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 3))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 4))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 5))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 6))
.DeepEquivalent());
}
TEST_F(VisibleUnitsTest, endOfParagraphFirstLetterPre) {
SetBodyContent(
"<style>pre::first-letter { color: red }</style><pre "
"id=sample>1ab\nde</pre>");
Node* sample = GetDocument().getElementById("sample");
Node* text = sample->firstChild();
EXPECT_EQ(Position(text, 3),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 0))
.DeepEquivalent());
EXPECT_EQ(Position(text, 3),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 1))
.DeepEquivalent());
EXPECT_EQ(Position(text, 3),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 2))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 3))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 4))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 5))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 6))
.DeepEquivalent());
}
TEST_F(VisibleUnitsTest, endOfParagraphShadow) {
const char* body_content =
"<a id=host><b id=one>1</b><b id=two>22</b></a><b id=three>333</b>";
const char* shadow_content =
"<p><content select=#two></content></p><p><content "
"select=#one></content></p>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Element* one = GetDocument().getElementById("one");
Element* two = GetDocument().getElementById("two");
Element* three = GetDocument().getElementById("three");
EXPECT_EQ(
Position(three->firstChild(), 3),
EndOfParagraph(CreateVisiblePositionInDOMTree(*one->firstChild(), 1))
.DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(one->firstChild(), 1),
EndOfParagraph(CreateVisiblePositionInFlatTree(*one->firstChild(), 1))
.DeepEquivalent());
EXPECT_EQ(
Position(three->firstChild(), 3),
EndOfParagraph(CreateVisiblePositionInDOMTree(*two->firstChild(), 2))
.DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(two->firstChild(), 2),
EndOfParagraph(CreateVisiblePositionInFlatTree(*two->firstChild(), 2))
.DeepEquivalent());
}
TEST_F(VisibleUnitsTest, endOfParagraphSimple) {
SetBodyContent("<div id=sample>1ab\nde</div>");
Node* sample = GetDocument().getElementById("sample");
Node* text = sample->firstChild();
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 0))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 1))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 2))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 3))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 4))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 5))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 6))
.DeepEquivalent());
}
TEST_F(VisibleUnitsTest, endOfParagraphSimplePre) {
SetBodyContent("<pre id=sample>1ab\nde</pre>");
Node* sample = GetDocument().getElementById("sample");
Node* text = sample->firstChild();
EXPECT_EQ(Position(text, 3),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 0))
.DeepEquivalent());
EXPECT_EQ(Position(text, 3),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 1))
.DeepEquivalent());
EXPECT_EQ(Position(text, 3),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 2))
.DeepEquivalent());
EXPECT_EQ(Position(text, 3),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 3))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 4))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 5))
.DeepEquivalent());
EXPECT_EQ(Position(text, 6),
EndOfParagraph(CreateVisiblePositionInDOMTree(*text, 6))
.DeepEquivalent());
}
TEST_F(VisibleUnitsTest, endOfSentence) {
const char* body_content = "<a id=host><b id=one>1</b><b id=two>22</b></a>";
const char* shadow_content =
"<p><i id=three>333</i> <content select=#two></content> <content "
"select=#one></content> <i id=four>4444</i></p>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Node* one = GetDocument().getElementById("one")->firstChild();
Node* two = GetDocument().getElementById("two")->firstChild();
Node* three = shadow_root->getElementById("three")->firstChild();
Node* four = shadow_root->getElementById("four")->firstChild();
EXPECT_EQ(
Position(two, 2),
EndOfSentence(CreateVisiblePositionInDOMTree(*one, 0)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(four, 4),
EndOfSentence(CreateVisiblePositionInFlatTree(*one, 0)).DeepEquivalent());
EXPECT_EQ(
Position(two, 2),
EndOfSentence(CreateVisiblePositionInDOMTree(*one, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(four, 4),
EndOfSentence(CreateVisiblePositionInFlatTree(*one, 1)).DeepEquivalent());
EXPECT_EQ(
Position(two, 2),
EndOfSentence(CreateVisiblePositionInDOMTree(*two, 0)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(four, 4),
EndOfSentence(CreateVisiblePositionInFlatTree(*two, 0)).DeepEquivalent());
EXPECT_EQ(
Position(two, 2),
EndOfSentence(CreateVisiblePositionInDOMTree(*two, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(four, 4),
EndOfSentence(CreateVisiblePositionInFlatTree(*two, 1)).DeepEquivalent());
EXPECT_EQ(Position(four, 4),
EndOfSentence(CreateVisiblePositionInDOMTree(*three, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(four, 4),
EndOfSentence(CreateVisiblePositionInFlatTree(*three, 1))
.DeepEquivalent());
EXPECT_EQ(
Position(four, 4),
EndOfSentence(CreateVisiblePositionInDOMTree(*four, 1)).DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(four, 4),
EndOfSentence(CreateVisiblePositionInFlatTree(*four, 1))
.DeepEquivalent());
}
TEST_F(VisibleUnitsTest, endOfWord) {
const char* body_content =
"<a id=host><b id=one>1</b> <b id=two>22</b></a><i id=three>333</i>";
const char* shadow_content =
"<p><u id=four>44444</u><content select=#two></content><span id=space> "
"</span><content select=#one></content><u id=five>55555</u></p>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Node* one = GetDocument().getElementById("one")->firstChild();
Node* two = GetDocument().getElementById("two")->firstChild();
Node* three = GetDocument().getElementById("three")->firstChild();
Node* four = shadow_root->getElementById("four")->firstChild();
Node* five = shadow_root->getElementById("five")->firstChild();
EXPECT_EQ(
Position(three, 3),
EndOfWord(CreateVisiblePositionInDOMTree(*one, 0)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(five, 5),
EndOfWord(CreateVisiblePositionInFlatTree(*one, 0)).DeepEquivalent());
EXPECT_EQ(
Position(three, 3),
EndOfWord(CreateVisiblePositionInDOMTree(*one, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(five, 5),
EndOfWord(CreateVisiblePositionInFlatTree(*one, 1)).DeepEquivalent());
EXPECT_EQ(
Position(three, 3),
EndOfWord(CreateVisiblePositionInDOMTree(*two, 0)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(two, 2),
EndOfWord(CreateVisiblePositionInFlatTree(*two, 0)).DeepEquivalent());
EXPECT_EQ(
Position(three, 3),
EndOfWord(CreateVisiblePositionInDOMTree(*two, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(two, 2),
EndOfWord(CreateVisiblePositionInFlatTree(*two, 1)).DeepEquivalent());
EXPECT_EQ(
Position(three, 3),
EndOfWord(CreateVisiblePositionInDOMTree(*three, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(three, 3),
EndOfWord(CreateVisiblePositionInFlatTree(*three, 1)).DeepEquivalent());
EXPECT_EQ(
Position(four, 5),
EndOfWord(CreateVisiblePositionInDOMTree(*four, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(two, 2),
EndOfWord(CreateVisiblePositionInFlatTree(*four, 1)).DeepEquivalent());
EXPECT_EQ(
Position(five, 5),
EndOfWord(CreateVisiblePositionInDOMTree(*five, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(five, 5),
EndOfWord(CreateVisiblePositionInFlatTree(*five, 1)).DeepEquivalent());
}
TEST_F(VisibleUnitsTest, isEndOfEditableOrNonEditableContent) {
const char* body_content =
"<a id=host><b id=one contenteditable>1</b><b id=two>22</b></a>";
const char* shadow_content =
"<content select=#two></content></p><p><content select=#one></content>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Element* one = GetDocument().getElementById("one");
Element* two = GetDocument().getElementById("two");
EXPECT_FALSE(IsEndOfEditableOrNonEditableContent(
CreateVisiblePositionInDOMTree(*one->firstChild(), 1)));
EXPECT_TRUE(IsEndOfEditableOrNonEditableContent(
CreateVisiblePositionInFlatTree(*one->firstChild(), 1)));
EXPECT_TRUE(IsEndOfEditableOrNonEditableContent(
CreateVisiblePositionInDOMTree(*two->firstChild(), 2)));
EXPECT_FALSE(IsEndOfEditableOrNonEditableContent(
CreateVisiblePositionInFlatTree(*two->firstChild(), 2)));
}
TEST_F(VisibleUnitsTest, isEndOfEditableOrNonEditableContentWithInput) {
const char* body_content = "<input id=sample value=ab>cde";
SetBodyContent(body_content);
Node* text = ToTextControlElement(GetDocument().getElementById("sample"))
->InnerEditorElement()
->firstChild();
EXPECT_FALSE(IsEndOfEditableOrNonEditableContent(
CreateVisiblePositionInDOMTree(*text, 0)));
EXPECT_FALSE(IsEndOfEditableOrNonEditableContent(
CreateVisiblePositionInFlatTree(*text, 0)));
EXPECT_FALSE(IsEndOfEditableOrNonEditableContent(
CreateVisiblePositionInDOMTree(*text, 1)));
EXPECT_FALSE(IsEndOfEditableOrNonEditableContent(
CreateVisiblePositionInFlatTree(*text, 1)));
EXPECT_TRUE(IsEndOfEditableOrNonEditableContent(
CreateVisiblePositionInDOMTree(*text, 2)));
EXPECT_TRUE(IsEndOfEditableOrNonEditableContent(
CreateVisiblePositionInFlatTree(*text, 2)));
}
TEST_F(VisibleUnitsTest, isEndOfLine) {
const char* body_content =
"<a id=host><b id=one>11</b><b id=two>22</b></a><i id=three>333</i><i "
"id=four>4444</i><br>";
const char* shadow_content =
"<div><u id=five>55555</u><content select=#two></content><br><u "
"id=six>666666</u><br><content select=#one></content><u "
"id=seven>7777777</u></div>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Node* one = GetDocument().getElementById("one")->firstChild();
Node* two = GetDocument().getElementById("two")->firstChild();
Node* three = GetDocument().getElementById("three")->firstChild();
Node* four = GetDocument().getElementById("four")->firstChild();
Node* five = shadow_root->getElementById("five")->firstChild();
Node* six = shadow_root->getElementById("six")->firstChild();
Node* seven = shadow_root->getElementById("seven")->firstChild();
EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInDOMTree(*one, 0)));
EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInFlatTree(*one, 0)));
EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInDOMTree(*one, 1)));
EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInFlatTree(*one, 1)));
EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInDOMTree(*two, 2)));
EXPECT_TRUE(IsEndOfLine(CreateVisiblePositionInFlatTree(*two, 2)));
EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInDOMTree(*three, 3)));
EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInFlatTree(*three, 3)));
EXPECT_TRUE(IsEndOfLine(CreateVisiblePositionInDOMTree(*four, 4)));
EXPECT_TRUE(IsEndOfLine(CreateVisiblePositionInFlatTree(*four, 4)));
EXPECT_TRUE(IsEndOfLine(CreateVisiblePositionInDOMTree(*five, 5)));
EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInFlatTree(*five, 5)));
EXPECT_TRUE(IsEndOfLine(CreateVisiblePositionInDOMTree(*six, 6)));
EXPECT_TRUE(IsEndOfLine(CreateVisiblePositionInFlatTree(*six, 6)));
EXPECT_TRUE(IsEndOfLine(CreateVisiblePositionInDOMTree(*seven, 7)));
EXPECT_TRUE(IsEndOfLine(CreateVisiblePositionInFlatTree(*seven, 7)));
}
TEST_F(VisibleUnitsTest, isLogicalEndOfLine) {
const char* body_content =
"<a id=host><b id=one>11</b><b id=two>22</b></a><i id=three>333</i><i "
"id=four>4444</i><br>";
const char* shadow_content =
"<div><u id=five>55555</u><content select=#two></content><br><u "
"id=six>666666</u><br><content select=#one></content><u "
"id=seven>7777777</u></div>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Node* one = GetDocument().getElementById("one")->firstChild();
Node* two = GetDocument().getElementById("two")->firstChild();
Node* three = GetDocument().getElementById("three")->firstChild();
Node* four = GetDocument().getElementById("four")->firstChild();
Node* five = shadow_root->getElementById("five")->firstChild();
Node* six = shadow_root->getElementById("six")->firstChild();
Node* seven = shadow_root->getElementById("seven")->firstChild();
EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*one, 0)));
EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInFlatTree(*one, 0)));
EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*one, 1)));
EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInFlatTree(*one, 1)));
EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*two, 2)));
EXPECT_TRUE(IsLogicalEndOfLine(CreateVisiblePositionInFlatTree(*two, 2)));
EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*three, 3)));
EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInFlatTree(*three, 3)));
EXPECT_TRUE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*four, 4)));
EXPECT_TRUE(IsLogicalEndOfLine(CreateVisiblePositionInFlatTree(*four, 4)));
EXPECT_TRUE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*five, 5)));
EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInFlatTree(*five, 5)));
EXPECT_TRUE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*six, 6)));
EXPECT_TRUE(IsLogicalEndOfLine(CreateVisiblePositionInFlatTree(*six, 6)));
EXPECT_TRUE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*seven, 7)));
EXPECT_TRUE(IsLogicalEndOfLine(CreateVisiblePositionInFlatTree(*seven, 7)));
}
TEST_F(VisibleUnitsTest, inSameLine) {
const char* body_content =
"<p id='host'>00<b id='one'>11</b><b id='two'>22</b>33</p>";
const char* shadow_content =
"<div><span id='s4'>44</span><content select=#two></content><br><span "
"id='s5'>55</span><br><content select=#one></content><span "
"id='s6'>66</span></div>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Element* body = GetDocument().body();
Element* one = body->QuerySelector("#one");
Element* two = body->QuerySelector("#two");
Element* four = shadow_root->QuerySelector("#s4");
Element* five = shadow_root->QuerySelector("#s5");
EXPECT_TRUE(InSameLine(PositionWithAffinityInDOMTree(*one, 0),
PositionWithAffinityInDOMTree(*two, 0)));
EXPECT_TRUE(InSameLine(PositionWithAffinityInDOMTree(*one->firstChild(), 0),
PositionWithAffinityInDOMTree(*two->firstChild(), 0)));
EXPECT_FALSE(
InSameLine(PositionWithAffinityInDOMTree(*one->firstChild(), 0),
PositionWithAffinityInDOMTree(*five->firstChild(), 0)));
EXPECT_FALSE(
InSameLine(PositionWithAffinityInDOMTree(*two->firstChild(), 0),
PositionWithAffinityInDOMTree(*four->firstChild(), 0)));
EXPECT_TRUE(InSameLine(CreateVisiblePositionInDOMTree(*one, 0),
CreateVisiblePositionInDOMTree(*two, 0)));
EXPECT_TRUE(
InSameLine(CreateVisiblePositionInDOMTree(*one->firstChild(), 0),
CreateVisiblePositionInDOMTree(*two->firstChild(), 0)));
EXPECT_FALSE(
InSameLine(CreateVisiblePositionInDOMTree(*one->firstChild(), 0),
CreateVisiblePositionInDOMTree(*five->firstChild(), 0)));
EXPECT_FALSE(
InSameLine(CreateVisiblePositionInDOMTree(*two->firstChild(), 0),
CreateVisiblePositionInDOMTree(*four->firstChild(), 0)));
EXPECT_FALSE(InSameLine(PositionWithAffinityInFlatTree(*one, 0),
PositionWithAffinityInFlatTree(*two, 0)));
EXPECT_FALSE(
InSameLine(PositionWithAffinityInFlatTree(*one->firstChild(), 0),
PositionWithAffinityInFlatTree(*two->firstChild(), 0)));
EXPECT_FALSE(
InSameLine(PositionWithAffinityInFlatTree(*one->firstChild(), 0),
PositionWithAffinityInFlatTree(*five->firstChild(), 0)));
EXPECT_TRUE(
InSameLine(PositionWithAffinityInFlatTree(*two->firstChild(), 0),
PositionWithAffinityInFlatTree(*four->firstChild(), 0)));
EXPECT_FALSE(InSameLine(CreateVisiblePositionInFlatTree(*one, 0),
CreateVisiblePositionInFlatTree(*two, 0)));
EXPECT_FALSE(
InSameLine(CreateVisiblePositionInFlatTree(*one->firstChild(), 0),
CreateVisiblePositionInFlatTree(*two->firstChild(), 0)));
EXPECT_FALSE(
InSameLine(CreateVisiblePositionInFlatTree(*one->firstChild(), 0),
CreateVisiblePositionInFlatTree(*five->firstChild(), 0)));
EXPECT_TRUE(
InSameLine(CreateVisiblePositionInFlatTree(*two->firstChild(), 0),
CreateVisiblePositionInFlatTree(*four->firstChild(), 0)));
}
TEST_F(VisibleUnitsTest, isEndOfParagraph) {
const char* body_content =
"<a id=host><b id=one>1</b><b id=two>22</b></a><b id=three>333</b>";
const char* shadow_content =
"<p><content select=#two></content></p><p><content "
"select=#one></content></p>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Node* one = GetDocument().getElementById("one")->firstChild();
Node* two = GetDocument().getElementById("two")->firstChild();
Node* three = GetDocument().getElementById("three")->firstChild();
EXPECT_FALSE(IsEndOfParagraph(CreateVisiblePositionInDOMTree(*one, 0)));
EXPECT_FALSE(IsEndOfParagraph(CreateVisiblePositionInFlatTree(*one, 0)));
EXPECT_FALSE(IsEndOfParagraph(CreateVisiblePositionInDOMTree(*one, 1)));
EXPECT_TRUE(IsEndOfParagraph(CreateVisiblePositionInFlatTree(*one, 1)));
EXPECT_FALSE(IsEndOfParagraph(CreateVisiblePositionInDOMTree(*two, 2)));
EXPECT_TRUE(IsEndOfParagraph(CreateVisiblePositionInFlatTree(*two, 2)));
EXPECT_FALSE(IsEndOfParagraph(CreateVisiblePositionInDOMTree(*three, 0)));
EXPECT_FALSE(IsEndOfParagraph(CreateVisiblePositionInFlatTree(*three, 0)));
EXPECT_TRUE(IsEndOfParagraph(CreateVisiblePositionInDOMTree(*three, 3)));
EXPECT_TRUE(IsEndOfParagraph(CreateVisiblePositionInFlatTree(*three, 3)));
}
TEST_F(VisibleUnitsTest, isStartOfLine) {
const char* body_content =
"<a id=host><b id=one>11</b><b id=two>22</b></a><i id=three>333</i><i "
"id=four>4444</i><br>";
const char* shadow_content =
"<div><u id=five>55555</u><content select=#two></content><br><u "
"id=six>666666</u><br><content select=#one></content><u "
"id=seven>7777777</u></div>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Node* one = GetDocument().getElementById("one")->firstChild();
Node* two = GetDocument().getElementById("two")->firstChild();
Node* three = GetDocument().getElementById("three")->firstChild();
Node* four = GetDocument().getElementById("four")->firstChild();
Node* five = shadow_root->getElementById("five")->firstChild();
Node* six = shadow_root->getElementById("six")->firstChild();
Node* seven = shadow_root->getElementById("seven")->firstChild();
EXPECT_TRUE(IsStartOfLine(CreateVisiblePositionInDOMTree(*one, 0)));
EXPECT_TRUE(IsStartOfLine(CreateVisiblePositionInFlatTree(*one, 0)));
EXPECT_FALSE(IsStartOfLine(CreateVisiblePositionInDOMTree(*one, 1)));
EXPECT_FALSE(IsStartOfLine(CreateVisiblePositionInFlatTree(*one, 1)));
EXPECT_FALSE(IsStartOfLine(CreateVisiblePositionInDOMTree(*two, 0)));
EXPECT_FALSE(IsStartOfLine(CreateVisiblePositionInFlatTree(*two, 0)));
EXPECT_FALSE(IsStartOfLine(CreateVisiblePositionInDOMTree(*three, 0)));
EXPECT_TRUE(IsStartOfLine(CreateVisiblePositionInFlatTree(*three, 0)));
EXPECT_FALSE(IsStartOfLine(CreateVisiblePositionInDOMTree(*four, 0)));
EXPECT_FALSE(IsStartOfLine(CreateVisiblePositionInFlatTree(*four, 0)));
EXPECT_TRUE(IsStartOfLine(CreateVisiblePositionInDOMTree(*five, 0)));
EXPECT_TRUE(IsStartOfLine(CreateVisiblePositionInFlatTree(*five, 0)));
EXPECT_TRUE(IsStartOfLine(CreateVisiblePositionInDOMTree(*six, 0)));
EXPECT_TRUE(IsStartOfLine(CreateVisiblePositionInFlatTree(*six, 0)));
EXPECT_FALSE(IsStartOfLine(CreateVisiblePositionInDOMTree(*seven, 0)));
EXPECT_FALSE(IsStartOfLine(CreateVisiblePositionInFlatTree(*seven, 0)));
}
TEST_F(VisibleUnitsTest, isStartOfParagraph) {
const char* body_content =
"<b id=zero>0</b><a id=host><b id=one>1</b><b id=two>22</b></a><b "
"id=three>333</b>";
const char* shadow_content =
"<p><content select=#two></content></p><p><content "
"select=#one></content></p>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Node* zero = GetDocument().getElementById("zero")->firstChild();
Node* one = GetDocument().getElementById("one")->firstChild();
Node* two = GetDocument().getElementById("two")->firstChild();
Node* three = GetDocument().getElementById("three")->firstChild();
EXPECT_TRUE(IsStartOfParagraph(CreateVisiblePositionInDOMTree(*zero, 0)));
EXPECT_TRUE(IsStartOfParagraph(CreateVisiblePositionInFlatTree(*zero, 0)));
EXPECT_FALSE(IsStartOfParagraph(CreateVisiblePositionInDOMTree(*one, 0)));
EXPECT_TRUE(IsStartOfParagraph(CreateVisiblePositionInFlatTree(*one, 0)));
EXPECT_FALSE(IsStartOfParagraph(CreateVisiblePositionInDOMTree(*one, 1)));
EXPECT_FALSE(IsStartOfParagraph(CreateVisiblePositionInFlatTree(*one, 1)));
EXPECT_FALSE(IsStartOfParagraph(CreateVisiblePositionInDOMTree(*two, 0)));
EXPECT_TRUE(IsStartOfParagraph(CreateVisiblePositionInFlatTree(*two, 0)));
EXPECT_FALSE(IsStartOfParagraph(CreateVisiblePositionInDOMTree(*three, 0)));
EXPECT_TRUE(IsStartOfParagraph(CreateVisiblePositionInFlatTree(*three, 0)));
}
TEST_F(VisibleUnitsTest, isVisuallyEquivalentCandidateWithHTMLHtmlElement) {
const char* body_content =
"<html><div id=one contenteditable>1</div><span id=two "
"contenteditable=false>22</span><span id=three "
"contenteditable=false>333</span><span id=four "
"contenteditable=false>333</span></html>";
SetBodyContent(body_content);
Node* one = GetDocument().QuerySelector("#one");
Node* two = GetDocument().QuerySelector("#two");
Node* three = GetDocument().QuerySelector("#three");
Node* four = GetDocument().QuerySelector("#four");
Element* html = GetDocument().createElement("html");
// Move two, three and four into second html element.
html->AppendChild(two);
html->AppendChild(three);
html->AppendChild(four);
one->appendChild(html);
UpdateAllLifecyclePhases();
EXPECT_FALSE(IsVisuallyEquivalentCandidate(
Position(GetDocument().documentElement(), 0)));
EXPECT_FALSE(IsVisuallyEquivalentCandidate(Position(one, 0)));
EXPECT_FALSE(IsVisuallyEquivalentCandidate(Position(one, 1)));
EXPECT_TRUE(IsVisuallyEquivalentCandidate(Position(one->firstChild(), 0)));
EXPECT_TRUE(IsVisuallyEquivalentCandidate(Position(one->firstChild(), 1)));
EXPECT_TRUE(IsVisuallyEquivalentCandidate(Position(html, 0)));
EXPECT_TRUE(IsVisuallyEquivalentCandidate(Position(html, 1)));
EXPECT_TRUE(IsVisuallyEquivalentCandidate(Position(html, 2)));
EXPECT_FALSE(IsVisuallyEquivalentCandidate(Position(two, 0)));
EXPECT_FALSE(IsVisuallyEquivalentCandidate(Position(two, 1)));
}
TEST_F(VisibleUnitsTest, isVisuallyEquivalentCandidateWithDocument) {
UpdateAllLifecyclePhases();
EXPECT_FALSE(IsVisuallyEquivalentCandidate(Position(&GetDocument(), 0)));
}
TEST_F(VisibleUnitsTest, localCaretRectOfPosition) {
const char* body_content =
"<p id='host'><b id='one'>1</b></p><b id='two'>22</b>";
const char* shadow_content =
"<b id='two'>22</b><content select=#one></content><b id='three'>333</b>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Element* one = GetDocument().getElementById("one");
const LocalCaretRect& caret_rect_from_dom_tree =
LocalCaretRectOfPosition(Position(one->firstChild(), 0));
const LocalCaretRect& caret_rect_from_flat_tree =
LocalCaretRectOfPosition(PositionInFlatTree(one->firstChild(), 0));
EXPECT_FALSE(caret_rect_from_dom_tree.IsEmpty());
EXPECT_EQ(caret_rect_from_dom_tree.layout_object,
caret_rect_from_flat_tree.layout_object);
EXPECT_EQ(caret_rect_from_dom_tree.rect, caret_rect_from_flat_tree.rect);
}
TEST_F(VisibleUnitsTest, logicalEndOfLine) {
const char* body_content =
"<a id=host><b id=one>11</b><b id=two>22</b></a><i id=three>333</i><i "
"id=four>4444</i><br>";
const char* shadow_content =
"<div><u id=five>55555</u><content select=#two></content><br><u "
"id=six>666666</u><br><content select=#one></content><u "
"id=seven>7777777</u></div>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Node* one = GetDocument().getElementById("one")->firstChild();
Node* two = GetDocument().getElementById("two")->firstChild();
Node* three = GetDocument().getElementById("three")->firstChild();
Node* four = GetDocument().getElementById("four")->firstChild();
Node* five = shadow_root->getElementById("five")->firstChild();
Node* six = shadow_root->getElementById("six")->firstChild();
Node* seven = shadow_root->getElementById("seven")->firstChild();
EXPECT_EQ(Position(seven, 7),
LogicalEndOfLine(CreateVisiblePositionInDOMTree(*one, 0))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(seven, 7),
LogicalEndOfLine(CreateVisiblePositionInFlatTree(*one, 0))
.DeepEquivalent());
EXPECT_EQ(Position(seven, 7),
LogicalEndOfLine(CreateVisiblePositionInDOMTree(*one, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(seven, 7),
LogicalEndOfLine(CreateVisiblePositionInFlatTree(*one, 1))
.DeepEquivalent());
EXPECT_EQ(Position(seven, 7),
LogicalEndOfLine(CreateVisiblePositionInDOMTree(*two, 0))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(two, 2),
LogicalEndOfLine(CreateVisiblePositionInFlatTree(*two, 0))
.DeepEquivalent());
// TODO(yosin) logicalEndOfLine(two, 1) -> (five, 5) is a broken result. We
// keep it as a marker for future change.
EXPECT_EQ(Position(five, 5),
LogicalEndOfLine(CreateVisiblePositionInDOMTree(*two, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(two, 2),
LogicalEndOfLine(CreateVisiblePositionInFlatTree(*two, 1))
.DeepEquivalent());
EXPECT_EQ(Position(five, 5),
LogicalEndOfLine(CreateVisiblePositionInDOMTree(*three, 0))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(four, 4),
LogicalEndOfLine(CreateVisiblePositionInFlatTree(*three, 1))
.DeepEquivalent());
EXPECT_EQ(Position(four, 4),
LogicalEndOfLine(CreateVisiblePositionInDOMTree(*four, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(four, 4),
LogicalEndOfLine(CreateVisiblePositionInFlatTree(*four, 1))
.DeepEquivalent());
EXPECT_EQ(Position(five, 5),
LogicalEndOfLine(CreateVisiblePositionInDOMTree(*five, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(two, 2),
LogicalEndOfLine(CreateVisiblePositionInFlatTree(*five, 1))
.DeepEquivalent());
EXPECT_EQ(Position(six, 6),
LogicalEndOfLine(CreateVisiblePositionInDOMTree(*six, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(six, 6),
LogicalEndOfLine(CreateVisiblePositionInFlatTree(*six, 1))
.DeepEquivalent());
EXPECT_EQ(Position(seven, 7),
LogicalEndOfLine(CreateVisiblePositionInDOMTree(*seven, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(seven, 7),
LogicalEndOfLine(CreateVisiblePositionInFlatTree(*seven, 1))
.DeepEquivalent());
}
TEST_F(VisibleUnitsTest, logicalStartOfLine) {
const char* body_content =
"<a id=host><b id=one>11</b><b id=two>22</b></a><i id=three>333</i><i "
"id=four>4444</i><br>";
const char* shadow_content =
"<div><u id=five>55555</u><content select=#two></content><br><u "
"id=six>666666</u><br><content select=#one></content><u "
"id=seven>7777777</u></div>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Node* one = GetDocument().getElementById("one")->firstChild();
Node* two = GetDocument().getElementById("two")->firstChild();
Node* three = GetDocument().getElementById("three")->firstChild();
Node* four = GetDocument().getElementById("four")->firstChild();
Node* five = shadow_root->getElementById("five")->firstChild();
Node* six = shadow_root->getElementById("six")->firstChild();
Node* seven = shadow_root->getElementById("seven")->firstChild();
EXPECT_EQ(Position(one, 0),
LogicalStartOfLine(CreateVisiblePositionInDOMTree(*one, 0))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(one, 0),
LogicalStartOfLine(CreateVisiblePositionInFlatTree(*one, 0))
.DeepEquivalent());
EXPECT_EQ(Position(one, 0),
LogicalStartOfLine(CreateVisiblePositionInDOMTree(*one, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(one, 0),
LogicalStartOfLine(CreateVisiblePositionInFlatTree(*one, 1))
.DeepEquivalent());
EXPECT_EQ(Position(one, 0),
LogicalStartOfLine(CreateVisiblePositionInDOMTree(*two, 0))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(five, 0),
LogicalStartOfLine(CreateVisiblePositionInFlatTree(*two, 0))
.DeepEquivalent());
EXPECT_EQ(Position(five, 0),
LogicalStartOfLine(CreateVisiblePositionInDOMTree(*two, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(five, 0),
LogicalStartOfLine(CreateVisiblePositionInFlatTree(*two, 1))
.DeepEquivalent());
EXPECT_EQ(Position(five, 0),
LogicalStartOfLine(CreateVisiblePositionInDOMTree(*three, 0))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(three, 0),
LogicalStartOfLine(CreateVisiblePositionInFlatTree(*three, 1))
.DeepEquivalent());
// TODO(yosin) logicalStartOfLine(four, 1) -> (two, 2) is a broken result.
// We keep it as a marker for future change.
EXPECT_EQ(Position(two, 2),
LogicalStartOfLine(CreateVisiblePositionInDOMTree(*four, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(three, 0),
LogicalStartOfLine(CreateVisiblePositionInFlatTree(*four, 1))
.DeepEquivalent());
EXPECT_EQ(Position(five, 0),
LogicalStartOfLine(CreateVisiblePositionInDOMTree(*five, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(five, 0),
LogicalStartOfLine(CreateVisiblePositionInFlatTree(*five, 1))
.DeepEquivalent());
EXPECT_EQ(Position(six, 0),
LogicalStartOfLine(CreateVisiblePositionInDOMTree(*six, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(six, 0),
LogicalStartOfLine(CreateVisiblePositionInFlatTree(*six, 1))
.DeepEquivalent());
EXPECT_EQ(Position(one, 0),
LogicalStartOfLine(CreateVisiblePositionInDOMTree(*seven, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(one, 0),
LogicalStartOfLine(CreateVisiblePositionInFlatTree(*seven, 1))
.DeepEquivalent());
}
TEST_F(VisibleUnitsTest, mostBackwardCaretPositionAfterAnchor) {
const char* body_content =
"<p id='host'><b id='one'>1</b></p><b id='two'>22</b>";
const char* shadow_content =
"<b id='two'>22</b><content select=#one></content><b id='three'>333</b>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Element* host = GetDocument().getElementById("host");
EXPECT_EQ(Position::LastPositionInNode(*host),
MostForwardCaretPosition(Position::AfterNode(*host)));
EXPECT_EQ(PositionInFlatTree::LastPositionInNode(*host),
MostForwardCaretPosition(PositionInFlatTree::AfterNode(*host)));
}
TEST_F(VisibleUnitsTest, mostBackwardCaretPositionFirstLetter) {
// Note: first-letter pseudo element contains letter and punctuations.
const char* body_content =
"<style>p:first-letter {color:red;}</style><p id=sample> (2)45 </p>";
SetBodyContent(body_content);
Node* sample = GetDocument().getElementById("sample")->firstChild();
EXPECT_EQ(Position(sample->parentNode(), 0),
MostBackwardCaretPosition(Position(sample, 0)));
EXPECT_EQ(Position(sample->parentNode(), 0),
MostBackwardCaretPosition(Position(sample, 1)));
EXPECT_EQ(Position(sample, 2),
MostBackwardCaretPosition(Position(sample, 2)));
EXPECT_EQ(Position(sample, 3),
MostBackwardCaretPosition(Position(sample, 3)));
EXPECT_EQ(Position(sample, 4),
MostBackwardCaretPosition(Position(sample, 4)));
EXPECT_EQ(Position(sample, 5),
MostBackwardCaretPosition(Position(sample, 5)));
EXPECT_EQ(Position(sample, 6),
MostBackwardCaretPosition(Position(sample, 6)));
EXPECT_EQ(Position(sample, 6),
MostBackwardCaretPosition(Position(sample, 7)));
EXPECT_EQ(Position(sample, 6),
MostBackwardCaretPosition(
Position::LastPositionInNode(*sample->parentNode())));
EXPECT_EQ(
Position(sample, 6),
MostBackwardCaretPosition(Position::AfterNode(*sample->parentNode())));
EXPECT_EQ(Position::LastPositionInNode(*GetDocument().body()),
MostBackwardCaretPosition(
Position::LastPositionInNode(*GetDocument().body())));
}
TEST_F(VisibleUnitsTest, mostBackwardCaretPositionFirstLetterSplit) {
V8TestingScope scope;
const char* body_content =
"<style>p:first-letter {color:red;}</style><p id=sample>abc</p>";
SetBodyContent(body_content);
Node* sample = GetDocument().getElementById("sample");
Node* first_letter = sample->firstChild();
// Split "abc" into "a" "bc"
Text* remaining = ToText(first_letter)->splitText(1, ASSERT_NO_EXCEPTION);
UpdateAllLifecyclePhases();
EXPECT_EQ(Position(sample, 0),
MostBackwardCaretPosition(Position(first_letter, 0)));
EXPECT_EQ(Position(first_letter, 1),
MostBackwardCaretPosition(Position(first_letter, 1)));
EXPECT_EQ(Position(first_letter, 1),
MostBackwardCaretPosition(Position(remaining, 0)));
EXPECT_EQ(Position(remaining, 1),
MostBackwardCaretPosition(Position(remaining, 1)));
EXPECT_EQ(Position(remaining, 2),
MostBackwardCaretPosition(Position(remaining, 2)));
EXPECT_EQ(Position(remaining, 2),
MostBackwardCaretPosition(Position::LastPositionInNode(*sample)));
EXPECT_EQ(Position(remaining, 2),
MostBackwardCaretPosition(Position::AfterNode(*sample)));
}
TEST_F(VisibleUnitsTest, mostForwardCaretPositionAfterAnchor) {
const char* body_content = "<p id='host'><b id='one'>1</b></p>";
const char* shadow_content =
"<b id='two'>22</b><content select=#one></content><b id='three'>333</b>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
UpdateAllLifecyclePhases();
Element* host = GetDocument().getElementById("host");
Element* one = GetDocument().getElementById("one");
Element* three = shadow_root->getElementById("three");
EXPECT_EQ(Position(one->firstChild(), 1),
MostBackwardCaretPosition(Position::AfterNode(*host)));
EXPECT_EQ(PositionInFlatTree(three->firstChild(), 3),
MostBackwardCaretPosition(PositionInFlatTree::AfterNode(*host)));
}
TEST_F(VisibleUnitsTest, mostForwardCaretPositionFirstLetter) {
// Note: first-letter pseudo element contains letter and punctuations.
const char* body_content =
"<style>p:first-letter {color:red;}</style><p id=sample> (2)45 </p>";
SetBodyContent(body_content);
Node* sample = GetDocument().getElementById("sample")->firstChild();
EXPECT_EQ(Position(GetDocument().body(), 0),
MostForwardCaretPosition(
Position::FirstPositionInNode(*GetDocument().body())));
EXPECT_EQ(
Position(sample, 1),
MostForwardCaretPosition(Position::BeforeNode(*sample->parentNode())));
EXPECT_EQ(Position(sample, 1),
MostForwardCaretPosition(
Position::FirstPositionInNode(*sample->parentNode())));
EXPECT_EQ(Position(sample, 1), MostForwardCaretPosition(Position(sample, 0)));
EXPECT_EQ(Position(sample, 1), MostForwardCaretPosition(Position(sample, 1)));
EXPECT_EQ(Position(sample, 2), MostForwardCaretPosition(Position(sample, 2)));
EXPECT_EQ(Position(sample, 3), MostForwardCaretPosition(Position(sample, 3)));
EXPECT_EQ(Position(sample, 4), MostForwardCaretPosition(Position(sample, 4)));
EXPECT_EQ(Position(sample, 5), MostForwardCaretPosition(Position(sample, 5)));
EXPECT_EQ(Position(sample, 7), MostForwardCaretPosition(Position(sample, 6)));
EXPECT_EQ(Position(sample, 7), MostForwardCaretPosition(Position(sample, 7)));
}
TEST_F(VisibleUnitsTest, nextPositionOf) {
const char* body_content =
"<b id=zero>0</b><p id=host><b id=one>1</b><b id=two>22</b></p><b "
"id=three>333</b>";
const char* shadow_content =
"<b id=four>4444</b><content select=#two></content><content "
"select=#one></content><b id=five>55555</b>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Element* zero = GetDocument().getElementById("zero");
Element* one = GetDocument().getElementById("one");
Element* two = GetDocument().getElementById("two");
Element* three = GetDocument().getElementById("three");
Element* four = shadow_root->getElementById("four");
Element* five = shadow_root->getElementById("five");
EXPECT_EQ(Position(one->firstChild(), 0),
NextPositionOf(CreateVisiblePosition(Position(zero, 1)))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(four->firstChild(), 0),
NextPositionOf(CreateVisiblePosition(PositionInFlatTree(zero, 1)))
.DeepEquivalent());
EXPECT_EQ(
Position(one->firstChild(), 1),
NextPositionOf(CreateVisiblePosition(Position(one, 0))).DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(one->firstChild(), 1),
NextPositionOf(CreateVisiblePosition(PositionInFlatTree(one, 0)))
.DeepEquivalent());
EXPECT_EQ(
Position(two->firstChild(), 1),
NextPositionOf(CreateVisiblePosition(Position(one, 1))).DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(five->firstChild(), 1),
NextPositionOf(CreateVisiblePosition(PositionInFlatTree(one, 1)))
.DeepEquivalent());
EXPECT_EQ(
Position(three->firstChild(), 0),
NextPositionOf(CreateVisiblePosition(Position(two, 2))).DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(one->firstChild(), 1),
NextPositionOf(CreateVisiblePosition(PositionInFlatTree(two, 2)))
.DeepEquivalent());
}
TEST_F(VisibleUnitsTest, previousPositionOf) {
const char* body_content =
"<b id=zero>0</b><p id=host><b id=one>1</b><b id=two>22</b></p><b "
"id=three>333</b>";
const char* shadow_content =
"<b id=four>4444</b><content select=#two></content><content "
"select=#one></content><b id=five>55555</b>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Node* zero = GetDocument().getElementById("zero")->firstChild();
Node* one = GetDocument().getElementById("one")->firstChild();
Node* two = GetDocument().getElementById("two")->firstChild();
Node* three = GetDocument().getElementById("three")->firstChild();
Node* four = shadow_root->getElementById("four")->firstChild();
Node* five = shadow_root->getElementById("five")->firstChild();
EXPECT_EQ(Position(zero, 0),
PreviousPositionOf(CreateVisiblePosition(Position(zero, 1)))
.DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(zero, 0),
PreviousPositionOf(CreateVisiblePosition(PositionInFlatTree(zero, 1)))
.DeepEquivalent());
EXPECT_EQ(Position(zero, 1),
PreviousPositionOf(CreateVisiblePosition(Position(one, 0)))
.DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(two, 1),
PreviousPositionOf(CreateVisiblePosition(PositionInFlatTree(one, 0)))
.DeepEquivalent());
EXPECT_EQ(Position(one, 0),
PreviousPositionOf(CreateVisiblePosition(Position(one, 1)))
.DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(two, 2),
PreviousPositionOf(CreateVisiblePosition(PositionInFlatTree(one, 1)))
.DeepEquivalent());
EXPECT_EQ(Position(one, 0),
PreviousPositionOf(CreateVisiblePosition(Position(two, 0)))
.DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(four, 3),
PreviousPositionOf(CreateVisiblePosition(PositionInFlatTree(two, 0)))
.DeepEquivalent());
// DOM tree to shadow tree
EXPECT_EQ(Position(two, 2),
PreviousPositionOf(CreateVisiblePosition(Position(three, 0)))
.DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(five, 5),
PreviousPositionOf(CreateVisiblePosition(PositionInFlatTree(three, 0)))
.DeepEquivalent());
// Shadow tree to DOM tree
EXPECT_EQ(Position(),
PreviousPositionOf(CreateVisiblePosition(Position(four, 0)))
.DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(zero, 1),
PreviousPositionOf(CreateVisiblePosition(PositionInFlatTree(four, 0)))
.DeepEquivalent());
// Note: Canonicalization maps (five, 0) to (four, 4) in DOM tree and
// (one, 1) in flat tree.
EXPECT_EQ(Position(four, 4),
PreviousPositionOf(CreateVisiblePosition(Position(five, 1)))
.DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(one, 1),
PreviousPositionOf(CreateVisiblePosition(PositionInFlatTree(five, 1)))
.DeepEquivalent());
}
TEST_F(VisibleUnitsTest, previousPositionOfOneCharPerLine) {
const char* body_content =
"<div id=sample style='font-size: 500px'>A&#x714a;&#xfa67;</div>";
SetBodyContent(body_content);
Node* sample = GetDocument().getElementById("sample")->firstChild();
// In case of each line has one character, VisiblePosition are:
// [C,Dn] [C,Up] [B, Dn] [B, Up]
// A A A A|
// B B| |B B
// |C C C C
EXPECT_EQ(PositionWithAffinity(Position(sample, 1)),
PreviousPositionOf(CreateVisiblePosition(Position(sample, 2)))
.ToPositionWithAffinity());
EXPECT_EQ(PositionWithAffinity(Position(sample, 1)),
PreviousPositionOf(CreateVisiblePosition(Position(sample, 2),
TextAffinity::kUpstream))
.ToPositionWithAffinity());
}
TEST_F(VisibleUnitsTest, previousPositionOfNoPreviousPosition) {
SetBodyContent(
"<span contenteditable='true'>"
"<span> </span>"
" " // This whitespace causes no previous position.
"<div id='anchor'> bar</div>"
"</span>");
const Position position(GetDocument().getElementById("anchor")->firstChild(),
1);
EXPECT_EQ(
Position(),
PreviousPositionOf(CreateVisiblePosition(position)).DeepEquivalent());
}
TEST_F(VisibleUnitsTest, rendersInDifferentPositionAfterAnchor) {
const char* body_content = "<p id='sample'>00</p>";
SetBodyContent(body_content);
Element* sample = GetDocument().getElementById("sample");
EXPECT_FALSE(RendersInDifferentPosition(Position(), Position()));
EXPECT_FALSE(
RendersInDifferentPosition(Position(), Position::AfterNode(*sample)))
<< "if one of position is null, the reuslt is false.";
EXPECT_FALSE(RendersInDifferentPosition(Position::AfterNode(*sample),
Position(sample, 1)));
EXPECT_FALSE(RendersInDifferentPosition(Position::LastPositionInNode(*sample),
Position(sample, 1)));
}
TEST_F(VisibleUnitsTest, rendersInDifferentPositionAfterAnchorWithHidden) {
const char* body_content =
"<p><span id=one>11</span><span id=two style='display:none'> "
"</span></p>";
SetBodyContent(body_content);
Element* one = GetDocument().getElementById("one");
Element* two = GetDocument().getElementById("two");
EXPECT_TRUE(RendersInDifferentPosition(Position::LastPositionInNode(*one),
Position(two, 0)))
<< "two doesn't have layout object";
}
TEST_F(VisibleUnitsTest,
rendersInDifferentPositionAfterAnchorWithDifferentLayoutObjects) {
const char* body_content =
"<p><span id=one>11</span><span id=two> </span></p>";
SetBodyContent(body_content);
Element* one = GetDocument().getElementById("one");
Element* two = GetDocument().getElementById("two");
EXPECT_FALSE(RendersInDifferentPosition(Position::LastPositionInNode(*one),
Position(two, 0)));
EXPECT_FALSE(RendersInDifferentPosition(Position::LastPositionInNode(*one),
Position(two, 1)))
<< "width of two is zero since contents is collapsed whitespaces";
}
TEST_F(VisibleUnitsTest, renderedOffset) {
const char* body_content =
"<div contenteditable><span id='sample1'>1</span><span "
"id='sample2'>22</span></div>";
SetBodyContent(body_content);
Element* sample1 = GetDocument().getElementById("sample1");
Element* sample2 = GetDocument().getElementById("sample2");
EXPECT_FALSE(
RendersInDifferentPosition(Position::AfterNode(*sample1->firstChild()),
Position(sample2->firstChild(), 0)));
EXPECT_FALSE(RendersInDifferentPosition(
Position::LastPositionInNode(*sample1->firstChild()),
Position(sample2->firstChild(), 0)));
}
TEST_F(VisibleUnitsTest, startOfDocument) {
const char* body_content = "<a id=host><b id=one>1</b><b id=two>22</b></a>";
const char* shadow_content =
"<p><content select=#two></content></p><p><content "
"select=#one></content></p>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Node* one = GetDocument().getElementById("one")->firstChild();
Node* two = GetDocument().getElementById("two")->firstChild();
EXPECT_EQ(Position(one, 0),
StartOfDocument(CreateVisiblePositionInDOMTree(*one, 0))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(two, 0),
StartOfDocument(CreateVisiblePositionInFlatTree(*one, 0))
.DeepEquivalent());
EXPECT_EQ(Position(one, 0),
StartOfDocument(CreateVisiblePositionInDOMTree(*two, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(two, 0),
StartOfDocument(CreateVisiblePositionInFlatTree(*two, 1))
.DeepEquivalent());
}
TEST_F(VisibleUnitsTest, startOfLine) {
const char* body_content =
"<a id=host><b id=one>11</b><b id=two>22</b></a><i id=three>333</i><i "
"id=four>4444</i><br>";
const char* shadow_content =
"<div><u id=five>55555</u><content select=#two></content><br><u "
"id=six>666666</u><br><content select=#one></content><u "
"id=seven>7777777</u></div>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Node* one = GetDocument().getElementById("one")->firstChild();
Node* two = GetDocument().getElementById("two")->firstChild();
Node* three = GetDocument().getElementById("three")->firstChild();
Node* four = GetDocument().getElementById("four")->firstChild();
Node* five = shadow_root->getElementById("five")->firstChild();
Node* six = shadow_root->getElementById("six")->firstChild();
Node* seven = shadow_root->getElementById("seven")->firstChild();
EXPECT_EQ(
Position(one, 0),
StartOfLine(CreateVisiblePositionInDOMTree(*one, 0)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(one, 0),
StartOfLine(CreateVisiblePositionInFlatTree(*one, 0)).DeepEquivalent());
EXPECT_EQ(
Position(one, 0),
StartOfLine(CreateVisiblePositionInDOMTree(*one, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(one, 0),
StartOfLine(CreateVisiblePositionInFlatTree(*one, 1)).DeepEquivalent());
EXPECT_EQ(
Position(one, 0),
StartOfLine(CreateVisiblePositionInDOMTree(*two, 0)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(five, 0),
StartOfLine(CreateVisiblePositionInFlatTree(*two, 0)).DeepEquivalent());
EXPECT_EQ(
Position(five, 0),
StartOfLine(CreateVisiblePositionInDOMTree(*two, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(five, 0),
StartOfLine(CreateVisiblePositionInFlatTree(*two, 1)).DeepEquivalent());
EXPECT_EQ(
Position(five, 0),
StartOfLine(CreateVisiblePositionInDOMTree(*three, 0)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(three, 0),
StartOfLine(CreateVisiblePositionInFlatTree(*three, 1)).DeepEquivalent());
// TODO(yosin) startOfLine(four, 1) -> (two, 2) is a broken result. We keep
// it as a marker for future change.
EXPECT_EQ(
Position(two, 2),
StartOfLine(CreateVisiblePositionInDOMTree(*four, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(three, 0),
StartOfLine(CreateVisiblePositionInFlatTree(*four, 1)).DeepEquivalent());
EXPECT_EQ(
Position(five, 0),
StartOfLine(CreateVisiblePositionInDOMTree(*five, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(five, 0),
StartOfLine(CreateVisiblePositionInFlatTree(*five, 1)).DeepEquivalent());
EXPECT_EQ(
Position(six, 0),
StartOfLine(CreateVisiblePositionInDOMTree(*six, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(six, 0),
StartOfLine(CreateVisiblePositionInFlatTree(*six, 1)).DeepEquivalent());
EXPECT_EQ(
Position(one, 0),
StartOfLine(CreateVisiblePositionInDOMTree(*seven, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(one, 0),
StartOfLine(CreateVisiblePositionInFlatTree(*seven, 1)).DeepEquivalent());
}
TEST_F(VisibleUnitsTest, startOfParagraph) {
const char* body_content =
"<b id=zero>0</b><a id=host><b id=one>1</b><b id=two>22</b></a><b "
"id=three>333</b>";
const char* shadow_content =
"<p><content select=#two></content></p><p><content "
"select=#one></content></p>";
SetBodyContent(body_content);
SetShadowContent(shadow_content, "host");
Node* zero = GetDocument().getElementById("zero")->firstChild();
Node* one = GetDocument().getElementById("one")->firstChild();
Node* two = GetDocument().getElementById("two")->firstChild();
Node* three = GetDocument().getElementById("three")->firstChild();
EXPECT_EQ(Position(zero, 0),
StartOfParagraph(CreateVisiblePositionInDOMTree(*one, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(one, 0),
StartOfParagraph(CreateVisiblePositionInFlatTree(*one, 1))
.DeepEquivalent());
EXPECT_EQ(Position(zero, 0),
StartOfParagraph(CreateVisiblePositionInDOMTree(*two, 2))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(two, 0),
StartOfParagraph(CreateVisiblePositionInFlatTree(*two, 2))
.DeepEquivalent());
// DOM version of |startOfParagraph()| doesn't take account contents in
// shadow tree.
EXPECT_EQ(Position(zero, 0),
StartOfParagraph(CreateVisiblePositionInDOMTree(*three, 2))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(three, 0),
StartOfParagraph(CreateVisiblePositionInFlatTree(*three, 2))
.DeepEquivalent());
// crbug.com/563777. startOfParagraph() unexpectedly returned a null
// position with nested editable <BODY>s.
Element* root = GetDocument().documentElement();
root->setInnerHTML(
"<style>* { display:inline-table; }</style><body "
"contenteditable=true><svg><svg><foreignObject>abc<svg></svg></"
"foreignObject></svg></svg></body>");
Element* old_body = GetDocument().body();
root->setInnerHTML(
"<body contenteditable=true><svg><foreignObject><style>def</style>");
DCHECK_NE(old_body, GetDocument().body());
Node* foreign_object = GetDocument().body()->firstChild()->firstChild();
foreign_object->insertBefore(old_body, foreign_object->firstChild());
Node* style_text = foreign_object->lastChild()->firstChild();
DCHECK(style_text->IsTextNode()) << style_text;
UpdateAllLifecyclePhases();
EXPECT_FALSE(StartOfParagraph(CreateVisiblePosition(Position(style_text, 0)))
.IsNull());
}
TEST_F(VisibleUnitsTest, startOfSentence) {
const char* body_content = "<a id=host><b id=one>1</b><b id=two>22</b></a>";
const char* shadow_content =
"<p><i id=three>333</i> <content select=#two></content> <content "
"select=#one></content> <i id=four>4444</i></p>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Node* one = GetDocument().getElementById("one")->firstChild();
Node* two = GetDocument().getElementById("two")->firstChild();
Node* three = shadow_root->getElementById("three")->firstChild();
Node* four = shadow_root->getElementById("four")->firstChild();
EXPECT_EQ(Position(one, 0),
StartOfSentence(CreateVisiblePositionInDOMTree(*one, 0))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(three, 0),
StartOfSentence(CreateVisiblePositionInFlatTree(*one, 0))
.DeepEquivalent());
EXPECT_EQ(Position(one, 0),
StartOfSentence(CreateVisiblePositionInDOMTree(*one, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(three, 0),
StartOfSentence(CreateVisiblePositionInFlatTree(*one, 1))
.DeepEquivalent());
EXPECT_EQ(Position(one, 0),
StartOfSentence(CreateVisiblePositionInDOMTree(*two, 0))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(three, 0),
StartOfSentence(CreateVisiblePositionInFlatTree(*two, 0))
.DeepEquivalent());
EXPECT_EQ(Position(one, 0),
StartOfSentence(CreateVisiblePositionInDOMTree(*two, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(three, 0),
StartOfSentence(CreateVisiblePositionInFlatTree(*two, 1))
.DeepEquivalent());
EXPECT_EQ(Position(three, 0),
StartOfSentence(CreateVisiblePositionInDOMTree(*three, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(three, 0),
StartOfSentence(CreateVisiblePositionInFlatTree(*three, 1))
.DeepEquivalent());
EXPECT_EQ(Position(three, 0),
StartOfSentence(CreateVisiblePositionInDOMTree(*four, 1))
.DeepEquivalent());
EXPECT_EQ(PositionInFlatTree(three, 0),
StartOfSentence(CreateVisiblePositionInFlatTree(*four, 1))
.DeepEquivalent());
}
TEST_F(VisibleUnitsTest, startOfWord) {
const char* body_content =
"<a id=host><b id=one>1</b> <b id=two>22</b></a><i id=three>333</i>";
const char* shadow_content =
"<p><u id=four>44444</u><content select=#two></content><span id=space> "
"</span><content select=#one></content><u id=five>55555</u></p>";
SetBodyContent(body_content);
ShadowRoot* shadow_root = SetShadowContent(shadow_content, "host");
Node* one = GetDocument().getElementById("one")->firstChild();
Node* two = GetDocument().getElementById("two")->firstChild();
Node* three = GetDocument().getElementById("three")->firstChild();
Node* four = shadow_root->getElementById("four")->firstChild();
Node* five = shadow_root->getElementById("five")->firstChild();
Node* space = shadow_root->getElementById("space")->firstChild();
EXPECT_EQ(
Position(one, 0),
StartOfWord(CreateVisiblePositionInDOMTree(*one, 0)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(space, 1),
StartOfWord(CreateVisiblePositionInFlatTree(*one, 0)).DeepEquivalent());
EXPECT_EQ(
Position(one, 0),
StartOfWord(CreateVisiblePositionInDOMTree(*one, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(space, 1),
StartOfWord(CreateVisiblePositionInFlatTree(*one, 1)).DeepEquivalent());
EXPECT_EQ(
Position(one, 0),
StartOfWord(CreateVisiblePositionInDOMTree(*two, 0)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(four, 0),
StartOfWord(CreateVisiblePositionInFlatTree(*two, 0)).DeepEquivalent());
EXPECT_EQ(
Position(one, 0),
StartOfWord(CreateVisiblePositionInDOMTree(*two, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(four, 0),
StartOfWord(CreateVisiblePositionInFlatTree(*two, 1)).DeepEquivalent());
EXPECT_EQ(
Position(one, 0),
StartOfWord(CreateVisiblePositionInDOMTree(*three, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(space, 1),
StartOfWord(CreateVisiblePositionInFlatTree(*three, 1)).DeepEquivalent());
EXPECT_EQ(
Position(four, 0),
StartOfWord(CreateVisiblePositionInDOMTree(*four, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(four, 0),
StartOfWord(CreateVisiblePositionInFlatTree(*four, 1)).DeepEquivalent());
EXPECT_EQ(
Position(space, 1),
StartOfWord(CreateVisiblePositionInDOMTree(*five, 1)).DeepEquivalent());
EXPECT_EQ(
PositionInFlatTree(space, 1),
StartOfWord(CreateVisiblePositionInFlatTree(*five, 1)).DeepEquivalent());
}
TEST_F(VisibleUnitsTest,
endsOfNodeAreVisuallyDistinctPositionsWithInvisibleChild) {
// Repro case of crbug.com/582247
const char* body_content =
"<button> </button><script>document.designMode = 'on'</script>";
SetBodyContent(body_content);
Node* button = GetDocument().QuerySelector("button");
EXPECT_TRUE(EndsOfNodeAreVisuallyDistinctPositions(button));
}
TEST_F(VisibleUnitsTest,
endsOfNodeAreVisuallyDistinctPositionsWithEmptyLayoutChild) {
// Repro case of crbug.com/584030
const char* body_content =
"<button><rt><script>document.designMode = 'on'</script></rt></button>";
SetBodyContent(body_content);
Node* button = GetDocument().QuerySelector("button");
EXPECT_TRUE(EndsOfNodeAreVisuallyDistinctPositions(button));
}
// Repro case of crbug.com/680428
TEST_F(VisibleUnitsTest, localSelectionRectOfPositionTemplateNotCrash) {
SetBodyContent("<div>foo<img></div>");
Node* node = GetDocument().QuerySelector("img");
IntRect rect =
AbsoluteSelectionBoundsOf(VisiblePosition::Create(PositionWithAffinity(
Position(node, PositionAnchorType::kAfterChildren))));
EXPECT_FALSE(rect.IsEmpty());
}
// Regression test for crbug.com/675429
TEST_F(VisibleUnitsTest,
canonicalizationWithCollapsedSpaceAndIsolatedCombiningCharacter) {
SetBodyContent("<p> &#x20E3;</p>"); // Leading space is necessary
Node* paragraph = GetDocument().QuerySelector("p");
Node* text = paragraph->firstChild();
Position start = CanonicalPositionOf(Position::BeforeNode(*paragraph));
EXPECT_EQ(Position(text, 2), start);
}
TEST_F(VisibleUnitsTest,
PreviousRootInlineBoxCandidatePositionWithDisplayNone) {
SetBodyContent(
"<div contenteditable>"
"<div id=one>one abc</div>"
"<div id=two>two <b id=none style=display:none>def</b> ghi</div>"
"</div>");
Element* const one = GetDocument().getElementById("one");
Element* const two = GetDocument().getElementById("two");
const VisiblePosition& visible_position =
CreateVisiblePosition(Position::LastPositionInNode(*two));
EXPECT_EQ(Position(one->firstChild(), 7),
PreviousRootInlineBoxCandidatePosition(
two->lastChild(), visible_position, kContentIsEditable));
}
} // namespace blink