blob: d4da1307f53ef120cc6886f833af23fe19e74f82 [file] [log] [blame]
[email protected]397c23962012-05-21 07:09:321// Copyright (c) 2012 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 "ppapi/tests/test_ime_input_event.h"
6
[email protected]397c23962012-05-21 07:09:327#include "ppapi/c/pp_errors.h"
8#include "ppapi/c/ppb_input_event.h"
[email protected]397c23962012-05-21 07:09:329#include "ppapi/cpp/input_event.h"
10#include "ppapi/cpp/module.h"
11#include "ppapi/tests/test_utils.h"
12#include "ppapi/tests/testing_instance.h"
13
14REGISTER_TEST_CASE(ImeInputEvent);
15
16namespace {
17
[email protected]28fccb32013-08-29 22:25:4618// Japanese Kanji letters
[email protected]397c23962012-05-21 07:09:3219const char* kCompositionChar[] = {
[email protected]28fccb32013-08-29 22:25:4620 "\xE6\x96\x87", // An example character of normal unicode.
21 "\xF0\xA0\xAE\x9F", // An example character of surrogate pair.
22 "\xF0\x9F\x98\x81" // An example character of surrogate pair(emoji).
[email protected]397c23962012-05-21 07:09:3223};
24
[email protected]28fccb32013-08-29 22:25:4625const char kCompositionText[] = "\xE6\x96\x87\xF0\xA0\xAE\x9F\xF0\x9F\x98\x81";
[email protected]397c23962012-05-21 07:09:3226
27#define FINISHED_WAITING_MESSAGE "TEST_IME_INPUT_EVENT_FINISHED_WAITING"
28
29} // namespace
30
31TestImeInputEvent::TestImeInputEvent(TestingInstance* instance)
32 : TestCase(instance),
33 input_event_interface_(NULL),
34 keyboard_input_event_interface_(NULL),
35 ime_input_event_interface_(NULL),
36 received_unexpected_event_(true),
37 received_finish_message_(false) {
38}
39
40TestImeInputEvent::~TestImeInputEvent() {
41 // Remove the special listener that only responds to a
42 // FINISHED_WAITING_MESSAGE string. See Init for where it gets added.
43 std::string js_code;
44 js_code = "var plugin = document.getElementById('plugin');"
45 "plugin.removeEventListener('message',"
46 " plugin.wait_for_messages_handler);"
47 "delete plugin.wait_for_messages_handler;";
48 instance_->EvalScript(js_code);
49}
50
51void TestImeInputEvent::RunTests(const std::string& filter) {
52 RUN_TEST(ImeCommit, filter);
53 RUN_TEST(ImeCancel, filter);
54 RUN_TEST(ImeUnawareCommit, filter);
55 RUN_TEST(ImeUnawareCancel, filter);
56}
57
58bool TestImeInputEvent::Init() {
59 input_event_interface_ = static_cast<const PPB_InputEvent*>(
60 pp::Module::Get()->GetBrowserInterface(PPB_INPUT_EVENT_INTERFACE));
61 keyboard_input_event_interface_ =
62 static_cast<const PPB_KeyboardInputEvent*>(
63 pp::Module::Get()->GetBrowserInterface(
64 PPB_KEYBOARD_INPUT_EVENT_INTERFACE));
[email protected]79cad342013-08-01 00:22:4865 ime_input_event_interface_ = static_cast<const PPB_IMEInputEvent*>(
[email protected]397c23962012-05-21 07:09:3266 pp::Module::Get()->GetBrowserInterface(
[email protected]79cad342013-08-01 00:22:4867 PPB_IME_INPUT_EVENT_INTERFACE));
[email protected]397c23962012-05-21 07:09:3268
69 bool success =
70 input_event_interface_ &&
71 keyboard_input_event_interface_ &&
72 ime_input_event_interface_ &&
73 CheckTestingInterface();
74
75 // Set up a listener for our message that signals that all input events have
76 // been received.
77 // Note the following code is dependent on some features of test_case.html.
78 // E.g., it is assumed that the DOM element where the plugin is embedded has
79 // an id of 'plugin', and there is a function 'IsTestingMessage' that allows
80 // us to ignore the messages that are intended for use by the testing
81 // framework itself.
82 std::string js_code =
83 "var plugin = document.getElementById('plugin');"
84 "var wait_for_messages_handler = function(message_event) {"
85 " if (!IsTestingMessage(message_event.data) &&"
86 " message_event.data === '" FINISHED_WAITING_MESSAGE "') {"
87 " plugin.postMessage('" FINISHED_WAITING_MESSAGE "');"
88 " }"
89 "};"
90 "plugin.addEventListener('message', wait_for_messages_handler);"
91 // Stash it on the plugin so we can remove it in the destructor.
92 "plugin.wait_for_messages_handler = wait_for_messages_handler;";
93 instance_->EvalScript(js_code);
94
95 return success;
96}
97
98bool TestImeInputEvent::HandleInputEvent(const pp::InputEvent& input_event) {
99 // Check whether the IME related events comes in the expected order.
100 switch (input_event.GetType()) {
101 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START:
102 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE:
103 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END:
104 case PP_INPUTEVENT_TYPE_IME_TEXT:
105 case PP_INPUTEVENT_TYPE_CHAR:
106 if (expected_events_.empty()) {
107 received_unexpected_event_ = true;
108 } else {
109 received_unexpected_event_ =
110 !AreEquivalentEvents(input_event.pp_resource(),
111 expected_events_.front().pp_resource());
112 expected_events_.erase(expected_events_.begin());
113 }
114 break;
115
116 default:
117 // Don't care for any other input event types for this test.
118 break;
119 }
120
121 // Handle all input events.
122 return true;
123}
124
125void TestImeInputEvent::HandleMessage(const pp::Var& message_data) {
126 if (message_data.is_string() &&
127 (message_data.AsString() == FINISHED_WAITING_MESSAGE)) {
128 testing_interface_->QuitMessageLoop(instance_->pp_instance());
129 received_finish_message_ = true;
130 }
131}
132
133void TestImeInputEvent::DidChangeView(const pp::View& view) {
134 view_rect_ = view.GetRect();
135}
136
137pp::InputEvent TestImeInputEvent::CreateImeCompositionStartEvent() {
[email protected]79cad342013-08-01 00:22:48138 return pp::IMEInputEvent(
[email protected]397c23962012-05-21 07:09:32139 instance_,
140 PP_INPUTEVENT_TYPE_IME_COMPOSITION_START,
141 100, // time_stamp
142 pp::Var(""),
143 std::vector<uint32_t>(),
144 -1, // target_segment
145 std::make_pair(0U, 0U) // selection
146 );
147}
148
149pp::InputEvent TestImeInputEvent::CreateImeCompositionUpdateEvent(
150 const std::string& text,
151 const std::vector<uint32_t>& segments,
152 int32_t target_segment,
153 const std::pair<uint32_t, uint32_t>& selection) {
[email protected]79cad342013-08-01 00:22:48154 return pp::IMEInputEvent(
[email protected]397c23962012-05-21 07:09:32155 instance_,
156 PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE,
157 100, // time_stamp
158 text,
159 segments,
160 target_segment,
161 selection
162 );
163}
164
165pp::InputEvent TestImeInputEvent::CreateImeCompositionEndEvent(
166 const std::string& text) {
[email protected]79cad342013-08-01 00:22:48167 return pp::IMEInputEvent(
[email protected]397c23962012-05-21 07:09:32168 instance_,
169 PP_INPUTEVENT_TYPE_IME_COMPOSITION_END,
170 100, // time_stamp
171 pp::Var(text),
172 std::vector<uint32_t>(),
173 -1, // target_segment
174 std::make_pair(0U, 0U) // selection
175 );
176}
177
178pp::InputEvent TestImeInputEvent::CreateImeTextEvent(const std::string& text) {
[email protected]79cad342013-08-01 00:22:48179 return pp::IMEInputEvent(
[email protected]397c23962012-05-21 07:09:32180 instance_,
181 PP_INPUTEVENT_TYPE_IME_TEXT,
182 100, // time_stamp
183 pp::Var(text),
184 std::vector<uint32_t>(),
185 -1, // target_segment
186 std::make_pair(0U, 0U) // selection
187 );
188}
189
190pp::InputEvent TestImeInputEvent::CreateCharEvent(const std::string& text) {
191 return pp::KeyboardInputEvent(
192 instance_,
193 PP_INPUTEVENT_TYPE_CHAR,
194 100, // time_stamp
195 0, // modifiers
196 0, // keycode
[email protected]9e1abbc2014-01-27 19:06:35197 pp::Var(text),
198 pp::Var());
[email protected]397c23962012-05-21 07:09:32199}
200
201void TestImeInputEvent::GetFocusBySimulatingMouseClick() {
202 // For receiving IME events, the plugin DOM node needs to be focused.
203 // The following code is for achieving that by simulating a mouse click event.
204 input_event_interface_->RequestInputEvents(instance_->pp_instance(),
205 PP_INPUTEVENT_CLASS_MOUSE);
206 SimulateInputEvent(pp::MouseInputEvent(
207 instance_,
208 PP_INPUTEVENT_TYPE_MOUSEDOWN,
209 100, // time_stamp
210 0, // modifiers
211 PP_INPUTEVENT_MOUSEBUTTON_LEFT,
212 pp::Point(
213 view_rect_.x() + view_rect_.width() / 2,
214 view_rect_.y() + view_rect_.height() / 2),
215 1, // click count
216 pp::Point())); // movement
217}
218
219// Simulates the input event and calls PostMessage to let us know when
220// we have received all resulting events from the browser.
221bool TestImeInputEvent::SimulateInputEvent(const pp::InputEvent& input_event) {
222 received_unexpected_event_ = false;
223 received_finish_message_ = false;
224 testing_interface_->SimulateInputEvent(instance_->pp_instance(),
225 input_event.pp_resource());
226 instance_->PostMessage(pp::Var(FINISHED_WAITING_MESSAGE));
227 testing_interface_->RunMessageLoop(instance_->pp_instance());
228 return received_finish_message_ && !received_unexpected_event_;
229}
230
231bool TestImeInputEvent::AreEquivalentEvents(PP_Resource received,
232 PP_Resource expected) {
233 if (!input_event_interface_->IsInputEvent(received) ||
234 !input_event_interface_->IsInputEvent(expected)) {
235 return false;
236 }
237
238 // Test common fields, except modifiers and time stamp, which may be changed
239 // by the browser.
240 int32_t received_type = input_event_interface_->GetType(received);
241 int32_t expected_type = input_event_interface_->GetType(expected);
242 if (received_type != expected_type)
243 return false;
244
245 // Test event type-specific fields.
246 switch (received_type) {
247 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START:
248 // COMPOSITION_START does not convey further information.
249 break;
250
251 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END:
252 case PP_INPUTEVENT_TYPE_IME_TEXT:
253 // For COMPOSITION_END and TEXT, GetText() has meaning.
254 return pp::Var(pp::PASS_REF,
255 ime_input_event_interface_->GetText(received)) ==
256 pp::Var(pp::PASS_REF,
257 ime_input_event_interface_->GetText(expected));
258
259 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE:
260 // For COMPOSITION_UPDATE, all fields must be checked.
261 {
262 uint32_t received_segment_number =
263 ime_input_event_interface_->GetSegmentNumber(received);
264 uint32_t expected_segment_number =
265 ime_input_event_interface_->GetSegmentNumber(expected);
266 if (received_segment_number != expected_segment_number)
267 return false;
268
269 // The "<=" is not a bug. i-th segment is represented as the pair of
270 // i-th and (i+1)-th offsets in Pepper IME API.
271 for (uint32_t i = 0; i <= received_segment_number; ++i) {
272 if (ime_input_event_interface_->GetSegmentOffset(received, i) !=
273 ime_input_event_interface_->GetSegmentOffset(expected, i))
274 return false;
275 }
276
277 uint32_t received_selection_start = 0;
278 uint32_t received_selection_end = 0;
279 uint32_t expected_selection_start = 0;
280 uint32_t expected_selection_end = 0;
281 ime_input_event_interface_->GetSelection(
282 received, &received_selection_start, &received_selection_end);
283 ime_input_event_interface_->GetSelection(
284 expected, &expected_selection_start, &expected_selection_end);
285 if (received_selection_start != expected_selection_start ||
286 received_selection_end != expected_selection_end) {
287 return true;
288 }
289
290 return pp::Var(pp::PASS_REF,
291 ime_input_event_interface_->GetText(received)) ==
292 pp::Var(pp::PASS_REF,
293 ime_input_event_interface_->GetText(expected)) &&
294 ime_input_event_interface_->GetTargetSegment(received) ==
295 ime_input_event_interface_->GetTargetSegment(expected);
296 }
297
298 case PP_INPUTEVENT_TYPE_CHAR:
299 return
300 keyboard_input_event_interface_->GetKeyCode(received) ==
301 keyboard_input_event_interface_->GetKeyCode(expected) &&
302 pp::Var(pp::PASS_REF,
303 keyboard_input_event_interface_->GetCharacterText(received)) ==
304 pp::Var(pp::PASS_REF,
305 keyboard_input_event_interface_->GetCharacterText(expected));
306
307 default:
308 break;
309 }
310 return true;
311}
312
313std::string TestImeInputEvent::TestImeCommit() {
314 GetFocusBySimulatingMouseClick();
315
316 input_event_interface_->RequestInputEvents(instance_->pp_instance(),
317 PP_INPUTEVENT_CLASS_KEYBOARD |
318 PP_INPUTEVENT_CLASS_IME);
319
320 std::vector<uint32_t> segments;
321 segments.push_back(0U);
322 segments.push_back(3U);
[email protected]28fccb32013-08-29 22:25:46323 segments.push_back(7U);
324 segments.push_back(11U);
[email protected]397c23962012-05-21 07:09:32325 pp::InputEvent update_event = CreateImeCompositionUpdateEvent(
[email protected]28fccb32013-08-29 22:25:46326 kCompositionText, segments, 1, std::make_pair(3U, 7U));
[email protected]397c23962012-05-21 07:09:32327
328 expected_events_.clear();
329 expected_events_.push_back(CreateImeCompositionStartEvent());
330 expected_events_.push_back(update_event);
331 expected_events_.push_back(CreateImeCompositionEndEvent(kCompositionText));
332 expected_events_.push_back(CreateImeTextEvent(kCompositionText));
333
334 // Simulate the case when IME successfully committed some text.
335 ASSERT_TRUE(SimulateInputEvent(update_event));
336 ASSERT_TRUE(SimulateInputEvent(CreateImeTextEvent(kCompositionText)));
337
338 ASSERT_TRUE(expected_events_.empty());
339 PASS();
340}
341
342std::string TestImeInputEvent::TestImeCancel() {
343 GetFocusBySimulatingMouseClick();
344
345 input_event_interface_->RequestInputEvents(instance_->pp_instance(),
346 PP_INPUTEVENT_CLASS_KEYBOARD |
347 PP_INPUTEVENT_CLASS_IME);
348
349 std::vector<uint32_t> segments;
350 segments.push_back(0U);
351 segments.push_back(3U);
[email protected]28fccb32013-08-29 22:25:46352 segments.push_back(7U);
353 segments.push_back(11U);
[email protected]397c23962012-05-21 07:09:32354 pp::InputEvent update_event = CreateImeCompositionUpdateEvent(
[email protected]28fccb32013-08-29 22:25:46355 kCompositionText, segments, 1, std::make_pair(3U, 7U));
[email protected]397c23962012-05-21 07:09:32356
357 expected_events_.clear();
358 expected_events_.push_back(CreateImeCompositionStartEvent());
359 expected_events_.push_back(update_event);
[email protected]007b3f82013-04-09 08:46:45360 expected_events_.push_back(CreateImeCompositionEndEvent(std::string()));
[email protected]397c23962012-05-21 07:09:32361
362 // Simulate the case when IME canceled composition.
363 ASSERT_TRUE(SimulateInputEvent(update_event));
[email protected]007b3f82013-04-09 08:46:45364 ASSERT_TRUE(SimulateInputEvent(CreateImeCompositionEndEvent(std::string())));
[email protected]397c23962012-05-21 07:09:32365
366 ASSERT_TRUE(expected_events_.empty());
367 PASS();
368}
369
370std::string TestImeInputEvent::TestImeUnawareCommit() {
371 GetFocusBySimulatingMouseClick();
372
373 input_event_interface_->ClearInputEventRequest(instance_->pp_instance(),
374 PP_INPUTEVENT_CLASS_IME);
375 input_event_interface_->RequestInputEvents(instance_->pp_instance(),
376 PP_INPUTEVENT_CLASS_KEYBOARD);
377
378 std::vector<uint32_t> segments;
379 segments.push_back(0U);
380 segments.push_back(3U);
[email protected]28fccb32013-08-29 22:25:46381 segments.push_back(7U);
382 segments.push_back(11U);
[email protected]397c23962012-05-21 07:09:32383 pp::InputEvent update_event = CreateImeCompositionUpdateEvent(
[email protected]28fccb32013-08-29 22:25:46384 kCompositionText, segments, 1, std::make_pair(3U, 7U));
[email protected]397c23962012-05-21 07:09:32385
386 expected_events_.clear();
387 expected_events_.push_back(CreateCharEvent(kCompositionChar[0]));
388 expected_events_.push_back(CreateCharEvent(kCompositionChar[1]));
389 expected_events_.push_back(CreateCharEvent(kCompositionChar[2]));
390
391 // Test for IME-unaware plugins. Commit event is translated to char events.
392 ASSERT_TRUE(SimulateInputEvent(update_event));
393 ASSERT_TRUE(SimulateInputEvent(CreateImeTextEvent(kCompositionText)));
394
395 ASSERT_TRUE(expected_events_.empty());
396 PASS();
397}
398
399
400std::string TestImeInputEvent::TestImeUnawareCancel() {
401 GetFocusBySimulatingMouseClick();
402
403 input_event_interface_->ClearInputEventRequest(instance_->pp_instance(),
404 PP_INPUTEVENT_CLASS_IME);
405 input_event_interface_->RequestInputEvents(instance_->pp_instance(),
406 PP_INPUTEVENT_CLASS_KEYBOARD);
407
408 std::vector<uint32_t> segments;
409 segments.push_back(0U);
410 segments.push_back(3U);
[email protected]28fccb32013-08-29 22:25:46411 segments.push_back(7U);
412 segments.push_back(11U);
[email protected]397c23962012-05-21 07:09:32413 pp::InputEvent update_event = CreateImeCompositionUpdateEvent(
[email protected]28fccb32013-08-29 22:25:46414 kCompositionText, segments, 1, std::make_pair(3U, 7U));
[email protected]397c23962012-05-21 07:09:32415
416 expected_events_.clear();
417
418 // Test for IME-unaware plugins. Cancel won't issue any events.
419 ASSERT_TRUE(SimulateInputEvent(update_event));
[email protected]007b3f82013-04-09 08:46:45420 ASSERT_TRUE(SimulateInputEvent(CreateImeCompositionEndEvent(std::string())));
[email protected]397c23962012-05-21 07:09:32421
422 ASSERT_TRUE(expected_events_.empty());
423 PASS();
424}