// Tests moving extent over to the other side of the vase and immediately
// passing the word boundary and going into word granularity.
TEST_F(GranularityStrategyTest, DirectionSwitchSideWordGranularityThenShrink)
{
    dummyPageHolder().frame().settings()->setDefaultFontSize(12);
    String str = "ab cd efghijkl mnopqr iiin, abc";
    RefPtrWillBeRawPtr<Text> text = document().createTextNode(str);
    document().body()->appendChild(text);
    dummyPageHolder().frame().settings()->setSelectionStrategy(SelectionStrategy::Direction);

    parseText(text.get());

    // "abcd efgh ijkl mno^pqr|> iiin, abc" (^ means base, | means extent, < means start, and > means end).
    selection().setSelection(VisibleSelection(Position(text, 18), Position(text, 21)));
    EXPECT_EQ_SELECTED_TEXT("pqr");
    // Move to the middle of word #4 selecting it - this will set the offset to
    // be half the width of "iiin".
    selection().moveRangeSelectionExtent(m_wordMiddles[4]);
    EXPECT_EQ_SELECTED_TEXT("pqr iiin");
    // Move to the middle of word #2 - extent will switch over to the other
    // side of the base, and we should enter word granularity since we pass
    // the word boundary. The offset should become negative since the width
    // of "efghjkkl" is greater than that of "iiin".
    int offset = m_letterPos[26].x() - m_wordMiddles[4].x();
    IntPoint p = IntPoint(m_wordMiddles[2].x() - offset - 1, m_wordMiddles[2].y());
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("efghijkl mno");
    p.move(m_letterPos[7].x() - m_letterPos[6].x(), 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("fghijkl mno");
}
// Tests moving selection extent over to the other side of the base
// on text "abcd efgh ijkl mno^pqr|> iiinmni, abc"
// (^ means base, | means extent, < means start, and > means end).
// Text needs to be laid out on a single line with no rotation.
void GranularityStrategyTest::testDirectionSwitchSide()
{
    // Move to the middle of word #4, selecting it - this will set the offset to
    // be half the width of "iiinmni.
    selection().moveRangeSelectionExtent(m_wordMiddles[4]);
    EXPECT_EQ_SELECTED_TEXT("pqr iiinmni");
    // Move back leaving only one letter selected.
    IntPoint p = m_wordMiddles[4];
    p.move(m_letterPos[19].x() - m_letterPos[29].x(), 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("p");
    // Confirm selection doesn't change if extent is positioned at base.
    p.move(m_letterPos[18].x() - m_letterPos[19].x(), 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("p");
    // Move over to the other side of the base. Confirm the offset is preserved.
    // (i.e. the selection start stays on the right of the extent)
    // Confirm we stay in character granularity until the beginning of the word
    // is passed.
    p.move(m_letterPos[17].x() - m_letterPos[18].x(), 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("o");
    p.move(m_letterPos[16].x() - m_letterPos[17].x(), 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("no");
    p.move(m_letterPos[14].x() - m_letterPos[16].x(), 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT(" mno");
    // Move to just one pixel on the right before the middle of the word #2.
    // We should switch to word granularity, so the selection shouldn't change.
    p.move(m_wordMiddles[2].x() - m_letterPos[14].x() + 1, 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT(" mno");
    // Move over the middle of the word. The word should get selected.
    // This should reduce the offset, but it should still stay greated than 0,
    // since the width of "iiinmni" is greater than the width of "ijkl".
    p.move(-2, 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("ijkl mno");
    // Move to just one pixel on the right of the middle of word #1.
    // The selection should now include the space between the words.
    p.move(m_wordMiddles[1].x() - m_letterPos[10].x() + 1, 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT(" ijkl mno");
    // Move over the middle of the word. The word should get selected.
    p.move(-2, 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("efgh ijkl mno");
}
TEST_F(GranularityStrategyTest, DirectionExpandVerticalAlign)
{
    // "abcdef ghij kl mno^p|>qr stuvwi inm  mnii," (^ means base, | means extent, < means start, and > means end).
    setupVerticalAlign("abcdef ghij kl m", "nopq", "r stuvwi inm mnii,", 18, 19);
    EXPECT_EQ_SELECTED_TEXT("p");
    testDirectionExpand();
}
TEST_F(GranularityStrategyTest, DirectionShrinkTranslateZ)
{
    RawPtr<Text> text = setupTranslateZ("abcdef ghij kl mnopqr iiinmni, abc");
    selection().setSelection(VisibleSelection(Position(text, 18), Position(text, 21)));
    EXPECT_EQ_SELECTED_TEXT("pqr");
    testDirectionShrink();
}
TEST_F(GranularityStrategyTest, DirectionSwitchSideTransform)
{
    RefPtrWillBeRawPtr<Text> text = setupTransform("abcd efgh ijkl mnopqr iiinmni, abc");
    selection().setSelection(VisibleSelection(Position(text, 18), Position(text, 21)));
    EXPECT_EQ_SELECTED_TEXT("pqr");
    testDirectionSwitchSide();
}
TEST_F(FrameSelectionTest, SelectWordAroundPosition)
{
    // "Foo Bar  Baz,"
    RefPtrWillBeRawPtr<Text> text = appendTextNode("Foo Bar&nbsp;&nbsp;Baz,");
    // "Fo|o Bar  Baz,"
    EXPECT_TRUE(selection().selectWordAroundPosition(VisiblePosition(Position(text, 2))));
    EXPECT_EQ_SELECTED_TEXT("Foo");
    // "Foo| Bar  Baz,"
    EXPECT_TRUE(selection().selectWordAroundPosition(VisiblePosition(Position(text, 3))));
    EXPECT_EQ_SELECTED_TEXT("Foo");
    // "Foo Bar | Baz,"
    EXPECT_FALSE(selection().selectWordAroundPosition(VisiblePosition(Position(text, 13))));
    // "Foo Bar  Baz|,"
    EXPECT_TRUE(selection().selectWordAroundPosition(VisiblePosition(Position(text, 22))));
    EXPECT_EQ_SELECTED_TEXT("Baz");
}
// Test for the default CharacterGranularityStrategy
TEST_F(GranularityStrategyTest, Character)
{
    dummyPageHolder().frame().settings()->setSelectionStrategy(SelectionStrategy::Character);
    dummyPageHolder().frame().settings()->setDefaultFontSize(12);
    // "Foo Bar Baz,"
    RefPtrWillBeRawPtr<Text> text = appendTextNode("Foo Bar Baz,");
    // "Foo B^a|>r Baz," (^ means base, | means extent, , < means start, and > means end).
    selection().setSelection(VisibleSelection(Position(text, 5), Position(text, 6)));
    EXPECT_EQ_SELECTED_TEXT("a");
    // "Foo B^ar B|>az,"
    selection().moveRangeSelectionExtent(visiblePositionToContentsPoint(createVisiblePosition(Position(text, 9))));
    EXPECT_EQ_SELECTED_TEXT("ar B");
    // "F<|oo B^ar Baz,"
    selection().moveRangeSelectionExtent(visiblePositionToContentsPoint(createVisiblePosition(Position(text, 1))));
    EXPECT_EQ_SELECTED_TEXT("oo B");
}
// Make sure we switch to word granularity right away when starting on a
// word boundary and extending.
TEST_F(GranularityStrategyTest, DirectionSwitchStartOnBoundary)
{
    dummyPageHolder().frame().settings()->setDefaultFontSize(12);
    String str = "ab cd efghijkl mnopqr iiin, abc";
    RefPtrWillBeRawPtr<Text> text = document().createTextNode(str);
    document().body()->appendChild(text);
    dummyPageHolder().frame().settings()->setSelectionStrategy(SelectionStrategy::Direction);

    parseText(text.get());

    // "ab cd efghijkl ^mnopqr |>stuvwi inm," (^ means base and | means extent,
    // > means end).
    selection().setSelection(VisibleSelection(Position(text, 15), Position(text, 22)));
    EXPECT_EQ_SELECTED_TEXT("mnopqr ");
    selection().moveRangeSelectionExtent(m_wordMiddles[4]);
    EXPECT_EQ_SELECTED_TEXT("mnopqr iiin");
}
TEST_F(GranularityStrategyTest, DirectionExpandTransform)
{
    RefPtrWillBeRawPtr<Text> text = setupTransform("abcdef ghij kl mnopqr stuvwi inm mnii,");
    // "abcdef ghij kl mno^p|>qr stuvwi inm  mnii," (^ means base, | means extent, < means start, and > means end).
    selection().setSelection(VisibleSelection(Position(text, 18), Position(text, 19)));
    EXPECT_EQ_SELECTED_TEXT("p");
    testDirectionExpand();
}
// DirectionGranularityStrategy strategy on rotated text should revert to the
// same behavior as CharacterGranularityStrategy
TEST_F(GranularityStrategyTest, DirectionRotate)
{
    RefPtrWillBeRawPtr<Text> text = setupRotate("Foo Bar Baz,");
    // "Foo B^a|>r Baz," (^ means base, | means extent, , < means start, and > means end).
    selection().setSelection(VisibleSelection(Position(text, 5), Position(text, 6)));
    EXPECT_EQ_SELECTED_TEXT("a");
    IntPoint p = m_letterPos[9];
    // Need to move by one pixel, otherwise this point is not evaluated
    // to the same line as the text by hit testing.
    p.move(1, 0);
    // "Foo B^ar B|>az,"
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("ar B");
    p = m_letterPos[1];
    p.move(1, 0);
    // "F<|oo B^ar Baz,"
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("oo B");
}
TEST_F(FrameSelectionTest, MoveRangeSelectionTest)
{
    // "Foo Bar Baz,"
    RefPtrWillBeRawPtr<Text> text = appendTextNode("Foo Bar Baz,");
    // Itinitializes with "Foo B|a>r Baz," (| means start and > means end).
    selection().setSelection(VisibleSelection(Position(text, 5), Position(text, 6)));
    EXPECT_EQ_SELECTED_TEXT("a");

    // "Foo B|ar B>az," with the Character granularity.
    selection().moveRangeSelection(VisiblePosition(Position(text, 5)), VisiblePosition(Position(text, 9)), CharacterGranularity);
    EXPECT_EQ_SELECTED_TEXT("ar B");
    // "Foo B|ar B>az," with the Word granularity.
    selection().moveRangeSelection(VisiblePosition(Position(text, 5)), VisiblePosition(Position(text, 9)), WordGranularity);
    EXPECT_EQ_SELECTED_TEXT("Bar Baz");
    // "Fo<o B|ar Baz," with the Character granularity.
    selection().moveRangeSelection(VisiblePosition(Position(text, 5)), VisiblePosition(Position(text, 2)), CharacterGranularity);
    EXPECT_EQ_SELECTED_TEXT("o B");
    // "Fo<o B|ar Baz," with the Word granularity.
    selection().moveRangeSelection(VisiblePosition(Position(text, 5)), VisiblePosition(Position(text, 2)), WordGranularity);
    EXPECT_EQ_SELECTED_TEXT("Foo Bar");
}
TEST_F(GranularityStrategyTest, DirectionSwitchSideFontSizes)
{
    setupFontSize("abcd efgh i", "jk", "l mnopqr iiinmni, abc", 18, 21);
    EXPECT_EQ_SELECTED_TEXT("pqr");
    testDirectionSwitchSide();
}
TEST_F(GranularityStrategyTest, DirectionSwitchSideVerticalAlign)
{
    setupVerticalAlign("abcd efgh ijkl", " mnopqr", " iiinmni, abc", 18, 21);
    EXPECT_EQ_SELECTED_TEXT("pqr");
    testDirectionSwitchSide();
}
TEST_F(GranularityStrategyTest, DirectionShrinkFontSizes)
{
    setupFontSize("abcdef ghij kl mnopqr ii", "inm", "ni, abc", 18, 21);
    EXPECT_EQ_SELECTED_TEXT("pqr");
    testDirectionShrink();
}
TEST_F(GranularityStrategyTest, DirectionShrinkVerticalAlign)
{
    setupVerticalAlign("abcdef ghij kl mnopqr ii", "inm", "ni, abc", 18, 21);
    EXPECT_EQ_SELECTED_TEXT("pqr");
    testDirectionShrink();
}
TEST_F(GranularityStrategyTest, DirectionExpandFontSizes)
{
    setupFontSize("abcdef ghij kl mnopqr st", "uv", "wi inm mnii,", 18, 19);
    EXPECT_EQ_SELECTED_TEXT("p");
    testDirectionExpand();
}
// Tests expanding selection on text "abcdef ghij kl mno^p|>qr stuvwi inm  mnii,"
// (^ means base, | means extent, < means start, and > means end).
// Text needs to be laid out on a single line with no rotation.
void GranularityStrategyTest::testDirectionExpand()
{
    // Expand selection using character granularity until the end of the word
    // is reached.
    // "abcdef ghij kl mno^pq|>r stuvwi inm  mnii,"
    selection().moveRangeSelectionExtent(m_letterPos[20]);
    EXPECT_EQ_SELECTED_TEXT("pq");
    // Move to the same postion shouldn't change anything.
    selection().moveRangeSelectionExtent(m_letterPos[20]);
    EXPECT_EQ_SELECTED_TEXT("pq");
    // "abcdef ghij kl mno^pqr|> stuvwi inm  mnii,"
    selection().moveRangeSelectionExtent(m_letterPos[21]);
    EXPECT_EQ_SELECTED_TEXT("pqr");
    // Selection should stay the same until the middle of the word is passed.
    // "abcdef ghij kl mno^pqr |>stuvwi inm  mnii," -
    selection().moveRangeSelectionExtent(m_letterPos[22]);
    EXPECT_EQ_SELECTED_TEXT("pqr ");
    // "abcdef ghij kl mno^pqr >st|uvwi inm  mnii,"
    selection().moveRangeSelectionExtent(m_letterPos[24]);
    EXPECT_EQ_SELECTED_TEXT("pqr ");
    IntPoint p = m_wordMiddles[4];
    p.move(-1, 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("pqr ");
    p.move(1, 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("pqr stuvwi");
    // Selection should stay the same until the end of the word is reached.
    // "abcdef ghij kl mno^pqr stuvw|i> inm  mnii,"
    selection().moveRangeSelectionExtent(m_letterPos[27]);
    EXPECT_EQ_SELECTED_TEXT("pqr stuvwi");
    // "abcdef ghij kl mno^pqr stuvwi|> inm  mnii,"
    selection().moveRangeSelectionExtent(m_letterPos[28]);
    EXPECT_EQ_SELECTED_TEXT("pqr stuvwi");
    // "abcdef ghij kl mno^pqr stuvwi |>inm  mnii,"
    selection().moveRangeSelectionExtent(m_letterPos[29]);
    EXPECT_EQ_SELECTED_TEXT("pqr stuvwi ");
    // Now expand slowly to the middle of word #5.
    int y = m_letterPos[29].y();
    for (int x = m_letterPos[29].x() + 1; x < m_wordMiddles[5].x(); x++) {
        selection().moveRangeSelectionExtent(IntPoint(x, y));
        selection().moveRangeSelectionExtent(IntPoint(x, y));
        EXPECT_EQ_SELECTED_TEXT("pqr stuvwi ");
    }
    selection().moveRangeSelectionExtent(m_wordMiddles[5]);
    EXPECT_EQ_SELECTED_TEXT("pqr stuvwi inm");
    // Jump over quickly to just before the middle of the word #6 and then
    // move over it.
    p = m_wordMiddles[6];
    p.move(-1, 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("pqr stuvwi inm ");
    p.move(1, 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("pqr stuvwi inm mnii");
}
// Tests shrinking selection on text "abcdef ghij kl mno^pqr|> iiinmni, abc"
// (^ means base, | means extent, < means start, and > means end).
// Text needs to be laid out on a single line with no rotation.
void GranularityStrategyTest::testDirectionShrink()
{
    // Move to the middle of word #4 to it and then move back, confirming
    // that the selection end is moving with the extent. The offset between the
    // extent and the selection end will be equal to half the width of "iiinmni".
    selection().moveRangeSelectionExtent(m_wordMiddles[4]);
    EXPECT_EQ_SELECTED_TEXT("pqr iiinmni");
    IntPoint p = m_wordMiddles[4];
    p.move(m_letterPos[28].x() - m_letterPos[29].x(), 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("pqr iiinmn");
    p.move(m_letterPos[27].x() - m_letterPos[28].x(), 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("pqr iiinm");
    p.move(m_letterPos[26].x() - m_letterPos[27].x(), 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("pqr iiin");
    // Move right by the width of char 30 ('m'). Selection shouldn't change,
    // but offset should be reduced.
    p.move(m_letterPos[27].x() - m_letterPos[26].x(), 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("pqr iiin");
    // Move back a couple of character widths and confirm the selection still
    // updates accordingly.
    p.move(m_letterPos[25].x() - m_letterPos[26].x(), 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("pqr iii");
    p.move(m_letterPos[24].x() - m_letterPos[25].x(), 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("pqr ii");
    // "Catch up" with the handle - move the extent to where the handle is.
    // "abcdef ghij kl mno^pqr ii|>inmni, abc"
    selection().moveRangeSelectionExtent(m_letterPos[24]);
    EXPECT_EQ_SELECTED_TEXT("pqr ii");
    // Move ahead and confirm the selection expands accordingly
    // "abcdef ghij kl mno^pqr iii|>nmni, abc"
    selection().moveRangeSelectionExtent(m_letterPos[25]);
    EXPECT_EQ_SELECTED_TEXT("pqr iii");

    // Confirm we stay in character granularity if the user moves within a word.
    // "abcdef ghij kl mno^pqr |>iiinmni, abc"
    selection().moveRangeSelectionExtent(m_letterPos[22]);
    EXPECT_EQ_SELECTED_TEXT("pqr ");
    // It's possible to get a move when position doesn't change.
    // It shouldn't affect anything.
    p = m_letterPos[22];
    p.move(1, 0);
    selection().moveRangeSelectionExtent(p);
    EXPECT_EQ_SELECTED_TEXT("pqr ");
    // "abcdef ghij kl mno^pqr i|>iinmni, abc"
    selection().moveRangeSelectionExtent(m_letterPos[23]);
    EXPECT_EQ_SELECTED_TEXT("pqr i");
}