Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ppapi / tests / test_input_event.cc
blob4fd0edab0e12af506562bfadd7c5f3807a410d5a
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.
5 #include "ppapi/tests/test_input_event.h"
7 #include "ppapi/c/pp_errors.h"
8 #include "ppapi/c/ppb_input_event.h"
9 #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"
14 REGISTER_TEST_CASE(InputEvent);
16 namespace {
18 const uint32_t kSpaceChar = 0x20;
19 const char* kSpaceString = " ";
20 const char* kSpaceCode = "Space";
22 #define FINISHED_WAITING_MESSAGE "TEST_INPUT_EVENT_FINISHED_WAITING"
24 pp::Point GetCenter(const pp::Rect& rect) {
25 return pp::Point(
26 rect.x() + rect.width() / 2,
27 rect.y() + rect.height() / 2);
30 } // namespace
32 void TestInputEvent::RunTests(const std::string& filter) {
33 RUN_TEST(Events, filter);
35 // The AcceptTouchEvent_N tests should not be run when the filter is empty;
36 // they can only be run one at a time.
37 // TODO(dmichael): Figure out a way to make these run in the same test fixture
38 // instance.
39 if (!ShouldRunAllTests(filter)) {
40 RUN_TEST(AcceptTouchEvent_1, filter);
41 RUN_TEST(AcceptTouchEvent_2, filter);
42 RUN_TEST(AcceptTouchEvent_3, filter);
43 RUN_TEST(AcceptTouchEvent_4, filter);
47 TestInputEvent::TestInputEvent(TestingInstance* instance)
48 : TestCase(instance),
49 input_event_interface_(NULL),
50 mouse_input_event_interface_(NULL),
51 wheel_input_event_interface_(NULL),
52 keyboard_input_event_interface_(NULL),
53 touch_input_event_interface_(NULL),
54 nested_event_(instance->pp_instance()),
55 view_rect_(),
56 expected_input_event_(0),
57 received_expected_event_(false),
58 received_finish_message_(false) {
61 TestInputEvent::~TestInputEvent() {
62 // Remove the special listener that only responds to a
63 // FINISHED_WAITING_MESSAGE string. See Init for where it gets added.
64 std::string js_code;
65 js_code += "var plugin = document.getElementById('plugin');"
66 "plugin.removeEventListener('message',"
67 " plugin.wait_for_messages_handler);"
68 "delete plugin.wait_for_messages_handler;";
69 instance_->EvalScript(js_code);
72 bool TestInputEvent::Init() {
73 input_event_interface_ = static_cast<const PPB_InputEvent*>(
74 pp::Module::Get()->GetBrowserInterface(PPB_INPUT_EVENT_INTERFACE));
75 mouse_input_event_interface_ = static_cast<const PPB_MouseInputEvent*>(
76 pp::Module::Get()->GetBrowserInterface(
77 PPB_MOUSE_INPUT_EVENT_INTERFACE));
78 wheel_input_event_interface_ = static_cast<const PPB_WheelInputEvent*>(
79 pp::Module::Get()->GetBrowserInterface(
80 PPB_WHEEL_INPUT_EVENT_INTERFACE));
81 keyboard_input_event_interface_ = static_cast<const PPB_KeyboardInputEvent*>(
82 pp::Module::Get()->GetBrowserInterface(
83 PPB_KEYBOARD_INPUT_EVENT_INTERFACE));
84 touch_input_event_interface_ = static_cast<const PPB_TouchInputEvent*>(
85 pp::Module::Get()->GetBrowserInterface(
86 PPB_TOUCH_INPUT_EVENT_INTERFACE));
88 bool success =
89 input_event_interface_ &&
90 mouse_input_event_interface_ &&
91 wheel_input_event_interface_ &&
92 keyboard_input_event_interface_ &&
93 touch_input_event_interface_ &&
94 CheckTestingInterface();
96 // Set up a listener for our message that signals that all input events have
97 // been received.
98 std::string js_code;
99 // Note the following code is dependent on some features of test_case.html.
100 // E.g., it is assumed that the DOM element where the plugin is embedded has
101 // an id of 'plugin', and there is a function 'IsTestingMessage' that allows
102 // us to ignore the messages that are intended for use by the testing
103 // framework itself.
104 js_code += "var plugin = document.getElementById('plugin');"
105 "var wait_for_messages_handler = function(message_event) {"
106 " if (!IsTestingMessage(message_event.data) &&"
107 " message_event.data === '" FINISHED_WAITING_MESSAGE "') {"
108 " plugin.postMessage('" FINISHED_WAITING_MESSAGE "');"
109 " }"
110 "};"
111 "plugin.addEventListener('message', wait_for_messages_handler);"
112 // Stash it on the plugin so we can remove it in the destructor.
113 "plugin.wait_for_messages_handler = wait_for_messages_handler;";
114 instance_->EvalScript(js_code);
116 return success;
119 pp::InputEvent TestInputEvent::CreateMouseEvent(
120 PP_InputEvent_Type type,
121 PP_InputEvent_MouseButton buttons) {
122 return pp::MouseInputEvent(
123 instance_,
124 type,
125 100, // time_stamp
126 0, // modifiers
127 buttons,
128 GetCenter(view_rect_),
129 1, // click count
130 pp::Point()); // movement
133 pp::InputEvent TestInputEvent::CreateWheelEvent() {
134 return pp::WheelInputEvent(
135 instance_,
136 100, // time_stamp
137 0, // modifiers
138 pp::FloatPoint(1, 2),
139 pp::FloatPoint(3, 4),
140 PP_TRUE); // scroll_by_page
143 pp::InputEvent TestInputEvent::CreateKeyEvent(PP_InputEvent_Type type,
144 uint32_t key_code,
145 const std::string& code) {
146 return pp::KeyboardInputEvent(
147 instance_,
148 type,
149 100, // time_stamp
150 0, // modifiers
151 key_code,
152 pp::Var(),
153 pp::Var(code));
156 pp::InputEvent TestInputEvent::CreateCharEvent(const std::string& text) {
157 return pp::KeyboardInputEvent(
158 instance_,
159 PP_INPUTEVENT_TYPE_CHAR,
160 100, // time_stamp
161 0, // modifiers
162 0, // keycode
163 pp::Var(text),
164 pp::Var());
167 pp::InputEvent TestInputEvent::CreateTouchEvent(PP_InputEvent_Type type,
168 const pp::FloatPoint& point) {
169 PP_TouchPoint touch_point = PP_MakeTouchPoint();
170 touch_point.position = point;
172 pp::TouchInputEvent touch_event(instance_, type, 100, 0);
173 touch_event.AddTouchPoint(PP_TOUCHLIST_TYPE_TOUCHES, touch_point);
174 touch_event.AddTouchPoint(PP_TOUCHLIST_TYPE_CHANGEDTOUCHES, touch_point);
175 touch_event.AddTouchPoint(PP_TOUCHLIST_TYPE_TARGETTOUCHES, touch_point);
177 return touch_event;
180 void TestInputEvent::PostMessageBarrier() {
181 received_finish_message_ = false;
182 instance_->PostMessage(pp::Var(FINISHED_WAITING_MESSAGE));
183 testing_interface_->RunMessageLoop(instance_->pp_instance());
184 nested_event_.Wait();
187 // Simulates the input event and calls PostMessage to let us know when
188 // we have received all resulting events from the browser.
189 bool TestInputEvent::SimulateInputEvent(
190 const pp::InputEvent& input_event) {
191 expected_input_event_ = pp::InputEvent(input_event.pp_resource());
192 received_expected_event_ = false;
193 testing_interface_->SimulateInputEvent(instance_->pp_instance(),
194 input_event.pp_resource());
195 PostMessageBarrier();
196 return received_expected_event_;
199 bool TestInputEvent::AreEquivalentEvents(PP_Resource received,
200 PP_Resource expected) {
201 if (!input_event_interface_->IsInputEvent(received) ||
202 !input_event_interface_->IsInputEvent(expected)) {
203 return false;
206 // Test common fields, except modifiers and time stamp, which may be changed
207 // by the browser.
208 int32_t received_type = input_event_interface_->GetType(received);
209 int32_t expected_type = input_event_interface_->GetType(expected);
210 if (received_type != expected_type) {
211 // Allow key down events to match "raw" key down events.
212 if (expected_type != PP_INPUTEVENT_TYPE_KEYDOWN &&
213 received_type != PP_INPUTEVENT_TYPE_RAWKEYDOWN) {
214 return false;
218 // Test event type-specific fields.
219 switch (input_event_interface_->GetType(received)) {
220 case PP_INPUTEVENT_TYPE_MOUSEDOWN:
221 case PP_INPUTEVENT_TYPE_MOUSEUP:
222 case PP_INPUTEVENT_TYPE_MOUSEMOVE:
223 case PP_INPUTEVENT_TYPE_MOUSEENTER:
224 case PP_INPUTEVENT_TYPE_MOUSELEAVE:
225 // Check mouse fields, except position and movement, which may be
226 // modified by the renderer.
227 return
228 mouse_input_event_interface_->GetButton(received) ==
229 mouse_input_event_interface_->GetButton(expected) &&
230 mouse_input_event_interface_->GetClickCount(received) ==
231 mouse_input_event_interface_->GetClickCount(expected);
233 case PP_INPUTEVENT_TYPE_WHEEL:
234 return
235 pp::FloatPoint(wheel_input_event_interface_->GetDelta(received)) ==
236 pp::FloatPoint(wheel_input_event_interface_->GetDelta(expected)) &&
237 pp::FloatPoint(wheel_input_event_interface_->GetTicks(received)) ==
238 pp::FloatPoint(wheel_input_event_interface_->GetTicks(expected)) &&
239 wheel_input_event_interface_->GetScrollByPage(received) ==
240 wheel_input_event_interface_->GetScrollByPage(expected);
242 case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
243 case PP_INPUTEVENT_TYPE_KEYDOWN:
244 case PP_INPUTEVENT_TYPE_KEYUP:
245 return
246 keyboard_input_event_interface_->GetKeyCode(received) ==
247 keyboard_input_event_interface_->GetKeyCode(expected);
249 case PP_INPUTEVENT_TYPE_CHAR:
250 return
251 keyboard_input_event_interface_->GetKeyCode(received) ==
252 keyboard_input_event_interface_->GetKeyCode(expected) &&
253 pp::Var(pp::PASS_REF,
254 keyboard_input_event_interface_->GetCharacterText(received)) ==
255 pp::Var(pp::PASS_REF,
256 keyboard_input_event_interface_->GetCharacterText(expected));
258 case PP_INPUTEVENT_TYPE_TOUCHSTART:
259 case PP_INPUTEVENT_TYPE_TOUCHMOVE:
260 case PP_INPUTEVENT_TYPE_TOUCHEND:
261 case PP_INPUTEVENT_TYPE_TOUCHCANCEL: {
262 if (!touch_input_event_interface_->IsTouchInputEvent(received) ||
263 !touch_input_event_interface_->IsTouchInputEvent(expected))
264 return false;
266 uint32_t touch_count = touch_input_event_interface_->GetTouchCount(
267 received, PP_TOUCHLIST_TYPE_TOUCHES);
268 if (touch_count <= 0 ||
269 touch_count != touch_input_event_interface_->GetTouchCount(expected,
270 PP_TOUCHLIST_TYPE_TOUCHES))
271 return false;
273 for (uint32_t i = 0; i < touch_count; ++i) {
274 PP_TouchPoint expected_point = touch_input_event_interface_->
275 GetTouchByIndex(expected, PP_TOUCHLIST_TYPE_TOUCHES, i);
276 PP_TouchPoint received_point = touch_input_event_interface_->
277 GetTouchByIndex(received, PP_TOUCHLIST_TYPE_TOUCHES, i);
279 if (expected_point.id != received_point.id ||
280 expected_point.radius != received_point.radius ||
281 expected_point.rotation_angle != received_point.rotation_angle ||
282 expected_point.pressure != received_point.pressure)
283 return false;
285 if (expected_point.position.x != received_point.position.x ||
286 expected_point.position.y != received_point.position.y)
287 return false;
289 return true;
292 default:
293 break;
296 return false;
299 bool TestInputEvent::HandleInputEvent(const pp::InputEvent& input_event) {
300 // Some events may cause extra events to be generated, so look for the
301 // first one that matches.
302 if (!received_expected_event_) {
303 received_expected_event_ = AreEquivalentEvents(
304 input_event.pp_resource(),
305 expected_input_event_.pp_resource());
307 // Handle all input events.
308 return true;
311 void TestInputEvent::HandleMessage(const pp::Var& message_data) {
312 if (message_data.is_string() &&
313 (message_data.AsString() == FINISHED_WAITING_MESSAGE)) {
314 testing_interface_->QuitMessageLoop(instance_->pp_instance());
315 received_finish_message_ = true;
316 nested_event_.Signal();
320 void TestInputEvent::DidChangeView(const pp::View& view) {
321 view_rect_ = view.GetRect();
324 std::string TestInputEvent::TestEvents() {
325 // Request all input event classes.
326 input_event_interface_->RequestInputEvents(instance_->pp_instance(),
327 PP_INPUTEVENT_CLASS_MOUSE |
328 PP_INPUTEVENT_CLASS_WHEEL |
329 PP_INPUTEVENT_CLASS_KEYBOARD |
330 PP_INPUTEVENT_CLASS_TOUCH);
331 PostMessageBarrier();
333 // Send the events and check that we received them.
334 ASSERT_TRUE(
335 SimulateInputEvent(CreateMouseEvent(PP_INPUTEVENT_TYPE_MOUSEDOWN,
336 PP_INPUTEVENT_MOUSEBUTTON_LEFT)));
337 ASSERT_TRUE(
338 SimulateInputEvent(CreateWheelEvent()));
339 ASSERT_TRUE(
340 SimulateInputEvent(CreateKeyEvent(PP_INPUTEVENT_TYPE_KEYDOWN,
341 kSpaceChar, kSpaceCode)));
342 ASSERT_TRUE(
343 SimulateInputEvent(CreateCharEvent(kSpaceString)));
344 ASSERT_TRUE(SimulateInputEvent(CreateTouchEvent(PP_INPUTEVENT_TYPE_TOUCHSTART,
345 pp::FloatPoint(12, 23))));
346 // Request only mouse events.
347 input_event_interface_->ClearInputEventRequest(instance_->pp_instance(),
348 PP_INPUTEVENT_CLASS_WHEEL |
349 PP_INPUTEVENT_CLASS_KEYBOARD);
350 PostMessageBarrier();
352 // Check that we only receive mouse events.
353 ASSERT_TRUE(
354 SimulateInputEvent(CreateMouseEvent(PP_INPUTEVENT_TYPE_MOUSEDOWN,
355 PP_INPUTEVENT_MOUSEBUTTON_LEFT)));
356 ASSERT_FALSE(
357 SimulateInputEvent(CreateWheelEvent()));
358 ASSERT_FALSE(
359 SimulateInputEvent(CreateKeyEvent(PP_INPUTEVENT_TYPE_KEYDOWN,
360 kSpaceChar, kSpaceCode)));
361 ASSERT_FALSE(
362 SimulateInputEvent(CreateCharEvent(kSpaceString)));
364 PASS();
367 std::string TestInputEvent::TestAcceptTouchEvent_1() {
368 // The browser normally sends touch-events to the renderer only if the page
369 // has touch-event handlers. Since test-case.html does not have any
370 // touch-event handler, it would normally not receive any touch events from
371 // the browser. However, if a plugin in the page does accept touch events,
372 // then the browser should start sending touch-events to the page. In this
373 // test, the plugin simply registers for touch-events. The real test is to
374 // verify that the browser knows to send touch-events to the renderer.
375 // If the plugin is removed from the page, then there are no more touch-event
376 // handlers in the page, and browser stops sending touch-events. So to make
377 // it possible to test this properly, the plugin is not removed from the page
378 // at the end of the test.
379 instance_->set_remove_plugin(false);
380 input_event_interface_->RequestInputEvents(instance_->pp_instance(),
381 PP_INPUTEVENT_CLASS_MOUSE |
382 PP_INPUTEVENT_CLASS_WHEEL |
383 PP_INPUTEVENT_CLASS_KEYBOARD |
384 PP_INPUTEVENT_CLASS_TOUCH);
385 PASS();
388 std::string TestInputEvent::TestAcceptTouchEvent_2() {
389 // See comment in TestAcceptTouchEvent_1.
390 instance_->set_remove_plugin(false);
391 input_event_interface_->RequestInputEvents(instance_->pp_instance(),
392 PP_INPUTEVENT_CLASS_MOUSE |
393 PP_INPUTEVENT_CLASS_WHEEL |
394 PP_INPUTEVENT_CLASS_KEYBOARD |
395 PP_INPUTEVENT_CLASS_TOUCH);
396 input_event_interface_->ClearInputEventRequest(instance_->pp_instance(),
397 PP_INPUTEVENT_CLASS_TOUCH);
398 PASS();
401 std::string TestInputEvent::TestAcceptTouchEvent_3() {
402 // See comment in TestAcceptTouchEvent_1.
403 instance_->set_remove_plugin(false);
404 input_event_interface_->RequestInputEvents(instance_->pp_instance(),
405 PP_INPUTEVENT_CLASS_MOUSE |
406 PP_INPUTEVENT_CLASS_WHEEL |
407 PP_INPUTEVENT_CLASS_KEYBOARD);
408 input_event_interface_->RequestFilteringInputEvents(instance_->pp_instance(),
409 PP_INPUTEVENT_CLASS_TOUCH);
410 PASS();
413 std::string TestInputEvent::TestAcceptTouchEvent_4() {
414 // See comment in TestAcceptTouchEvent_1.
415 instance_->set_remove_plugin(false);
416 input_event_interface_->RequestInputEvents(instance_->pp_instance(),
417 PP_INPUTEVENT_CLASS_MOUSE |
418 PP_INPUTEVENT_CLASS_WHEEL |
419 PP_INPUTEVENT_CLASS_KEYBOARD);
420 input_event_interface_->RequestInputEvents(instance_->pp_instance(),
421 PP_INPUTEVENT_CLASS_TOUCH);
422 PASS();