| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/editing/InputMethodController.h" | 5 #include "core/editing/InputMethodController.h" |
| 6 | 6 |
| 7 #include "core/dom/Document.h" | 7 #include "core/dom/Document.h" |
| 8 #include "core/dom/Element.h" | 8 #include "core/dom/Element.h" |
| 9 #include "core/dom/Range.h" | 9 #include "core/dom/Range.h" |
| 10 #include "core/editing/Editor.h" | 10 #include "core/editing/Editor.h" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 namespace blink { | 21 namespace blink { |
| 22 | 22 |
| 23 class InputMethodControllerTest : public ::testing::Test { | 23 class InputMethodControllerTest : public ::testing::Test { |
| 24 protected: | 24 protected: |
| 25 InputMethodController& controller() { | 25 InputMethodController& controller() { |
| 26 return frame().inputMethodController(); | 26 return frame().inputMethodController(); |
| 27 } | 27 } |
| 28 Document& document() const { return *m_document; } | 28 Document& document() const { return *m_document; } |
| 29 LocalFrame& frame() const { return m_dummyPageHolder->frame(); } | 29 LocalFrame& frame() const { return m_dummyPageHolder->frame(); } |
| 30 Element* insertHTMLElement(const char* elementCode, const char* elementId); | 30 Element* insertHTMLElement(const char* elementCode, const char* elementId); |
| 31 void createHTMLWithCompositionInputEventListeners(); |
| 32 void createHTMLWithCompositionEndEventListener(const SelectionType); |
| 31 | 33 |
| 32 private: | 34 private: |
| 33 void SetUp() override; | 35 void SetUp() override; |
| 34 | 36 |
| 35 std::unique_ptr<DummyPageHolder> m_dummyPageHolder; | 37 std::unique_ptr<DummyPageHolder> m_dummyPageHolder; |
| 36 Persistent<Document> m_document; | 38 Persistent<Document> m_document; |
| 37 }; | 39 }; |
| 38 | 40 |
| 39 void InputMethodControllerTest::SetUp() { | 41 void InputMethodControllerTest::SetUp() { |
| 40 m_dummyPageHolder = DummyPageHolder::create(IntSize(800, 600)); | 42 m_dummyPageHolder = DummyPageHolder::create(IntSize(800, 600)); |
| 41 m_document = &m_dummyPageHolder->document(); | 43 m_document = &m_dummyPageHolder->document(); |
| 42 DCHECK(m_document); | 44 DCHECK(m_document); |
| 43 } | 45 } |
| 44 | 46 |
| 45 Element* InputMethodControllerTest::insertHTMLElement(const char* elementCode, | 47 Element* InputMethodControllerTest::insertHTMLElement(const char* elementCode, |
| 46 const char* elementId) { | 48 const char* elementId) { |
| 47 document().write(elementCode); | 49 document().write(elementCode); |
| 48 document().updateStyleAndLayout(); | 50 document().updateStyleAndLayout(); |
| 49 Element* element = document().getElementById(elementId); | 51 Element* element = document().getElementById(elementId); |
| 50 element->focus(); | 52 element->focus(); |
| 51 return element; | 53 return element; |
| 52 } | 54 } |
| 53 | 55 |
| 56 void InputMethodControllerTest::createHTMLWithCompositionInputEventListeners() { |
| 57 document().settings()->setScriptEnabled(true); |
| 58 Element* editable = |
| 59 insertHTMLElement("<div id='sample' contenteditable></div>", "sample"); |
| 60 Element* script = document().createElement("script"); |
| 61 script->setInnerHTML( |
| 62 "document.getElementById('sample').addEventListener('beforeinput', " |
| 63 " event => document.title = `beforeinput.data:${event.data};`);" |
| 64 "document.getElementById('sample').addEventListener('input', " |
| 65 " event => document.title += `input.data:${event.data};`);" |
| 66 "document.getElementById('sample').addEventListener('compositionend', " |
| 67 " event => document.title += `compositionend.data:${event.data};`);"); |
| 68 document().body()->appendChild(script); |
| 69 document().view()->updateAllLifecyclePhases(); |
| 70 editable->focus(); |
| 71 } |
| 72 |
| 73 void InputMethodControllerTest::createHTMLWithCompositionEndEventListener( |
| 74 const SelectionType type) { |
| 75 document().settings()->setScriptEnabled(true); |
| 76 Element* editable = |
| 77 insertHTMLElement("<div id='sample' contentEditable></div>", "sample"); |
| 78 Element* script = document().createElement("script"); |
| 79 |
| 80 switch (type) { |
| 81 case NoSelection: |
| 82 script->setInnerHTML( |
| 83 // If the caret position is set before firing 'compositonend' event |
| 84 // (and it should), the final caret position will be reset to null. |
| 85 "document.getElementById('sample').addEventListener('compositionend'," |
| 86 " event => getSelection().removeAllRanges());"); |
| 87 break; |
| 88 case CaretSelection: |
| 89 script->setInnerHTML( |
| 90 // If the caret position is set before firing 'compositonend' event |
| 91 // (and it should), the final caret position will be reset to [3,3]. |
| 92 "document.getElementById('sample').addEventListener('compositionend'," |
| 93 " event => {" |
| 94 " const node = document.getElementById('sample').firstChild;" |
| 95 " getSelection().collapse(node, 3);" |
| 96 "});"); |
| 97 break; |
| 98 case RangeSelection: |
| 99 script->setInnerHTML( |
| 100 // If the caret position is set before firing 'compositonend' event |
| 101 // (and it should), the final caret position will be reset to [2,4]. |
| 102 "document.getElementById('sample').addEventListener('compositionend'," |
| 103 " event => {" |
| 104 " const node = document.getElementById('sample').firstChild;" |
| 105 " const selection = getSelection();" |
| 106 " selection.collapse(node, 2);" |
| 107 " selection.extend(node, 4);" |
| 108 "});"); |
| 109 break; |
| 110 default: |
| 111 NOTREACHED(); |
| 112 } |
| 113 document().body()->appendChild(script); |
| 114 document().view()->updateAllLifecyclePhases(); |
| 115 editable->focus(); |
| 116 } |
| 117 |
| 54 TEST_F(InputMethodControllerTest, BackspaceFromEndOfInput) { | 118 TEST_F(InputMethodControllerTest, BackspaceFromEndOfInput) { |
| 55 HTMLInputElement* input = | 119 HTMLInputElement* input = |
| 56 toHTMLInputElement(insertHTMLElement("<input id='sample'>", "sample")); | 120 toHTMLInputElement(insertHTMLElement("<input id='sample'>", "sample")); |
| 57 | 121 |
| 58 input->setValue("fooX"); | 122 input->setValue("fooX"); |
| 59 document().updateStyleAndLayout(); | 123 document().updateStyleAndLayout(); |
| 60 controller().setEditableSelectionOffsets(PlainTextRange(4, 4)); | 124 controller().setEditableSelectionOffsets(PlainTextRange(4, 4)); |
| 61 EXPECT_STREQ("fooX", input->value().utf8().data()); | 125 EXPECT_STREQ("fooX", input->value().utf8().data()); |
| 62 controller().extendSelectionAndDelete(0, 0); | 126 controller().extendSelectionAndDelete(0, 0); |
| 63 EXPECT_STREQ("fooX", input->value().utf8().data()); | 127 EXPECT_STREQ("fooX", input->value().utf8().data()); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 input->setValue("fooX"); | 160 input->setValue("fooX"); |
| 97 document().updateStyleAndLayout(); | 161 document().updateStyleAndLayout(); |
| 98 controller().setEditableSelectionOffsets(PlainTextRange(4, 4)); | 162 controller().setEditableSelectionOffsets(PlainTextRange(4, 4)); |
| 99 EXPECT_STREQ("fooX", input->value().utf8().data()); | 163 EXPECT_STREQ("fooX", input->value().utf8().data()); |
| 100 controller().extendSelectionAndDelete(0, 1); | 164 controller().extendSelectionAndDelete(0, 1); |
| 101 EXPECT_STREQ("fooX", input->value().utf8().data()); | 165 EXPECT_STREQ("fooX", input->value().utf8().data()); |
| 102 } | 166 } |
| 103 | 167 |
| 104 TEST_F(InputMethodControllerTest, SetCompositionFromExistingText) { | 168 TEST_F(InputMethodControllerTest, SetCompositionFromExistingText) { |
| 105 Element* div = insertHTMLElement( | 169 Element* div = insertHTMLElement( |
| 106 "<div id='sample' contenteditable='true'>hello world</div>", "sample"); | 170 "<div id='sample' contenteditable>hello world</div>", "sample"); |
| 107 | 171 |
| 108 Vector<CompositionUnderline> underlines; | 172 Vector<CompositionUnderline> underlines; |
| 109 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); | 173 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); |
| 110 controller().setCompositionFromExistingText(underlines, 0, 5); | 174 controller().setCompositionFromExistingText(underlines, 0, 5); |
| 111 | 175 |
| 112 Range* range = controller().compositionRange(); | 176 Range* range = controller().compositionRange(); |
| 113 EXPECT_EQ(0, range->startOffset()); | 177 EXPECT_EQ(0, range->startOffset()); |
| 114 EXPECT_EQ(5, range->endOffset()); | 178 EXPECT_EQ(5, range->endOffset()); |
| 115 | 179 |
| 116 PlainTextRange plainTextRange(PlainTextRange::create(*div, *range)); | 180 PlainTextRange plainTextRange(PlainTextRange::create(*div, *range)); |
| 117 EXPECT_EQ(0u, plainTextRange.start()); | 181 EXPECT_EQ(0u, plainTextRange.start()); |
| 118 EXPECT_EQ(5u, plainTextRange.end()); | 182 EXPECT_EQ(5u, plainTextRange.end()); |
| 119 } | 183 } |
| 120 | 184 |
| 121 TEST_F(InputMethodControllerTest, SetCompositionKeepingStyle) { | 185 TEST_F(InputMethodControllerTest, SetCompositionKeepingStyle) { |
| 122 Element* div = insertHTMLElement( | 186 Element* div = insertHTMLElement( |
| 123 "<div id='sample' " | 187 "<div id='sample' " |
| 124 "contenteditable='true'>abc1<b>2</b>34567<b>8</b>9</div>", | 188 "contenteditable>abc1<b>2</b>34567<b>8</b>9</div>", |
| 125 "sample"); | 189 "sample"); |
| 126 | 190 |
| 127 Vector<CompositionUnderline> underlines; | 191 Vector<CompositionUnderline> underlines; |
| 128 underlines.append(CompositionUnderline(3, 12, Color(255, 0, 0), false, 0)); | 192 underlines.append(CompositionUnderline(3, 12, Color(255, 0, 0), false, 0)); |
| 129 controller().setCompositionFromExistingText(underlines, 3, 12); | 193 controller().setCompositionFromExistingText(underlines, 3, 12); |
| 130 | 194 |
| 131 // Subtract a character. | 195 // Subtract a character. |
| 132 controller().setComposition(String("12345789"), underlines, 8, 8); | 196 controller().setComposition(String("12345789"), underlines, 8, 8); |
| 133 EXPECT_STREQ("abc1<b>2</b>3457<b>8</b>9", div->innerHTML().utf8().data()); | 197 EXPECT_STREQ("abc1<b>2</b>3457<b>8</b>9", div->innerHTML().utf8().data()); |
| 134 | 198 |
| 135 // Append a character. | 199 // Append a character. |
| 136 controller().setComposition(String("123456789"), underlines, 9, 9); | 200 controller().setComposition(String("123456789"), underlines, 9, 9); |
| 137 EXPECT_STREQ("abc1<b>2</b>34567<b>8</b>9", div->innerHTML().utf8().data()); | 201 EXPECT_STREQ("abc1<b>2</b>34567<b>8</b>9", div->innerHTML().utf8().data()); |
| 138 | 202 |
| 139 // Subtract and append characters. | 203 // Subtract and append characters. |
| 140 controller().setComposition(String("123hello789"), underlines, 11, 11); | 204 controller().setComposition(String("123hello789"), underlines, 11, 11); |
| 141 EXPECT_STREQ("abc1<b>2</b>3hello7<b>8</b>9", div->innerHTML().utf8().data()); | 205 EXPECT_STREQ("abc1<b>2</b>3hello7<b>8</b>9", div->innerHTML().utf8().data()); |
| 142 } | 206 } |
| 143 | 207 |
| 144 TEST_F(InputMethodControllerTest, SetCompositionWithEmojiKeepingStyle) { | 208 TEST_F(InputMethodControllerTest, SetCompositionWithEmojiKeepingStyle) { |
| 145 // U+1F3E0 = 0xF0 0x9F 0x8F 0xA0 (UTF8). It's an emoji character. | 209 // U+1F3E0 = 0xF0 0x9F 0x8F 0xA0 (UTF8). It's an emoji character. |
| 146 Element* div = insertHTMLElement( | 210 Element* div = insertHTMLElement( |
| 147 "<div id='sample' contenteditable='true'><b>🏠</b></div>", | 211 "<div id='sample' contenteditable><b>🏠</b></div>", "sample"); |
| 148 "sample"); | |
| 149 | 212 |
| 150 Vector<CompositionUnderline> underlines; | 213 Vector<CompositionUnderline> underlines; |
| 151 underlines.append(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0)); | 214 underlines.append(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0)); |
| 152 | 215 |
| 153 controller().setCompositionFromExistingText(underlines, 0, 2); | 216 controller().setCompositionFromExistingText(underlines, 0, 2); |
| 154 | 217 |
| 155 // 0xF0 0x9F 0x8F 0xAB is also an emoji character, with the same leading | 218 // 0xF0 0x9F 0x8F 0xAB is also an emoji character, with the same leading |
| 156 // surrogate pair to the previous one. | 219 // surrogate pair to the previous one. |
| 157 controller().setComposition(String::fromUTF8("\xF0\x9F\x8F\xAB"), underlines, | 220 controller().setComposition(String::fromUTF8("\xF0\x9F\x8F\xAB"), underlines, |
| 158 2, 2); | 221 2, 2); |
| 159 EXPECT_STREQ("<b>\xF0\x9F\x8F\xAB</b>", div->innerHTML().utf8().data()); | 222 EXPECT_STREQ("<b>\xF0\x9F\x8F\xAB</b>", div->innerHTML().utf8().data()); |
| 160 | 223 |
| 161 controller().setComposition(String::fromUTF8("\xF0\x9F\x8F\xA0"), underlines, | 224 controller().setComposition(String::fromUTF8("\xF0\x9F\x8F\xA0"), underlines, |
| 162 2, 2); | 225 2, 2); |
| 163 EXPECT_STREQ("<b>\xF0\x9F\x8F\xA0</b>", div->innerHTML().utf8().data()); | 226 EXPECT_STREQ("<b>\xF0\x9F\x8F\xA0</b>", div->innerHTML().utf8().data()); |
| 164 } | 227 } |
| 165 | 228 |
| 166 TEST_F(InputMethodControllerTest, | 229 TEST_F(InputMethodControllerTest, |
| 167 SetCompositionWithTeluguSignVisargaKeepingStyle) { | 230 SetCompositionWithTeluguSignVisargaKeepingStyle) { |
| 168 // U+0C03 = 0xE0 0xB0 0x83 (UTF8), a telugu sign visarga with one code point. | 231 // U+0C03 = 0xE0 0xB0 0x83 (UTF8), a telugu sign visarga with one code point. |
| 169 // It's one grapheme cluster if separated. It can also form one grapheme | 232 // It's one grapheme cluster if separated. It can also form one grapheme |
| 170 // cluster with another code point(e.g, itself). | 233 // cluster with another code point(e.g, itself). |
| 171 Element* div = insertHTMLElement( | 234 Element* div = insertHTMLElement( |
| 172 "<div id='sample' contenteditable='true'><b>ః</b></div>", "sample"); | 235 "<div id='sample' contenteditable><b>ః</b></div>", "sample"); |
| 173 | 236 |
| 174 Vector<CompositionUnderline> underlines; | 237 Vector<CompositionUnderline> underlines; |
| 175 underlines.append(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0)); | 238 underlines.append(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0)); |
| 176 controller().setCompositionFromExistingText(underlines, 0, 1); | 239 controller().setCompositionFromExistingText(underlines, 0, 1); |
| 177 | 240 |
| 178 // 0xE0 0xB0 0x83 0xE0 0xB0 0x83, a telugu character with 2 code points in | 241 // 0xE0 0xB0 0x83 0xE0 0xB0 0x83, a telugu character with 2 code points in |
| 179 // 1 grapheme cluster. | 242 // 1 grapheme cluster. |
| 180 controller().setComposition(String::fromUTF8("\xE0\xB0\x83\xE0\xB0\x83"), | 243 controller().setComposition(String::fromUTF8("\xE0\xB0\x83\xE0\xB0\x83"), |
| 181 underlines, 2, 2); | 244 underlines, 2, 2); |
| 182 EXPECT_STREQ("<b>\xE0\xB0\x83\xE0\xB0\x83</b>", | 245 EXPECT_STREQ("<b>\xE0\xB0\x83\xE0\xB0\x83</b>", |
| 183 div->innerHTML().utf8().data()); | 246 div->innerHTML().utf8().data()); |
| 184 | 247 |
| 185 controller().setComposition(String::fromUTF8("\xE0\xB0\x83"), underlines, 1, | 248 controller().setComposition(String::fromUTF8("\xE0\xB0\x83"), underlines, 1, |
| 186 1); | 249 1); |
| 187 EXPECT_STREQ("<b>\xE0\xB0\x83</b>", div->innerHTML().utf8().data()); | 250 EXPECT_STREQ("<b>\xE0\xB0\x83</b>", div->innerHTML().utf8().data()); |
| 188 } | 251 } |
| 189 | 252 |
| 190 TEST_F(InputMethodControllerTest, SelectionOnConfirmExistingText) { | 253 TEST_F(InputMethodControllerTest, SelectionOnConfirmExistingText) { |
| 191 insertHTMLElement("<div id='sample' contenteditable='true'>hello world</div>", | 254 insertHTMLElement("<div id='sample' contenteditable>hello world</div>", |
| 192 "sample"); | 255 "sample"); |
| 193 | 256 |
| 194 Vector<CompositionUnderline> underlines; | 257 Vector<CompositionUnderline> underlines; |
| 195 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); | 258 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); |
| 196 controller().setCompositionFromExistingText(underlines, 0, 5); | 259 controller().setCompositionFromExistingText(underlines, 0, 5); |
| 197 | 260 |
| 198 controller().finishComposingText(InputMethodController::KeepSelection); | 261 controller().finishComposingText(InputMethodController::KeepSelection); |
| 199 EXPECT_EQ(0, frame().selection().start().computeOffsetInContainerNode()); | 262 EXPECT_EQ(0, frame().selection().start().computeOffsetInContainerNode()); |
| 200 EXPECT_EQ(0, frame().selection().end().computeOffsetInContainerNode()); | 263 EXPECT_EQ(0, frame().selection().end().computeOffsetInContainerNode()); |
| 201 } | 264 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 225 controller().setComposition(String(""), underlines, 0, 3); | 288 controller().setComposition(String(""), underlines, 0, 3); |
| 226 | 289 |
| 227 EXPECT_STREQ("", input->value().utf8().data()); | 290 EXPECT_STREQ("", input->value().utf8().data()); |
| 228 } | 291 } |
| 229 | 292 |
| 230 TEST_F(InputMethodControllerTest, | 293 TEST_F(InputMethodControllerTest, |
| 231 SetCompositionFromExistingTextWithCollapsedWhiteSpace) { | 294 SetCompositionFromExistingTextWithCollapsedWhiteSpace) { |
| 232 // Creates a div with one leading new line char. The new line char is hidden | 295 // Creates a div with one leading new line char. The new line char is hidden |
| 233 // from the user and IME, but is visible to InputMethodController. | 296 // from the user and IME, but is visible to InputMethodController. |
| 234 Element* div = insertHTMLElement( | 297 Element* div = insertHTMLElement( |
| 235 "<div id='sample' contenteditable='true'>\nhello world</div>", "sample"); | 298 "<div id='sample' contenteditable>\nhello world</div>", "sample"); |
| 236 | 299 |
| 237 Vector<CompositionUnderline> underlines; | 300 Vector<CompositionUnderline> underlines; |
| 238 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); | 301 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); |
| 239 controller().setCompositionFromExistingText(underlines, 0, 5); | 302 controller().setCompositionFromExistingText(underlines, 0, 5); |
| 240 | 303 |
| 241 Range* range = controller().compositionRange(); | 304 Range* range = controller().compositionRange(); |
| 242 EXPECT_EQ(1, range->startOffset()); | 305 EXPECT_EQ(1, range->startOffset()); |
| 243 EXPECT_EQ(6, range->endOffset()); | 306 EXPECT_EQ(6, range->endOffset()); |
| 244 | 307 |
| 245 PlainTextRange plainTextRange(PlainTextRange::create(*div, *range)); | 308 PlainTextRange plainTextRange(PlainTextRange::create(*div, *range)); |
| 246 EXPECT_EQ(0u, plainTextRange.start()); | 309 EXPECT_EQ(0u, plainTextRange.start()); |
| 247 EXPECT_EQ(5u, plainTextRange.end()); | 310 EXPECT_EQ(5u, plainTextRange.end()); |
| 248 } | 311 } |
| 249 | 312 |
| 250 TEST_F(InputMethodControllerTest, | 313 TEST_F(InputMethodControllerTest, |
| 251 SetCompositionFromExistingTextWithInvalidOffsets) { | 314 SetCompositionFromExistingTextWithInvalidOffsets) { |
| 252 insertHTMLElement("<div id='sample' contenteditable='true'>test</div>", | 315 insertHTMLElement("<div id='sample' contenteditable>test</div>", "sample"); |
| 253 "sample"); | |
| 254 | 316 |
| 255 Vector<CompositionUnderline> underlines; | 317 Vector<CompositionUnderline> underlines; |
| 256 underlines.append(CompositionUnderline(7, 8, Color(255, 0, 0), false, 0)); | 318 underlines.append(CompositionUnderline(7, 8, Color(255, 0, 0), false, 0)); |
| 257 controller().setCompositionFromExistingText(underlines, 7, 8); | 319 controller().setCompositionFromExistingText(underlines, 7, 8); |
| 258 | 320 |
| 259 EXPECT_FALSE(controller().compositionRange()); | 321 EXPECT_FALSE(controller().compositionRange()); |
| 260 } | 322 } |
| 261 | 323 |
| 262 TEST_F(InputMethodControllerTest, ConfirmPasswordComposition) { | 324 TEST_F(InputMethodControllerTest, ConfirmPasswordComposition) { |
| 263 HTMLInputElement* input = toHTMLInputElement(insertHTMLElement( | 325 HTMLInputElement* input = toHTMLInputElement(insertHTMLElement( |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 550 document().updateStyleAndLayout(); | 612 document().updateStyleAndLayout(); |
| 551 controller().setEditableSelectionOffsets(PlainTextRange(2, 2)); | 613 controller().setEditableSelectionOffsets(PlainTextRange(2, 2)); |
| 552 EXPECT_STREQ("\xF0\x9F\x8F\x86\xF0\x9F\x8F\x86", | 614 EXPECT_STREQ("\xF0\x9F\x8F\x86\xF0\x9F\x8F\x86", |
| 553 input->value().utf8().data()); | 615 input->value().utf8().data()); |
| 554 controller().deleteSurroundingText(1, 1); | 616 controller().deleteSurroundingText(1, 1); |
| 555 EXPECT_STREQ("", input->value().utf8().data()); | 617 EXPECT_STREQ("", input->value().utf8().data()); |
| 556 } | 618 } |
| 557 | 619 |
| 558 TEST_F(InputMethodControllerTest, DeleteSurroundingTextForMultipleNodes) { | 620 TEST_F(InputMethodControllerTest, DeleteSurroundingTextForMultipleNodes) { |
| 559 Element* div = insertHTMLElement( | 621 Element* div = insertHTMLElement( |
| 560 "<div id='sample' contenteditable='true'>aaa" | 622 "<div id='sample' contenteditable>aaa" |
| 561 "<div id='sample2' contenteditable='true'>bbb" | 623 "<div id='sample2' contenteditable>bbb" |
| 562 "<div id='sample3' contenteditable='true'>ccc" | 624 "<div id='sample3' contenteditable>ccc" |
| 563 "<div id='sample4' contenteditable='true'>ddd" | 625 "<div id='sample4' contenteditable>ddd" |
| 564 "<div id='sample5' contenteditable='true'>eee" | 626 "<div id='sample5' contenteditable>eee" |
| 565 "</div></div></div></div></div>", | 627 "</div></div></div></div></div>", |
| 566 "sample"); | 628 "sample"); |
| 567 | 629 |
| 568 controller().setEditableSelectionOffsets(PlainTextRange(8, 8)); | 630 controller().setEditableSelectionOffsets(PlainTextRange(8, 8)); |
| 569 EXPECT_STREQ("aaa\nbbb\nccc\nddd\neee", div->innerText().utf8().data()); | 631 EXPECT_STREQ("aaa\nbbb\nccc\nddd\neee", div->innerText().utf8().data()); |
| 570 EXPECT_EQ(8u, controller().getSelectionOffsets().start()); | 632 EXPECT_EQ(8u, controller().getSelectionOffsets().start()); |
| 571 EXPECT_EQ(8u, controller().getSelectionOffsets().end()); | 633 EXPECT_EQ(8u, controller().getSelectionOffsets().end()); |
| 572 | 634 |
| 573 controller().deleteSurroundingText(1, 0); | 635 controller().deleteSurroundingText(1, 0); |
| 574 EXPECT_STREQ("aaa\nbbbccc\nddd\neee", div->innerText().utf8().data()); | 636 EXPECT_STREQ("aaa\nbbbccc\nddd\neee", div->innerText().utf8().data()); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 641 EXPECT_STREQ("heABllo", input->value().utf8().data()); | 703 EXPECT_STREQ("heABllo", input->value().utf8().data()); |
| 642 EXPECT_EQ(7u, controller().getSelectionOffsets().start()); | 704 EXPECT_EQ(7u, controller().getSelectionOffsets().start()); |
| 643 EXPECT_EQ(7u, controller().getSelectionOffsets().end()); | 705 EXPECT_EQ(7u, controller().getSelectionOffsets().end()); |
| 644 } | 706 } |
| 645 | 707 |
| 646 TEST_F(InputMethodControllerTest, | 708 TEST_F(InputMethodControllerTest, |
| 647 SetCompositionForContentEditableWithNewCaretPositions) { | 709 SetCompositionForContentEditableWithNewCaretPositions) { |
| 648 // There are 7 nodes and 5+1+5+1+3+4+3 characters: "hello", '\n', "world", | 710 // There are 7 nodes and 5+1+5+1+3+4+3 characters: "hello", '\n', "world", |
| 649 // "\n", "012", "3456", "789". | 711 // "\n", "012", "3456", "789". |
| 650 Element* div = insertHTMLElement( | 712 Element* div = insertHTMLElement( |
| 651 "<div id='sample' contenteditable='true'>" | 713 "<div id='sample' contenteditable>" |
| 652 "hello" | 714 "hello" |
| 653 "<div id='sample2' contenteditable='true'>world" | 715 "<div id='sample2' contenteditable>world" |
| 654 "<p>012<b>3456</b><i>789</i></p>" | 716 "<p>012<b>3456</b><i>789</i></p>" |
| 655 "</div>" | 717 "</div>" |
| 656 "</div>", | 718 "</div>", |
| 657 "sample"); | 719 "sample"); |
| 658 | 720 |
| 659 controller().setEditableSelectionOffsets(PlainTextRange(17, 17)); | 721 controller().setEditableSelectionOffsets(PlainTextRange(17, 17)); |
| 660 EXPECT_STREQ("hello\nworld\n0123456789", div->innerText().utf8().data()); | 722 EXPECT_STREQ("hello\nworld\n0123456789", div->innerText().utf8().data()); |
| 661 EXPECT_EQ(17u, controller().getSelectionOffsets().start()); | 723 EXPECT_EQ(17u, controller().getSelectionOffsets().start()); |
| 662 EXPECT_EQ(17u, controller().getSelectionOffsets().end()); | 724 EXPECT_EQ(17u, controller().getSelectionOffsets().end()); |
| 663 | 725 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 737 // The caret exceeds right boundary. | 799 // The caret exceeds right boundary. |
| 738 // "hello\nworld\n01234AB56789*". | 800 // "hello\nworld\n01234AB56789*". |
| 739 controller().setComposition("AB", underlines, 100, 100); | 801 controller().setComposition("AB", underlines, 100, 100); |
| 740 EXPECT_STREQ("hello\nworld\n01234AB56789", div->innerText().utf8().data()); | 802 EXPECT_STREQ("hello\nworld\n01234AB56789", div->innerText().utf8().data()); |
| 741 EXPECT_EQ(24u, controller().getSelectionOffsets().start()); | 803 EXPECT_EQ(24u, controller().getSelectionOffsets().start()); |
| 742 EXPECT_EQ(24u, controller().getSelectionOffsets().end()); | 804 EXPECT_EQ(24u, controller().getSelectionOffsets().end()); |
| 743 } | 805 } |
| 744 | 806 |
| 745 TEST_F(InputMethodControllerTest, SetCompositionWithEmptyText) { | 807 TEST_F(InputMethodControllerTest, SetCompositionWithEmptyText) { |
| 746 Element* div = insertHTMLElement( | 808 Element* div = insertHTMLElement( |
| 747 "<div id='sample' contenteditable='true'>hello</div>", "sample"); | 809 "<div id='sample' contenteditable>hello</div>", "sample"); |
| 748 | 810 |
| 749 controller().setEditableSelectionOffsets(PlainTextRange(2, 2)); | 811 controller().setEditableSelectionOffsets(PlainTextRange(2, 2)); |
| 750 EXPECT_STREQ("hello", div->innerText().utf8().data()); | 812 EXPECT_STREQ("hello", div->innerText().utf8().data()); |
| 751 EXPECT_EQ(2u, controller().getSelectionOffsets().start()); | 813 EXPECT_EQ(2u, controller().getSelectionOffsets().start()); |
| 752 EXPECT_EQ(2u, controller().getSelectionOffsets().end()); | 814 EXPECT_EQ(2u, controller().getSelectionOffsets().end()); |
| 753 | 815 |
| 754 Vector<CompositionUnderline> underlines0; | 816 Vector<CompositionUnderline> underlines0; |
| 755 underlines0.append(CompositionUnderline(0, 0, Color(255, 0, 0), false, 0)); | 817 underlines0.append(CompositionUnderline(0, 0, Color(255, 0, 0), false, 0)); |
| 756 Vector<CompositionUnderline> underlines2; | 818 Vector<CompositionUnderline> underlines2; |
| 757 underlines2.append(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0)); | 819 underlines2.append(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0)); |
| 758 | 820 |
| 759 controller().setComposition("AB", underlines2, 2, 2); | 821 controller().setComposition("AB", underlines2, 2, 2); |
| 760 // With previous composition. | 822 // With previous composition. |
| 761 controller().setComposition("", underlines0, 2, 2); | 823 controller().setComposition("", underlines0, 2, 2); |
| 762 EXPECT_STREQ("hello", div->innerText().utf8().data()); | 824 EXPECT_STREQ("hello", div->innerText().utf8().data()); |
| 763 EXPECT_EQ(4u, controller().getSelectionOffsets().start()); | 825 EXPECT_EQ(4u, controller().getSelectionOffsets().start()); |
| 764 EXPECT_EQ(4u, controller().getSelectionOffsets().end()); | 826 EXPECT_EQ(4u, controller().getSelectionOffsets().end()); |
| 765 | 827 |
| 766 // Without previous composition. | 828 // Without previous composition. |
| 767 controller().setComposition("", underlines0, -1, -1); | 829 controller().setComposition("", underlines0, -1, -1); |
| 768 EXPECT_STREQ("hello", div->innerText().utf8().data()); | 830 EXPECT_STREQ("hello", div->innerText().utf8().data()); |
| 769 EXPECT_EQ(3u, controller().getSelectionOffsets().start()); | 831 EXPECT_EQ(3u, controller().getSelectionOffsets().start()); |
| 770 EXPECT_EQ(3u, controller().getSelectionOffsets().end()); | 832 EXPECT_EQ(3u, controller().getSelectionOffsets().end()); |
| 771 } | 833 } |
| 772 | 834 |
| 773 TEST_F(InputMethodControllerTest, InsertLineBreakWhileComposingText) { | 835 TEST_F(InputMethodControllerTest, InsertLineBreakWhileComposingText) { |
| 774 Element* div = insertHTMLElement( | 836 Element* div = |
| 775 "<div id='sample' contenteditable='true'></div>", "sample"); | 837 insertHTMLElement("<div id='sample' contenteditable></div>", "sample"); |
| 776 | 838 |
| 777 Vector<CompositionUnderline> underlines; | 839 Vector<CompositionUnderline> underlines; |
| 778 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); | 840 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); |
| 779 controller().setComposition("hello", underlines, 5, 5); | 841 controller().setComposition("hello", underlines, 5, 5); |
| 780 EXPECT_STREQ("hello", div->innerText().utf8().data()); | 842 EXPECT_STREQ("hello", div->innerText().utf8().data()); |
| 781 EXPECT_EQ(5u, controller().getSelectionOffsets().start()); | 843 EXPECT_EQ(5u, controller().getSelectionOffsets().start()); |
| 782 EXPECT_EQ(5u, controller().getSelectionOffsets().end()); | 844 EXPECT_EQ(5u, controller().getSelectionOffsets().end()); |
| 783 | 845 |
| 784 frame().editor().insertLineBreak(); | 846 frame().editor().insertLineBreak(); |
| 785 EXPECT_STREQ("\n\n", div->innerText().utf8().data()); | 847 EXPECT_STREQ("\n\n", div->innerText().utf8().data()); |
| 786 EXPECT_EQ(1u, controller().getSelectionOffsets().start()); | 848 EXPECT_EQ(1u, controller().getSelectionOffsets().start()); |
| 787 EXPECT_EQ(1u, controller().getSelectionOffsets().end()); | 849 EXPECT_EQ(1u, controller().getSelectionOffsets().end()); |
| 788 } | 850 } |
| 789 | 851 |
| 790 TEST_F(InputMethodControllerTest, InsertLineBreakAfterConfirmingText) { | 852 TEST_F(InputMethodControllerTest, InsertLineBreakAfterConfirmingText) { |
| 791 Element* div = insertHTMLElement( | 853 Element* div = |
| 792 "<div id='sample' contenteditable='true'></div>", "sample"); | 854 insertHTMLElement("<div id='sample' contenteditable></div>", "sample"); |
| 793 | 855 |
| 794 controller().commitText("hello", 0); | 856 controller().commitText("hello", 0); |
| 795 EXPECT_STREQ("hello", div->innerText().utf8().data()); | 857 EXPECT_STREQ("hello", div->innerText().utf8().data()); |
| 796 | 858 |
| 797 controller().setEditableSelectionOffsets(PlainTextRange(2, 2)); | 859 controller().setEditableSelectionOffsets(PlainTextRange(2, 2)); |
| 798 EXPECT_EQ(2u, controller().getSelectionOffsets().start()); | 860 EXPECT_EQ(2u, controller().getSelectionOffsets().start()); |
| 799 EXPECT_EQ(2u, controller().getSelectionOffsets().end()); | 861 EXPECT_EQ(2u, controller().getSelectionOffsets().end()); |
| 800 | 862 |
| 801 frame().editor().insertLineBreak(); | 863 frame().editor().insertLineBreak(); |
| 802 EXPECT_STREQ("he\nllo", div->innerText().utf8().data()); | 864 EXPECT_STREQ("he\nllo", div->innerText().utf8().data()); |
| 803 EXPECT_EQ(3u, controller().getSelectionOffsets().start()); | 865 EXPECT_EQ(3u, controller().getSelectionOffsets().start()); |
| 804 EXPECT_EQ(3u, controller().getSelectionOffsets().end()); | 866 EXPECT_EQ(3u, controller().getSelectionOffsets().end()); |
| 805 } | 867 } |
| 806 | 868 |
| 807 TEST_F(InputMethodControllerTest, CompositionInputEventIsComposing) { | 869 TEST_F(InputMethodControllerTest, CompositionInputEventIsComposing) { |
| 808 document().settings()->setScriptEnabled(true); | 870 document().settings()->setScriptEnabled(true); |
| 809 Element* editable = insertHTMLElement( | 871 Element* editable = |
| 810 "<div id='sample' contentEditable='true'></div>", "sample"); | 872 insertHTMLElement("<div id='sample' contenteditable></div>", "sample"); |
| 811 Element* script = document().createElement("script"); | 873 Element* script = document().createElement("script"); |
| 812 script->setInnerHTML( | 874 script->setInnerHTML( |
| 813 "document.getElementById('sample').addEventListener('beforeinput', " | 875 "document.getElementById('sample').addEventListener('beforeinput', " |
| 814 "function(event) {" | 876 " event => document.title = " |
| 815 " document.title = `beforeinput.isComposing:${event.isComposing};`;" | 877 " `beforeinput.isComposing:${event.isComposing};`);" |
| 816 "});" | |
| 817 "document.getElementById('sample').addEventListener('input', " | 878 "document.getElementById('sample').addEventListener('input', " |
| 818 "function(event) {" | 879 " event => document.title += " |
| 819 " document.title += `input.isComposing:${event.isComposing};`;" | 880 " `input.isComposing:${event.isComposing};`);"); |
| 820 "});"); | |
| 821 document().body()->appendChild(script); | 881 document().body()->appendChild(script); |
| 822 document().view()->updateAllLifecyclePhases(); | 882 document().view()->updateAllLifecyclePhases(); |
| 823 | 883 |
| 824 // Simulate composition in the |contentEditable|. | 884 // Simulate composition in the |contentEditable|. |
| 825 Vector<CompositionUnderline> underlines; | 885 Vector<CompositionUnderline> underlines; |
| 826 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); | 886 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); |
| 827 editable->focus(); | 887 editable->focus(); |
| 828 | 888 |
| 829 document().setTitle(emptyString()); | 889 document().setTitle(emptyString()); |
| 830 controller().setComposition("foo", underlines, 0, 3); | 890 controller().setComposition("foo", underlines, 0, 3); |
| 831 EXPECT_STREQ("beforeinput.isComposing:true;input.isComposing:true;", | 891 EXPECT_STREQ("beforeinput.isComposing:true;input.isComposing:true;", |
| 832 document().title().utf8().data()); | 892 document().title().utf8().data()); |
| 833 | 893 |
| 834 document().setTitle(emptyString()); | 894 document().setTitle(emptyString()); |
| 835 controller().finishComposingText(InputMethodController::KeepSelection); | 895 controller().finishComposingText(InputMethodController::KeepSelection); |
| 836 // Last pair of InputEvent should also be inside composition scope. | 896 // Last pair of InputEvent should also be inside composition scope. |
| 837 EXPECT_STREQ("beforeinput.isComposing:true;input.isComposing:true;", | 897 EXPECT_STREQ("beforeinput.isComposing:true;input.isComposing:true;", |
| 838 document().title().utf8().data()); | 898 document().title().utf8().data()); |
| 839 } | 899 } |
| 840 | 900 |
| 841 TEST_F(InputMethodControllerTest, CompositionInputEventData) { | 901 TEST_F(InputMethodControllerTest, CompositionInputEventForReplace) { |
| 842 document().settings()->setScriptEnabled(true); | 902 createHTMLWithCompositionInputEventListeners(); |
| 843 Element* editable = insertHTMLElement( | |
| 844 "<div id='sample' contentEditable='true'></div>", "sample"); | |
| 845 Element* script = document().createElement("script"); | |
| 846 script->setInnerHTML( | |
| 847 "document.getElementById('sample').addEventListener('beforeinput', " | |
| 848 "function(event) {" | |
| 849 " document.title = `beforeinput.data:${event.data};`;" | |
| 850 "});" | |
| 851 "document.getElementById('sample').addEventListener('input', " | |
| 852 "function(event) {" | |
| 853 " document.title += `input.data:${event.data};`;" | |
| 854 "});"); | |
| 855 document().body()->appendChild(script); | |
| 856 document().view()->updateAllLifecyclePhases(); | |
| 857 | 903 |
| 858 // Simulate composition in the |contentEditable|. | 904 // Simulate composition in the |contentEditable|. |
| 859 Vector<CompositionUnderline> underlines; | 905 Vector<CompositionUnderline> underlines; |
| 860 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); | 906 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); |
| 861 editable->focus(); | |
| 862 | 907 |
| 863 document().setTitle(emptyString()); | 908 document().setTitle(emptyString()); |
| 864 controller().setComposition("n", underlines, 0, 1); | 909 controller().setComposition("hell", underlines, 4, 4); |
| 910 EXPECT_STREQ("beforeinput.data:hell;input.data:hell;", |
| 911 document().title().utf8().data()); |
| 912 |
| 913 // Replace the existing composition. |
| 914 // TODO(yabinh): should be "beforeinput.data:hello;input.data:hello;". |
| 915 document().setTitle(emptyString()); |
| 916 controller().setComposition("hello", underlines, 0, 0); |
| 917 EXPECT_STREQ("beforeinput.data:o;input.data:o;", |
| 918 document().title().utf8().data()); |
| 919 } |
| 920 |
| 921 TEST_F(InputMethodControllerTest, CompositionInputEventForConfirm) { |
| 922 createHTMLWithCompositionInputEventListeners(); |
| 923 |
| 924 // Simulate composition in the |contentEditable|. |
| 925 Vector<CompositionUnderline> underlines; |
| 926 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); |
| 927 |
| 928 document().setTitle(emptyString()); |
| 929 controller().setComposition("hello", underlines, 5, 5); |
| 930 EXPECT_STREQ("beforeinput.data:hello;input.data:hello;", |
| 931 document().title().utf8().data()); |
| 932 |
| 933 // Confirm the ongoing composition. |
| 934 document().setTitle(emptyString()); |
| 935 controller().finishComposingText(InputMethodController::KeepSelection); |
| 936 EXPECT_STREQ( |
| 937 "beforeinput.data:hello;input.data:hello;compositionend.data:hello;", |
| 938 document().title().utf8().data()); |
| 939 } |
| 940 |
| 941 TEST_F(InputMethodControllerTest, CompositionInputEventForDelete) { |
| 942 createHTMLWithCompositionInputEventListeners(); |
| 943 |
| 944 // Simulate composition in the |contentEditable|. |
| 945 Vector<CompositionUnderline> underlines; |
| 946 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); |
| 947 |
| 948 document().setTitle(emptyString()); |
| 949 controller().setComposition("hello", underlines, 5, 5); |
| 950 EXPECT_STREQ("beforeinput.data:hello;input.data:hello;", |
| 951 document().title().utf8().data()); |
| 952 |
| 953 // Delete the existing composition. |
| 954 document().setTitle(emptyString()); |
| 955 controller().setComposition("", underlines, 0, 0); |
| 956 EXPECT_STREQ("beforeinput.data:;compositionend.data:;", |
| 957 document().title().utf8().data()); |
| 958 } |
| 959 |
| 960 TEST_F(InputMethodControllerTest, CompositionInputEventForInsert) { |
| 961 createHTMLWithCompositionInputEventListeners(); |
| 962 |
| 963 // Simulate composition in the |contentEditable|. |
| 964 Vector<CompositionUnderline> underlines; |
| 965 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); |
| 966 |
| 967 // Insert new text without previous composition. |
| 968 document().setTitle(emptyString()); |
| 969 document().updateStyleAndLayout(); |
| 970 controller().commitText("hello", 0); |
| 971 EXPECT_STREQ("beforeinput.data:hello;input.data:hello;", |
| 972 document().title().utf8().data()); |
| 973 |
| 974 document().setTitle(emptyString()); |
| 975 controller().setComposition("n", underlines, 1, 1); |
| 865 EXPECT_STREQ("beforeinput.data:n;input.data:n;", | 976 EXPECT_STREQ("beforeinput.data:n;input.data:n;", |
| 866 document().title().utf8().data()); | 977 document().title().utf8().data()); |
| 867 | 978 |
| 979 // Insert new text with previous composition. |
| 868 document().setTitle(emptyString()); | 980 document().setTitle(emptyString()); |
| 869 controller().setComposition("ni", underlines, 0, 1); | 981 document().updateStyleAndLayout(); |
| 870 EXPECT_STREQ("beforeinput.data:i;input.data:i;", | 982 controller().commitText("hello", 1); |
| 871 document().title().utf8().data()); | 983 EXPECT_STREQ( |
| 984 "beforeinput.data:hello;input.data:hello;compositionend.data:hello;", |
| 985 document().title().utf8().data()); |
| 986 } |
| 872 | 987 |
| 873 document().setTitle(emptyString()); | 988 TEST_F(InputMethodControllerTest, CompositionEndEventForConfirm) { |
| 874 controller().finishComposingText(InputMethodController::KeepSelection); | 989 createHTMLWithCompositionEndEventListener(CaretSelection); |
| 875 EXPECT_STREQ("beforeinput.data:ni;input.data:ni;", | 990 |
| 876 document().title().utf8().data()); | 991 // Simulate composition in the |contentEditable|. |
| 992 Vector<CompositionUnderline> underlines; |
| 993 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); |
| 994 |
| 995 controller().setComposition("hello", underlines, 1, 1); |
| 996 document().updateStyleAndLayout(); |
| 997 EXPECT_EQ(1u, controller().getSelectionOffsets().start()); |
| 998 EXPECT_EQ(1u, controller().getSelectionOffsets().end()); |
| 999 |
| 1000 // Confirm the ongoing composition. Note that it moves the caret to the end of |
| 1001 // text [5,5] before firing 'compositonend' event. |
| 1002 controller().finishComposingText(InputMethodController::DoNotKeepSelection); |
| 1003 document().updateStyleAndLayout(); |
| 1004 EXPECT_EQ(3u, controller().getSelectionOffsets().start()); |
| 1005 EXPECT_EQ(3u, controller().getSelectionOffsets().end()); |
| 1006 } |
| 1007 |
| 1008 TEST_F(InputMethodControllerTest, CompositionEndEventForInsert) { |
| 1009 createHTMLWithCompositionEndEventListener(CaretSelection); |
| 1010 |
| 1011 // Simulate composition in the |contentEditable|. |
| 1012 Vector<CompositionUnderline> underlines; |
| 1013 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); |
| 1014 |
| 1015 controller().setComposition("n", underlines, 1, 1); |
| 1016 |
| 1017 // Insert new text with previous composition. Note that it moves the caret to |
| 1018 // [4,4] before firing 'compositonend' event. |
| 1019 document().updateStyleAndLayout(); |
| 1020 controller().commitText("hello", -1); |
| 1021 document().updateStyleAndLayout(); |
| 1022 EXPECT_EQ(3u, controller().getSelectionOffsets().start()); |
| 1023 EXPECT_EQ(3u, controller().getSelectionOffsets().end()); |
| 1024 } |
| 1025 |
| 1026 TEST_F(InputMethodControllerTest, CompositionEndEventWithRangeSelection) { |
| 1027 createHTMLWithCompositionEndEventListener(RangeSelection); |
| 1028 |
| 1029 // Simulate composition in the |contentEditable|. |
| 1030 Vector<CompositionUnderline> underlines; |
| 1031 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); |
| 1032 |
| 1033 controller().setComposition("hello", underlines, 1, 1); |
| 1034 document().updateStyleAndLayout(); |
| 1035 EXPECT_EQ(1u, controller().getSelectionOffsets().start()); |
| 1036 EXPECT_EQ(1u, controller().getSelectionOffsets().end()); |
| 1037 |
| 1038 // Confirm the ongoing composition. Note that it moves the caret to the end of |
| 1039 // text [5,5] before firing 'compositonend' event. |
| 1040 controller().finishComposingText(InputMethodController::DoNotKeepSelection); |
| 1041 document().updateStyleAndLayout(); |
| 1042 EXPECT_EQ(2u, controller().getSelectionOffsets().start()); |
| 1043 EXPECT_EQ(4u, controller().getSelectionOffsets().end()); |
| 1044 } |
| 1045 |
| 1046 TEST_F(InputMethodControllerTest, CompositionEndEventWithNoSelection) { |
| 1047 createHTMLWithCompositionEndEventListener(NoSelection); |
| 1048 |
| 1049 // Simulate composition in the |contentEditable|. |
| 1050 Vector<CompositionUnderline> underlines; |
| 1051 underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); |
| 1052 |
| 1053 controller().setComposition("hello", underlines, 1, 1); |
| 1054 document().updateStyleAndLayout(); |
| 1055 EXPECT_EQ(1u, controller().getSelectionOffsets().start()); |
| 1056 EXPECT_EQ(1u, controller().getSelectionOffsets().end()); |
| 1057 |
| 1058 // Confirm the ongoing composition. Note that it moves the caret to the end of |
| 1059 // text [5,5] before firing 'compositonend' event. |
| 1060 controller().finishComposingText(InputMethodController::DoNotKeepSelection); |
| 1061 document().updateStyleAndLayout(); |
| 1062 EXPECT_TRUE(controller().getSelectionOffsets().isNull()); |
| 877 } | 1063 } |
| 878 | 1064 |
| 879 } // namespace blink | 1065 } // namespace blink |
| OLD | NEW |