1197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch// found in the LICENSE file.
4197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
5197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "config.h"
6197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "core/editing/InputMethodController.h"
7197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
8197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "core/dom/Element.h"
9197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "core/dom/Range.h"
10197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "core/frame/LocalFrame.h"
11197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "core/html/HTMLDocument.h"
12197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "core/html/HTMLInputElement.h"
13197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "core/testing/DummyPageHolder.h"
14197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include <gtest/gtest.h>
15197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
16197021e6b966cfb06891637935ef33fff06433d1Ben Murdochusing namespace blink;
17197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
18197021e6b966cfb06891637935ef33fff06433d1Ben Murdochnamespace {
19197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
20197021e6b966cfb06891637935ef33fff06433d1Ben Murdochclass InputMethodControllerTest : public ::testing::Test {
21197021e6b966cfb06891637935ef33fff06433d1Ben Murdochprotected:
22197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    InputMethodController& controller() { return frame().inputMethodController(); }
23197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    HTMLDocument& document() const { return *m_document; }
24197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    LocalFrame& frame() const { return m_dummyPageHolder->frame(); }
25197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    Element* insertHTMLElement(const char* elementCode, const char* elementId);
26197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
27197021e6b966cfb06891637935ef33fff06433d1Ben Murdochprivate:
28197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    virtual void SetUp() OVERRIDE;
29197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
30197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    OwnPtr<DummyPageHolder> m_dummyPageHolder;
31197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    HTMLDocument* m_document;
32197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch};
33197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
34197021e6b966cfb06891637935ef33fff06433d1Ben Murdochvoid InputMethodControllerTest::SetUp()
35197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch{
36197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    m_dummyPageHolder = DummyPageHolder::create(IntSize(800, 600));
37197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    m_document = toHTMLDocument(&m_dummyPageHolder->document());
38197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    ASSERT(m_document);
39197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch}
40197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
41197021e6b966cfb06891637935ef33fff06433d1Ben MurdochElement* InputMethodControllerTest::insertHTMLElement(
42197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    const char* elementCode, const char* elementId)
43197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch{
44197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    document().write(elementCode);
45197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    document().updateLayout();
46197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    Element* element = document().getElementById(elementId);
47197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    element->focus();
48197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    return element;
49197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch}
50197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
51197021e6b966cfb06891637935ef33fff06433d1Ben MurdochTEST_F(InputMethodControllerTest, BackspaceFromEndOfInput)
52197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch{
53197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    HTMLInputElement* input = toHTMLInputElement(
54197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch        insertHTMLElement("<input id='sample'>", "sample"));
55197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
56197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    input->setValue("fooX");
57197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    controller().setEditableSelectionOffsets(PlainTextRange(4, 4));
58197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_STREQ("fooX", input->value().utf8().data());
59c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    controller().extendSelectionAndDelete(0, 0);
60c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    EXPECT_STREQ("fooX", input->value().utf8().data());
61c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)
62c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    input->setValue("fooX");
63c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    controller().setEditableSelectionOffsets(PlainTextRange(4, 4));
64c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    EXPECT_STREQ("fooX", input->value().utf8().data());
65197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    controller().extendSelectionAndDelete(1, 0);
66197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_STREQ("foo", input->value().utf8().data());
67197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
68197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    input->setValue(String::fromUTF8("foo\xE2\x98\x85")); // U+2605 == "black star"
69197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    controller().setEditableSelectionOffsets(PlainTextRange(4, 4));
70197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_STREQ("foo\xE2\x98\x85", input->value().utf8().data());
71197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    controller().extendSelectionAndDelete(1, 0);
72197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_STREQ("foo", input->value().utf8().data());
73197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
74197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    input->setValue(String::fromUTF8("foo\xF0\x9F\x8F\x86")); // U+1F3C6 == "trophy"
75197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    controller().setEditableSelectionOffsets(PlainTextRange(4, 4));
76197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_STREQ("foo\xF0\x9F\x8F\x86", input->value().utf8().data());
77197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    controller().extendSelectionAndDelete(1, 0);
78197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_STREQ("foo", input->value().utf8().data());
79197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
80197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    input->setValue(String::fromUTF8("foo\xE0\xB8\x81\xE0\xB9\x89")); // composed U+0E01 "ka kai" + U+0E49 "mai tho"
81197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    controller().setEditableSelectionOffsets(PlainTextRange(4, 4));
82197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_STREQ("foo\xE0\xB8\x81\xE0\xB9\x89", input->value().utf8().data());
83197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    controller().extendSelectionAndDelete(1, 0);
84197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_STREQ("foo", input->value().utf8().data());
85c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)
86c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    input->setValue("fooX");
87c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    controller().setEditableSelectionOffsets(PlainTextRange(4, 4));
88c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    EXPECT_STREQ("fooX", input->value().utf8().data());
89c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    controller().extendSelectionAndDelete(0, 1);
90c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    EXPECT_STREQ("fooX", input->value().utf8().data());
91197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch}
92197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
93197021e6b966cfb06891637935ef33fff06433d1Ben MurdochTEST_F(InputMethodControllerTest, SetCompositionFromExistingText)
94197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch{
95197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    Element* div = insertHTMLElement(
96197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch        "<div id='sample' contenteditable='true'>hello world</div>", "sample");
97197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
98197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    Vector<CompositionUnderline> underlines;
99197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0));
100197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    controller().setCompositionFromExistingText(underlines, 0, 5);
101197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
102197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    RefPtrWillBeRawPtr<Range> range = controller().compositionRange();
103197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_EQ(0, range->startOffset());
104197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_EQ(5, range->endOffset());
105197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
106197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    PlainTextRange plainTextRange(PlainTextRange::create(*div, *range.get()));
107197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_EQ(0u, plainTextRange.start());
108197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_EQ(5u, plainTextRange.end());
109197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch}
110197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
111197021e6b966cfb06891637935ef33fff06433d1Ben MurdochTEST_F(InputMethodControllerTest, SetCompositionFromExistingTextWithCollapsedWhiteSpace)
112197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch{
113197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    // Creates a div with one leading new line char. The new line char is hidden
114197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    // from the user and IME, but is visible to InputMethodController.
115197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    Element* div = insertHTMLElement(
116197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch        "<div id='sample' contenteditable='true'>\nhello world</div>", "sample");
117197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
118197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    Vector<CompositionUnderline> underlines;
119197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0));
120197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    controller().setCompositionFromExistingText(underlines, 0, 5);
121197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
122197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    RefPtrWillBeRawPtr<Range> range = controller().compositionRange();
123197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_EQ(1, range->startOffset());
124197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_EQ(6, range->endOffset());
125197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
126197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    PlainTextRange plainTextRange(PlainTextRange::create(*div, *range.get()));
127197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_EQ(0u, plainTextRange.start());
128197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    EXPECT_EQ(5u, plainTextRange.end());
129197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch}
130197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
1317242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano TucciTEST_F(InputMethodControllerTest, SetCompositionFromExistingTextWithInvalidOffsets)
1327242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci{
1337242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    insertHTMLElement("<div id='sample' contenteditable='true'>test</div>", "sample");
1347242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1357242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    Vector<CompositionUnderline> underlines;
1367242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    underlines.append(CompositionUnderline(7, 8, Color(255, 0, 0), false, 0));
1377242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    controller().setCompositionFromExistingText(underlines, 7, 8);
1387242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1397242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    EXPECT_FALSE(controller().compositionRange());
1407242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci}
1417242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
142197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch} // namespace
143