OLD | NEW |
---|---|
(Empty) | |
1 // 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 | |
7 #include "ppapi/c/pp_errors.h" | |
8 #include "ppapi/c/ppb_input_event.h" | |
9 #include "ppapi/c/dev/ppb_ime_input_event_dev.h" | |
yzshen1
2012/05/15 18:03:48
sort this section, please.
kinaba
2012/05/16 10:13:57
Done.
| |
10 #include "ppapi/c/dev/ppb_testing_dev.h" | |
11 #include "ppapi/cpp/input_event.h" | |
12 #include "ppapi/cpp/module.h" | |
13 #include "ppapi/cpp/dev/ime_input_event_dev.h" | |
14 #include "ppapi/tests/test_utils.h" | |
15 #include "ppapi/tests/testing_instance.h" | |
16 | |
17 REGISTER_TEST_CASE(ImeInputEvent); | |
18 | |
19 namespace { | |
20 | |
21 const char *(kCompositionChar[]) = { | |
22 "\xE6\x96\x87", "\xE5\xAD\x97", "\xE5\x88\x97" | |
23 }; | |
24 | |
25 const char kCompositionText[] = "\xE6\x96\x87\xE5\xAD\x97\xE5\x88\x97"; | |
26 | |
27 #define FINISHED_WAITING_MESSAGE "TEST_IME_INPUT_EVENT_FINISHED_WAITING" | |
28 | |
29 } // namespace | |
30 | |
31 void TestImeInputEvent::RunTests(const std::string& filter) { | |
yzshen1
2012/05/15 18:03:48
Keep the definitions in the same order as the decl
kinaba
2012/05/16 10:13:57
Done.
| |
32 RUN_TEST(ImeCommit, filter); | |
33 RUN_TEST(ImeCancel, filter); | |
34 RUN_TEST(ImeUnawareCommit, filter); | |
35 RUN_TEST(ImeUnawareCancel, filter); | |
36 } | |
37 | |
38 TestImeInputEvent::TestImeInputEvent(TestingInstance* instance) | |
39 : TestCase(instance), | |
40 input_event_interface_(NULL), | |
41 keyboard_input_event_interface_(NULL), | |
42 ime_input_event_interface_(NULL) { | |
yzshen1
2012/05/15 18:03:48
Please also init those boolean members.
kinaba
2012/05/16 10:13:57
Done.
| |
43 } | |
44 | |
45 TestImeInputEvent::~TestImeInputEvent() { | |
46 // Remove the special listener that only responds to a | |
47 // FINISHED_WAITING_MESSAGE string. See Init for where it gets added. | |
48 std::string js_code; | |
49 js_code += "var plugin = document.getElementById('plugin');" | |
yzshen1
2012/05/15 18:03:48
Why do we need to do a '+=' here? (and line 81)
kinaba
2012/05/16 10:13:57
Done. We don't need it.
| |
50 "plugin.removeEventListener('message'," | |
51 " plugin.wait_for_messages_handler);" | |
52 "delete plugin.wait_for_messages_handler;"; | |
53 instance_->EvalScript(js_code); | |
54 } | |
55 | |
56 bool TestImeInputEvent::Init() { | |
57 input_event_interface_ = static_cast<const PPB_InputEvent*>( | |
58 pp::Module::Get()->GetBrowserInterface(PPB_INPUT_EVENT_INTERFACE)); | |
59 keyboard_input_event_interface_ = | |
60 static_cast<const PPB_KeyboardInputEvent*>( | |
61 pp::Module::Get()->GetBrowserInterface( | |
62 PPB_KEYBOARD_INPUT_EVENT_INTERFACE)); | |
63 ime_input_event_interface_ = static_cast<const PPB_IMEInputEvent_Dev*>( | |
64 pp::Module::Get()->GetBrowserInterface( | |
65 PPB_IME_INPUT_EVENT_DEV_INTERFACE)); | |
66 | |
67 bool success = | |
68 input_event_interface_ && | |
69 keyboard_input_event_interface_ && | |
70 ime_input_event_interface_ && | |
71 CheckTestingInterface(); | |
72 | |
73 // Set up a listener for our message that signals that all input events have | |
74 // been received. | |
75 std::string js_code; | |
76 // Note the following code is dependent on some features of test_case.html. | |
77 // E.g., it is assumed that the DOM element where the plugin is embedded has | |
78 // an id of 'plugin', and there is a function 'IsTestingMessage' that allows | |
79 // us to ignore the messages that are intended for use by the testing | |
80 // framework itself. | |
81 js_code += "var plugin = document.getElementById('plugin');" | |
82 "var wait_for_messages_handler = function(message_event) {" | |
83 " if (!IsTestingMessage(message_event.data) &&" | |
84 " message_event.data === '" FINISHED_WAITING_MESSAGE "') {" | |
85 " plugin.postMessage('" FINISHED_WAITING_MESSAGE "');" | |
86 " }" | |
87 "};" | |
88 "plugin.addEventListener('message', wait_for_messages_handler);" | |
89 // Stash it on the plugin so we can remove it in the destructor. | |
90 "plugin.wait_for_messages_handler = wait_for_messages_handler;"; | |
91 instance_->EvalScript(js_code); | |
92 | |
93 return success; | |
94 } | |
95 | |
96 pp::InputEvent TestImeInputEvent::CreateImeCompositionStartEvent() { | |
97 return pp::IMEInputEvent_Dev( | |
98 instance_, | |
99 PP_INPUTEVENT_TYPE_IME_COMPOSITION_START, | |
100 100, // time_stamp | |
101 pp::Var(""), | |
102 std::vector<uint32_t>(), | |
103 -1, // target_segment | |
104 std::make_pair(0U, 0U) // selection | |
105 ); | |
106 } | |
107 | |
108 pp::InputEvent TestImeInputEvent::CreateImeCompositionUpdateEvent( | |
109 const std::string& text, | |
110 const std::vector<uint32_t>& segments, | |
111 int32_t target_segment, | |
112 const std::pair<uint32_t, uint32_t>& selection) { | |
113 return pp::IMEInputEvent_Dev( | |
114 instance_, | |
115 PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE, | |
116 100, // time_stamp | |
117 text, | |
118 segments, | |
119 target_segment, | |
120 selection | |
121 ); | |
122 } | |
123 | |
124 pp::InputEvent TestImeInputEvent::CreateImeCompositionEndEvent( | |
125 const std::string& text) { | |
126 return pp::IMEInputEvent_Dev( | |
127 instance_, | |
128 PP_INPUTEVENT_TYPE_IME_COMPOSITION_END, | |
129 100, // time_stamp | |
130 pp::Var(text), | |
131 std::vector<uint32_t>(), | |
132 -1, // target_segment | |
133 std::make_pair(0U, 0U) // selection | |
134 ); | |
135 } | |
136 | |
137 pp::InputEvent TestImeInputEvent::CreateImeTextEvent(const std::string& text) { | |
138 return pp::IMEInputEvent_Dev( | |
139 instance_, | |
140 PP_INPUTEVENT_TYPE_IME_TEXT, | |
141 100, // time_stamp | |
142 pp::Var(text), | |
143 std::vector<uint32_t>(), | |
144 -1, // target_segment | |
145 std::make_pair(0U, 0U) // selection | |
146 ); | |
147 } | |
148 | |
149 pp::InputEvent TestImeInputEvent::CreateCharEvent(const std::string& text) { | |
150 return pp::KeyboardInputEvent( | |
151 instance_, | |
152 PP_INPUTEVENT_TYPE_CHAR, | |
153 100, // time_stamp | |
154 0, // modifiers | |
155 0, // keycode | |
156 pp::Var(text)); | |
157 } | |
158 | |
159 void TestImeInputEvent::GetFocusBySimulatingMouseClick() { | |
160 // For receiving IME events, the plugin DOM node needs to be focused. | |
161 // The following code is for achieving that by simulating a mouse click event. | |
162 input_event_interface_->RequestInputEvents(instance_->pp_instance(), | |
163 PP_INPUTEVENT_CLASS_MOUSE); | |
164 SimulateInputEvent(pp::MouseInputEvent( | |
165 instance_, | |
166 PP_INPUTEVENT_TYPE_MOUSEDOWN, | |
167 100, // time_stamp | |
168 0, // modifiers | |
169 PP_INPUTEVENT_MOUSEBUTTON_LEFT, | |
170 pp::Point( | |
171 view_rect_.x() + view_rect_.width() / 2, | |
172 view_rect_.y() + view_rect_.height() / 2), | |
173 1, // click count | |
174 pp::Point())); // movement | |
175 } | |
176 | |
177 // Simulates the input event and calls PostMessage to let us know when | |
178 // we have received all resulting events from the browser. | |
179 bool TestImeInputEvent::SimulateInputEvent(const pp::InputEvent& input_event) { | |
180 received_unexpected_event_ = false; | |
181 received_finish_message_ = false; | |
182 testing_interface_->SimulateInputEvent(instance_->pp_instance(), | |
183 input_event.pp_resource()); | |
184 instance_->PostMessage(pp::Var(FINISHED_WAITING_MESSAGE)); | |
185 testing_interface_->RunMessageLoop(instance_->pp_instance()); | |
186 return received_finish_message_ && !received_unexpected_event_; | |
187 } | |
188 | |
189 bool TestImeInputEvent::AreEquivalentEvents(PP_Resource received, | |
190 PP_Resource expected) { | |
191 if (!input_event_interface_->IsInputEvent(received) || | |
192 !input_event_interface_->IsInputEvent(expected)) { | |
193 return false; | |
194 } | |
195 | |
196 // Test common fields, except modifiers and time stamp, which may be changed | |
197 // by the browser. | |
198 int32_t received_type = input_event_interface_->GetType(received); | |
199 int32_t expected_type = input_event_interface_->GetType(expected); | |
200 if (received_type != expected_type) | |
201 return false; | |
202 | |
203 // Test event type-specific fields. | |
204 switch (input_event_interface_->GetType(received)) { | |
yzshen1
2012/05/15 18:03:48
received_type?
kinaba
2012/05/16 10:13:57
Done.
| |
205 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START: | |
206 // COMPOSITION_START does not convey further information. | |
207 break; | |
208 | |
209 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END: | |
210 case PP_INPUTEVENT_TYPE_IME_TEXT: | |
211 // For COMPOSITION_END and TEXT, GetText() has meaning. | |
212 return pp::Var(pp::PASS_REF, | |
213 ime_input_event_interface_->GetText(received)) == | |
214 pp::Var(pp::PASS_REF, | |
215 ime_input_event_interface_->GetText(expected)); | |
216 | |
217 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE: | |
218 // For COMPOSITION_UPDATE, all fields must be checked. | |
219 { | |
220 uint32_t receivedSegmentNumber = | |
yzshen1
2012/05/15 18:03:48
name_variables_this_way (and some other places).
kinaba
2012/05/16 10:13:57
Done.
| |
221 ime_input_event_interface_->GetSegmentNumber(received); | |
222 uint32_t expectedSegmentNumber = | |
223 ime_input_event_interface_->GetSegmentNumber(received); | |
yzshen1
2012/05/15 18:03:48
expected?
kinaba
2012/05/16 10:13:57
Done. Good catch.
| |
224 if (receivedSegmentNumber != expectedSegmentNumber) | |
225 return false; | |
226 | |
227 // The "<=" is not a bug. i-th segment is represented as the pair of | |
228 // i-th and (i+1)-th offsets in Pepper IME API. | |
229 for (uint32_t i = 0; i <= receivedSegmentNumber; ++i) { | |
230 if (ime_input_event_interface_->GetSegmentOffset(received, i) != | |
231 ime_input_event_interface_->GetSegmentOffset(expected, i)) | |
232 return false; | |
233 } | |
234 | |
235 uint32_t receivedSelectionStart; | |
236 uint32_t receivedSelectionEnd; | |
237 uint32_t expectedSelectionStart; | |
238 uint32_t expectedSelectionEnd; | |
239 ime_input_event_interface_->GetSelection( | |
240 received, &receivedSelectionStart, &receivedSelectionEnd); | |
241 ime_input_event_interface_->GetSelection( | |
242 expected, &expectedSelectionStart, &expectedSelectionEnd); | |
243 if (receivedSelectionStart != expectedSelectionStart || | |
244 receivedSelectionEnd != expectedSelectionEnd) { | |
245 return true; | |
246 } | |
247 | |
248 return pp::Var(pp::PASS_REF, | |
249 ime_input_event_interface_->GetText(received)) == | |
250 pp::Var(pp::PASS_REF, | |
251 ime_input_event_interface_->GetText(expected)) && | |
252 ime_input_event_interface_->GetTargetSegment(received) == | |
253 ime_input_event_interface_->GetTargetSegment(received); | |
yzshen1
2012/05/15 18:03:48
expected? :)
kinaba
2012/05/16 10:13:57
Done. expected is expected.
| |
254 } | |
255 | |
256 case PP_INPUTEVENT_TYPE_CHAR: | |
257 return | |
258 keyboard_input_event_interface_->GetKeyCode(received) == | |
259 keyboard_input_event_interface_->GetKeyCode(expected) && | |
260 pp::Var(pp::PASS_REF, | |
261 keyboard_input_event_interface_->GetCharacterText(received)) == | |
262 pp::Var(pp::PASS_REF, | |
263 keyboard_input_event_interface_->GetCharacterText(expected)); | |
264 | |
265 default: | |
266 break; | |
267 } | |
268 return true; | |
269 } | |
270 | |
271 bool TestImeInputEvent::HandleInputEvent(const pp::InputEvent& input_event) { | |
272 // Check whether the IME related events comes in the expected order. | |
273 switch (input_event.GetType()) { | |
274 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START: | |
275 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE: | |
276 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END: | |
277 case PP_INPUTEVENT_TYPE_IME_TEXT: | |
278 case PP_INPUTEVENT_TYPE_CHAR: | |
279 if (expected_events_.empty()) { | |
280 received_unexpected_event_ = true; | |
281 } else { | |
282 received_unexpected_event_ = | |
283 !AreEquivalentEvents(input_event.pp_resource(), | |
284 expected_events_.front().pp_resource()); | |
285 expected_events_.erase(expected_events_.begin()); | |
286 } | |
287 break; | |
288 | |
289 default: | |
290 break; | |
291 } | |
292 | |
293 // Handle all input events. | |
294 return true; | |
295 } | |
296 | |
297 void TestImeInputEvent::HandleMessage(const pp::Var& message_data) { | |
298 if (message_data.is_string() && | |
299 (message_data.AsString() == FINISHED_WAITING_MESSAGE)) { | |
300 testing_interface_->QuitMessageLoop(instance_->pp_instance()); | |
301 received_finish_message_ = true; | |
302 } | |
303 } | |
304 | |
305 void TestImeInputEvent::DidChangeView(const pp::View& view) { | |
306 view_rect_ = view.GetRect(); | |
307 } | |
308 | |
309 std::string TestImeInputEvent::TestImeCommit() { | |
310 GetFocusBySimulatingMouseClick(); | |
311 | |
312 input_event_interface_->RequestInputEvents(instance_->pp_instance(), | |
313 PP_INPUTEVENT_CLASS_KEYBOARD | | |
314 PP_INPUTEVENT_CLASS_IME); | |
315 | |
316 std::vector<uint32_t> segments; | |
317 segments.push_back(0U); | |
318 segments.push_back(3U); | |
319 segments.push_back(6U); | |
320 segments.push_back(9U); | |
321 pp::InputEvent update_event = CreateImeCompositionUpdateEvent( | |
322 kCompositionText, segments, 1, std::make_pair(3U, 6U)); | |
323 | |
324 expected_events_.clear(); | |
325 expected_events_.push_back(CreateImeCompositionStartEvent()); | |
326 expected_events_.push_back(update_event); | |
327 expected_events_.push_back(CreateImeCompositionEndEvent(kCompositionText)); | |
328 expected_events_.push_back(CreateImeTextEvent(kCompositionText)); | |
329 | |
330 // Simulate the case when IME successfully committed some text. | |
331 ASSERT_TRUE( | |
332 SimulateInputEvent(update_event)); | |
333 ASSERT_TRUE( | |
334 SimulateInputEvent(CreateImeTextEvent(kCompositionText))); | |
335 | |
336 ASSERT_TRUE(expected_events_.empty()); | |
337 PASS(); | |
338 } | |
339 | |
340 std::string TestImeInputEvent::TestImeCancel() { | |
341 GetFocusBySimulatingMouseClick(); | |
342 | |
343 input_event_interface_->RequestInputEvents(instance_->pp_instance(), | |
344 PP_INPUTEVENT_CLASS_KEYBOARD | | |
345 PP_INPUTEVENT_CLASS_IME); | |
346 | |
347 std::vector<uint32_t> segments; | |
348 segments.push_back(0U); | |
349 segments.push_back(3U); | |
350 segments.push_back(6U); | |
351 segments.push_back(9U); | |
352 pp::InputEvent update_event = CreateImeCompositionUpdateEvent( | |
353 kCompositionText, segments, 1, std::make_pair(3U, 6U)); | |
354 | |
355 expected_events_.clear(); | |
356 expected_events_.push_back(CreateImeCompositionStartEvent()); | |
357 expected_events_.push_back(update_event); | |
358 expected_events_.push_back(CreateImeCompositionEndEvent("")); | |
359 | |
360 // Simulate the case when IME canceled composition. | |
361 ASSERT_TRUE( | |
362 SimulateInputEvent(update_event)); | |
363 ASSERT_TRUE( | |
364 SimulateInputEvent(CreateImeCompositionEndEvent(""))); | |
365 | |
366 ASSERT_TRUE(expected_events_.empty()); | |
367 PASS(); | |
368 } | |
369 | |
370 std::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); | |
381 segments.push_back(6U); | |
382 segments.push_back(9U); | |
383 pp::InputEvent update_event = CreateImeCompositionUpdateEvent( | |
384 kCompositionText, segments, 1, std::make_pair(3U, 6U)); | |
385 | |
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 | |
400 std::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); | |
411 segments.push_back(6U); | |
412 segments.push_back(9U); | |
413 pp::InputEvent update_event = CreateImeCompositionUpdateEvent( | |
414 kCompositionText, segments, 1, std::make_pair(3U, 6U)); | |
415 | |
416 expected_events_.clear(); | |
417 | |
418 // Test for IME-unaware plugins. Cancel won't issue any events. | |
419 ASSERT_TRUE(SimulateInputEvent(update_event)); | |
420 ASSERT_TRUE(SimulateInputEvent(CreateImeCompositionEndEvent(""))); | |
421 | |
422 ASSERT_TRUE(expected_events_.empty()); | |
423 PASS(); | |
424 } | |
425 | |
OLD | NEW |