1 /*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 // This file contains the definition for EventSender.
32 //
33 // Some notes about drag and drop handling:
34 // Windows drag and drop goes through a system call to doDragDrop. At that
35 // point, program control is given to Windows which then periodically makes
36 // callbacks into the webview. This won't work for layout tests, so instead,
37 // we queue up all the mouse move and mouse up events. When the test tries to
38 // start a drag (by calling EvenSendingController::doDragDrop), we take the
39 // events in the queue and replay them.
40 // The behavior of queuing events and replaying them can be disabled by a
41 // layout test by setting eventSender.dragMode to false.
42
43 #include "EventSender.h"
44
45 #include "KeyCodeMapping.h"
46 #include "MockSpellCheck.h"
47 #include "TestCommon.h"
48 #include "TestInterfaces.h"
49 #include "public/platform/WebDragData.h"
50 #include "public/platform/WebString.h"
51 #include "public/platform/WebVector.h"
52 #include "public/testing/WebTestDelegate.h"
53 #include "public/testing/WebTestProxy.h"
54 #include "public/web/WebContextMenuData.h"
55 #include "public/web/WebTouchPoint.h"
56 #include "public/web/WebView.h"
57 #include <deque>
58
59 #ifdef WIN32
60 #include "public/web/win/WebInputEventFactory.h"
61 #elif __APPLE__
62 #include "public/web/mac/WebInputEventFactory.h"
63 #elif defined(ANDROID)
64 #include "public/web/android/WebInputEventFactory.h"
65 #elif defined(TOOLKIT_GTK)
66 #include "public/web/gtk/WebInputEventFactory.h"
67 #endif
68
69 // FIXME: layout before each event?
70
71 using namespace std;
72 using namespace blink;
73
74 namespace WebTestRunner {
75
76 WebPoint EventSender::lastMousePos;
77 WebMouseEvent::Button EventSender::pressedButton = WebMouseEvent::ButtonNone;
78 WebMouseEvent::Button EventSender::lastButtonType = WebMouseEvent::ButtonNone;
79
80 namespace {
81
82 struct SavedEvent {
83 enum SavedEventType {
84 Unspecified,
85 MouseUp,
86 MouseMove,
87 LeapForward
88 };
89
90 SavedEventType type;
91 WebMouseEvent::Button buttonType; // For MouseUp.
92 WebPoint pos; // For MouseMove.
93 int milliseconds; // For LeapForward.
94
SavedEventWebTestRunner::__anonb6ee7a0d0111::SavedEvent95 SavedEvent()
96 : type(Unspecified)
97 , buttonType(WebMouseEvent::ButtonNone)
98 , milliseconds(0) { }
99 };
100
101 WebDragData currentDragData;
102 WebDragOperation currentDragEffect;
103 WebDragOperationsMask currentDragEffectsAllowed;
104 bool replayingSavedEvents = false;
105 deque<SavedEvent> mouseEventQueue;
106 int touchModifiers;
107 vector<WebTouchPoint> touchPoints;
108
109 // Time and place of the last mouse up event.
110 double lastClickTimeSec = 0;
111 WebPoint lastClickPos;
112 int clickCount = 0;
113
114 // maximum distance (in space and time) for a mouse click
115 // to register as a double or triple click
116 const double multipleClickTimeSec = 1;
117 const int multipleClickRadiusPixels = 5;
118
119 // How much we should scroll per event - the value here is chosen to
120 // match the WebKit impl and layout test results.
121 const float scrollbarPixelsPerTick = 40.0f;
122
outsideMultiClickRadius(const WebPoint & a,const WebPoint & b)123 inline bool outsideMultiClickRadius(const WebPoint& a, const WebPoint& b)
124 {
125 return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)) >
126 multipleClickRadiusPixels * multipleClickRadiusPixels;
127 }
128
129 // Used to offset the time the event hander things an event happened. This is
130 // done so tests can run without a delay, but bypass checks that are time
131 // dependent (e.g., dragging has a timeout vs selection).
132 uint32 timeOffsetMs = 0;
133
getCurrentEventTimeSec(WebTestDelegate * delegate)134 double getCurrentEventTimeSec(WebTestDelegate* delegate)
135 {
136 return (delegate->getCurrentTimeInMillisecond() + timeOffsetMs) / 1000.0;
137 }
138
advanceEventTime(int32_t deltaMs)139 void advanceEventTime(int32_t deltaMs)
140 {
141 timeOffsetMs += deltaMs;
142 }
143
initMouseEvent(WebInputEvent::Type t,WebMouseEvent::Button b,const WebPoint & pos,WebMouseEvent * e,double ts)144 void initMouseEvent(WebInputEvent::Type t, WebMouseEvent::Button b, const WebPoint& pos, WebMouseEvent* e, double ts)
145 {
146 e->type = t;
147 e->button = b;
148 e->modifiers = 0;
149 e->x = pos.x;
150 e->y = pos.y;
151 e->globalX = pos.x;
152 e->globalY = pos.y;
153 e->timeStampSeconds = ts;
154 e->clickCount = clickCount;
155 }
156
applyKeyModifier(const string & modifierName,WebInputEvent * event)157 void applyKeyModifier(const string& modifierName, WebInputEvent* event)
158 {
159 const char* characters = modifierName.c_str();
160 if (!strcmp(characters, "ctrlKey")
161 #ifndef __APPLE__
162 || !strcmp(characters, "addSelectionKey")
163 #endif
164 ) {
165 event->modifiers |= WebInputEvent::ControlKey;
166 } else if (!strcmp(characters, "shiftKey") || !strcmp(characters, "rangeSelectionKey"))
167 event->modifiers |= WebInputEvent::ShiftKey;
168 else if (!strcmp(characters, "altKey")) {
169 event->modifiers |= WebInputEvent::AltKey;
170 #ifdef __APPLE__
171 } else if (!strcmp(characters, "metaKey") || !strcmp(characters, "addSelectionKey")) {
172 event->modifiers |= WebInputEvent::MetaKey;
173 #else
174 } else if (!strcmp(characters, "metaKey")) {
175 event->modifiers |= WebInputEvent::MetaKey;
176 #endif
177 } else if (!strcmp(characters, "autoRepeat")) {
178 event->modifiers |= WebInputEvent::IsAutoRepeat;
179 }
180 }
181
applyKeyModifiers(const CppVariant * argument,WebInputEvent * event)182 void applyKeyModifiers(const CppVariant* argument, WebInputEvent* event)
183 {
184 if (argument->isObject()) {
185 vector<string> modifiers = argument->toStringVector();
186 for (vector<string>::const_iterator i = modifiers.begin(); i != modifiers.end(); ++i)
187 applyKeyModifier(*i, event);
188 } else if (argument->isString()) {
189 applyKeyModifier(argument->toString(), event);
190 }
191 }
192
193 // Get the edit command corresponding to a keyboard event.
194 // Returns true if the specified event corresponds to an edit command, the name
195 // of the edit command will be stored in |*name|.
getEditCommand(const WebKeyboardEvent & event,string * name)196 bool getEditCommand(const WebKeyboardEvent& event, string* name)
197 {
198 #ifdef __APPLE__
199 // We only cares about Left,Right,Up,Down keys with Command or Command+Shift
200 // modifiers. These key events correspond to some special movement and
201 // selection editor commands, and was supposed to be handled in
202 // WebKit/chromium/src/EditorClientImpl.cpp. But these keys will be marked
203 // as system key, which prevents them from being handled. Thus they must be
204 // handled specially.
205 if ((event.modifiers & ~WebKeyboardEvent::ShiftKey) != WebKeyboardEvent::MetaKey)
206 return false;
207
208 switch (event.windowsKeyCode) {
209 case VKEY_LEFT:
210 *name = "MoveToBeginningOfLine";
211 break;
212 case VKEY_RIGHT:
213 *name = "MoveToEndOfLine";
214 break;
215 case VKEY_UP:
216 *name = "MoveToBeginningOfDocument";
217 break;
218 case VKEY_DOWN:
219 *name = "MoveToEndOfDocument";
220 break;
221 default:
222 return false;
223 }
224
225 if (event.modifiers & WebKeyboardEvent::ShiftKey)
226 name->append("AndModifySelection");
227
228 return true;
229 #else
230 return false;
231 #endif
232 }
233
234 // Key event location code introduced in DOM Level 3.
235 // See also: http://www.w3.org/TR/DOM-Level-3-Events/#events-keyboardevents
236 enum KeyLocationCode {
237 DOMKeyLocationStandard = 0x00,
238 DOMKeyLocationLeft = 0x01,
239 DOMKeyLocationRight = 0x02,
240 DOMKeyLocationNumpad = 0x03
241 };
242
243 }
244
EventSender(TestInterfaces * interfaces)245 EventSender::EventSender(TestInterfaces* interfaces)
246 : m_testInterfaces(interfaces)
247 , m_delegate(0)
248 {
249 // Initialize the map that associates methods of this class with the names
250 // they will use when called by JavaScript. The actual binding of those
251 // names to their methods will be done by calling bindToJavaScript() (defined
252 // by CppBoundClass, the parent to EventSender).
253 bindMethod("addTouchPoint", &EventSender::addTouchPoint);
254 bindMethod("beginDragWithFiles", &EventSender::beginDragWithFiles);
255 bindMethod("cancelTouchPoint", &EventSender::cancelTouchPoint);
256 bindMethod("clearKillRing", &EventSender::clearKillRing);
257 bindMethod("clearTouchPoints", &EventSender::clearTouchPoints);
258 bindMethod("contextClick", &EventSender::contextClick);
259 bindMethod("continuousMouseScrollBy", &EventSender::continuousMouseScrollBy);
260 bindMethod("dispatchMessage", &EventSender::dispatchMessage);
261 bindMethod("dumpFilenameBeingDragged", &EventSender::dumpFilenameBeingDragged);
262 bindMethod("enableDOMUIEventLogging", &EventSender::enableDOMUIEventLogging);
263 bindMethod("fireKeyboardEventsToElement", &EventSender::fireKeyboardEventsToElement);
264 bindMethod("keyDown", &EventSender::keyDown);
265 bindMethod("leapForward", &EventSender::leapForward);
266 bindMethod("mouseDown", &EventSender::mouseDown);
267 bindMethod("mouseMoveTo", &EventSender::mouseMoveTo);
268 bindMethod("mouseScrollBy", &EventSender::mouseScrollBy);
269 bindMethod("mouseUp", &EventSender::mouseUp);
270 bindMethod("mouseDragBegin", &EventSender::mouseDragBegin);
271 bindMethod("mouseDragEnd", &EventSender::mouseDragEnd);
272 bindMethod("mouseMomentumBegin", &EventSender::mouseMomentumBegin);
273 bindMethod("mouseMomentumScrollBy", &EventSender::mouseMomentumScrollBy);
274 bindMethod("mouseMomentumEnd", &EventSender::mouseMomentumEnd);
275 bindMethod("releaseTouchPoint", &EventSender::releaseTouchPoint);
276 bindMethod("scheduleAsynchronousClick", &EventSender::scheduleAsynchronousClick);
277 bindMethod("scheduleAsynchronousKeyDown", &EventSender::scheduleAsynchronousKeyDown);
278 bindMethod("setTouchModifier", &EventSender::setTouchModifier);
279 bindMethod("textZoomIn", &EventSender::textZoomIn);
280 bindMethod("textZoomOut", &EventSender::textZoomOut);
281 bindMethod("touchCancel", &EventSender::touchCancel);
282 bindMethod("touchEnd", &EventSender::touchEnd);
283 bindMethod("touchMove", &EventSender::touchMove);
284 bindMethod("touchStart", &EventSender::touchStart);
285 bindMethod("updateTouchPoint", &EventSender::updateTouchPoint);
286 bindMethod("gestureFlingCancel", &EventSender::gestureFlingCancel);
287 bindMethod("gestureFlingStart", &EventSender::gestureFlingStart);
288 bindMethod("gestureScrollBegin", &EventSender::gestureScrollBegin);
289 bindMethod("gestureScrollEnd", &EventSender::gestureScrollEnd);
290 bindMethod("gestureScrollFirstPoint", &EventSender::gestureScrollFirstPoint);
291 bindMethod("gestureScrollUpdate", &EventSender::gestureScrollUpdate);
292 bindMethod("gestureScrollUpdateWithoutPropagation", &EventSender::gestureScrollUpdateWithoutPropagation);
293 bindMethod("gestureTap", &EventSender::gestureTap);
294 bindMethod("gestureTapDown", &EventSender::gestureTapDown);
295 bindMethod("gestureShowPress", &EventSender::gestureShowPress);
296 bindMethod("gestureTapCancel", &EventSender::gestureTapCancel);
297 bindMethod("gestureLongPress", &EventSender::gestureLongPress);
298 bindMethod("gestureLongTap", &EventSender::gestureLongTap);
299 bindMethod("gestureTwoFingerTap", &EventSender::gestureTwoFingerTap);
300 bindMethod("zoomPageIn", &EventSender::zoomPageIn);
301 bindMethod("zoomPageOut", &EventSender::zoomPageOut);
302 bindMethod("setPageScaleFactor", &EventSender::setPageScaleFactor);
303
304 bindProperty("forceLayoutOnEvents", &forceLayoutOnEvents);
305
306 // When set to true (the default value), we batch mouse move and mouse up
307 // events so we can simulate drag & drop.
308 bindProperty("dragMode", &dragMode);
309 #ifdef WIN32
310 bindProperty("WM_KEYDOWN", &wmKeyDown);
311 bindProperty("WM_KEYUP", &wmKeyUp);
312 bindProperty("WM_CHAR", &wmChar);
313 bindProperty("WM_DEADCHAR", &wmDeadChar);
314 bindProperty("WM_SYSKEYDOWN", &wmSysKeyDown);
315 bindProperty("WM_SYSKEYUP", &wmSysKeyUp);
316 bindProperty("WM_SYSCHAR", &wmSysChar);
317 bindProperty("WM_SYSDEADCHAR", &wmSysDeadChar);
318 #endif
319 }
320
~EventSender()321 EventSender::~EventSender()
322 {
323 }
324
setContextMenuData(const WebContextMenuData & contextMenuData)325 void EventSender::setContextMenuData(const WebContextMenuData& contextMenuData)
326 {
327 m_lastContextMenuData = WebScopedPtr<WebContextMenuData>(new WebContextMenuData(contextMenuData));
328 }
329
reset()330 void EventSender::reset()
331 {
332 // The test should have finished a drag and the mouse button state.
333 BLINK_ASSERT(currentDragData.isNull());
334 currentDragData.reset();
335 currentDragEffect = blink::WebDragOperationNone;
336 currentDragEffectsAllowed = blink::WebDragOperationNone;
337 if (webview() && pressedButton != WebMouseEvent::ButtonNone)
338 webview()->mouseCaptureLost();
339 pressedButton = WebMouseEvent::ButtonNone;
340 dragMode.set(true);
341 forceLayoutOnEvents.set(true);
342 #ifdef WIN32
343 wmKeyDown.set(WM_KEYDOWN);
344 wmKeyUp.set(WM_KEYUP);
345 wmChar.set(WM_CHAR);
346 wmDeadChar.set(WM_DEADCHAR);
347 wmSysKeyDown.set(WM_SYSKEYDOWN);
348 wmSysKeyUp.set(WM_SYSKEYUP);
349 wmSysChar.set(WM_SYSCHAR);
350 wmSysDeadChar.set(WM_SYSDEADCHAR);
351 #endif
352 lastMousePos = WebPoint(0, 0);
353 lastClickTimeSec = 0;
354 lastClickPos = WebPoint(0, 0);
355 clickCount = 0;
356 lastButtonType = WebMouseEvent::ButtonNone;
357 timeOffsetMs = 0;
358 touchModifiers = 0;
359 touchPoints.clear();
360 m_taskList.revokeAll();
361 m_currentGestureLocation = WebPoint(0, 0);
362 mouseEventQueue.clear();
363 }
364
doDragDrop(const WebDragData & dragData,WebDragOperationsMask mask)365 void EventSender::doDragDrop(const WebDragData& dragData, WebDragOperationsMask mask)
366 {
367 WebMouseEvent event;
368 initMouseEvent(WebInputEvent::MouseDown, pressedButton, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
369 WebPoint clientPoint(event.x, event.y);
370 WebPoint screenPoint(event.globalX, event.globalY);
371 currentDragData = dragData;
372 currentDragEffectsAllowed = mask;
373 currentDragEffect = webview()->dragTargetDragEnter(dragData, clientPoint, screenPoint, currentDragEffectsAllowed, 0);
374
375 // Finish processing events.
376 replaySavedEvents();
377 }
378
dumpFilenameBeingDragged(const CppArgumentList &,CppVariant *)379 void EventSender::dumpFilenameBeingDragged(const CppArgumentList&, CppVariant*)
380 {
381 WebString filename;
382 WebVector<WebDragData::Item> items = currentDragData.items();
383 for (size_t i = 0; i < items.size(); ++i) {
384 if (items[i].storageType == WebDragData::Item::StorageTypeBinaryData) {
385 filename = items[i].title;
386 break;
387 }
388 }
389 m_delegate->printMessage(std::string("Filename being dragged: ") + filename.utf8().data() + "\n");
390 }
391
getButtonTypeFromButtonNumber(int buttonCode)392 WebMouseEvent::Button EventSender::getButtonTypeFromButtonNumber(int buttonCode)
393 {
394 if (!buttonCode)
395 return WebMouseEvent::ButtonLeft;
396 if (buttonCode == 2)
397 return WebMouseEvent::ButtonRight;
398 return WebMouseEvent::ButtonMiddle;
399 }
400
getButtonNumberFromSingleArg(const CppArgumentList & arguments)401 int EventSender::getButtonNumberFromSingleArg(const CppArgumentList& arguments)
402 {
403 int buttonCode = 0;
404 if (arguments.size() > 0 && arguments[0].isNumber())
405 buttonCode = arguments[0].toInt32();
406 return buttonCode;
407 }
408
updateClickCountForButton(WebMouseEvent::Button buttonType)409 void EventSender::updateClickCountForButton(WebMouseEvent::Button buttonType)
410 {
411 if ((getCurrentEventTimeSec(m_delegate) - lastClickTimeSec < multipleClickTimeSec)
412 && (!outsideMultiClickRadius(lastMousePos, lastClickPos))
413 && (buttonType == lastButtonType))
414 ++clickCount;
415 else {
416 clickCount = 1;
417 lastButtonType = buttonType;
418 }
419 }
420
421 //
422 // Implemented javascript methods.
423 //
424
mouseDown(const CppArgumentList & arguments,CppVariant * result)425 void EventSender::mouseDown(const CppArgumentList& arguments, CppVariant* result)
426 {
427 if (result) // Could be 0 if invoked asynchronously.
428 result->setNull();
429
430 if (shouldForceLayoutOnEvents())
431 webview()->layout();
432
433 int buttonNumber = getButtonNumberFromSingleArg(arguments);
434 BLINK_ASSERT(buttonNumber != -1);
435
436 WebMouseEvent::Button buttonType = getButtonTypeFromButtonNumber(buttonNumber);
437
438 updateClickCountForButton(buttonType);
439
440 WebMouseEvent event;
441 pressedButton = buttonType;
442 initMouseEvent(WebInputEvent::MouseDown, buttonType, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
443 if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString()))
444 applyKeyModifiers(&(arguments[1]), &event);
445 webview()->handleInputEvent(event);
446 }
447
mouseUp(const CppArgumentList & arguments,CppVariant * result)448 void EventSender::mouseUp(const CppArgumentList& arguments, CppVariant* result)
449 {
450 if (result) // Could be 0 if invoked asynchronously.
451 result->setNull();
452
453 if (shouldForceLayoutOnEvents())
454 webview()->layout();
455
456 int buttonNumber = getButtonNumberFromSingleArg(arguments);
457 BLINK_ASSERT(buttonNumber != -1);
458
459 WebMouseEvent::Button buttonType = getButtonTypeFromButtonNumber(buttonNumber);
460
461 if (isDragMode() && !replayingSavedEvents) {
462 SavedEvent savedEvent;
463 savedEvent.type = SavedEvent::MouseUp;
464 savedEvent.buttonType = buttonType;
465 mouseEventQueue.push_back(savedEvent);
466 replaySavedEvents();
467 } else {
468 WebMouseEvent event;
469 initMouseEvent(WebInputEvent::MouseUp, buttonType, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
470 if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString()))
471 applyKeyModifiers(&(arguments[1]), &event);
472 doMouseUp(event);
473 }
474 }
475
doMouseUp(const WebMouseEvent & e)476 void EventSender::doMouseUp(const WebMouseEvent& e)
477 {
478 webview()->handleInputEvent(e);
479
480 pressedButton = WebMouseEvent::ButtonNone;
481 lastClickTimeSec = e.timeStampSeconds;
482 lastClickPos = lastMousePos;
483
484 // If we're in a drag operation, complete it.
485 if (currentDragData.isNull())
486 return;
487
488 WebPoint clientPoint(e.x, e.y);
489 WebPoint screenPoint(e.globalX, e.globalY);
490 finishDragAndDrop(e, webview()->dragTargetDragOver(clientPoint, screenPoint, currentDragEffectsAllowed, 0));
491 }
492
finishDragAndDrop(const WebMouseEvent & e,blink::WebDragOperation dragEffect)493 void EventSender::finishDragAndDrop(const WebMouseEvent& e, blink::WebDragOperation dragEffect)
494 {
495 WebPoint clientPoint(e.x, e.y);
496 WebPoint screenPoint(e.globalX, e.globalY);
497 currentDragEffect = dragEffect;
498 if (currentDragEffect)
499 webview()->dragTargetDrop(clientPoint, screenPoint, 0);
500 else
501 webview()->dragTargetDragLeave();
502 webview()->dragSourceEndedAt(clientPoint, screenPoint, currentDragEffect);
503 webview()->dragSourceSystemDragEnded();
504
505 currentDragData.reset();
506 }
507
mouseMoveTo(const CppArgumentList & arguments,CppVariant * result)508 void EventSender::mouseMoveTo(const CppArgumentList& arguments, CppVariant* result)
509 {
510 result->setNull();
511
512 if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
513 return;
514 if (shouldForceLayoutOnEvents())
515 webview()->layout();
516
517 WebPoint mousePos(arguments[0].toInt32(), arguments[1].toInt32());
518
519 if (isDragMode() && pressedButton == WebMouseEvent::ButtonLeft && !replayingSavedEvents) {
520 SavedEvent savedEvent;
521 savedEvent.type = SavedEvent::MouseMove;
522 savedEvent.pos = mousePos;
523 mouseEventQueue.push_back(savedEvent);
524 } else {
525 WebMouseEvent event;
526 initMouseEvent(WebInputEvent::MouseMove, pressedButton, mousePos, &event, getCurrentEventTimeSec(m_delegate));
527 if (arguments.size() >= 3 && (arguments[2].isObject() || arguments[2].isString()))
528 applyKeyModifiers(&(arguments[2]), &event);
529 doMouseMove(event);
530 }
531 }
532
doMouseMove(const WebMouseEvent & e)533 void EventSender::doMouseMove(const WebMouseEvent& e)
534 {
535 lastMousePos = WebPoint(e.x, e.y);
536
537 webview()->handleInputEvent(e);
538
539 if (pressedButton == WebMouseEvent::ButtonNone || currentDragData.isNull())
540 return;
541 WebPoint clientPoint(e.x, e.y);
542 WebPoint screenPoint(e.globalX, e.globalY);
543 currentDragEffect = webview()->dragTargetDragOver(clientPoint, screenPoint, currentDragEffectsAllowed, 0);
544 }
545
keyDown(const CppArgumentList & arguments,CppVariant * result)546 void EventSender::keyDown(const CppArgumentList& arguments, CppVariant* result)
547 {
548 if (result)
549 result->setNull();
550 if (arguments.size() < 1 || !arguments[0].isString())
551 return;
552 bool generateChar = false;
553
554 // FIXME: I'm not exactly sure how we should convert the string to a key
555 // event. This seems to work in the cases I tested.
556 // FIXME: Should we also generate a KEY_UP?
557 string codeStr = arguments[0].toString();
558
559 // Convert \n -> VK_RETURN. Some layout tests use \n to mean "Enter", when
560 // Windows uses \r for "Enter".
561 int code = 0;
562 int text = 0;
563 bool needsShiftKeyModifier = false;
564 if ("\n" == codeStr) {
565 generateChar = true;
566 text = code = VKEY_RETURN;
567 } else if ("rightArrow" == codeStr)
568 code = VKEY_RIGHT;
569 else if ("downArrow" == codeStr)
570 code = VKEY_DOWN;
571 else if ("leftArrow" == codeStr)
572 code = VKEY_LEFT;
573 else if ("upArrow" == codeStr)
574 code = VKEY_UP;
575 else if ("insert" == codeStr)
576 code = VKEY_INSERT;
577 else if ("delete" == codeStr)
578 code = VKEY_DELETE;
579 else if ("pageUp" == codeStr)
580 code = VKEY_PRIOR;
581 else if ("pageDown" == codeStr)
582 code = VKEY_NEXT;
583 else if ("home" == codeStr)
584 code = VKEY_HOME;
585 else if ("end" == codeStr)
586 code = VKEY_END;
587 else if ("printScreen" == codeStr)
588 code = VKEY_SNAPSHOT;
589 else if ("menu" == codeStr)
590 code = VKEY_APPS;
591 else if ("leftControl" == codeStr)
592 code = VKEY_LCONTROL;
593 else if ("rightControl" == codeStr)
594 code = VKEY_RCONTROL;
595 else if ("leftShift" == codeStr)
596 code = VKEY_LSHIFT;
597 else if ("rightShift" == codeStr)
598 code = VKEY_RSHIFT;
599 else if ("leftAlt" == codeStr)
600 code = VKEY_LMENU;
601 else if ("rightAlt" == codeStr)
602 code = VKEY_RMENU;
603 else if ("numLock" == codeStr)
604 code = VKEY_NUMLOCK;
605 else {
606 // Compare the input string with the function-key names defined by the
607 // DOM spec (i.e. "F1",...,"F24"). If the input string is a function-key
608 // name, set its key code.
609 for (int i = 1; i <= 24; ++i) {
610 char functionChars[10];
611 snprintf(functionChars, 10, "F%d", i);
612 string functionKeyName(functionChars);
613 if (functionKeyName == codeStr) {
614 code = VKEY_F1 + (i - 1);
615 break;
616 }
617 }
618 if (!code) {
619 WebString webCodeStr = WebString::fromUTF8(codeStr.data(), codeStr.size());
620 BLINK_ASSERT(webCodeStr.length() == 1);
621 text = code = webCodeStr.at(0);
622 needsShiftKeyModifier = needsShiftModifier(code);
623 if ((code & 0xFF) >= 'a' && (code & 0xFF) <= 'z')
624 code -= 'a' - 'A';
625 generateChar = true;
626 }
627
628 if ("(" == codeStr) {
629 code = '9';
630 needsShiftKeyModifier = true;
631 }
632 }
633
634 // For one generated keyboard event, we need to generate a keyDown/keyUp
635 // pair; refer to EventSender.cpp in Tools/DumpRenderTree/win.
636 // On Windows, we might also need to generate a char event to mimic the
637 // Windows event flow; on other platforms we create a merged event and test
638 // the event flow that that platform provides.
639 WebKeyboardEvent eventDown, eventChar, eventUp;
640 eventDown.type = WebInputEvent::RawKeyDown;
641 eventDown.modifiers = 0;
642 eventDown.windowsKeyCode = code;
643 #if defined(__linux__) && defined(TOOLKIT_GTK)
644 eventDown.nativeKeyCode = NativeKeyCodeForWindowsKeyCode(code);
645 #endif
646
647 if (generateChar) {
648 eventDown.text[0] = text;
649 eventDown.unmodifiedText[0] = text;
650 }
651 eventDown.setKeyIdentifierFromWindowsKeyCode();
652
653 if (arguments.size() >= 2 && (arguments[1].isObject() || arguments[1].isString())) {
654 applyKeyModifiers(&(arguments[1]), &eventDown);
655 #if WIN32 || __APPLE__ || defined(ANDROID) || defined(TOOLKIT_GTK)
656 eventDown.isSystemKey = WebInputEventFactory::isSystemKeyEvent(eventDown);
657 #endif
658 }
659
660 if (needsShiftKeyModifier)
661 eventDown.modifiers |= WebInputEvent::ShiftKey;
662
663 // See if KeyLocation argument is given.
664 if (arguments.size() >= 3 && arguments[2].isNumber()) {
665 int location = arguments[2].toInt32();
666 if (location == DOMKeyLocationNumpad)
667 eventDown.modifiers |= WebInputEvent::IsKeyPad;
668 }
669
670 eventChar = eventUp = eventDown;
671 eventUp.type = WebInputEvent::KeyUp;
672 // EventSender.m forces a layout here, with at least one
673 // test (fast/forms/focus-control-to-page.html) relying on this.
674 if (shouldForceLayoutOnEvents())
675 webview()->layout();
676
677 // In the browser, if a keyboard event corresponds to an editor command,
678 // the command will be dispatched to the renderer just before dispatching
679 // the keyboard event, and then it will be executed in the
680 // RenderView::handleCurrentKeyboardEvent() method, which is called from
681 // third_party/WebKit/Source/WebKit/chromium/src/EditorClientImpl.cpp.
682 // We just simulate the same behavior here.
683 string editCommand;
684 if (getEditCommand(eventDown, &editCommand))
685 m_delegate->setEditCommand(editCommand, "");
686
687 webview()->handleInputEvent(eventDown);
688
689 if (code == VKEY_ESCAPE && !currentDragData.isNull()) {
690 WebMouseEvent event;
691 initMouseEvent(WebInputEvent::MouseDown, pressedButton, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
692 finishDragAndDrop(event, blink::WebDragOperationNone);
693 }
694
695 m_delegate->clearEditCommand();
696
697 if (generateChar) {
698 eventChar.type = WebInputEvent::Char;
699 eventChar.keyIdentifier[0] = '\0';
700 webview()->handleInputEvent(eventChar);
701 }
702
703 webview()->handleInputEvent(eventUp);
704 }
705
dispatchMessage(const CppArgumentList & arguments,CppVariant * result)706 void EventSender::dispatchMessage(const CppArgumentList& arguments, CppVariant* result)
707 {
708 result->setNull();
709
710 #ifdef WIN32
711 if (arguments.size() == 3) {
712 // Grab the message id to see if we need to dispatch it.
713 int msg = arguments[0].toInt32();
714
715 // WebKit's version of this function stuffs a MSG struct and uses
716 // TranslateMessage and DispatchMessage. We use a WebKeyboardEvent, which
717 // doesn't need to receive the DeadChar and SysDeadChar messages.
718 if (msg == WM_DEADCHAR || msg == WM_SYSDEADCHAR)
719 return;
720
721 if (shouldForceLayoutOnEvents())
722 webview()->layout();
723
724 unsigned long lparam = static_cast<unsigned long>(arguments[2].toDouble());
725 webview()->handleInputEvent(WebInputEventFactory::keyboardEvent(0, msg, arguments[1].toInt32(), lparam));
726 } else
727 BLINK_ASSERT_NOT_REACHED();
728 #endif
729 }
730
needsShiftModifier(int keyCode)731 bool EventSender::needsShiftModifier(int keyCode)
732 {
733 // If code is an uppercase letter, assign a SHIFT key to
734 // eventDown.modifier, this logic comes from
735 // Tools/DumpRenderTree/win/EventSender.cpp
736 return (keyCode & 0xFF) >= 'A' && (keyCode & 0xFF) <= 'Z';
737 }
738
leapForward(const CppArgumentList & arguments,CppVariant * result)739 void EventSender::leapForward(const CppArgumentList& arguments, CppVariant* result)
740 {
741 result->setNull();
742
743 if (arguments.size() < 1 || !arguments[0].isNumber())
744 return;
745
746 int milliseconds = arguments[0].toInt32();
747 if (isDragMode() && pressedButton == WebMouseEvent::ButtonLeft && !replayingSavedEvents) {
748 SavedEvent savedEvent;
749 savedEvent.type = SavedEvent::LeapForward;
750 savedEvent.milliseconds = milliseconds;
751 mouseEventQueue.push_back(savedEvent);
752 } else
753 doLeapForward(milliseconds);
754 }
755
doLeapForward(int milliseconds)756 void EventSender::doLeapForward(int milliseconds)
757 {
758 advanceEventTime(milliseconds);
759 }
760
761 // Apple's port of WebKit zooms by a factor of 1.2 (see
762 // WebKit/WebView/WebView.mm)
textZoomIn(const CppArgumentList &,CppVariant * result)763 void EventSender::textZoomIn(const CppArgumentList&, CppVariant* result)
764 {
765 webview()->setTextZoomFactor(webview()->textZoomFactor() * 1.2f);
766 result->setNull();
767 }
768
textZoomOut(const CppArgumentList &,CppVariant * result)769 void EventSender::textZoomOut(const CppArgumentList&, CppVariant* result)
770 {
771 webview()->setTextZoomFactor(webview()->textZoomFactor() / 1.2f);
772 result->setNull();
773 }
774
zoomPageIn(const CppArgumentList &,CppVariant * result)775 void EventSender::zoomPageIn(const CppArgumentList&, CppVariant* result)
776 {
777 const vector<WebTestProxyBase*>& windowList = m_testInterfaces->windowList();
778
779 for (size_t i = 0; i < windowList.size(); ++i)
780 windowList.at(i)->webView()->setZoomLevel(windowList.at(i)->webView()->zoomLevel() + 1);
781 result->setNull();
782 }
783
zoomPageOut(const CppArgumentList &,CppVariant * result)784 void EventSender::zoomPageOut(const CppArgumentList&, CppVariant* result)
785 {
786 const vector<WebTestProxyBase*>& windowList = m_testInterfaces->windowList();
787
788 for (size_t i = 0; i < windowList.size(); ++i)
789 windowList.at(i)->webView()->setZoomLevel(windowList.at(i)->webView()->zoomLevel() - 1);
790 result->setNull();
791 }
792
setPageScaleFactor(const CppArgumentList & arguments,CppVariant * result)793 void EventSender::setPageScaleFactor(const CppArgumentList& arguments, CppVariant* result)
794 {
795 if (arguments.size() < 3 || !arguments[0].isNumber() || !arguments[1].isNumber() || !arguments[2].isNumber())
796 return;
797
798 float scaleFactor = static_cast<float>(arguments[0].toDouble());
799 int x = arguments[1].toInt32();
800 int y = arguments[2].toInt32();
801 webview()->setPageScaleFactorLimits(scaleFactor, scaleFactor);
802 webview()->setPageScaleFactor(scaleFactor, WebPoint(x, y));
803 result->setNull();
804 }
805
mouseScrollBy(const CppArgumentList & arguments,CppVariant * result)806 void EventSender::mouseScrollBy(const CppArgumentList& arguments, CppVariant* result)
807 {
808 WebMouseWheelEvent event;
809 initMouseWheelEvent(arguments, result, false, &event);
810 webview()->handleInputEvent(event);
811 }
812
continuousMouseScrollBy(const CppArgumentList & arguments,CppVariant * result)813 void EventSender::continuousMouseScrollBy(const CppArgumentList& arguments, CppVariant* result)
814 {
815 WebMouseWheelEvent event;
816 initMouseWheelEvent(arguments, result, true, &event);
817 webview()->handleInputEvent(event);
818 }
819
replaySavedEvents()820 void EventSender::replaySavedEvents()
821 {
822 replayingSavedEvents = true;
823 while (!mouseEventQueue.empty()) {
824 SavedEvent e = mouseEventQueue.front();
825 mouseEventQueue.pop_front();
826
827 switch (e.type) {
828 case SavedEvent::MouseMove: {
829 WebMouseEvent event;
830 initMouseEvent(WebInputEvent::MouseMove, pressedButton, e.pos, &event, getCurrentEventTimeSec(m_delegate));
831 doMouseMove(event);
832 break;
833 }
834 case SavedEvent::LeapForward:
835 doLeapForward(e.milliseconds);
836 break;
837 case SavedEvent::MouseUp: {
838 WebMouseEvent event;
839 initMouseEvent(WebInputEvent::MouseUp, e.buttonType, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
840 doMouseUp(event);
841 break;
842 }
843 default:
844 BLINK_ASSERT_NOT_REACHED();
845 }
846 }
847
848 replayingSavedEvents = false;
849 }
850
851 // Because actual context menu is implemented by the browser side,
852 // this function does only what LayoutTests are expecting:
853 // - Many test checks the count of items. So returning non-zero value makes sense.
854 // - Some test compares the count before and after some action. So changing the count based on flags
855 // also makes sense. This function is doing such for some flags.
856 // - Some test even checks actual string content. So providing it would be also helpful.
857 //
makeMenuItemStringsFor(WebContextMenuData * contextMenu,WebTestDelegate * delegate)858 static vector<WebString> makeMenuItemStringsFor(WebContextMenuData* contextMenu, WebTestDelegate* delegate)
859 {
860 // These constants are based on Safari's context menu because tests are made for it.
861 static const char* nonEditableMenuStrings[] = { "Back", "Reload Page", "Open in Dashbaord", "<separator>", "View Source", "Save Page As", "Print Page", "Inspect Element", 0 };
862 static const char* editableMenuStrings[] = { "Cut", "Copy", "<separator>", "Paste", "Spelling and Grammar", "Substitutions, Transformations", "Font", "Speech", "Paragraph Direction", "<separator>", 0 };
863
864 // This is possible because mouse events are cancelleable.
865 if (!contextMenu)
866 return vector<WebString>();
867
868 vector<WebString> strings;
869
870 if (contextMenu->isEditable) {
871 for (const char** item = editableMenuStrings; *item; ++item)
872 strings.push_back(WebString::fromUTF8(*item));
873 WebVector<WebString> suggestions;
874 MockSpellCheck::fillSuggestionList(contextMenu->misspelledWord, &suggestions);
875 for (size_t i = 0; i < suggestions.size(); ++i)
876 strings.push_back(suggestions[i]);
877 } else {
878 for (const char** item = nonEditableMenuStrings; *item; ++item)
879 strings.push_back(WebString::fromUTF8(*item));
880 }
881
882 return strings;
883 }
884
contextClick(const CppArgumentList & arguments,CppVariant * result)885 void EventSender::contextClick(const CppArgumentList& arguments, CppVariant* result)
886 {
887 if (shouldForceLayoutOnEvents())
888 webview()->layout();
889
890 updateClickCountForButton(WebMouseEvent::ButtonRight);
891
892 // Clears last context menu data because we need to know if the context menu be requested
893 // after following mouse events.
894 m_lastContextMenuData.reset();
895
896 // Generate right mouse down and up.
897 WebMouseEvent event;
898 // This is a hack to work around only allowing a single pressed button since we want to
899 // test the case where both the left and right mouse buttons are pressed.
900 if (pressedButton == WebMouseEvent::ButtonNone)
901 pressedButton = WebMouseEvent::ButtonRight;
902 initMouseEvent(WebInputEvent::MouseDown, WebMouseEvent::ButtonRight, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
903 webview()->handleInputEvent(event);
904
905 #ifdef WIN32
906 initMouseEvent(WebInputEvent::MouseUp, WebMouseEvent::ButtonRight, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
907 webview()->handleInputEvent(event);
908
909 pressedButton = WebMouseEvent::ButtonNone;
910 #endif
911
912 NPObject* resultArray = WebBindings::makeStringArray(makeMenuItemStringsFor(m_lastContextMenuData.get(), m_delegate));
913 result->set(resultArray);
914 WebBindings::releaseObject(resultArray);
915
916 m_lastContextMenuData.reset();
917 }
918
919 class MouseDownTask: public WebMethodTask<EventSender> {
920 public:
MouseDownTask(EventSender * obj,const CppArgumentList & arg)921 MouseDownTask(EventSender* obj, const CppArgumentList& arg)
922 : WebMethodTask<EventSender>(obj), m_arguments(arg) { }
runIfValid()923 virtual void runIfValid() { m_object->mouseDown(m_arguments, 0); }
924
925 private:
926 CppArgumentList m_arguments;
927 };
928
929 class MouseUpTask: public WebMethodTask<EventSender> {
930 public:
MouseUpTask(EventSender * obj,const CppArgumentList & arg)931 MouseUpTask(EventSender* obj, const CppArgumentList& arg)
932 : WebMethodTask<EventSender>(obj), m_arguments(arg) { }
runIfValid()933 virtual void runIfValid() { m_object->mouseUp(m_arguments, 0); }
934
935 private:
936 CppArgumentList m_arguments;
937 };
938
scheduleAsynchronousClick(const CppArgumentList & arguments,CppVariant * result)939 void EventSender::scheduleAsynchronousClick(const CppArgumentList& arguments, CppVariant* result)
940 {
941 result->setNull();
942 m_delegate->postTask(new MouseDownTask(this, arguments));
943 m_delegate->postTask(new MouseUpTask(this, arguments));
944 }
945
946 class KeyDownTask : public WebMethodTask<EventSender> {
947 public:
KeyDownTask(EventSender * obj,const CppArgumentList & arg)948 KeyDownTask(EventSender* obj, const CppArgumentList& arg)
949 : WebMethodTask<EventSender>(obj), m_arguments(arg) { }
runIfValid()950 virtual void runIfValid() { m_object->keyDown(m_arguments, 0); }
951
952 private:
953 CppArgumentList m_arguments;
954 };
955
scheduleAsynchronousKeyDown(const CppArgumentList & arguments,CppVariant * result)956 void EventSender::scheduleAsynchronousKeyDown(const CppArgumentList& arguments, CppVariant* result)
957 {
958 result->setNull();
959 m_delegate->postTask(new KeyDownTask(this, arguments));
960 }
961
beginDragWithFiles(const CppArgumentList & arguments,CppVariant * result)962 void EventSender::beginDragWithFiles(const CppArgumentList& arguments, CppVariant* result)
963 {
964 currentDragData.initialize();
965 vector<string> files = arguments[0].toStringVector();
966 WebVector<WebString> absoluteFilenames(files.size());
967 for (size_t i = 0; i < files.size(); ++i) {
968 WebDragData::Item item;
969 item.storageType = WebDragData::Item::StorageTypeFilename;
970 item.filenameData = m_delegate->getAbsoluteWebStringFromUTF8Path(files[i]);
971 currentDragData.addItem(item);
972 absoluteFilenames[i] = item.filenameData;
973 }
974 currentDragData.setFilesystemId(m_delegate->registerIsolatedFileSystem(absoluteFilenames));
975 currentDragEffectsAllowed = blink::WebDragOperationCopy;
976
977 // Provide a drag source.
978 webview()->dragTargetDragEnter(currentDragData, lastMousePos, lastMousePos, currentDragEffectsAllowed, 0);
979
980 // dragMode saves events and then replays them later. We don't need/want that.
981 dragMode.set(false);
982
983 // Make the rest of eventSender think a drag is in progress.
984 pressedButton = WebMouseEvent::ButtonLeft;
985
986 result->setNull();
987 }
988
addTouchPoint(const CppArgumentList & arguments,CppVariant * result)989 void EventSender::addTouchPoint(const CppArgumentList& arguments, CppVariant* result)
990 {
991 result->setNull();
992
993 WebTouchPoint touchPoint;
994 touchPoint.state = WebTouchPoint::StatePressed;
995 touchPoint.position = WebPoint(arguments[0].toInt32(), arguments[1].toInt32());
996 touchPoint.screenPosition = touchPoint.position;
997
998 if (arguments.size() > 2) {
999 int radiusX = arguments[2].toInt32();
1000 int radiusY = radiusX;
1001 if (arguments.size() > 3)
1002 radiusY = arguments[3].toInt32();
1003
1004 touchPoint.radiusX = radiusX;
1005 touchPoint.radiusY = radiusY;
1006 }
1007
1008 int lowestId = 0;
1009 for (size_t i = 0; i < touchPoints.size(); i++) {
1010 if (touchPoints[i].id == lowestId)
1011 lowestId++;
1012 }
1013 touchPoint.id = lowestId;
1014 touchPoints.push_back(touchPoint);
1015 }
1016
clearTouchPoints(const CppArgumentList &,CppVariant * result)1017 void EventSender::clearTouchPoints(const CppArgumentList&, CppVariant* result)
1018 {
1019 result->setNull();
1020 touchPoints.clear();
1021 }
1022
releaseTouchPoint(const CppArgumentList & arguments,CppVariant * result)1023 void EventSender::releaseTouchPoint(const CppArgumentList& arguments, CppVariant* result)
1024 {
1025 result->setNull();
1026
1027 const unsigned index = arguments[0].toInt32();
1028 BLINK_ASSERT(index < touchPoints.size());
1029
1030 WebTouchPoint* touchPoint = &touchPoints[index];
1031 touchPoint->state = WebTouchPoint::StateReleased;
1032 }
1033
setTouchModifier(const CppArgumentList & arguments,CppVariant * result)1034 void EventSender::setTouchModifier(const CppArgumentList& arguments, CppVariant* result)
1035 {
1036 result->setNull();
1037
1038 int mask = 0;
1039 const string keyName = arguments[0].toString();
1040 if (keyName == "shift")
1041 mask = WebInputEvent::ShiftKey;
1042 else if (keyName == "alt")
1043 mask = WebInputEvent::AltKey;
1044 else if (keyName == "ctrl")
1045 mask = WebInputEvent::ControlKey;
1046 else if (keyName == "meta")
1047 mask = WebInputEvent::MetaKey;
1048
1049 if (arguments[1].toBoolean())
1050 touchModifiers |= mask;
1051 else
1052 touchModifiers &= ~mask;
1053 }
1054
updateTouchPoint(const CppArgumentList & arguments,CppVariant * result)1055 void EventSender::updateTouchPoint(const CppArgumentList& arguments, CppVariant* result)
1056 {
1057 result->setNull();
1058
1059 const unsigned index = arguments[0].toInt32();
1060 BLINK_ASSERT(index < touchPoints.size());
1061
1062 WebPoint position(arguments[1].toInt32(), arguments[2].toInt32());
1063 WebTouchPoint* touchPoint = &touchPoints[index];
1064 touchPoint->state = WebTouchPoint::StateMoved;
1065 touchPoint->position = position;
1066 touchPoint->screenPosition = position;
1067 }
1068
cancelTouchPoint(const CppArgumentList & arguments,CppVariant * result)1069 void EventSender::cancelTouchPoint(const CppArgumentList& arguments, CppVariant* result)
1070 {
1071 result->setNull();
1072
1073 const unsigned index = arguments[0].toInt32();
1074 BLINK_ASSERT(index < touchPoints.size());
1075
1076 WebTouchPoint* touchPoint = &touchPoints[index];
1077 touchPoint->state = WebTouchPoint::StateCancelled;
1078 }
1079
sendCurrentTouchEvent(const WebInputEvent::Type type)1080 void EventSender::sendCurrentTouchEvent(const WebInputEvent::Type type)
1081 {
1082 BLINK_ASSERT(static_cast<unsigned>(WebTouchEvent::touchesLengthCap) > touchPoints.size());
1083 if (shouldForceLayoutOnEvents())
1084 webview()->layout();
1085
1086 WebTouchEvent touchEvent;
1087 touchEvent.type = type;
1088 touchEvent.modifiers = touchModifiers;
1089 touchEvent.timeStampSeconds = getCurrentEventTimeSec(m_delegate);
1090 touchEvent.touchesLength = touchPoints.size();
1091 for (unsigned i = 0; i < touchPoints.size(); ++i)
1092 touchEvent.touches[i] = touchPoints[i];
1093 webview()->handleInputEvent(touchEvent);
1094
1095 for (unsigned i = 0; i < touchPoints.size(); ++i) {
1096 WebTouchPoint* touchPoint = &touchPoints[i];
1097 if (touchPoint->state == WebTouchPoint::StateReleased) {
1098 touchPoints.erase(touchPoints.begin() + i);
1099 --i;
1100 } else
1101 touchPoint->state = WebTouchPoint::StateStationary;
1102 }
1103 }
1104
mouseDragBegin(const CppArgumentList & arguments,CppVariant * result)1105 void EventSender::mouseDragBegin(const CppArgumentList& arguments, CppVariant* result)
1106 {
1107 WebMouseWheelEvent event;
1108 initMouseEvent(WebInputEvent::MouseWheel, WebMouseEvent::ButtonNone, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
1109 event.phase = WebMouseWheelEvent::PhaseBegan;
1110 event.hasPreciseScrollingDeltas = true;
1111 webview()->handleInputEvent(event);
1112 }
1113
mouseDragEnd(const CppArgumentList & arguments,CppVariant * result)1114 void EventSender::mouseDragEnd(const CppArgumentList& arguments, CppVariant* result)
1115 {
1116 WebMouseWheelEvent event;
1117 initMouseEvent(WebInputEvent::MouseWheel, WebMouseEvent::ButtonNone, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
1118 event.phase = WebMouseWheelEvent::PhaseEnded;
1119 event.hasPreciseScrollingDeltas = true;
1120 webview()->handleInputEvent(event);
1121 }
1122
mouseMomentumBegin(const CppArgumentList & arguments,CppVariant * result)1123 void EventSender::mouseMomentumBegin(const CppArgumentList& arguments, CppVariant* result)
1124 {
1125 WebMouseWheelEvent event;
1126 initMouseEvent(WebInputEvent::MouseWheel, WebMouseEvent::ButtonNone, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
1127 event.momentumPhase = WebMouseWheelEvent::PhaseBegan;
1128 event.hasPreciseScrollingDeltas = true;
1129 webview()->handleInputEvent(event);
1130 }
1131
mouseMomentumScrollBy(const CppArgumentList & arguments,CppVariant * result)1132 void EventSender::mouseMomentumScrollBy(const CppArgumentList& arguments, CppVariant* result)
1133 {
1134 WebMouseWheelEvent event;
1135 initMouseWheelEvent(arguments, result, true, &event);
1136 event.momentumPhase = WebMouseWheelEvent::PhaseChanged;
1137 event.hasPreciseScrollingDeltas = true;
1138 webview()->handleInputEvent(event);
1139 }
1140
mouseMomentumEnd(const CppArgumentList & arguments,CppVariant * result)1141 void EventSender::mouseMomentumEnd(const CppArgumentList& arguments, CppVariant* result)
1142 {
1143 WebMouseWheelEvent event;
1144 initMouseEvent(WebInputEvent::MouseWheel, WebMouseEvent::ButtonNone, lastMousePos, &event, getCurrentEventTimeSec(m_delegate));
1145 event.momentumPhase = WebMouseWheelEvent::PhaseEnded;
1146 event.hasPreciseScrollingDeltas = true;
1147 webview()->handleInputEvent(event);
1148 }
1149
initMouseWheelEvent(const CppArgumentList & arguments,CppVariant * result,bool continuous,WebMouseWheelEvent * event)1150 void EventSender::initMouseWheelEvent(const CppArgumentList& arguments, CppVariant* result, bool continuous, WebMouseWheelEvent* event)
1151 {
1152 result->setNull();
1153
1154 if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
1155 return;
1156
1157 // Force a layout here just to make sure every position has been
1158 // determined before we send events (as well as all the other methods
1159 // that send an event do).
1160 if (shouldForceLayoutOnEvents())
1161 webview()->layout();
1162
1163 int horizontal = arguments[0].toInt32();
1164 int vertical = arguments[1].toInt32();
1165 int paged = false;
1166 int hasPreciseScrollingDeltas = false;
1167
1168 if (arguments.size() > 2 && arguments[2].isBool())
1169 paged = arguments[2].toBoolean();
1170
1171 if (arguments.size() > 3 && arguments[3].isBool())
1172 hasPreciseScrollingDeltas = arguments[3].toBoolean();
1173
1174 initMouseEvent(WebInputEvent::MouseWheel, pressedButton, lastMousePos, event, getCurrentEventTimeSec(m_delegate));
1175 event->wheelTicksX = static_cast<float>(horizontal);
1176 event->wheelTicksY = static_cast<float>(vertical);
1177 event->deltaX = event->wheelTicksX;
1178 event->deltaY = event->wheelTicksY;
1179 event->scrollByPage = paged;
1180 event->hasPreciseScrollingDeltas = hasPreciseScrollingDeltas;
1181
1182 if (continuous) {
1183 event->wheelTicksX /= scrollbarPixelsPerTick;
1184 event->wheelTicksY /= scrollbarPixelsPerTick;
1185 } else {
1186 event->deltaX *= scrollbarPixelsPerTick;
1187 event->deltaY *= scrollbarPixelsPerTick;
1188 }
1189 }
1190
touchEnd(const CppArgumentList &,CppVariant * result)1191 void EventSender::touchEnd(const CppArgumentList&, CppVariant* result)
1192 {
1193 result->setNull();
1194 sendCurrentTouchEvent(WebInputEvent::TouchEnd);
1195 }
1196
touchMove(const CppArgumentList &,CppVariant * result)1197 void EventSender::touchMove(const CppArgumentList&, CppVariant* result)
1198 {
1199 result->setNull();
1200 sendCurrentTouchEvent(WebInputEvent::TouchMove);
1201 }
1202
touchStart(const CppArgumentList &,CppVariant * result)1203 void EventSender::touchStart(const CppArgumentList&, CppVariant* result)
1204 {
1205 result->setNull();
1206 sendCurrentTouchEvent(WebInputEvent::TouchStart);
1207 }
1208
touchCancel(const CppArgumentList &,CppVariant * result)1209 void EventSender::touchCancel(const CppArgumentList&, CppVariant* result)
1210 {
1211 result->setNull();
1212 sendCurrentTouchEvent(WebInputEvent::TouchCancel);
1213 }
1214
gestureScrollBegin(const CppArgumentList & arguments,CppVariant * result)1215 void EventSender::gestureScrollBegin(const CppArgumentList& arguments, CppVariant* result)
1216 {
1217 result->setNull();
1218 gestureEvent(WebInputEvent::GestureScrollBegin, arguments);
1219 }
1220
gestureScrollEnd(const CppArgumentList & arguments,CppVariant * result)1221 void EventSender::gestureScrollEnd(const CppArgumentList& arguments, CppVariant* result)
1222 {
1223 result->setNull();
1224 gestureEvent(WebInputEvent::GestureScrollEnd, arguments);
1225 }
1226
gestureScrollUpdate(const CppArgumentList & arguments,CppVariant * result)1227 void EventSender::gestureScrollUpdate(const CppArgumentList& arguments, CppVariant* result)
1228 {
1229 result->setNull();
1230 gestureEvent(WebInputEvent::GestureScrollUpdate, arguments);
1231 }
1232
gestureScrollUpdateWithoutPropagation(const CppArgumentList & arguments,CppVariant * result)1233 void EventSender::gestureScrollUpdateWithoutPropagation(const CppArgumentList& arguments, CppVariant* result)
1234 {
1235 result->setNull();
1236 gestureEvent(WebInputEvent::GestureScrollUpdateWithoutPropagation, arguments);
1237 }
1238
gestureTap(const CppArgumentList & arguments,CppVariant * result)1239 void EventSender::gestureTap(const CppArgumentList& arguments, CppVariant* result)
1240 {
1241 result->setNull();
1242 gestureEvent(WebInputEvent::GestureTap, arguments);
1243 }
1244
gestureTapDown(const CppArgumentList & arguments,CppVariant * result)1245 void EventSender::gestureTapDown(const CppArgumentList& arguments, CppVariant* result)
1246 {
1247 result->setNull();
1248 gestureEvent(WebInputEvent::GestureTapDown, arguments);
1249 }
1250
gestureShowPress(const CppArgumentList & arguments,CppVariant * result)1251 void EventSender::gestureShowPress(const CppArgumentList& arguments, CppVariant* result)
1252 {
1253 result->setNull();
1254 gestureEvent(WebInputEvent::GestureShowPress, arguments);
1255 }
1256
gestureTapCancel(const CppArgumentList & arguments,CppVariant * result)1257 void EventSender::gestureTapCancel(const CppArgumentList& arguments, CppVariant* result)
1258 {
1259 result->setNull();
1260 gestureEvent(WebInputEvent::GestureTapCancel, arguments);
1261 }
1262
gestureLongPress(const CppArgumentList & arguments,CppVariant * result)1263 void EventSender::gestureLongPress(const CppArgumentList& arguments, CppVariant* result)
1264 {
1265 result->setNull();
1266 gestureEvent(WebInputEvent::GestureLongPress, arguments);
1267 }
1268
gestureLongTap(const CppArgumentList & arguments,CppVariant * result)1269 void EventSender::gestureLongTap(const CppArgumentList& arguments, CppVariant* result)
1270 {
1271 result->setNull();
1272 gestureEvent(WebInputEvent::GestureLongTap, arguments);
1273 }
1274
gestureTwoFingerTap(const CppArgumentList & arguments,CppVariant * result)1275 void EventSender::gestureTwoFingerTap(const CppArgumentList& arguments, CppVariant* result)
1276 {
1277 result->setNull();
1278 gestureEvent(WebInputEvent::GestureTwoFingerTap, arguments);
1279 }
1280
gestureScrollFirstPoint(const CppArgumentList & arguments,CppVariant * result)1281 void EventSender::gestureScrollFirstPoint(const CppArgumentList& arguments, CppVariant* result)
1282 {
1283 result->setNull();
1284 if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
1285 return;
1286
1287 WebPoint point(arguments[0].toInt32(), arguments[1].toInt32());
1288 m_currentGestureLocation = point;
1289 }
1290
gestureEvent(WebInputEvent::Type type,const CppArgumentList & arguments)1291 void EventSender::gestureEvent(WebInputEvent::Type type, const CppArgumentList& arguments)
1292 {
1293 if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
1294 return;
1295
1296 WebPoint point(arguments[0].toInt32(), arguments[1].toInt32());
1297
1298 WebGestureEvent event;
1299 event.type = type;
1300
1301 switch (type) {
1302 case WebInputEvent::GestureScrollUpdate:
1303 case WebInputEvent::GestureScrollUpdateWithoutPropagation:
1304 event.data.scrollUpdate.deltaX = static_cast<float>(arguments[0].toDouble());
1305 event.data.scrollUpdate.deltaY = static_cast<float>(arguments[1].toDouble());
1306 event.x = m_currentGestureLocation.x;
1307 event.y = m_currentGestureLocation.y;
1308 m_currentGestureLocation.x = m_currentGestureLocation.x + event.data.scrollUpdate.deltaX;
1309 m_currentGestureLocation.y = m_currentGestureLocation.y + event.data.scrollUpdate.deltaY;
1310 break;
1311
1312 case WebInputEvent::GestureScrollBegin:
1313 m_currentGestureLocation = WebPoint(point.x, point.y);
1314 event.x = m_currentGestureLocation.x;
1315 event.y = m_currentGestureLocation.y;
1316 break;
1317 case WebInputEvent::GestureScrollEnd:
1318 case WebInputEvent::GestureFlingStart:
1319 event.x = m_currentGestureLocation.x;
1320 event.y = m_currentGestureLocation.y;
1321 break;
1322 case WebInputEvent::GestureTap:
1323 if (arguments.size() >= 3)
1324 event.data.tap.tapCount = static_cast<float>(arguments[2].toDouble());
1325 else
1326 event.data.tap.tapCount = 1;
1327 event.x = point.x;
1328 event.y = point.y;
1329 break;
1330 case WebInputEvent::GestureTapUnconfirmed:
1331 if (arguments.size() >= 3)
1332 event.data.tap.tapCount = static_cast<float>(arguments[2].toDouble());
1333 else
1334 event.data.tap.tapCount = 1;
1335 event.x = point.x;
1336 event.y = point.y;
1337 break;
1338 case WebInputEvent::GestureTapDown:
1339 event.x = point.x;
1340 event.y = point.y;
1341 if (arguments.size() >= 4) {
1342 event.data.tapDown.width = static_cast<float>(arguments[2].toDouble());
1343 event.data.tapDown.height = static_cast<float>(arguments[3].toDouble());
1344 }
1345 break;
1346 case WebInputEvent::GestureShowPress:
1347 event.x = point.x;
1348 event.y = point.y;
1349 if (arguments.size() >= 4) {
1350 event.data.showPress.width = static_cast<float>(arguments[2].toDouble());
1351 event.data.showPress.height = static_cast<float>(arguments[3].toDouble());
1352 }
1353 break;
1354 case WebInputEvent::GestureTapCancel:
1355 event.x = point.x;
1356 event.y = point.y;
1357 break;
1358 case WebInputEvent::GestureLongPress:
1359 event.x = point.x;
1360 event.y = point.y;
1361 if (arguments.size() >= 4) {
1362 event.data.longPress.width = static_cast<float>(arguments[2].toDouble());
1363 event.data.longPress.height = static_cast<float>(arguments[3].toDouble());
1364 }
1365 break;
1366 case WebInputEvent::GestureLongTap:
1367 event.x = point.x;
1368 event.y = point.y;
1369 if (arguments.size() >= 4) {
1370 event.data.longPress.width = static_cast<float>(arguments[2].toDouble());
1371 event.data.longPress.height = static_cast<float>(arguments[3].toDouble());
1372 }
1373 break;
1374 case WebInputEvent::GestureTwoFingerTap:
1375 event.x = point.x;
1376 event.y = point.y;
1377 if (arguments.size() >= 4) {
1378 event.data.twoFingerTap.firstFingerWidth = static_cast<float>(arguments[2].toDouble());
1379 event.data.twoFingerTap.firstFingerHeight = static_cast<float>(arguments[3].toDouble());
1380 }
1381 break;
1382 default:
1383 BLINK_ASSERT_NOT_REACHED();
1384 }
1385
1386 event.globalX = event.x;
1387 event.globalY = event.y;
1388 event.timeStampSeconds = getCurrentEventTimeSec(m_delegate);
1389
1390 if (shouldForceLayoutOnEvents())
1391 webview()->layout();
1392
1393 webview()->handleInputEvent(event);
1394
1395 // Long press might start a drag drop session. Complete it if so.
1396 if (type == WebInputEvent::GestureLongPress && !currentDragData.isNull()) {
1397 WebMouseEvent mouseEvent;
1398 initMouseEvent(WebInputEvent::MouseDown, pressedButton, point, &mouseEvent, getCurrentEventTimeSec(m_delegate));
1399 finishDragAndDrop(mouseEvent, blink::WebDragOperationNone);
1400 }
1401 }
1402
gestureFlingCancel(const CppArgumentList &,CppVariant * result)1403 void EventSender::gestureFlingCancel(const CppArgumentList&, CppVariant* result)
1404 {
1405 result->setNull();
1406
1407 WebGestureEvent event;
1408 event.type = WebInputEvent::GestureFlingCancel;
1409 event.timeStampSeconds = getCurrentEventTimeSec(m_delegate);
1410
1411 if (shouldForceLayoutOnEvents())
1412 webview()->layout();
1413
1414 webview()->handleInputEvent(event);
1415 }
1416
gestureFlingStart(const CppArgumentList & arguments,CppVariant * result)1417 void EventSender::gestureFlingStart(const CppArgumentList& arguments, CppVariant* result)
1418 {
1419 result->setNull();
1420 if (arguments.size() < 4)
1421 return;
1422
1423 for (int i = 0; i < 4; i++)
1424 if (!arguments[i].isNumber())
1425 return;
1426
1427 WebGestureEvent event;
1428 event.type = WebInputEvent::GestureFlingStart;
1429
1430 event.x = static_cast<float>(arguments[0].toDouble());
1431 event.y = static_cast<float>(arguments[1].toDouble());
1432 event.globalX = event.x;
1433 event.globalY = event.y;
1434
1435 event.data.flingStart.velocityX = static_cast<float>(arguments[2].toDouble());
1436 event.data.flingStart.velocityY = static_cast<float>(arguments[3].toDouble());
1437 event.timeStampSeconds = getCurrentEventTimeSec(m_delegate);
1438
1439 if (shouldForceLayoutOnEvents())
1440 webview()->layout();
1441
1442 webview()->handleInputEvent(event);
1443 }
1444
1445 //
1446 // Unimplemented stubs
1447 //
1448
enableDOMUIEventLogging(const CppArgumentList &,CppVariant * result)1449 void EventSender::enableDOMUIEventLogging(const CppArgumentList&, CppVariant* result)
1450 {
1451 result->setNull();
1452 }
1453
fireKeyboardEventsToElement(const CppArgumentList &,CppVariant * result)1454 void EventSender::fireKeyboardEventsToElement(const CppArgumentList&, CppVariant* result)
1455 {
1456 result->setNull();
1457 }
1458
clearKillRing(const CppArgumentList &,CppVariant * result)1459 void EventSender::clearKillRing(const CppArgumentList&, CppVariant* result)
1460 {
1461 result->setNull();
1462 }
1463
1464 }
1465