| Index: third_party/WebKit/Source/core/editing/LayoutPositionTest.cpp
|
| diff --git a/third_party/WebKit/Source/core/editing/LayoutPositionTest.cpp b/third_party/WebKit/Source/core/editing/LayoutPositionTest.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..495132fabc23ce0edc67807f51a873e3baab4c45
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/core/editing/LayoutPositionTest.cpp
|
| @@ -0,0 +1,307 @@
|
| +// Copyright 2016 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/LayoutPosition.h"
|
| +
|
| +#include "core/dom/Element.h"
|
| +#include "core/dom/NodeTraversal.h"
|
| +#include "core/dom/Text.h"
|
| +#include "core/editing/EditingTestBase.h"
|
| +#include "core/editing/VisibleUnits.h"
|
| +#include "core/layout/LayoutView.h"
|
| +#include "core/layout/line/InlineTextBox.h"
|
| +#include "wtf/Noncopyable.h"
|
| +
|
| +namespace blink {
|
| +
|
| +class LayoutPositionTest : public EditingTestBase {
|
| + WTF_MAKE_NONCOPYABLE(LayoutPositionTest);
|
| +
|
| +public:
|
| + // |LayoutPosition| constructors
|
| + LayoutPosition afterAnchorOf(LayoutObject*);
|
| + LayoutPosition beforeAnchorOf(LayoutObject*);
|
| + LayoutPosition beforeChildrenOf(LayoutObject*);
|
| + LayoutPosition textPositionOf(InlineBox*, int offsetInBox);
|
| +
|
| + // |LayoutPosition| member variable getters
|
| + static PositionAnchorType anchorTypeOf(const LayoutPosition&);
|
| + static InlineBox* inlineBoxOf(const LayoutPosition&);
|
| + static LayoutObject* layoutObjectOf(const LayoutPosition&);
|
| + static int textOffsetOf(const LayoutPosition&);
|
| +
|
| +protected:
|
| + LayoutPositionTest() = default;
|
| +
|
| + FloatQuad caretQuadOf(const LayoutPosition& position)
|
| + {
|
| + return position.computeCaretQuad();
|
| + }
|
| +
|
| + // Shortcuts
|
| + LayoutPosition layoutPositionAfter(Node* node)
|
| + {
|
| + return LayoutPosition::create(Position::afterNode(node));
|
| + }
|
| +
|
| + LayoutPosition layoutPositionBefore(Node* node)
|
| + {
|
| + return LayoutPosition::create(Position::beforeNode(node));
|
| + }
|
| +
|
| + LayoutPosition layoutPositionOf(Node* node, int offset)
|
| + {
|
| + return LayoutPosition::create(Position(node, offset));
|
| + }
|
| +};
|
| +
|
| +// static
|
| +LayoutPosition LayoutPositionTest::afterAnchorOf(LayoutObject* layoutObject)
|
| +{
|
| + return LayoutPosition::afterAnchorOf(layoutObject);
|
| +}
|
| +
|
| +// static
|
| +LayoutPosition LayoutPositionTest::beforeAnchorOf(LayoutObject* layoutObject)
|
| +{
|
| + return LayoutPosition::beforeAnchorOf(layoutObject);
|
| +}
|
| +
|
| +// static
|
| +LayoutPosition LayoutPositionTest::beforeChildrenOf(LayoutObject* layoutObject)
|
| +{
|
| + return LayoutPosition::beforeChildrenOf(layoutObject);
|
| +}
|
| +
|
| +LayoutPosition LayoutPositionTest::textPositionOf(InlineBox* box, int offsetInBox)
|
| +{
|
| + return LayoutPosition(InlineBoxPosition(box, offsetInBox));
|
| +}
|
| +
|
| +// static
|
| +PositionAnchorType LayoutPositionTest::anchorTypeOf(const LayoutPosition& position)
|
| +{
|
| + return position.m_anchorType;
|
| +}
|
| +
|
| +// static
|
| +InlineBox* LayoutPositionTest::inlineBoxOf(const LayoutPosition& position)
|
| +{
|
| + return position.m_inlineBox;
|
| +}
|
| +
|
| +// static
|
| +LayoutObject* LayoutPositionTest::layoutObjectOf(const LayoutPosition& position)
|
| +{
|
| + return position.m_layoutObject;
|
| +}
|
| +
|
| +// static
|
| +int LayoutPositionTest::textOffsetOf(const LayoutPosition& position)
|
| +{
|
| + ASSERT(position.isOffsetInAnchor());
|
| + return position.m_offsetInBox;
|
| +}
|
| +
|
| +TEST_F(LayoutPositionTest, canPlaceCaret)
|
| +{
|
| + setBodyContent("<div> 234 <br> </div>");
|
| + updateAllLifecyclePhases();
|
| +
|
| + // Layout Tree of this test:
|
| + // +LayoutView {#document} (0,0)+800x600
|
| + // | +LayoutBlockFlow {HTML} (0,0)+800x600
|
| + // | | +LayoutBlockFlow {BODY} (8,8)+784x584
|
| + // | | | +LayoutBlockFlow {DIV} (0,0)+784x2
|
| + // | | | | | | +-RootInlineBox DIV frameRect=(0,0)+4x2 bidiLevel=0
|
| + // | | | | | | | +InlineTextBox "234 " start=2 end=5 bidiLevel=0
|
| + // | | | | +LayoutText {" 234 "}
|
| + // ------------>LayoutBR {BR}
|
| + Element* const body = document().body();
|
| + Node* const div = body->firstChild();
|
| + Node* const text = div->firstChild();
|
| + Node* const br = text->nextSibling();
|
| + Node* const lastText = div->lastChild();
|
| +
|
| + EXPECT_TRUE(layoutPositionOf(body, 0).canPlaceCaret());
|
| + EXPECT_TRUE(layoutPositionBefore(div).canPlaceCaret());
|
| +
|
| + EXPECT_TRUE(layoutPositionOf(div, 0).canPlaceCaret());
|
| + EXPECT_TRUE(layoutPositionBefore(text).canPlaceCaret());
|
| + EXPECT_TRUE(layoutPositionAfter(text).canPlaceCaret());
|
| + EXPECT_TRUE(layoutPositionOf(text, 0).canPlaceCaret());
|
| + EXPECT_TRUE(layoutPositionOf(text, 1).canPlaceCaret());
|
| + EXPECT_TRUE(layoutPositionOf(text, 2).canPlaceCaret());
|
| + EXPECT_TRUE(layoutPositionOf(text, 3).canPlaceCaret());
|
| + EXPECT_TRUE(layoutPositionOf(text, 4).canPlaceCaret());
|
| + EXPECT_TRUE(layoutPositionOf(text, 5).canPlaceCaret());
|
| + EXPECT_TRUE(layoutPositionOf(text, 6).canPlaceCaret());
|
| + EXPECT_TRUE(layoutPositionOf(text, 6).canPlaceCaret());
|
| +
|
| + EXPECT_FALSE(layoutPositionBefore(br).canPlaceCaret());
|
| + EXPECT_FALSE(layoutPositionOf(div, 1).canPlaceCaret());
|
| + EXPECT_FALSE(layoutPositionAfter(br).canPlaceCaret())
|
| + << "Since it is hard to compute caret quad for after BR, we don't allow to place caret after BR.";
|
| +
|
| + EXPECT_FALSE(layoutPositionBefore(lastText).canPlaceCaret())
|
| + << "We can't place caret before collapsed whitespace.";
|
| + EXPECT_FALSE(layoutPositionOf(div, 2).canPlaceCaret())
|
| + << "We can't place caret before collapsed whitespace.";
|
| + EXPECT_FALSE(layoutPositionAfter(lastText).canPlaceCaret())
|
| + << "We can't place caret before collapsed whitespace.";
|
| + EXPECT_FALSE(layoutPositionOf(div, 3).canPlaceCaret())
|
| + << "We can't place caret before collapsed whitespace.";
|
| +
|
| + EXPECT_TRUE(layoutPositionAfter(div).canPlaceCaret());
|
| + EXPECT_TRUE(layoutPositionOf(body, 1).canPlaceCaret());
|
| +}
|
| +
|
| +TEST_F(LayoutPositionTest, ctorLeftToRightSimple)
|
| +{
|
| + setBodyContent("<div id=one>222</div>");
|
| + updateAllLifecyclePhases();
|
| +
|
| + Element* const body = document().body();
|
| + Element* const one = body->querySelector("#one", ASSERT_NO_EXCEPTION);
|
| + InlineTextBox* const textBox = toLayoutText(one->firstChild()->layoutObject())->firstTextBox();
|
| +
|
| + EXPECT_EQ(beforeAnchorOf(one->layoutObject()), layoutPositionOf(body, 0));
|
| + EXPECT_EQ(afterAnchorOf(one->layoutObject()), layoutPositionOf(body, 1));
|
| +
|
| + EXPECT_EQ(beforeAnchorOf(one->layoutObject()), layoutPositionBefore(one))
|
| + << "beforeAnchor(one) is a valid position";
|
| + EXPECT_EQ(textPositionOf(textBox, 0), LayoutPosition::create(Position::firstPositionInNode(one)))
|
| + << "beforeChildren(one) should be text box position";
|
| + EXPECT_EQ(textPositionOf(textBox, 1), layoutPositionOf(one->firstChild(), 1))
|
| + << "offsetInAnchor('222') should be text box position";
|
| + EXPECT_EQ(textPositionOf(textBox, 3), LayoutPosition::create(Position::lastPositionInNode(one)))
|
| + << "afterChildren(one) should be end of text box";
|
| + EXPECT_EQ(afterAnchorOf(one->layoutObject()), layoutPositionAfter(one))
|
| + << "afterAnchor(one) is a valid position";
|
| +
|
| + EXPECT_EQ(layoutPositionOf(body, 0), layoutPositionBefore(one))
|
| + << "(body, 0) and before(one) should be same.";
|
| + EXPECT_EQ(layoutPositionOf(body, 1), layoutPositionAfter(one))
|
| + << "(body, 0) and after(one) should be same.";
|
| +
|
| + EXPECT_EQ(layoutPositionOf(one, 0), layoutPositionOf(one->firstChild(), 0))
|
| + << "(one, 0) and (text, 0) should be same.";
|
| + EXPECT_EQ(layoutPositionOf(one, 1), layoutPositionOf(one->firstChild(), 3))
|
| + << "(one, 1) and (text, 3) should be same.";
|
| +}
|
| +
|
| +// See http://unicode.org/cldr/utility/bidi.jsp for BiDi level and ordering.
|
| +TEST_F(LayoutPositionTest, ctorRightToLeftMixed)
|
| +{
|
| + setBodyContent("<div id=one>mark 3.1% مارْك 2.0.</div>");
|
| + updateAllLifecyclePhases();
|
| +
|
| + Element* body = document().body();
|
| + Element* one = body->querySelector("#one", ASSERT_NO_EXCEPTION);
|
| + Node* text = one->firstChild();
|
| + // |text| node has four inline boxes based on BiIDi level.
|
| + // Node: "mark 3.1% "(L0) "ARABIC"(L1) "2.0"(L2) "."(L0)
|
| + // Layout: "mark 3.1% " "2.0" "ARABIC" "."
|
| + InlineTextBox* const textBox0 = toLayoutText(text->layoutObject())->firstTextBox();
|
| + InlineTextBox* const textBox1 = textBox0->nextTextBox();
|
| + InlineTextBox* const textBox2 = textBox1->nextTextBox();
|
| + InlineTextBox* const textBox3 = textBox2->nextTextBox();
|
| + ASSERT(textBox3 == toLayoutText(text->layoutObject())->lastTextBox());
|
| +
|
| + EXPECT_EQ(textPositionOf(textBox0, 0), layoutPositionOf(text, 0));
|
| + EXPECT_EQ(textPositionOf(textBox0, 1), layoutPositionOf(text, 1));
|
| + EXPECT_EQ(textPositionOf(textBox0, 9), layoutPositionOf(text, 9));
|
| +
|
| + EXPECT_EQ(textPositionOf(textBox2, 10), layoutPositionOf(text, 10));
|
| + EXPECT_EQ(textPositionOf(textBox2, 11), layoutPositionOf(text, 11));
|
| + EXPECT_EQ(textPositionOf(textBox2, 14), layoutPositionOf(text, 14));
|
| + EXPECT_EQ(textPositionOf(textBox2, 15), layoutPositionOf(text, 15));
|
| +
|
| + EXPECT_EQ(textPositionOf(textBox1, 16), layoutPositionOf(text, 16));
|
| + EXPECT_EQ(textPositionOf(textBox1, 17), layoutPositionOf(text, 17));
|
| + EXPECT_EQ(textPositionOf(textBox1, 18), layoutPositionOf(text, 18));
|
| +
|
| + EXPECT_EQ(textPositionOf(textBox3, 19), layoutPositionOf(text, 19));
|
| +}
|
| +
|
| +TEST_F(LayoutPositionTest, ctorRightToLeftWithBidiOverride)
|
| +{
|
| + setBodyContent("<span id=one dir=rtl>abc <bdo id=two dir=rtl>def</bdo> ghi</span>");
|
| + updateAllLifecyclePhases();
|
| +
|
| + Element* body = document().body();
|
| + Element* one = body->querySelector("#one", ASSERT_NO_EXCEPTION);
|
| + Element* two = body->querySelector("#two", ASSERT_NO_EXCEPTION);
|
| +
|
| + Node* firstText = one->firstChild();
|
| + Node* rtlText = two->firstChild();
|
| + Node* lastText = one->lastChild();
|
| +
|
| + InlineTextBox* firstTextBox = toLayoutText(firstText->layoutObject())->lastTextBox();
|
| + InlineTextBox* rtlTextBox = toLayoutText(rtlText->layoutObject())->firstTextBox();
|
| + InlineTextBox* lastTextBox = toLayoutText(lastText->layoutObject())->firstTextBox();
|
| +
|
| + EXPECT_EQ(textPositionOf(firstTextBox, 0), layoutPositionOf(firstText, 0));
|
| + EXPECT_EQ(textPositionOf(firstTextBox, 1), layoutPositionOf(firstText, 1));
|
| + EXPECT_EQ(textPositionOf(firstTextBox, 2), layoutPositionOf(firstText, 2));
|
| +
|
| + EXPECT_EQ(textPositionOf(rtlTextBox, 0), layoutPositionOf(rtlText, 0));
|
| + EXPECT_EQ(textPositionOf(rtlTextBox, 1), layoutPositionOf(rtlText, 1));
|
| + EXPECT_EQ(textPositionOf(rtlTextBox, 2), layoutPositionOf(rtlText, 2));
|
| +
|
| + EXPECT_EQ(textPositionOf(lastTextBox->nextTextBox(), 0), layoutPositionOf(lastText, 0));
|
| + EXPECT_EQ(textPositionOf(lastTextBox, 1), layoutPositionOf(lastText, 1));
|
| + EXPECT_EQ(textPositionOf(lastTextBox, 2), layoutPositionOf(lastText, 2));
|
| + EXPECT_EQ(textPositionOf(lastTextBox, 3), layoutPositionOf(lastText, 3));
|
| +}
|
| +
|
| +TEST_F(LayoutPositionTest, isCaretEquivalentWithBr)
|
| +{
|
| + setBodyContent("<div>one<br>two</div>");
|
| + updateAllLifecyclePhases();
|
| + Element* div = document().querySelector("div", ASSERT_NO_EXCEPTION);
|
| + Node* one = div->firstChild();
|
| + Node* two = div->lastChild();
|
| + Element* br = document().querySelector("br", ASSERT_NO_EXCEPTION);
|
| +
|
| + const LayoutPosition& beforeBr = layoutPositionBefore(br);
|
| + const LayoutPosition& afterBr = layoutPositionAfter(br);
|
| + const LayoutPosition& one3 = layoutPositionOf(one, 3);
|
| + const LayoutPosition& two0 = layoutPositionOf(two, 0);
|
| +
|
| + EXPECT_FALSE(beforeBr.isCaretEquivalent(afterBr));
|
| + EXPECT_TRUE(one3.isCaretEquivalent(beforeBr))
|
| + << "End of text and before BR should be equivalent.";
|
| + EXPECT_FALSE(two0.isCaretEquivalent(afterBr))
|
| + << "Since we can't place caret after BR, after BR and first position of next line aren't equivalent.";
|
| +}
|
| +
|
| +TEST_F(LayoutPositionTest, isCaretEquivalentWithCollapsedWhitespace)
|
| +{
|
| + setBodyContent("<div> 234 </div>");
|
| + updateAllLifecyclePhases();
|
| + Element* div = document().querySelector("div", ASSERT_NO_EXCEPTION);
|
| + Node* text = div->firstChild();
|
| +
|
| + const LayoutPosition& before2 = layoutPositionOf(text, 2);
|
| + EXPECT_TRUE(before2.isCaretEquivalent(layoutPositionOf(text, 0)));
|
| + EXPECT_TRUE(before2.isCaretEquivalent(layoutPositionOf(text, 1)));
|
| + EXPECT_FALSE(before2.isCaretEquivalent(layoutPositionBefore(div)));
|
| + EXPECT_EQ(Position(div, 0), mostBackwardCaretPosition(Position(text, 2)));
|
| +
|
| + const LayoutPosition& before5 = layoutPositionOf(text, 5);
|
| + EXPECT_TRUE(before5.isCaretEquivalent(layoutPositionOf(text, 6)));
|
| + EXPECT_TRUE(before5.isCaretEquivalent(layoutPositionOf(text, 7)));
|
| + EXPECT_FALSE(before2.isCaretEquivalent(layoutPositionAfter(div)));
|
| +}
|
| +
|
| +TEST_F(LayoutPositionTest, null)
|
| +{
|
| + EXPECT_TRUE(LayoutPosition().isNull());
|
| + EXPECT_FALSE(LayoutPosition().isNotNull());
|
| + EXPECT_TRUE(LayoutPosition() == LayoutPosition());
|
| + EXPECT_FALSE(LayoutPosition() != LayoutPosition());
|
| +}
|
| +
|
| +} // namespace blink
|
|
|