Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / html / HTMLTextFormControlElementTest.cpp
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "core/html/HTMLTextFormControlElement.h"
7
8 #include "core/dom/Position.h"
9 #include "core/dom/Text.h"
10 #include "core/editing/FrameSelection.h"
11 #include "core/editing/SpellChecker.h"
12 #include "core/editing/VisibleSelection.h"
13 #include "core/editing/VisibleUnits.h"
14 #include "core/frame/FrameView.h"
15 #include "core/html/HTMLBRElement.h"
16 #include "core/html/HTMLDocument.h"
17 #include "core/html/HTMLInputElement.h"
18 #include "core/html/HTMLTextAreaElement.h"
19 #include "core/loader/EmptyClients.h"
20 #include "core/page/SpellCheckerClient.h"
21 #include "core/rendering/RenderTreeAsText.h"
22 #include "core/testing/DummyPageHolder.h"
23 #include "core/testing/UnitTestHelpers.h"
24 #include "wtf/OwnPtr.h"
25 #include <gtest/gtest.h>
26
27 using namespace blink;
28
29 namespace {
30
31 class HTMLTextFormControlElementTest : public ::testing::Test {
32 protected:
33     virtual void SetUp() override;
34
35     DummyPageHolder& page() const { return *m_dummyPageHolder; }
36     HTMLDocument& document() const { return *m_document; }
37     HTMLTextFormControlElement& textControl() const { return *m_textControl; }
38     HTMLInputElement& input() const { return *m_input; }
39
40     int layoutCount() const { return page().frameView().layoutCount(); }
41     void forceLayoutFlag();
42
43 private:
44     OwnPtr<SpellCheckerClient> m_spellCheckerClient;
45     OwnPtr<DummyPageHolder> m_dummyPageHolder;
46
47     RefPtrWillBePersistent<HTMLDocument> m_document;
48     RefPtrWillBePersistent<HTMLTextFormControlElement> m_textControl;
49     RefPtrWillBePersistent<HTMLInputElement> m_input;
50 };
51
52 class DummyTextCheckerClient : public EmptyTextCheckerClient {
53 public:
54     ~DummyTextCheckerClient() { }
55
56     virtual bool shouldEraseMarkersAfterChangeSelection(TextCheckingType) const override { return false; }
57 };
58
59 class DummySpellCheckerClient : public EmptySpellCheckerClient {
60 public:
61     virtual ~DummySpellCheckerClient() { }
62
63     virtual bool isContinuousSpellCheckingEnabled() override { return true; }
64     virtual bool isGrammarCheckingEnabled() override { return true; }
65
66     virtual TextCheckerClient& textChecker() override { return m_dummyTextCheckerClient; }
67
68 private:
69     DummyTextCheckerClient m_dummyTextCheckerClient;
70 };
71
72 void HTMLTextFormControlElementTest::SetUp()
73 {
74     Page::PageClients pageClients;
75     fillWithEmptyClients(pageClients);
76     m_spellCheckerClient = adoptPtr(new DummySpellCheckerClient);
77     pageClients.spellCheckerClient = m_spellCheckerClient.get();
78     m_dummyPageHolder = DummyPageHolder::create(IntSize(800, 600), &pageClients);
79
80     m_document = toHTMLDocument(&m_dummyPageHolder->document());
81     m_document->documentElement()->setInnerHTML("<body><textarea id=textarea></textarea><input id=input /></body>", ASSERT_NO_EXCEPTION);
82     m_document->view()->updateLayoutAndStyleIfNeededRecursive();
83     m_textControl = toHTMLTextFormControlElement(m_document->getElementById("textarea"));
84     m_textControl->focus();
85     m_input = toHTMLInputElement(m_document->getElementById("input"));
86 }
87
88 void HTMLTextFormControlElementTest::forceLayoutFlag()
89 {
90     FrameView& frameView = page().frameView();
91     IntRect frameRect = frameView.frameRect();
92     frameRect.setWidth(frameRect.width() + 1);
93     frameRect.setHeight(frameRect.height() + 1);
94     page().frameView().setFrameRect(frameRect);
95 }
96
97 TEST_F(HTMLTextFormControlElementTest, SetSelectionRange)
98 {
99     EXPECT_EQ(0, textControl().selectionStart());
100     EXPECT_EQ(0, textControl().selectionEnd());
101
102     textControl().setInnerEditorValue("Hello, text form.");
103     EXPECT_EQ(0, textControl().selectionStart());
104     EXPECT_EQ(0, textControl().selectionEnd());
105
106     textControl().setSelectionRange(1, 3);
107     EXPECT_EQ(1, textControl().selectionStart());
108     EXPECT_EQ(3, textControl().selectionEnd());
109 }
110
111 TEST_F(HTMLTextFormControlElementTest, SetSelectionRangeDoesNotCauseLayout)
112 {
113     input().focus();
114     input().setValue("Hello, input form.");
115     input().setSelectionRange(1, 1);
116     FrameSelection& frameSelection = document().frame()->selection();
117     forceLayoutFlag();
118     LayoutRect oldCaretRect = frameSelection.absoluteCaretBounds();
119     EXPECT_FALSE(oldCaretRect.isEmpty());
120     int startLayoutCount = layoutCount();
121     input().setSelectionRange(1, 1);
122     EXPECT_EQ(startLayoutCount, layoutCount());
123     LayoutRect newCaretRect = frameSelection.absoluteCaretBounds();
124     EXPECT_EQ(oldCaretRect, newCaretRect);
125
126     forceLayoutFlag();
127     oldCaretRect = frameSelection.absoluteCaretBounds();
128     EXPECT_FALSE(oldCaretRect.isEmpty());
129     startLayoutCount = layoutCount();
130     input().setSelectionRange(2, 2);
131     EXPECT_EQ(startLayoutCount, layoutCount());
132     newCaretRect = frameSelection.absoluteCaretBounds();
133     EXPECT_NE(oldCaretRect, newCaretRect);
134 }
135
136 typedef Position (*PositionFunction)(const Position&);
137 typedef VisiblePosition(*VisblePositionFunction)(const VisiblePosition&);
138
139 void testFunctionEquivalence(const Position& position, PositionFunction positionFunction, VisblePositionFunction visibleFunction)
140 {
141     VisiblePosition visiblePosition(position);
142     VisiblePosition expected = visibleFunction(visiblePosition);
143     VisiblePosition actual = VisiblePosition(positionFunction(position));
144     EXPECT_EQ(expected, actual);
145 }
146
147 static VisiblePosition startOfWord(const VisiblePosition& position)
148 {
149     return startOfWord(position, LeftWordIfOnBoundary);
150 }
151
152 static VisiblePosition endOfWord(const VisiblePosition& position)
153 {
154     return endOfWord(position, RightWordIfOnBoundary);
155 }
156
157 void testBoundary(HTMLDocument& document, HTMLTextFormControlElement& textControl)
158 {
159     for (unsigned i = 0; i < textControl.innerEditorValue().length(); i++) {
160         textControl.setSelectionRange(i, i);
161         Position position = document.frame()->selection().start();
162         SCOPED_TRACE(::testing::Message() << "offset " << position.deprecatedEditingOffset() << " of " << nodePositionAsStringForTesting(position.deprecatedNode()).ascii().data());
163         {
164             SCOPED_TRACE("HTMLTextFormControlElement::startOfWord");
165             testFunctionEquivalence(position, HTMLTextFormControlElement::startOfWord, startOfWord);
166         }
167         {
168             SCOPED_TRACE("HTMLTextFormControlElement::endOfWord");
169             testFunctionEquivalence(position, HTMLTextFormControlElement::endOfWord, endOfWord);
170         }
171         {
172             SCOPED_TRACE("HTMLTextFormControlElement::startOfSentence");
173             testFunctionEquivalence(position, HTMLTextFormControlElement::startOfSentence, startOfSentence);
174         }
175         {
176             SCOPED_TRACE("HTMLTextFormControlElement::endOfSentence");
177             testFunctionEquivalence(position, HTMLTextFormControlElement::endOfSentence, endOfSentence);
178         }
179     }
180 }
181
182 TEST_F(HTMLTextFormControlElementTest, WordAndSentenceBoundary)
183 {
184     HTMLElement* innerText = textControl().innerEditorElement();
185     {
186         SCOPED_TRACE("String is value.");
187         innerText->removeChildren();
188         innerText->setNodeValue("Hel\nlo, text form.\n");
189         testBoundary(document(), textControl());
190     }
191     {
192         SCOPED_TRACE("A Text node and a BR element");
193         innerText->removeChildren();
194         innerText->setNodeValue("");
195         innerText->appendChild(Text::create(document(), "Hello, text form."));
196         innerText->appendChild(HTMLBRElement::create(document()));
197         testBoundary(document(), textControl());
198     }
199     {
200         SCOPED_TRACE("Text nodes.");
201         innerText->removeChildren();
202         innerText->setNodeValue("");
203         innerText->appendChild(Text::create(document(), "Hel\nlo, te"));
204         innerText->appendChild(Text::create(document(), "xt form."));
205         testBoundary(document(), textControl());
206     }
207 }
208
209 TEST_F(HTMLTextFormControlElementTest, SpellCheckDoesNotCauseUpdateLayout)
210 {
211     HTMLInputElement* input = toHTMLInputElement(document().getElementById("input"));
212     input->focus();
213     input->setValue("Hello, input field");
214     VisibleSelection oldSelection = document().frame()->selection().selection();
215
216     Position newPosition(input->innerEditorElement()->firstChild(), 3, Position::PositionIsOffsetInAnchor);
217     VisibleSelection newSelection(newPosition, DOWNSTREAM);
218     document().frame()->selection().setSelection(newSelection, FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle | FrameSelection::DoNotUpdateAppearance);
219     ASSERT_EQ(3, input->selectionStart());
220
221     OwnPtrWillBePersistent<SpellChecker> spellChecker(SpellChecker::create(page().frame()));
222     forceLayoutFlag();
223     int startCount = layoutCount();
224     spellChecker->respondToChangedSelection(oldSelection, FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle);
225     EXPECT_EQ(startCount, layoutCount());
226 }
227
228 }