PositionInComposedTree toPositionInComposedTree(const Position& pos) { if (pos.isNull()) return PositionInComposedTree(); if (pos.isOffsetInAnchor()) { Node* anchor = pos.anchorNode(); if (anchor->offsetInCharacters()) return PositionInComposedTree(anchor, pos.computeOffsetInContainerNode()); ASSERT(!anchor->isSlotOrActiveInsertionPoint()); int offset = pos.computeOffsetInContainerNode(); Node* child = NodeTraversal::childAt(*anchor, offset); if (!child) { if (anchor->isShadowRoot()) return PositionInComposedTree(anchor->shadowHost(), PositionAnchorType::AfterChildren); return PositionInComposedTree(anchor, PositionAnchorType::AfterChildren); } child->updateDistribution(); if (child->isSlotOrActiveInsertionPoint()) { if (anchor->isShadowRoot()) return PositionInComposedTree(anchor->shadowHost(), offset); return PositionInComposedTree(anchor, offset); } if (Node* parent = ComposedTreeTraversal::parent(*child)) return PositionInComposedTree(parent, ComposedTreeTraversal::index(*child)); // When |pos| isn't appeared in composed tree, we map |pos| to after // children of shadow host. // e.g. "foo",0 in <progress>foo</progress> if (anchor->isShadowRoot()) return PositionInComposedTree(anchor->shadowHost(), PositionAnchorType::AfterChildren); return PositionInComposedTree(anchor, PositionAnchorType::AfterChildren); } return PositionInComposedTree(pos.anchorNode(), pos.anchorType()); }
TEST_F(PositionTest, ToPositionInComposedTreeWithInactiveInsertionPoint) { const char* bodyContent = "<p id='p'><content></content></p>"; setBodyContent(bodyContent); RefPtrWillBeRawPtr<Element> anchor = document().getElementById("p"); EXPECT_EQ(PositionInComposedTree(anchor.get(), 0), toPositionInComposedTree(Position(anchor.get(), 0))); EXPECT_EQ(PositionInComposedTree(anchor, PositionAnchorType::AfterChildren), toPositionInComposedTree(Position(anchor.get(), 1))); }
TEST_F(PositionTest, ToPositionInComposedTreeWithShadowRootContainingSingleContent) { const char* bodyContent = "<p id='host'>00<b id='one'>11</b>22</p>"; const char* shadowContent = "<content select=#one></content>"; setBodyContent(bodyContent); RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = setShadowContent(shadowContent, "host"); RefPtrWillBeRawPtr<Element> host = document().getElementById("host"); EXPECT_EQ(PositionInComposedTree(host.get(), 0), toPositionInComposedTree(Position(shadowRoot.get(), 0))); EXPECT_EQ(PositionInComposedTree(host.get(), PositionAnchorType::AfterChildren), toPositionInComposedTree(Position(shadowRoot.get(), 1))); }
TEST_F(PositionTest, ToPositionInComposedTreeWithActiveInsertionPoint) { const char* bodyContent = "<p id='host'>00<b id='one'>11</b>22</p>"; const char* shadowContent = "<a id='a'><content select=#one id='content'></content><content></content></a>"; setBodyContent(bodyContent); RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = setShadowContent(shadowContent, "host"); RefPtrWillBeRawPtr<Element> anchor = shadowRoot->getElementById("a"); EXPECT_EQ(PositionInComposedTree(anchor.get(), 0), toPositionInComposedTree(Position(anchor.get(), 0))); EXPECT_EQ(PositionInComposedTree(anchor.get(), 1), toPositionInComposedTree(Position(anchor.get(), 1))); EXPECT_EQ(PositionInComposedTree(anchor, PositionAnchorType::AfterChildren), toPositionInComposedTree(Position(anchor.get(), 2))); }
TEST_F(EditingUtilitiesTest, NextNodeIndex) { const char* bodyContent = "<p id='host'>00<b id='one'>11</b><b id='two'>22</b>33</p>"; const char* shadowContent = "<content select=#two></content><content select=#one></content>"; setBodyContent(bodyContent); setShadowContent(shadowContent, "host"); Node* host = document().getElementById("host"); Node* two = document().getElementById("two"); EXPECT_EQ(Position(host, 3), nextPositionOf(Position(two, 2), PositionMoveType::CodePoint)); EXPECT_EQ(PositionInComposedTree(host, 1), nextPositionOf(PositionInComposedTree(two, 2), PositionMoveType::CodePoint)); }
// This test comes from "editing/style/block-style-progress-crash.html". TEST_F(PositionTest, ToPositionInComposedTreeWithNotDistributed) { setBodyContent("<progress id=sample>foo</progress>"); Element* sample = document().getElementById("sample"); EXPECT_EQ(PositionInComposedTree(sample, PositionAnchorType::AfterChildren), toPositionInComposedTree(Position(sample, 0))); }
TEST_F(EditingUtilitiesTest, isFirstPositionAfterTable) { const char* bodyContent = "<div contenteditable id=host><table id=table><tr><td>1</td></tr></table><b id=two>22</b></div>"; const char* shadowContent = "<content select=#two></content><content select=#table></content>"; setBodyContent(bodyContent); setShadowContent(shadowContent, "host"); updateLayoutAndStyleForPainting(); Node* host = document().getElementById("host"); Node* table = document().getElementById("table"); EXPECT_EQ(table, isFirstPositionAfterTable(createVisiblePosition(Position::afterNode(table)))); EXPECT_EQ(table, isFirstPositionAfterTable(createVisiblePosition(PositionInComposedTree::afterNode(table)))); EXPECT_EQ(table, isFirstPositionAfterTable(createVisiblePosition(Position::lastPositionInNode(table)))); EXPECT_EQ(table, isFirstPositionAfterTable(createVisiblePosition(PositionInComposedTree::lastPositionInNode(table)))); EXPECT_EQ(nullptr, isFirstPositionAfterTable(createVisiblePosition(Position(host, 2)))); EXPECT_EQ(table, isFirstPositionAfterTable(createVisiblePosition(PositionInComposedTree(host, 2)))); EXPECT_EQ(nullptr, isFirstPositionAfterTable(createVisiblePosition(Position::afterNode(host)))); EXPECT_EQ(nullptr, isFirstPositionAfterTable(createVisiblePosition(PositionInComposedTree::afterNode(host)))); EXPECT_EQ(nullptr, isFirstPositionAfterTable(createVisiblePosition(Position::lastPositionInNode(host)))); EXPECT_EQ(table, isFirstPositionAfterTable(createVisiblePosition(PositionInComposedTree::lastPositionInNode(host)))); }
TEST_F(EditingUtilitiesTest, directionOfEnclosingBlock) { const char* bodyContent = "<p id='host'><b id='one'></b><b id='two'>22</b></p>"; const char* shadowContent = "<content select=#two></content><p dir=rtl><content select=#one></content><p>"; setBodyContent(bodyContent); setShadowContent(shadowContent, "host"); updateLayoutAndStyleForPainting(); Node* one = document().getElementById("one"); EXPECT_EQ(LTR, directionOfEnclosingBlock(Position(one, 0))); EXPECT_EQ(RTL, directionOfEnclosingBlock(PositionInComposedTree(one, 0))); }
TEST_F(EditingUtilitiesTest, enclosingNodeOfType) { const char* bodyContent = "<p id='host'><b id='one'>11</b></p>"; const char* shadowContent = "<content select=#two></content><div id='three'><content select=#one></div></content>"; setBodyContent(bodyContent); RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = setShadowContent(shadowContent, "host"); updateLayoutAndStyleForPainting(); Node* host = document().getElementById("host"); Node* one = document().getElementById("one"); Node* three = shadowRoot->getElementById("three"); EXPECT_EQ(host, enclosingNodeOfType(Position(one, 0), isEnclosingBlock)); EXPECT_EQ(three, enclosingNodeOfType(PositionInComposedTree(one, 0), isEnclosingBlock)); }
TEST_F(EditingUtilitiesTest, firstEditablePositionAfterPositionInRoot) { const char* bodyContent = "<p id='host' contenteditable><b id='one'>1</b><b id='two'>22</b></p>"; const char* shadowContent = "<content select=#two></content><content select=#one></content><b id='three'>333</b>"; setBodyContent(bodyContent); RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = setShadowContent(shadowContent, "host"); updateLayoutAndStyleForPainting(); Element* host = document().getElementById("host"); Node* one = document().getElementById("one"); Node* two = document().getElementById("two"); Node* three = shadowRoot->getElementById("three"); EXPECT_EQ(Position(one, 0), firstEditablePositionAfterPositionInRoot(Position(one, 0), *host)); EXPECT_EQ(Position(one->firstChild(), 0), firstEditableVisiblePositionAfterPositionInRoot(Position(one, 0), *host).deepEquivalent()); EXPECT_EQ(PositionInComposedTree(one, 0), firstEditablePositionAfterPositionInRoot(PositionInComposedTree(one, 0), *host)); EXPECT_EQ(PositionInComposedTree(two->firstChild(), 2), firstEditableVisiblePositionAfterPositionInRoot(PositionInComposedTree(one, 0), *host).deepEquivalent()); EXPECT_EQ(Position::firstPositionInNode(host), firstEditablePositionAfterPositionInRoot(Position(three, 0), *host)); EXPECT_EQ(Position(one->firstChild(), 0), firstEditableVisiblePositionAfterPositionInRoot(Position(three, 0), *host).deepEquivalent()); EXPECT_EQ(PositionInComposedTree::afterNode(host), firstEditablePositionAfterPositionInRoot(PositionInComposedTree(three, 0), *host)); EXPECT_EQ(PositionInComposedTree::lastPositionInNode(host), firstEditableVisiblePositionAfterPositionInRoot(PositionInComposedTree(three, 0), *host).deepEquivalent()); }
TEST_F(EditingUtilitiesTest, NextVisuallyDistinctCandidate) { const char* bodyContent = "<p id='host'>00<b id='one'>11</b><b id='two'>22</b><b id='three'>33</b></p>"; const char* shadowContent = "<content select=#two></content><content select=#one></content><content select=#three></content>"; setBodyContent(bodyContent); setShadowContent(shadowContent, "host"); updateLayoutAndStyleForPainting(); Node* one = document().getElementById("one"); Node* two = document().getElementById("two"); Node* three = document().getElementById("three"); EXPECT_EQ(Position(two->firstChild(), 1), nextVisuallyDistinctCandidate(Position(one, 1))); EXPECT_EQ(PositionInComposedTree(three->firstChild(), 1), nextVisuallyDistinctCandidate(PositionInComposedTree(one, 1))); }
TEST_F(VisiblePositionTest, ShadowV0DistributedNodes) { const char* bodyContent = "<p id='host'>00<b id='one'>11</b><b id='two'>22</b>33</p>"; const char* shadowContent = "<a><span id='s4'>44</span><content select=#two></content><span id='s5'>55</span><content select=#one></content><span id='s6'>66</span></a>"; setBodyContent(bodyContent); RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = setShadowContent(shadowContent, "host"); RefPtrWillBeRawPtr<Element> body = document().body(); RefPtrWillBeRawPtr<Element> one = body->querySelector("#one", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> two = body->querySelector("#two", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> four = shadowRoot->querySelector("#s4", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> five = shadowRoot->querySelector("#s5", ASSERT_NO_EXCEPTION); EXPECT_EQ(Position(one->firstChild(), 0), canonicalPositionOf(Position(one, 0))); EXPECT_EQ(Position(one->firstChild(), 0), createVisiblePosition(Position(one, 0)).deepEquivalent()); EXPECT_EQ(Position(one->firstChild(), 2), canonicalPositionOf(Position(two.get(), 0))); EXPECT_EQ(Position(one->firstChild(), 2), createVisiblePosition(Position(two.get(), 0)).deepEquivalent()); EXPECT_EQ(PositionInComposedTree(five->firstChild(), 2), canonicalPositionOf(PositionInComposedTree(one.get(), 0))); EXPECT_EQ(PositionInComposedTree(five->firstChild(), 2), createVisiblePosition(PositionInComposedTree(one.get(), 0)).deepEquivalent()); EXPECT_EQ(PositionInComposedTree(four->firstChild(), 2), canonicalPositionOf(PositionInComposedTree(two.get(), 0))); EXPECT_EQ(PositionInComposedTree(four->firstChild(), 2), createVisiblePosition(PositionInComposedTree(two.get(), 0)).deepEquivalent()); }
TEST_F(PositionTest, NodeAsRangeLastNodeNull) { EXPECT_EQ(nullptr, Position().nodeAsRangeLastNode()); EXPECT_EQ(nullptr, PositionInComposedTree().nodeAsRangeLastNode()); }