Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(163)

Side by Side Diff: components/test_runner/event_sender.cc

Issue 2707183003: Move //components/test_runner back into //content/shell (Closed)
Patch Set: Trim DEPS Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/test_runner/event_sender.h"
6
7 #include <stddef.h>
8
9 #include <memory>
10
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/command_line.h"
14 #include "base/files/file_path.h"
15 #include "base/logging.h"
16 #include "base/macros.h"
17 #include "base/strings/string16.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "build/build_config.h"
22 #include "components/test_runner/mock_spell_check.h"
23 #include "components/test_runner/test_interfaces.h"
24 #include "components/test_runner/web_test_delegate.h"
25 #include "components/test_runner/web_view_test_proxy.h"
26 #include "components/test_runner/web_widget_test_proxy.h"
27 #include "gin/handle.h"
28 #include "gin/object_template_builder.h"
29 #include "gin/wrappable.h"
30 #include "net/base/filename_util.h"
31 #include "third_party/WebKit/public/platform/URLConversion.h"
32 #include "third_party/WebKit/public/platform/WebCoalescedInputEvent.h"
33 #include "third_party/WebKit/public/platform/WebGestureEvent.h"
34 #include "third_party/WebKit/public/platform/WebKeyboardEvent.h"
35 #include "third_party/WebKit/public/platform/WebPointerProperties.h"
36 #include "third_party/WebKit/public/platform/WebString.h"
37 #include "third_party/WebKit/public/platform/WebTouchEvent.h"
38 #include "third_party/WebKit/public/platform/WebVector.h"
39 #include "third_party/WebKit/public/web/WebContextMenuData.h"
40 #include "third_party/WebKit/public/web/WebFrameWidget.h"
41 #include "third_party/WebKit/public/web/WebKit.h"
42 #include "third_party/WebKit/public/web/WebLocalFrame.h"
43 #include "third_party/WebKit/public/web/WebPagePopup.h"
44 #include "third_party/WebKit/public/web/WebView.h"
45 #include "ui/events/blink/blink_event_util.h"
46 #include "ui/events/keycodes/dom/keycode_converter.h"
47 #include "ui/events/keycodes/keyboard_codes.h"
48 #include "v8/include/v8.h"
49
50 using blink::WebContextMenuData;
51 using blink::WebDragData;
52 using blink::WebDragOperationsMask;
53 using blink::WebFloatPoint;
54 using blink::WebGestureEvent;
55 using blink::WebInputEvent;
56 using blink::WebInputEventResult;
57 using blink::WebKeyboardEvent;
58 using blink::WebLocalFrame;
59 using blink::WebMenuItemInfo;
60 using blink::WebMouseEvent;
61 using blink::WebMouseWheelEvent;
62 using blink::WebPagePopup;
63 using blink::WebPoint;
64 using blink::WebPointerProperties;
65 using blink::WebString;
66 using blink::WebTouchEvent;
67 using blink::WebTouchPoint;
68 using blink::WebURL;
69 using blink::WebVector;
70 using blink::WebView;
71
72 namespace test_runner {
73
74 namespace {
75
76 const int kRawMousePointerId = -1;
77 const char* const kPointerTypeStringUnknown = "";
78 const char* const kPointerTypeStringMouse = "mouse";
79 const char* const kPointerTypeStringTouch = "touch";
80 const char* const kPointerTypeStringPen = "pen";
81 const char* const kPointerTypeStringEraser = "eraser";
82
83 // Assigns |pointerType| from the provided |args|. Returns false if there was
84 // any error.
85 bool getPointerType(gin::Arguments* args,
86 bool isOnlyMouseAndPenAllowed,
87 WebPointerProperties::PointerType& pointerType) {
88 if (args->PeekNext().IsEmpty())
89 return true;
90 std::string pointer_type_string;
91 if (!args->GetNext(&pointer_type_string)) {
92 args->ThrowError();
93 return false;
94 }
95 if (isOnlyMouseAndPenAllowed &&
96 (pointer_type_string == kPointerTypeStringUnknown ||
97 pointer_type_string == kPointerTypeStringTouch)) {
98 args->ThrowError();
99 return false;
100 }
101 if (pointer_type_string == kPointerTypeStringUnknown) {
102 pointerType = WebMouseEvent::PointerType::Unknown;
103 } else if (pointer_type_string == kPointerTypeStringMouse) {
104 pointerType = WebMouseEvent::PointerType::Mouse;
105 } else if (pointer_type_string == kPointerTypeStringTouch) {
106 pointerType = WebMouseEvent::PointerType::Touch;
107 } else if (pointer_type_string == kPointerTypeStringPen) {
108 pointerType = WebMouseEvent::PointerType::Pen;
109 } else if (pointer_type_string == kPointerTypeStringEraser) {
110 pointerType = WebMouseEvent::PointerType::Eraser;
111 } else {
112 args->ThrowError();
113 return false;
114 }
115 return true;
116 }
117
118 // Parses |pointerType|, |rawPointerId|, |pressure|, |tiltX| and |tiltY| from
119 // the provided |args|. Returns false if there was any error, assuming the last
120 // 3 of the five parsed parameters are optional.
121 bool getMousePenPointerProperties(
122 gin::Arguments* args,
123 WebPointerProperties::PointerType& pointerType,
124 int& rawPointerId,
125 float& pressure,
126 int& tiltX,
127 int& tiltY) {
128 pointerType = WebPointerProperties::PointerType::Mouse;
129 rawPointerId = kRawMousePointerId;
130 pressure = std::numeric_limits<float>::quiet_NaN();
131 tiltX = 0;
132 tiltY = 0;
133
134 // Only allow pen or mouse through this API.
135 if (!getPointerType(args, false, pointerType))
136 return false;
137 if (!args->PeekNext().IsEmpty()) {
138 if (!args->GetNext(&rawPointerId)) {
139 args->ThrowError();
140 return false;
141 }
142
143 // Parse optional params
144 if (!args->PeekNext().IsEmpty()) {
145 if (!args->GetNext(&pressure)) {
146 args->ThrowError();
147 return false;
148 }
149 if (!args->PeekNext().IsEmpty()) {
150 if (!args->GetNext(&tiltX)) {
151 args->ThrowError();
152 return false;
153 }
154 if (!args->PeekNext().IsEmpty()) {
155 if (!args->GetNext(&tiltY)) {
156 args->ThrowError();
157 return false;
158 }
159 }
160 }
161 }
162 }
163
164 return true;
165 }
166
167 WebMouseEvent::Button GetButtonTypeFromButtonNumber(int button_code) {
168 switch (button_code) {
169 case -1:
170 return WebMouseEvent::Button::NoButton;
171 case 0:
172 return WebMouseEvent::Button::Left;
173 case 1:
174 return WebMouseEvent::Button::Middle;
175 case 2:
176 return WebMouseEvent::Button::Right;
177 }
178 NOTREACHED();
179 return WebMouseEvent::Button::NoButton;
180 }
181
182 int GetWebMouseEventModifierForButton(WebMouseEvent::Button button) {
183 switch (button) {
184 case WebMouseEvent::Button::NoButton:
185 return 0;
186 case WebMouseEvent::Button::Left:
187 return WebMouseEvent::LeftButtonDown;
188 case WebMouseEvent::Button::Middle:
189 return WebMouseEvent::MiddleButtonDown;
190 case WebMouseEvent::Button::Right:
191 return WebMouseEvent::RightButtonDown;
192 case WebPointerProperties::Button::X1:
193 case WebPointerProperties::Button::X2:
194 case WebPointerProperties::Button::Eraser:
195 return 0; // Not implemented yet
196 }
197 NOTREACHED();
198 return 0;
199 }
200
201 const int kButtonsInModifiers = WebMouseEvent::LeftButtonDown
202 | WebMouseEvent::MiddleButtonDown | WebMouseEvent::RightButtonDown;
203
204 int modifiersWithButtons(int modifiers, int buttons) {
205 return (modifiers & ~kButtonsInModifiers)
206 | (buttons & kButtonsInModifiers);
207 }
208
209 void InitMouseEventGeneric(WebMouseEvent::Button b,
210 int current_buttons,
211 const WebPoint& pos,
212 int click_count,
213 WebPointerProperties::PointerType pointerType,
214 int pointerId,
215 float pressure,
216 int tiltX,
217 int tiltY,
218 WebMouseEvent* e) {
219 e->button = b;
220 e->x = pos.x;
221 e->y = pos.y;
222 e->globalX = pos.x;
223 e->globalY = pos.y;
224 e->pointerType = pointerType;
225 e->id = pointerId;
226 e->force = pressure;
227 e->tiltX = tiltX;
228 e->tiltY = tiltY;
229 e->clickCount = click_count;
230 }
231
232 void InitMouseEvent(WebMouseEvent::Button b,
233 int current_buttons,
234 const WebPoint& pos,
235 int click_count,
236 WebMouseEvent* e) {
237 InitMouseEventGeneric(b, current_buttons, pos, click_count,
238 WebPointerProperties::PointerType::Mouse, 0, 0.0, 0, 0,
239 e);
240 }
241
242 void InitGestureEventFromMouseWheel(const WebMouseWheelEvent& wheel_event,
243 WebGestureEvent* gesture_event) {
244 gesture_event->sourceDevice = blink::WebGestureDeviceTouchpad;
245 gesture_event->x = wheel_event.x;
246 gesture_event->y = wheel_event.y;
247 gesture_event->globalX = wheel_event.globalX;
248 gesture_event->globalY = wheel_event.globalY;
249 }
250
251 int GetKeyModifier(const std::string& modifier_name) {
252 const char* characters = modifier_name.c_str();
253 if (!strcmp(characters, "ctrlKey")
254 #ifndef __APPLE__
255 || !strcmp(characters, "addSelectionKey")
256 #endif
257 ) {
258 return WebInputEvent::ControlKey;
259 } else if (!strcmp(characters, "shiftKey") ||
260 !strcmp(characters, "rangeSelectionKey")) {
261 return WebInputEvent::ShiftKey;
262 } else if (!strcmp(characters, "altKey")) {
263 return WebInputEvent::AltKey;
264 #ifdef __APPLE__
265 } else if (!strcmp(characters, "metaKey") ||
266 !strcmp(characters, "addSelectionKey")) {
267 return WebInputEvent::MetaKey;
268 #else
269 } else if (!strcmp(characters, "metaKey")) {
270 return WebInputEvent::MetaKey;
271 #endif
272 } else if (!strcmp(characters, "autoRepeat")) {
273 return WebInputEvent::IsAutoRepeat;
274 } else if (!strcmp(characters, "copyKey")) {
275 #ifdef __APPLE__
276 return WebInputEvent::AltKey;
277 #else
278 return WebInputEvent::ControlKey;
279 #endif
280 } else if (!strcmp(characters, "accessKey")) {
281 #ifdef __APPLE__
282 return WebInputEvent::AltKey | WebInputEvent::ControlKey;
283 #else
284 return WebInputEvent::AltKey;
285 #endif
286 } else if (!strcmp(characters, "leftButton")) {
287 return WebInputEvent::LeftButtonDown;
288 } else if (!strcmp(characters, "middleButton")) {
289 return WebInputEvent::MiddleButtonDown;
290 } else if (!strcmp(characters, "rightButton")) {
291 return WebInputEvent::RightButtonDown;
292 } else if (!strcmp(characters, "capsLockOn")) {
293 return WebInputEvent::CapsLockOn;
294 } else if (!strcmp(characters, "numLockOn")) {
295 return WebInputEvent::NumLockOn;
296 } else if (!strcmp(characters, "locationLeft")) {
297 return WebInputEvent::IsLeft;
298 } else if (!strcmp(characters, "locationRight")) {
299 return WebInputEvent::IsRight;
300 } else if (!strcmp(characters, "locationNumpad")) {
301 return WebInputEvent::IsKeyPad;
302 } else if (!strcmp(characters, "isComposing")) {
303 return WebInputEvent::IsComposing;
304 } else if (!strcmp(characters, "altGraphKey")) {
305 return WebInputEvent::AltGrKey;
306 } else if (!strcmp(characters, "fnKey")) {
307 return WebInputEvent::FnKey;
308 } else if (!strcmp(characters, "symbolKey")) {
309 return WebInputEvent::SymbolKey;
310 } else if (!strcmp(characters, "scrollLockOn")) {
311 return WebInputEvent::ScrollLockOn;
312 }
313
314 return 0;
315 }
316
317 int GetKeyModifiers(const std::vector<std::string>& modifier_names) {
318 int modifiers = 0;
319 for (std::vector<std::string>::const_iterator it = modifier_names.begin();
320 it != modifier_names.end(); ++it) {
321 modifiers |= GetKeyModifier(*it);
322 }
323 return modifiers;
324 }
325
326 int GetKeyModifiersFromV8(v8::Isolate* isolate, v8::Local<v8::Value> value) {
327 std::vector<std::string> modifier_names;
328 if (value->IsString()) {
329 modifier_names.push_back(gin::V8ToString(value));
330 } else if (value->IsArray()) {
331 gin::Converter<std::vector<std::string> >::FromV8(
332 isolate, value, &modifier_names);
333 }
334 return GetKeyModifiers(modifier_names);
335 }
336
337 WebMouseWheelEvent::Phase GetMouseWheelEventPhase(
338 const std::string& phase_name) {
339 if (phase_name == "phaseNone") {
340 return WebMouseWheelEvent::PhaseNone;
341 } else if (phase_name == "phaseBegan") {
342 return WebMouseWheelEvent::PhaseBegan;
343 } else if (phase_name == "phaseStationary") {
344 return WebMouseWheelEvent::PhaseStationary;
345 } else if (phase_name == "phaseChanged") {
346 return WebMouseWheelEvent::PhaseChanged;
347 } else if (phase_name == "phaseEnded") {
348 return WebMouseWheelEvent::PhaseEnded;
349 } else if (phase_name == "phaseCancelled") {
350 return WebMouseWheelEvent::PhaseCancelled;
351 } else if (phase_name == "phaseMayBegin") {
352 return WebMouseWheelEvent::PhaseMayBegin;
353 }
354
355 return WebMouseWheelEvent::PhaseNone;
356 }
357
358 WebMouseWheelEvent::Phase GetMouseWheelEventPhaseFromV8(
359 v8::Local<v8::Value> value) {
360 if (value->IsString())
361 return GetMouseWheelEventPhase(gin::V8ToString(value));
362 return WebMouseWheelEvent::PhaseNone;
363 }
364
365 // Maximum distance (in space and time) for a mouse click to register as a
366 // double or triple click.
367 const double kMultipleClickTimeSec = 1;
368 const int kMultipleClickRadiusPixels = 5;
369 const char kSubMenuDepthIdentifier[] = "_";
370 const char kSubMenuIdentifier[] = " >";
371 const char kSeparatorIdentifier[] = "---------";
372 const char kDisabledIdentifier[] = "#";
373 const char kCheckedIdentifier[] = "*";
374
375 bool OutsideMultiClickRadius(const WebPoint& a, const WebPoint& b) {
376 return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)) >
377 kMultipleClickRadiusPixels * kMultipleClickRadiusPixels;
378 }
379
380 void PopulateCustomItems(const WebVector<WebMenuItemInfo>& customItems,
381 const std::string& prefix, std::vector<std::string>* strings) {
382 for (size_t i = 0; i < customItems.size(); ++i) {
383 std::string prefixCopy = prefix;
384 if (!customItems[i].enabled)
385 prefixCopy = kDisabledIdentifier + prefix;
386 if (customItems[i].checked)
387 prefixCopy = kCheckedIdentifier + prefix;
388 if (customItems[i].type == blink::WebMenuItemInfo::Separator) {
389 strings->push_back(prefixCopy + kSeparatorIdentifier);
390 } else if (customItems[i].type == blink::WebMenuItemInfo::SubMenu) {
391 strings->push_back(prefixCopy + customItems[i].label.utf8() +
392 customItems[i].icon.utf8() + kSubMenuIdentifier);
393 PopulateCustomItems(customItems[i].subMenuItems, prefixCopy +
394 kSubMenuDepthIdentifier, strings);
395 } else {
396 strings->push_back(prefixCopy + customItems[i].label.utf8() +
397 customItems[i].icon.utf8());
398 }
399 }
400 }
401
402 // Because actual context menu is implemented by the browser side,
403 // this function does only what LayoutTests are expecting:
404 // - Many test checks the count of items. So returning non-zero value makes
405 // sense.
406 // - Some test compares the count before and after some action. So changing the
407 // count based on flags also makes sense. This function is doing such for some
408 // flags.
409 // - Some test even checks actual string content. So providing it would be also
410 // helpful.
411 std::vector<std::string> MakeMenuItemStringsFor(
412 WebContextMenuData* context_menu,
413 WebTestDelegate* delegate) {
414 // These constants are based on Safari's context menu because tests are made
415 // for it.
416 static const char* kNonEditableMenuStrings[] = {
417 "Back",
418 "Reload Page",
419 "Open in Dashbaord",
420 "<separator>",
421 "View Source",
422 "Save Page As",
423 "Print Page",
424 "Inspect Element",
425 0
426 };
427 static const char* kEditableMenuStrings[] = {
428 "Cut",
429 "Copy",
430 "<separator>",
431 "Paste",
432 "Spelling and Grammar",
433 "Substitutions, Transformations",
434 "Font",
435 "Speech",
436 "Paragraph Direction",
437 "<separator>",
438 0
439 };
440
441 // This is possible because mouse events are cancelleable.
442 if (!context_menu)
443 return std::vector<std::string>();
444
445 std::vector<std::string> strings;
446
447 // Populate custom menu items if provided by blink.
448 PopulateCustomItems(context_menu->customItems, "", &strings);
449
450 if (context_menu->isEditable) {
451 for (const char** item = kEditableMenuStrings; *item; ++item) {
452 strings.push_back(*item);
453 }
454 WebVector<WebString> suggestions;
455 MockSpellCheck::FillSuggestionList(context_menu->misspelledWord,
456 &suggestions);
457 for (size_t i = 0; i < suggestions.size(); ++i) {
458 strings.push_back(suggestions[i].utf8());
459 }
460 } else {
461 for (const char** item = kNonEditableMenuStrings; *item; ++item) {
462 strings.push_back(*item);
463 }
464 }
465
466 return strings;
467 }
468
469 // How much we should scroll per event - the value here is chosen to match the
470 // WebKit impl and layout test results.
471 const float kScrollbarPixelsPerTick = 40.0f;
472
473 // Get the edit command corresponding to a keyboard event.
474 // Returns true if the specified event corresponds to an edit command, the name
475 // of the edit command will be stored in |*name|.
476 bool GetEditCommand(const WebKeyboardEvent& event, std::string* name) {
477 #if defined(OS_MACOSX)
478 // We only cares about Left,Right,Up,Down keys with Command or Command+Shift
479 // modifiers. These key events correspond to some special movement and
480 // selection editor commands. These keys will be marked as system key, which
481 // prevents them from being handled. Thus they must be handled specially.
482 if ((event.modifiers() & ~WebKeyboardEvent::ShiftKey) !=
483 WebKeyboardEvent::MetaKey)
484 return false;
485
486 switch (event.windowsKeyCode) {
487 case ui::VKEY_LEFT:
488 *name = "MoveToBeginningOfLine";
489 break;
490 case ui::VKEY_RIGHT:
491 *name = "MoveToEndOfLine";
492 break;
493 case ui::VKEY_UP:
494 *name = "MoveToBeginningOfDocument";
495 break;
496 case ui::VKEY_DOWN:
497 *name = "MoveToEndOfDocument";
498 break;
499 default:
500 return false;
501 }
502
503 if (event.modifiers() & WebKeyboardEvent::ShiftKey)
504 name->append("AndModifySelection");
505
506 return true;
507 #else
508 return false;
509 #endif
510 }
511
512 bool IsSystemKeyEvent(const WebKeyboardEvent& event) {
513 #if defined(OS_MACOSX)
514 return event.modifiers() & WebInputEvent::MetaKey &&
515 event.windowsKeyCode != ui::VKEY_B &&
516 event.windowsKeyCode != ui::VKEY_I;
517 #else
518 return !!(event.modifiers() & WebInputEvent::AltKey);
519 #endif
520 }
521
522 bool GetScrollUnits(gin::Arguments* args, WebGestureEvent::ScrollUnits* units) {
523 std::string units_string;
524 if (!args->PeekNext().IsEmpty()) {
525 if (args->PeekNext()->IsString())
526 args->GetNext(&units_string);
527 if (units_string == "Page") {
528 *units = WebGestureEvent::Page;
529 return true;
530 } else if (units_string == "Pixels") {
531 *units = WebGestureEvent::Pixels;
532 return true;
533 } else if (units_string == "PrecisePixels") {
534 *units = WebGestureEvent::PrecisePixels;
535 return true;
536 } else {
537 args->ThrowError();
538 return false;
539 }
540 } else {
541 *units = WebGestureEvent::PrecisePixels;
542 return true;
543 }
544 }
545
546 const char* kSourceDeviceStringTouchpad = "touchpad";
547 const char* kSourceDeviceStringTouchscreen = "touchscreen";
548
549 } // namespace
550
551 class EventSenderBindings : public gin::Wrappable<EventSenderBindings> {
552 public:
553 static gin::WrapperInfo kWrapperInfo;
554
555 static void Install(base::WeakPtr<EventSender> sender,
556 blink::WebLocalFrame* frame);
557
558 private:
559 explicit EventSenderBindings(base::WeakPtr<EventSender> sender);
560 ~EventSenderBindings() override;
561
562 // gin::Wrappable:
563 gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
564 v8::Isolate* isolate) override;
565
566 // Bound methods:
567 void EnableDOMUIEventLogging();
568 void FireKeyboardEventsToElement();
569 void ClearKillRing();
570 std::vector<std::string> ContextClick();
571 void TextZoomIn();
572 void TextZoomOut();
573 void ZoomPageIn();
574 void ZoomPageOut();
575 void SetPageZoomFactor(double factor);
576 void ClearTouchPoints();
577 void ReleaseTouchPoint(unsigned index);
578 void UpdateTouchPoint(unsigned index,
579 double x,
580 double y,
581 gin::Arguments* args);
582 void CancelTouchPoint(unsigned index);
583 void SetTouchModifier(const std::string& key_name, bool set_mask);
584 void SetTouchCancelable(bool cancelable);
585 void DumpFilenameBeingDragged();
586 void GestureFlingCancel();
587 void GestureFlingStart(float x,
588 float y,
589 float velocity_x,
590 float velocity_y,
591 gin::Arguments* args);
592 bool IsFlinging() const;
593 void GestureScrollFirstPoint(int x, int y);
594 void TouchStart(gin::Arguments* args);
595 void TouchMove(gin::Arguments* args);
596 void TouchCancel(gin::Arguments* args);
597 void TouchEnd(gin::Arguments* args);
598 void NotifyStartOfTouchScroll();
599 void LeapForward(int milliseconds);
600 double LastEventTimestamp();
601 void BeginDragWithFiles(const std::vector<std::string>& files);
602 void AddTouchPoint(double x, double y, gin::Arguments* args);
603 void GestureScrollBegin(gin::Arguments* args);
604 void GestureScrollEnd(gin::Arguments* args);
605 void GestureScrollUpdate(gin::Arguments* args);
606 void GesturePinchBegin(gin::Arguments* args);
607 void GesturePinchEnd(gin::Arguments* args);
608 void GesturePinchUpdate(gin::Arguments* args);
609 void GestureTap(gin::Arguments* args);
610 void GestureTapDown(gin::Arguments* args);
611 void GestureShowPress(gin::Arguments* args);
612 void GestureTapCancel(gin::Arguments* args);
613 void GestureLongPress(gin::Arguments* args);
614 void GestureLongTap(gin::Arguments* args);
615 void GestureTwoFingerTap(gin::Arguments* args);
616 void ContinuousMouseScrollBy(gin::Arguments* args);
617 void MouseMoveTo(gin::Arguments* args);
618 void MouseLeave();
619 void MouseScrollBy(gin::Arguments* args);
620 void ScheduleAsynchronousClick(gin::Arguments* args);
621 void ScheduleAsynchronousKeyDown(gin::Arguments* args);
622 void MouseDown(gin::Arguments* args);
623 void MouseUp(gin::Arguments* args);
624 void SetMouseButtonState(gin::Arguments* args);
625 void KeyDown(gin::Arguments* args);
626
627 // Binding properties:
628 bool ForceLayoutOnEvents() const;
629 void SetForceLayoutOnEvents(bool force);
630 bool IsDragMode() const;
631 void SetIsDragMode(bool drag_mode);
632
633 #if defined(OS_WIN)
634 int WmKeyDown() const;
635 void SetWmKeyDown(int key_down);
636
637 int WmKeyUp() const;
638 void SetWmKeyUp(int key_up);
639
640 int WmChar() const;
641 void SetWmChar(int wm_char);
642
643 int WmDeadChar() const;
644 void SetWmDeadChar(int dead_char);
645
646 int WmSysKeyDown() const;
647 void SetWmSysKeyDown(int key_down);
648
649 int WmSysKeyUp() const;
650 void SetWmSysKeyUp(int key_up);
651
652 int WmSysChar() const;
653 void SetWmSysChar(int sys_char);
654
655 int WmSysDeadChar() const;
656 void SetWmSysDeadChar(int sys_dead_char);
657 #endif
658
659 base::WeakPtr<EventSender> sender_;
660
661 DISALLOW_COPY_AND_ASSIGN(EventSenderBindings);
662 };
663
664 gin::WrapperInfo EventSenderBindings::kWrapperInfo = {gin::kEmbedderNativeGin};
665
666 EventSenderBindings::EventSenderBindings(base::WeakPtr<EventSender> sender)
667 : sender_(sender) {
668 }
669
670 EventSenderBindings::~EventSenderBindings() {}
671
672 // static
673 void EventSenderBindings::Install(base::WeakPtr<EventSender> sender,
674 WebLocalFrame* frame) {
675 v8::Isolate* isolate = blink::mainThreadIsolate();
676 v8::HandleScope handle_scope(isolate);
677 v8::Local<v8::Context> context = frame->mainWorldScriptContext();
678 if (context.IsEmpty())
679 return;
680
681 v8::Context::Scope context_scope(context);
682
683 gin::Handle<EventSenderBindings> bindings =
684 gin::CreateHandle(isolate, new EventSenderBindings(sender));
685 if (bindings.IsEmpty())
686 return;
687 v8::Local<v8::Object> global = context->Global();
688 global->Set(gin::StringToV8(isolate, "eventSender"), bindings.ToV8());
689 }
690
691 gin::ObjectTemplateBuilder
692 EventSenderBindings::GetObjectTemplateBuilder(v8::Isolate* isolate) {
693 return gin::Wrappable<EventSenderBindings>::GetObjectTemplateBuilder(isolate)
694 .SetMethod("enableDOMUIEventLogging",
695 &EventSenderBindings::EnableDOMUIEventLogging)
696 .SetMethod("fireKeyboardEventsToElement",
697 &EventSenderBindings::FireKeyboardEventsToElement)
698 .SetMethod("clearKillRing", &EventSenderBindings::ClearKillRing)
699 .SetMethod("contextClick", &EventSenderBindings::ContextClick)
700 .SetMethod("textZoomIn", &EventSenderBindings::TextZoomIn)
701 .SetMethod("textZoomOut", &EventSenderBindings::TextZoomOut)
702 .SetMethod("zoomPageIn", &EventSenderBindings::ZoomPageIn)
703 .SetMethod("zoomPageOut", &EventSenderBindings::ZoomPageOut)
704 .SetMethod("setPageZoomFactor", &EventSenderBindings::SetPageZoomFactor)
705 .SetMethod("clearTouchPoints", &EventSenderBindings::ClearTouchPoints)
706 .SetMethod("releaseTouchPoint", &EventSenderBindings::ReleaseTouchPoint)
707 .SetMethod("updateTouchPoint", &EventSenderBindings::UpdateTouchPoint)
708 .SetMethod("cancelTouchPoint", &EventSenderBindings::CancelTouchPoint)
709 .SetMethod("setTouchModifier", &EventSenderBindings::SetTouchModifier)
710 .SetMethod("setTouchCancelable", &EventSenderBindings::SetTouchCancelable)
711 .SetMethod("dumpFilenameBeingDragged",
712 &EventSenderBindings::DumpFilenameBeingDragged)
713 .SetMethod("gestureFlingCancel", &EventSenderBindings::GestureFlingCancel)
714 .SetMethod("gestureFlingStart", &EventSenderBindings::GestureFlingStart)
715 .SetMethod("isFlinging", &EventSenderBindings::IsFlinging)
716 .SetMethod("gestureScrollFirstPoint",
717 &EventSenderBindings::GestureScrollFirstPoint)
718 .SetMethod("touchStart", &EventSenderBindings::TouchStart)
719 .SetMethod("touchMove", &EventSenderBindings::TouchMove)
720 .SetMethod("touchCancel", &EventSenderBindings::TouchCancel)
721 .SetMethod("touchEnd", &EventSenderBindings::TouchEnd)
722 .SetMethod("notifyStartOfTouchScroll",
723 &EventSenderBindings::NotifyStartOfTouchScroll)
724 .SetMethod("leapForward", &EventSenderBindings::LeapForward)
725 .SetMethod("lastEventTimestamp", &EventSenderBindings::LastEventTimestamp)
726 .SetMethod("beginDragWithFiles", &EventSenderBindings::BeginDragWithFiles)
727 .SetMethod("addTouchPoint", &EventSenderBindings::AddTouchPoint)
728 .SetMethod("gestureScrollBegin", &EventSenderBindings::GestureScrollBegin)
729 .SetMethod("gestureScrollEnd", &EventSenderBindings::GestureScrollEnd)
730 .SetMethod("gestureScrollUpdate",
731 &EventSenderBindings::GestureScrollUpdate)
732 .SetMethod("gesturePinchBegin", &EventSenderBindings::GesturePinchBegin)
733 .SetMethod("gesturePinchEnd", &EventSenderBindings::GesturePinchEnd)
734 .SetMethod("gesturePinchUpdate", &EventSenderBindings::GesturePinchUpdate)
735 .SetMethod("gestureTap", &EventSenderBindings::GestureTap)
736 .SetMethod("gestureTapDown", &EventSenderBindings::GestureTapDown)
737 .SetMethod("gestureShowPress", &EventSenderBindings::GestureShowPress)
738 .SetMethod("gestureTapCancel", &EventSenderBindings::GestureTapCancel)
739 .SetMethod("gestureLongPress", &EventSenderBindings::GestureLongPress)
740 .SetMethod("gestureLongTap", &EventSenderBindings::GestureLongTap)
741 .SetMethod("gestureTwoFingerTap",
742 &EventSenderBindings::GestureTwoFingerTap)
743 .SetMethod("continuousMouseScrollBy",
744 &EventSenderBindings::ContinuousMouseScrollBy)
745 .SetMethod("keyDown", &EventSenderBindings::KeyDown)
746 .SetMethod("mouseDown", &EventSenderBindings::MouseDown)
747 .SetMethod("mouseMoveTo", &EventSenderBindings::MouseMoveTo)
748 .SetMethod("mouseLeave", &EventSenderBindings::MouseLeave)
749 .SetMethod("mouseScrollBy", &EventSenderBindings::MouseScrollBy)
750 .SetMethod("mouseUp", &EventSenderBindings::MouseUp)
751 .SetMethod("setMouseButtonState",
752 &EventSenderBindings::SetMouseButtonState)
753 .SetMethod("scheduleAsynchronousClick",
754 &EventSenderBindings::ScheduleAsynchronousClick)
755 .SetMethod("scheduleAsynchronousKeyDown",
756 &EventSenderBindings::ScheduleAsynchronousKeyDown)
757 .SetProperty("forceLayoutOnEvents",
758 &EventSenderBindings::ForceLayoutOnEvents,
759 &EventSenderBindings::SetForceLayoutOnEvents)
760 #if defined(OS_WIN)
761 .SetProperty("WM_KEYDOWN", &EventSenderBindings::WmKeyDown,
762 &EventSenderBindings::SetWmKeyDown)
763 .SetProperty("WM_KEYUP", &EventSenderBindings::WmKeyUp,
764 &EventSenderBindings::SetWmKeyUp)
765 .SetProperty("WM_CHAR", &EventSenderBindings::WmChar,
766 &EventSenderBindings::SetWmChar)
767 .SetProperty("WM_DEADCHAR", &EventSenderBindings::WmDeadChar,
768 &EventSenderBindings::SetWmDeadChar)
769 .SetProperty("WM_SYSKEYDOWN", &EventSenderBindings::WmSysKeyDown,
770 &EventSenderBindings::SetWmSysKeyDown)
771 .SetProperty("WM_SYSKEYUP", &EventSenderBindings::WmSysKeyUp,
772 &EventSenderBindings::SetWmSysKeyUp)
773 .SetProperty("WM_SYSCHAR", &EventSenderBindings::WmSysChar,
774 &EventSenderBindings::SetWmSysChar)
775 .SetProperty("WM_SYSDEADCHAR", &EventSenderBindings::WmSysDeadChar,
776 &EventSenderBindings::SetWmSysDeadChar)
777 #endif
778 .SetProperty("dragMode", &EventSenderBindings::IsDragMode,
779 &EventSenderBindings::SetIsDragMode);
780 }
781
782 void EventSenderBindings::EnableDOMUIEventLogging() {
783 if (sender_)
784 sender_->EnableDOMUIEventLogging();
785 }
786
787 void EventSenderBindings::FireKeyboardEventsToElement() {
788 if (sender_)
789 sender_->FireKeyboardEventsToElement();
790 }
791
792 void EventSenderBindings::ClearKillRing() {
793 if (sender_)
794 sender_->ClearKillRing();
795 }
796
797 std::vector<std::string> EventSenderBindings::ContextClick() {
798 if (sender_)
799 return sender_->ContextClick();
800 return std::vector<std::string>();
801 }
802
803 void EventSenderBindings::TextZoomIn() {
804 if (sender_)
805 sender_->TextZoomIn();
806 }
807
808 void EventSenderBindings::TextZoomOut() {
809 if (sender_)
810 sender_->TextZoomOut();
811 }
812
813 void EventSenderBindings::ZoomPageIn() {
814 if (sender_)
815 sender_->ZoomPageIn();
816 }
817
818 void EventSenderBindings::ZoomPageOut() {
819 if (sender_)
820 sender_->ZoomPageOut();
821 }
822
823 void EventSenderBindings::SetPageZoomFactor(double factor) {
824 if (sender_)
825 sender_->SetPageZoomFactor(factor);
826 }
827
828 void EventSenderBindings::ClearTouchPoints() {
829 if (sender_)
830 sender_->ClearTouchPoints();
831 }
832
833 void EventSenderBindings::ReleaseTouchPoint(unsigned index) {
834 if (sender_)
835 sender_->ReleaseTouchPoint(index);
836 }
837
838 void EventSenderBindings::UpdateTouchPoint(unsigned index,
839 double x,
840 double y,
841 gin::Arguments* args) {
842 if (sender_) {
843 sender_->UpdateTouchPoint(index, static_cast<float>(x),
844 static_cast<float>(y), args);
845 }
846 }
847
848 void EventSenderBindings::CancelTouchPoint(unsigned index) {
849 if (sender_)
850 sender_->CancelTouchPoint(index);
851 }
852
853 void EventSenderBindings::SetTouchModifier(const std::string& key_name,
854 bool set_mask) {
855 if (sender_)
856 sender_->SetTouchModifier(key_name, set_mask);
857 }
858
859 void EventSenderBindings::SetTouchCancelable(bool cancelable) {
860 if (sender_)
861 sender_->SetTouchCancelable(cancelable);
862 }
863
864 void EventSenderBindings::DumpFilenameBeingDragged() {
865 if (sender_)
866 sender_->DumpFilenameBeingDragged();
867 }
868
869 void EventSenderBindings::GestureFlingCancel() {
870 if (sender_)
871 sender_->GestureFlingCancel();
872 }
873
874 void EventSenderBindings::GestureFlingStart(float x,
875 float y,
876 float velocity_x,
877 float velocity_y,
878 gin::Arguments* args) {
879 if (sender_)
880 sender_->GestureFlingStart(x, y, velocity_x, velocity_y, args);
881 }
882
883 bool EventSenderBindings::IsFlinging() const {
884 if (sender_)
885 return sender_->IsFlinging();
886 return false;
887 }
888
889 void EventSenderBindings::GestureScrollFirstPoint(int x, int y) {
890 if (sender_)
891 sender_->GestureScrollFirstPoint(x, y);
892 }
893
894 void EventSenderBindings::TouchStart(gin::Arguments* args) {
895 if (sender_)
896 sender_->TouchStart(args);
897 }
898
899 void EventSenderBindings::TouchMove(gin::Arguments* args) {
900 if (sender_)
901 sender_->TouchMove(args);
902 }
903
904 void EventSenderBindings::TouchCancel(gin::Arguments* args) {
905 if (sender_)
906 sender_->TouchCancel(args);
907 }
908
909 void EventSenderBindings::TouchEnd(gin::Arguments* args) {
910 if (sender_)
911 sender_->TouchEnd(args);
912 }
913
914 void EventSenderBindings::NotifyStartOfTouchScroll() {
915 if (sender_)
916 sender_->NotifyStartOfTouchScroll();
917 }
918
919 void EventSenderBindings::LeapForward(int milliseconds) {
920 if (sender_)
921 sender_->LeapForward(milliseconds);
922 }
923
924 double EventSenderBindings::LastEventTimestamp() {
925 if (sender_)
926 return sender_->last_event_timestamp();
927 return 0;
928 }
929
930 void EventSenderBindings::BeginDragWithFiles(
931 const std::vector<std::string>& files) {
932 if (sender_)
933 sender_->BeginDragWithFiles(files);
934 }
935
936 void EventSenderBindings::AddTouchPoint(double x,
937 double y,
938 gin::Arguments* args) {
939 if (sender_)
940 sender_->AddTouchPoint(static_cast<float>(x), static_cast<float>(y), args);
941 }
942
943 void EventSenderBindings::GestureScrollBegin(gin::Arguments* args) {
944 if (sender_)
945 sender_->GestureScrollBegin(args);
946 }
947
948 void EventSenderBindings::GestureScrollEnd(gin::Arguments* args) {
949 if (sender_)
950 sender_->GestureScrollEnd(args);
951 }
952
953 void EventSenderBindings::GestureScrollUpdate(gin::Arguments* args) {
954 if (sender_)
955 sender_->GestureScrollUpdate(args);
956 }
957
958 void EventSenderBindings::GesturePinchBegin(gin::Arguments* args) {
959 if (sender_)
960 sender_->GesturePinchBegin(args);
961 }
962
963 void EventSenderBindings::GesturePinchEnd(gin::Arguments* args) {
964 if (sender_)
965 sender_->GesturePinchEnd(args);
966 }
967
968 void EventSenderBindings::GesturePinchUpdate(gin::Arguments* args) {
969 if (sender_)
970 sender_->GesturePinchUpdate(args);
971 }
972
973 void EventSenderBindings::GestureTap(gin::Arguments* args) {
974 if (sender_)
975 sender_->GestureTap(args);
976 }
977
978 void EventSenderBindings::GestureTapDown(gin::Arguments* args) {
979 if (sender_)
980 sender_->GestureTapDown(args);
981 }
982
983 void EventSenderBindings::GestureShowPress(gin::Arguments* args) {
984 if (sender_)
985 sender_->GestureShowPress(args);
986 }
987
988 void EventSenderBindings::GestureTapCancel(gin::Arguments* args) {
989 if (sender_)
990 sender_->GestureTapCancel(args);
991 }
992
993 void EventSenderBindings::GestureLongPress(gin::Arguments* args) {
994 if (sender_)
995 sender_->GestureLongPress(args);
996 }
997
998 void EventSenderBindings::GestureLongTap(gin::Arguments* args) {
999 if (sender_)
1000 sender_->GestureLongTap(args);
1001 }
1002
1003 void EventSenderBindings::GestureTwoFingerTap(gin::Arguments* args) {
1004 if (sender_)
1005 sender_->GestureTwoFingerTap(args);
1006 }
1007
1008 void EventSenderBindings::ContinuousMouseScrollBy(gin::Arguments* args) {
1009 if (sender_)
1010 sender_->MouseScrollBy(args, EventSender::MouseScrollType::PIXEL);
1011 }
1012
1013 void EventSenderBindings::MouseMoveTo(gin::Arguments* args) {
1014 if (sender_)
1015 sender_->MouseMoveTo(args);
1016 }
1017
1018 void EventSenderBindings::MouseLeave() {
1019 if (sender_)
1020 sender_->MouseLeave();
1021 }
1022
1023 void EventSenderBindings::MouseScrollBy(gin::Arguments* args) {
1024 if (sender_)
1025 sender_->MouseScrollBy(args, EventSender::MouseScrollType::TICK);
1026 }
1027
1028 void EventSenderBindings::ScheduleAsynchronousClick(gin::Arguments* args) {
1029 if (!sender_)
1030 return;
1031
1032 int button_number = 0;
1033 int modifiers = 0;
1034 if (!args->PeekNext().IsEmpty()) {
1035 args->GetNext(&button_number);
1036 if (!args->PeekNext().IsEmpty())
1037 modifiers = GetKeyModifiersFromV8(args->isolate(), args->PeekNext());
1038 }
1039 sender_->ScheduleAsynchronousClick(button_number, modifiers);
1040 }
1041
1042 void EventSenderBindings::ScheduleAsynchronousKeyDown(gin::Arguments* args) {
1043 if (!sender_)
1044 return;
1045
1046 std::string code_str;
1047 int modifiers = 0;
1048 int location = DOMKeyLocationStandard;
1049 args->GetNext(&code_str);
1050 if (!args->PeekNext().IsEmpty()) {
1051 v8::Local<v8::Value> value;
1052 args->GetNext(&value);
1053 modifiers = GetKeyModifiersFromV8(args->isolate(), value);
1054 if (!args->PeekNext().IsEmpty())
1055 args->GetNext(&location);
1056 }
1057 sender_->ScheduleAsynchronousKeyDown(code_str, modifiers,
1058 static_cast<KeyLocationCode>(location));
1059 }
1060
1061 void EventSenderBindings::MouseDown(gin::Arguments* args) {
1062 if (!sender_)
1063 return;
1064
1065 int button_number = 0;
1066 int modifiers = 0;
1067 if (!args->PeekNext().IsEmpty()) {
1068 if (!args->GetNext(&button_number)) {
1069 args->ThrowError();
1070 return;
1071 }
1072 if (!args->PeekNext().IsEmpty()) {
1073 modifiers = GetKeyModifiersFromV8(args->isolate(), args->PeekNext());
1074 args->Skip();
1075 }
1076 }
1077
1078 WebPointerProperties::PointerType pointerType =
1079 WebPointerProperties::PointerType::Mouse;
1080 int pointerId = 0;
1081 float pressure = 0;
1082 int tiltX = 0;
1083 int tiltY = 0;
1084 if (!getMousePenPointerProperties(args, pointerType, pointerId, pressure,
1085 tiltX, tiltY))
1086 return;
1087
1088 sender_->PointerDown(button_number, modifiers, pointerType, pointerId,
1089 pressure, tiltX, tiltY);
1090 }
1091
1092 void EventSenderBindings::MouseUp(gin::Arguments* args) {
1093 if (!sender_)
1094 return;
1095
1096 int button_number = 0;
1097 int modifiers = 0;
1098 if (!args->PeekNext().IsEmpty()) {
1099 if (!args->GetNext(&button_number)) {
1100 args->ThrowError();
1101 return;
1102 }
1103 if (!args->PeekNext().IsEmpty()) {
1104 modifiers = GetKeyModifiersFromV8(args->isolate(), args->PeekNext());
1105 args->Skip();
1106 }
1107 }
1108
1109 WebPointerProperties::PointerType pointerType =
1110 WebPointerProperties::PointerType::Mouse;
1111 int pointerId = 0;
1112 float pressure = 0;
1113 int tiltX = 0;
1114 int tiltY = 0;
1115 if (!getMousePenPointerProperties(args, pointerType, pointerId, pressure,
1116 tiltX, tiltY))
1117 return;
1118
1119 sender_->PointerUp(button_number, modifiers, pointerType, pointerId, pressure,
1120 tiltX, tiltY);
1121 }
1122
1123 void EventSenderBindings::SetMouseButtonState(gin::Arguments* args) {
1124 if (!sender_)
1125 return;
1126
1127 int button_number;
1128 if (!args->GetNext(&button_number)) {
1129 args->ThrowError();
1130 return;
1131 }
1132
1133 int modifiers = -1; // Default to the modifier implied by button_number
1134 if (!args->PeekNext().IsEmpty()) {
1135 modifiers = GetKeyModifiersFromV8(args->isolate(), args->PeekNext());
1136 }
1137
1138 sender_->SetMouseButtonState(button_number, modifiers);
1139 }
1140
1141 void EventSenderBindings::KeyDown(gin::Arguments* args) {
1142 if (!sender_)
1143 return;
1144
1145 std::string code_str;
1146 int modifiers = 0;
1147 int location = DOMKeyLocationStandard;
1148 args->GetNext(&code_str);
1149 if (!args->PeekNext().IsEmpty()) {
1150 v8::Local<v8::Value> value;
1151 args->GetNext(&value);
1152 modifiers = GetKeyModifiersFromV8(args->isolate(), value);
1153 if (!args->PeekNext().IsEmpty())
1154 args->GetNext(&location);
1155 }
1156 sender_->KeyDown(code_str, modifiers, static_cast<KeyLocationCode>(location));
1157 }
1158
1159 bool EventSenderBindings::ForceLayoutOnEvents() const {
1160 if (sender_)
1161 return sender_->force_layout_on_events();
1162 return false;
1163 }
1164
1165 void EventSenderBindings::SetForceLayoutOnEvents(bool force) {
1166 if (sender_)
1167 sender_->set_force_layout_on_events(force);
1168 }
1169
1170 bool EventSenderBindings::IsDragMode() const {
1171 if (sender_)
1172 return sender_->is_drag_mode();
1173 return true;
1174 }
1175
1176 void EventSenderBindings::SetIsDragMode(bool drag_mode) {
1177 if (sender_)
1178 sender_->set_is_drag_mode(drag_mode);
1179 }
1180
1181 #if defined(OS_WIN)
1182 int EventSenderBindings::WmKeyDown() const {
1183 if (sender_)
1184 return sender_->wm_key_down();
1185 return 0;
1186 }
1187
1188 void EventSenderBindings::SetWmKeyDown(int key_down) {
1189 if (sender_)
1190 sender_->set_wm_key_down(key_down);
1191 }
1192
1193 int EventSenderBindings::WmKeyUp() const {
1194 if (sender_)
1195 return sender_->wm_key_up();
1196 return 0;
1197 }
1198
1199 void EventSenderBindings::SetWmKeyUp(int key_up) {
1200 if (sender_)
1201 sender_->set_wm_key_up(key_up);
1202 }
1203
1204 int EventSenderBindings::WmChar() const {
1205 if (sender_)
1206 return sender_->wm_char();
1207 return 0;
1208 }
1209
1210 void EventSenderBindings::SetWmChar(int wm_char) {
1211 if (sender_)
1212 sender_->set_wm_char(wm_char);
1213 }
1214
1215 int EventSenderBindings::WmDeadChar() const {
1216 if (sender_)
1217 return sender_->wm_dead_char();
1218 return 0;
1219 }
1220
1221 void EventSenderBindings::SetWmDeadChar(int dead_char) {
1222 if (sender_)
1223 sender_->set_wm_dead_char(dead_char);
1224 }
1225
1226 int EventSenderBindings::WmSysKeyDown() const {
1227 if (sender_)
1228 return sender_->wm_sys_key_down();
1229 return 0;
1230 }
1231
1232 void EventSenderBindings::SetWmSysKeyDown(int key_down) {
1233 if (sender_)
1234 sender_->set_wm_sys_key_down(key_down);
1235 }
1236
1237 int EventSenderBindings::WmSysKeyUp() const {
1238 if (sender_)
1239 return sender_->wm_sys_key_up();
1240 return 0;
1241 }
1242
1243 void EventSenderBindings::SetWmSysKeyUp(int key_up) {
1244 if (sender_)
1245 sender_->set_wm_sys_key_up(key_up);
1246 }
1247
1248 int EventSenderBindings::WmSysChar() const {
1249 if (sender_)
1250 return sender_->wm_sys_char();
1251 return 0;
1252 }
1253
1254 void EventSenderBindings::SetWmSysChar(int sys_char) {
1255 if (sender_)
1256 sender_->set_wm_sys_char(sys_char);
1257 }
1258
1259 int EventSenderBindings::WmSysDeadChar() const {
1260 if (sender_)
1261 return sender_->wm_sys_dead_char();
1262 return 0;
1263 }
1264
1265 void EventSenderBindings::SetWmSysDeadChar(int sys_dead_char) {
1266 if (sender_)
1267 sender_->set_wm_sys_dead_char(sys_dead_char);
1268 }
1269 #endif
1270
1271 // EventSender -----------------------------------------------------------------
1272
1273 WebMouseEvent::Button EventSender::last_button_type_ =
1274 WebMouseEvent::Button::NoButton;
1275
1276 EventSender::SavedEvent::SavedEvent()
1277 : type(TYPE_UNSPECIFIED),
1278 button_type(WebMouseEvent::Button::NoButton),
1279 milliseconds(0),
1280 modifiers(0) {}
1281
1282 EventSender::EventSender(WebWidgetTestProxyBase* web_widget_test_proxy_base)
1283 : web_widget_test_proxy_base_(web_widget_test_proxy_base),
1284 replaying_saved_events_(false),
1285 weak_factory_(this) {
1286 Reset();
1287 }
1288
1289 EventSender::~EventSender() {}
1290
1291 void EventSender::Reset() {
1292 DCHECK(current_drag_data_.isNull());
1293 current_drag_data_.reset();
1294 current_drag_effect_ = blink::WebDragOperationNone;
1295 current_drag_effects_allowed_ = blink::WebDragOperationNone;
1296 if (widget() &&
1297 current_pointer_state_[kRawMousePointerId].pressed_button_ !=
1298 WebMouseEvent::Button::NoButton)
1299 widget()->mouseCaptureLost();
1300 current_pointer_state_.clear();
1301 is_drag_mode_ = true;
1302 force_layout_on_events_ = true;
1303
1304 #if defined(OS_WIN)
1305 wm_key_down_ = WM_KEYDOWN;
1306 wm_key_up_ = WM_KEYUP;
1307 wm_char_ = WM_CHAR;
1308 wm_dead_char_ = WM_DEADCHAR;
1309 wm_sys_key_down_ = WM_SYSKEYDOWN;
1310 wm_sys_key_up_ = WM_SYSKEYUP;
1311 wm_sys_char_ = WM_SYSCHAR;
1312 wm_sys_dead_char_ = WM_SYSDEADCHAR;
1313 #endif
1314
1315 last_click_time_sec_ = 0;
1316 last_click_pos_ = WebPoint(0, 0);
1317 last_button_type_ = WebMouseEvent::Button::NoButton;
1318 touch_points_.clear();
1319 last_context_menu_data_.reset();
1320 weak_factory_.InvalidateWeakPtrs();
1321 current_gesture_location_ = WebPoint(0, 0);
1322 mouse_event_queue_.clear();
1323
1324 time_offset_ms_ = 0;
1325 click_count_ = 0;
1326
1327 touch_modifiers_ = 0;
1328 touch_cancelable_ = true;
1329 touch_points_.clear();
1330 }
1331
1332 void EventSender::Install(WebLocalFrame* frame) {
1333 EventSenderBindings::Install(weak_factory_.GetWeakPtr(), frame);
1334 }
1335
1336 void EventSender::SetContextMenuData(const WebContextMenuData& data) {
1337 last_context_menu_data_.reset(new WebContextMenuData(data));
1338 }
1339
1340 int EventSender::ModifiersForPointer(int pointer_id) {
1341 return modifiersWithButtons(
1342 current_pointer_state_[pointer_id].modifiers_,
1343 current_pointer_state_[pointer_id].current_buttons_);
1344 }
1345
1346 void EventSender::DoDragDrop(const WebDragData& drag_data,
1347 WebDragOperationsMask mask) {
1348 WebMouseEvent raw_event(WebInputEvent::MouseDown,
1349 ModifiersForPointer(kRawMousePointerId),
1350 GetCurrentEventTimeSec());
1351 InitMouseEvent(current_pointer_state_[kRawMousePointerId].pressed_button_,
1352 current_pointer_state_[kRawMousePointerId].current_buttons_,
1353 current_pointer_state_[kRawMousePointerId].last_pos_,
1354 click_count_, &raw_event);
1355
1356 std::unique_ptr<WebInputEvent> widget_event =
1357 TransformScreenToWidgetCoordinates(raw_event);
1358 const WebMouseEvent* event =
1359 widget_event.get() ? static_cast<WebMouseEvent*>(widget_event.get())
1360 : &raw_event;
1361
1362 WebPoint client_point(event->x, event->y);
1363 WebPoint screen_point(event->globalX, event->globalY);
1364 current_drag_data_ = drag_data;
1365 current_drag_effects_allowed_ = mask;
1366 current_drag_effect_ = mainFrameWidget()->dragTargetDragEnter(
1367 drag_data, client_point, screen_point, current_drag_effects_allowed_,
1368 modifiersWithButtons(
1369 current_pointer_state_[kRawMousePointerId].modifiers_,
1370 current_pointer_state_[kRawMousePointerId].current_buttons_));
1371
1372 // Finish processing events.
1373 ReplaySavedEvents();
1374 }
1375
1376 void EventSender::MouseDown(int button_number, int modifiers) {
1377 PointerDown(button_number, modifiers,
1378 WebPointerProperties::PointerType::Mouse, kRawMousePointerId, 0.0,
1379 0, 0);
1380 }
1381
1382 void EventSender::MouseUp(int button_number, int modifiers) {
1383 PointerUp(button_number, modifiers, WebPointerProperties::PointerType::Mouse,
1384 kRawMousePointerId, 0.0, 0, 0);
1385 }
1386
1387 void EventSender::PointerDown(int button_number,
1388 int modifiers,
1389 WebPointerProperties::PointerType pointerType,
1390 int pointerId,
1391 float pressure,
1392 int tiltX,
1393 int tiltY) {
1394 if (force_layout_on_events_)
1395 widget()->updateAllLifecyclePhases();
1396
1397 DCHECK_NE(-1, button_number);
1398
1399 WebMouseEvent::Button button_type =
1400 GetButtonTypeFromButtonNumber(button_number);
1401
1402 int click_count = 0;
1403 current_pointer_state_[pointerId].pressed_button_ = button_type;
1404 current_pointer_state_[pointerId].current_buttons_ |=
1405 GetWebMouseEventModifierForButton(button_type);
1406 current_pointer_state_[pointerId].modifiers_ = modifiers;
1407
1408 if (pointerType == WebPointerProperties::PointerType::Mouse) {
1409 UpdateClickCountForButton(button_type);
1410 click_count = click_count_;
1411 }
1412 WebMouseEvent event(WebInputEvent::MouseDown, ModifiersForPointer(pointerId),
1413 GetCurrentEventTimeSec());
1414 InitMouseEventGeneric(current_pointer_state_[pointerId].pressed_button_,
1415 current_pointer_state_[pointerId].current_buttons_,
1416 current_pointer_state_[pointerId].last_pos_,
1417 click_count, pointerType, pointerId, pressure, tiltX,
1418 tiltY, &event);
1419
1420 HandleInputEventOnViewOrPopup(event);
1421 }
1422
1423 void EventSender::PointerUp(int button_number,
1424 int modifiers,
1425 WebPointerProperties::PointerType pointerType,
1426 int pointerId,
1427 float pressure,
1428 int tiltX,
1429 int tiltY) {
1430 if (force_layout_on_events_)
1431 widget()->updateAllLifecyclePhases();
1432
1433 DCHECK_NE(-1, button_number);
1434
1435 WebMouseEvent::Button button_type =
1436 GetButtonTypeFromButtonNumber(button_number);
1437
1438 if (pointerType == WebPointerProperties::PointerType::Mouse &&
1439 is_drag_mode_ && !replaying_saved_events_) {
1440 SavedEvent saved_event;
1441 saved_event.type = SavedEvent::TYPE_MOUSE_UP;
1442 saved_event.button_type = button_type;
1443 saved_event.modifiers = modifiers;
1444 mouse_event_queue_.push_back(saved_event);
1445 ReplaySavedEvents();
1446 } else {
1447 current_pointer_state_[pointerId].modifiers_ = modifiers;
1448 current_pointer_state_[pointerId].current_buttons_ &=
1449 ~GetWebMouseEventModifierForButton(button_type);
1450 current_pointer_state_[pointerId].pressed_button_ =
1451 WebMouseEvent::Button::NoButton;
1452
1453 WebMouseEvent event(WebInputEvent::MouseUp, ModifiersForPointer(pointerId),
1454 GetCurrentEventTimeSec());
1455 int click_count = pointerType == WebPointerProperties::PointerType::Mouse
1456 ? click_count_
1457 : 0;
1458 InitMouseEventGeneric(
1459 button_type, current_pointer_state_[pointerId].current_buttons_,
1460 current_pointer_state_[pointerId].last_pos_, click_count, pointerType,
1461 pointerId, pressure, tiltX, tiltY, &event);
1462 HandleInputEventOnViewOrPopup(event);
1463 if (pointerType == WebPointerProperties::PointerType::Mouse)
1464 DoDragAfterMouseUp(event);
1465 }
1466 }
1467
1468 void EventSender::SetMouseButtonState(int button_number, int modifiers) {
1469 current_pointer_state_[kRawMousePointerId].pressed_button_ =
1470 GetButtonTypeFromButtonNumber(button_number);
1471 current_pointer_state_[kRawMousePointerId].current_buttons_ =
1472 (modifiers == -1)
1473 ? GetWebMouseEventModifierForButton(
1474 current_pointer_state_[kRawMousePointerId].pressed_button_)
1475 : modifiers & kButtonsInModifiers;
1476 }
1477
1478 void EventSender::KeyDown(const std::string& code_str,
1479 int modifiers,
1480 KeyLocationCode location) {
1481 // FIXME: I'm not exactly sure how we should convert the string to a key
1482 // event. This seems to work in the cases I tested.
1483 // FIXME: Should we also generate a KEY_UP?
1484
1485 bool generate_char = false;
1486
1487 // Convert \n -> VK_RETURN. Some layout tests use \n to mean "Enter", when
1488 // Windows uses \r for "Enter".
1489 int code = 0;
1490 int text = 0;
1491 bool needs_shift_key_modifier = false;
1492 std::string domKeyString;
1493 std::string domCodeString;
1494
1495 if ("Enter" == code_str) {
1496 generate_char = true;
1497 text = code = ui::VKEY_RETURN;
1498 domKeyString.assign("Enter");
1499 domCodeString.assign("Enter");
1500 } else if ("ArrowRight" == code_str) {
1501 code = ui::VKEY_RIGHT;
1502 domKeyString.assign("ArrowRight");
1503 domCodeString.assign("ArrowRight");
1504 } else if ("ArrowDown" == code_str) {
1505 code = ui::VKEY_DOWN;
1506 domKeyString.assign("ArrowDown");
1507 domCodeString.assign("ArrowDown");
1508 } else if ("ArrowLeft" == code_str) {
1509 code = ui::VKEY_LEFT;
1510 domKeyString.assign("ArrowLeft");
1511 domCodeString.assign("ArrowLeft");
1512 } else if ("ArrowUp" == code_str) {
1513 code = ui::VKEY_UP;
1514 domKeyString.assign("ArrowUp");
1515 domCodeString.assign("ArrowUp");
1516 } else if ("Insert" == code_str) {
1517 code = ui::VKEY_INSERT;
1518 domKeyString.assign("Insert");
1519 domCodeString.assign("Insert");
1520 } else if ("Delete" == code_str) {
1521 code = ui::VKEY_DELETE;
1522 domKeyString.assign("Delete");
1523 domCodeString.assign("Delete");
1524 } else if ("PageUp" == code_str) {
1525 code = ui::VKEY_PRIOR;
1526 domKeyString.assign("PageUp");
1527 domCodeString.assign("PageUp");
1528 } else if ("PageDown" == code_str) {
1529 code = ui::VKEY_NEXT;
1530 domKeyString.assign("PageDown");
1531 domCodeString.assign("PageDown");
1532 } else if ("Home" == code_str) {
1533 code = ui::VKEY_HOME;
1534 domKeyString.assign("Home");
1535 domCodeString.assign("Home");
1536 } else if ("End" == code_str) {
1537 code = ui::VKEY_END;
1538 domKeyString.assign("End");
1539 domCodeString.assign("End");
1540 } else if ("PrintScreen" == code_str) {
1541 code = ui::VKEY_SNAPSHOT;
1542 domKeyString.assign("PrintScreen");
1543 domCodeString.assign("PrintScreen");
1544 } else if ("ContextMenu" == code_str) {
1545 code = ui::VKEY_APPS;
1546 domKeyString.assign("ContextMenu");
1547 domCodeString.assign("ContextMenu");
1548 } else if ("ControlLeft" == code_str) {
1549 code = ui::VKEY_CONTROL;
1550 domKeyString.assign("Control");
1551 domCodeString.assign("ControlLeft");
1552 location = DOMKeyLocationLeft;
1553 } else if ("ControlRight" == code_str) {
1554 code = ui::VKEY_CONTROL;
1555 domKeyString.assign("Control");
1556 domCodeString.assign("ControlRight");
1557 location = DOMKeyLocationRight;
1558 } else if ("ShiftLeft" == code_str) {
1559 code = ui::VKEY_SHIFT;
1560 domKeyString.assign("Shift");
1561 domCodeString.assign("ShiftLeft");
1562 location = DOMKeyLocationLeft;
1563 } else if ("ShiftRight" == code_str) {
1564 code = ui::VKEY_SHIFT;
1565 domKeyString.assign("Shift");
1566 domCodeString.assign("ShiftRight");
1567 location = DOMKeyLocationRight;
1568 } else if ("AltLeft" == code_str) {
1569 code = ui::VKEY_MENU;
1570 domKeyString.assign("Alt");
1571 domCodeString.assign("AltLeft");
1572 location = DOMKeyLocationLeft;
1573 } else if ("AltRight" == code_str) {
1574 code = ui::VKEY_MENU;
1575 domKeyString.assign("Alt");
1576 domCodeString.assign("AltRight");
1577 location = DOMKeyLocationRight;
1578 } else if ("NumLock" == code_str) {
1579 code = ui::VKEY_NUMLOCK;
1580 domKeyString.assign("NumLock");
1581 domCodeString.assign("NumLock");
1582 } else if ("Backspace" == code_str) {
1583 code = ui::VKEY_BACK;
1584 domKeyString.assign("Backspace");
1585 domCodeString.assign("Backspace");
1586 } else if ("Escape" == code_str) {
1587 code = ui::VKEY_ESCAPE;
1588 domKeyString.assign("Escape");
1589 domCodeString.assign("Escape");
1590 } else if ("Tab" == code_str) {
1591 code = ui::VKEY_TAB;
1592 domKeyString.assign("Tab");
1593 domCodeString.assign("Tab");
1594 } else if ("Cut" == code_str || "Copy" == code_str || "Paste" == code_str) {
1595 // No valid KeyboardCode for Cut/Copy/Paste.
1596 code = 0;
1597 domKeyString.assign(code_str);
1598 // It's OK to assign the same string as the DomCode strings happens to be
1599 // the same for these keys.
1600 domCodeString.assign(code_str);
1601 } else {
1602 // Compare the input string with the function-key names defined by the
1603 // DOM spec (i.e. "F1",...,"F24"). If the input string is a function-key
1604 // name, set its key code.
1605 for (int i = 1; i <= 24; ++i) {
1606 std::string function_key_name = base::StringPrintf("F%d", i);
1607 if (function_key_name == code_str) {
1608 code = ui::VKEY_F1 + (i - 1);
1609 domKeyString = function_key_name;
1610 domCodeString = function_key_name;
1611 break;
1612 }
1613 }
1614 if (!code) {
1615 base::string16 code_str16 = base::UTF8ToUTF16(code_str);
1616 if (code_str16.size() != 1u) {
1617 v8::Isolate* isolate = blink::mainThreadIsolate();
1618 isolate->ThrowException(v8::Exception::TypeError(
1619 gin::StringToV8(isolate, "Invalid web code.")));
1620 return;
1621 }
1622 text = code = code_str16[0];
1623 needs_shift_key_modifier = base::IsAsciiUpper(code & 0xFF);
1624 if (base::IsAsciiLower(code & 0xFF))
1625 code -= 'a' - 'A';
1626 if (base::IsAsciiAlpha(code)) {
1627 domKeyString.assign(code_str);
1628 domCodeString.assign("Key");
1629 domCodeString.push_back(
1630 base::ToUpperASCII(static_cast<base::char16>(code)));
1631 } else if (base::IsAsciiDigit(code)) {
1632 domKeyString.assign(code_str);
1633 domCodeString.assign("Digit");
1634 domCodeString.push_back(code);
1635 } else if (code == ' ') {
1636 domKeyString.assign(code_str);
1637 domCodeString.assign("Space");
1638 } else if (code == 9) {
1639 domKeyString.assign("Tab");
1640 domCodeString.assign("Tab");
1641 }
1642 generate_char = true;
1643 }
1644
1645 if ("(" == code_str) {
1646 code = '9';
1647 needs_shift_key_modifier = true;
1648 domKeyString.assign("(");
1649 domCodeString.assign("Digit9");
1650 }
1651 }
1652
1653 if (needs_shift_key_modifier)
1654 modifiers |= WebInputEvent::ShiftKey;
1655
1656 // See if KeyLocation argument is given.
1657 switch (location) {
1658 case DOMKeyLocationStandard:
1659 break;
1660 case DOMKeyLocationLeft:
1661 modifiers |= WebInputEvent::IsLeft;
1662 break;
1663 case DOMKeyLocationRight:
1664 modifiers |= WebInputEvent::IsRight;
1665 break;
1666 case DOMKeyLocationNumpad:
1667 modifiers |= WebInputEvent::IsKeyPad;
1668 break;
1669 }
1670
1671 // For one generated keyboard event, we need to generate a keyDown/keyUp
1672 // pair;
1673 // On Windows, we might also need to generate a char event to mimic the
1674 // Windows event flow; on other platforms we create a merged event and test
1675 // the event flow that that platform provides.
1676 WebKeyboardEvent event_down(WebInputEvent::RawKeyDown, modifiers,
1677 GetCurrentEventTimeSec());
1678 event_down.windowsKeyCode = code;
1679 event_down.domKey = static_cast<int>(
1680 ui::KeycodeConverter::KeyStringToDomKey(domKeyString));
1681 event_down.domCode = static_cast<int>(
1682 ui::KeycodeConverter::CodeStringToDomCode(domCodeString));
1683
1684 if (generate_char) {
1685 event_down.text[0] = text;
1686 event_down.unmodifiedText[0] = text;
1687 }
1688
1689 if (event_down.modifiers() != 0)
1690 event_down.isSystemKey = IsSystemKeyEvent(event_down);
1691
1692 WebKeyboardEvent event_up = event_down;
1693 event_up.setType(WebInputEvent::KeyUp);
1694 // EventSender.m forces a layout here, with at least one
1695 // test (fast/forms/focus-control-to-page.html) relying on this.
1696 if (force_layout_on_events_)
1697 widget()->updateAllLifecyclePhases();
1698
1699 // In the browser, if a keyboard event corresponds to an editor command,
1700 // the command will be dispatched to the renderer just before dispatching
1701 // the keyboard event, and then it will be executed in the
1702 // RenderView::handleCurrentKeyboardEvent() method.
1703 // We just simulate the same behavior here.
1704 std::string edit_command;
1705 if (GetEditCommand(event_down, &edit_command))
1706 delegate()->SetEditCommand(edit_command, "");
1707
1708 HandleInputEventOnViewOrPopup(event_down);
1709
1710 if (code == ui::VKEY_ESCAPE && !current_drag_data_.isNull()) {
1711 WebMouseEvent event(WebInputEvent::MouseDown,
1712 ModifiersForPointer(kRawMousePointerId),
1713 GetCurrentEventTimeSec());
1714 InitMouseEvent(current_pointer_state_[kRawMousePointerId].pressed_button_,
1715 current_pointer_state_[kRawMousePointerId].current_buttons_,
1716 current_pointer_state_[kRawMousePointerId].last_pos_,
1717 click_count_, &event);
1718 FinishDragAndDrop(event, blink::WebDragOperationNone);
1719 }
1720
1721 delegate()->ClearEditCommand();
1722
1723 if (generate_char) {
1724 WebKeyboardEvent event_char = event_up;
1725 event_char.setType(WebInputEvent::Char);
1726 HandleInputEventOnViewOrPopup(event_char);
1727 }
1728
1729 HandleInputEventOnViewOrPopup(event_up);
1730 }
1731
1732 void EventSender::EnableDOMUIEventLogging() {}
1733
1734 void EventSender::FireKeyboardEventsToElement() {}
1735
1736 void EventSender::ClearKillRing() {}
1737
1738 std::vector<std::string> EventSender::ContextClick() {
1739 if (force_layout_on_events_)
1740 widget()->updateAllLifecyclePhases();
1741
1742 UpdateClickCountForButton(WebMouseEvent::Button::Right);
1743
1744 // Clears last context menu data because we need to know if the context menu
1745 // be requested after following mouse events.
1746 last_context_menu_data_.reset();
1747
1748 // Generate right mouse down and up.
1749 // This is a hack to work around only allowing a single pressed button since
1750 // we want to test the case where both the left and right mouse buttons are
1751 // pressed.
1752 // TODO(mustaq): This hack seems unused here! But do we need this hack at all
1753 // after adding current_buttons_.
1754 if (current_pointer_state_[kRawMousePointerId].pressed_button_ ==
1755 WebMouseEvent::Button::NoButton) {
1756 current_pointer_state_[kRawMousePointerId].pressed_button_ =
1757 WebMouseEvent::Button::Right;
1758 current_pointer_state_[kRawMousePointerId].current_buttons_ |=
1759 GetWebMouseEventModifierForButton(
1760 current_pointer_state_[kRawMousePointerId].pressed_button_);
1761 }
1762 WebMouseEvent event(WebInputEvent::MouseDown,
1763 ModifiersForPointer(kRawMousePointerId),
1764 GetCurrentEventTimeSec());
1765 InitMouseEvent(WebMouseEvent::Button::Right,
1766 current_pointer_state_[kRawMousePointerId].current_buttons_,
1767 current_pointer_state_[kRawMousePointerId].last_pos_,
1768 click_count_, &event);
1769 HandleInputEventOnViewOrPopup(event);
1770
1771 #if defined(OS_WIN)
1772 current_pointer_state_[kRawMousePointerId].current_buttons_ &=
1773 ~GetWebMouseEventModifierForButton(WebMouseEvent::Button::Right);
1774 current_pointer_state_[kRawMousePointerId].pressed_button_ =
1775 WebMouseEvent::Button::NoButton;
1776
1777 WebMouseEvent mouseUpEvent(WebInputEvent::MouseUp,
1778 ModifiersForPointer(kRawMousePointerId),
1779 GetCurrentEventTimeSec());
1780 InitMouseEvent(WebMouseEvent::Button::Right,
1781 current_pointer_state_[kRawMousePointerId].current_buttons_,
1782 current_pointer_state_[kRawMousePointerId].last_pos_,
1783 click_count_, &mouseUpEvent);
1784 HandleInputEventOnViewOrPopup(mouseUpEvent);
1785 #endif
1786
1787 std::vector<std::string> menu_items =
1788 MakeMenuItemStringsFor(last_context_menu_data_.get(), delegate());
1789 last_context_menu_data_.reset();
1790 return menu_items;
1791 }
1792
1793 void EventSender::TextZoomIn() {
1794 view()->setTextZoomFactor(view()->textZoomFactor() * 1.2f);
1795 }
1796
1797 void EventSender::TextZoomOut() {
1798 view()->setTextZoomFactor(view()->textZoomFactor() / 1.2f);
1799 }
1800
1801 void EventSender::ZoomPageIn() {
1802 const std::vector<WebViewTestProxyBase*>& window_list =
1803 interfaces()->GetWindowList();
1804
1805 for (size_t i = 0; i < window_list.size(); ++i) {
1806 window_list.at(i)->web_view()->setZoomLevel(
1807 window_list.at(i)->web_view()->zoomLevel() + 1);
1808 }
1809 }
1810
1811 void EventSender::ZoomPageOut() {
1812 const std::vector<WebViewTestProxyBase*>& window_list =
1813 interfaces()->GetWindowList();
1814
1815 for (size_t i = 0; i < window_list.size(); ++i) {
1816 window_list.at(i)->web_view()->setZoomLevel(
1817 window_list.at(i)->web_view()->zoomLevel() - 1);
1818 }
1819 }
1820
1821 void EventSender::SetPageZoomFactor(double zoom_factor) {
1822 const std::vector<WebViewTestProxyBase*>& window_list =
1823 interfaces()->GetWindowList();
1824
1825 for (size_t i = 0; i < window_list.size(); ++i) {
1826 window_list.at(i)->web_view()->setZoomLevel(std::log(zoom_factor) /
1827 std::log(1.2));
1828 }
1829 }
1830
1831 void EventSender::ClearTouchPoints() {
1832 touch_points_.clear();
1833 }
1834
1835 void EventSender::ThrowTouchPointError() {
1836 v8::Isolate* isolate = blink::mainThreadIsolate();
1837 isolate->ThrowException(v8::Exception::TypeError(
1838 gin::StringToV8(isolate, "Invalid touch point.")));
1839 }
1840
1841 void EventSender::ReleaseTouchPoint(unsigned index) {
1842 if (index >= touch_points_.size()) {
1843 ThrowTouchPointError();
1844 return;
1845 }
1846
1847 WebTouchPoint* touch_point = &touch_points_[index];
1848 touch_point->state = WebTouchPoint::StateReleased;
1849 }
1850
1851 void EventSender::UpdateTouchPoint(unsigned index,
1852 float x,
1853 float y,
1854 gin::Arguments* args) {
1855 if (index >= touch_points_.size()) {
1856 ThrowTouchPointError();
1857 return;
1858 }
1859
1860 WebTouchPoint* touch_point = &touch_points_[index];
1861 touch_point->state = WebTouchPoint::StateMoved;
1862 touch_point->position = WebFloatPoint(x, y);
1863 touch_point->screenPosition = touch_point->position;
1864
1865 InitPointerProperties(args, touch_point, &touch_point->radiusX,
1866 &touch_point->radiusY);
1867 }
1868
1869 void EventSender::CancelTouchPoint(unsigned index) {
1870 if (index >= touch_points_.size()) {
1871 ThrowTouchPointError();
1872 return;
1873 }
1874
1875 WebTouchPoint* touch_point = &touch_points_[index];
1876 touch_point->state = WebTouchPoint::StateCancelled;
1877 }
1878
1879 void EventSender::SetTouchModifier(const std::string& key_name,
1880 bool set_mask) {
1881 int mask = GetKeyModifier(key_name);
1882
1883 if (set_mask)
1884 touch_modifiers_ |= mask;
1885 else
1886 touch_modifiers_ &= ~mask;
1887 }
1888
1889 void EventSender::SetTouchCancelable(bool cancelable) {
1890 touch_cancelable_ = cancelable;
1891 }
1892
1893 void EventSender::DumpFilenameBeingDragged() {
1894 if (current_drag_data_.isNull())
1895 return;
1896
1897 WebVector<WebDragData::Item> items = current_drag_data_.items();
1898 for (size_t i = 0; i < items.size(); ++i) {
1899 if (items[i].storageType == WebDragData::Item::StorageTypeBinaryData) {
1900 WebURL url = items[i].binaryDataSourceURL;
1901 WebString filename_extension = items[i].binaryDataFilenameExtension;
1902 WebString content_disposition = items[i].binaryDataContentDisposition;
1903 base::FilePath filename =
1904 net::GenerateFileName(url, content_disposition.utf8(),
1905 std::string(), // referrer_charset
1906 std::string(), // suggested_name
1907 std::string(), // mime_type
1908 std::string()); // default_name
1909 #if defined(OS_WIN)
1910 filename = filename.ReplaceExtension(filename_extension.utf16());
1911 #else
1912 filename = filename.ReplaceExtension(filename_extension.utf8());
1913 #endif
1914 delegate()->PrintMessage(std::string("Filename being dragged: ") +
1915 filename.AsUTF8Unsafe() + "\n");
1916 return;
1917 }
1918 }
1919 }
1920
1921 void EventSender::GestureFlingCancel() {
1922 WebGestureEvent event(WebInputEvent::GestureFlingCancel,
1923 WebInputEvent::NoModifiers, GetCurrentEventTimeSec());
1924 // Generally it won't matter what device we use here, and since it might
1925 // be cumbersome to expect all callers to specify a device, we'll just
1926 // choose Touchpad here.
1927 event.sourceDevice = blink::WebGestureDeviceTouchpad;
1928
1929 if (force_layout_on_events_)
1930 widget()->updateAllLifecyclePhases();
1931
1932 HandleInputEventOnViewOrPopup(event);
1933 }
1934
1935 void EventSender::GestureFlingStart(float x,
1936 float y,
1937 float velocity_x,
1938 float velocity_y,
1939 gin::Arguments* args) {
1940 WebGestureEvent event(WebInputEvent::GestureFlingStart,
1941 WebInputEvent::NoModifiers, GetCurrentEventTimeSec());
1942
1943 std::string device_string;
1944 if (!args->PeekNext().IsEmpty() && args->PeekNext()->IsString())
1945 args->GetNext(&device_string);
1946
1947 if (device_string == kSourceDeviceStringTouchpad) {
1948 event.sourceDevice = blink::WebGestureDeviceTouchpad;
1949 } else if (device_string == kSourceDeviceStringTouchscreen) {
1950 event.sourceDevice = blink::WebGestureDeviceTouchscreen;
1951 } else {
1952 args->ThrowError();
1953 return;
1954 }
1955
1956 float max_start_velocity = std::max(fabs(velocity_x), fabs(velocity_y));
1957 if (!max_start_velocity) {
1958 v8::Isolate* isolate = blink::mainThreadIsolate();
1959 isolate->ThrowException(v8::Exception::TypeError(
1960 gin::StringToV8(isolate, "Invalid max start velocity.")));
1961 return;
1962 }
1963
1964 event.x = x;
1965 event.y = y;
1966 event.globalX = event.x;
1967 event.globalY = event.y;
1968
1969 event.data.flingStart.velocityX = velocity_x;
1970 event.data.flingStart.velocityY = velocity_y;
1971
1972 if (force_layout_on_events_)
1973 widget()->updateAllLifecyclePhases();
1974
1975 HandleInputEventOnViewOrPopup(event);
1976 }
1977
1978 bool EventSender::IsFlinging() const {
1979 return view()->isFlinging();
1980 }
1981
1982 void EventSender::GestureScrollFirstPoint(int x, int y) {
1983 current_gesture_location_ = WebPoint(x, y);
1984 }
1985
1986 void EventSender::TouchStart(gin::Arguments* args) {
1987 SendCurrentTouchEvent(WebInputEvent::TouchStart, args);
1988 }
1989
1990 void EventSender::TouchMove(gin::Arguments* args) {
1991 SendCurrentTouchEvent(WebInputEvent::TouchMove, args);
1992 }
1993
1994 void EventSender::TouchCancel(gin::Arguments* args) {
1995 SendCurrentTouchEvent(WebInputEvent::TouchCancel, args);
1996 }
1997
1998 void EventSender::TouchEnd(gin::Arguments* args) {
1999 SendCurrentTouchEvent(WebInputEvent::TouchEnd, args);
2000 }
2001
2002 void EventSender::NotifyStartOfTouchScroll() {
2003 WebTouchEvent event(WebInputEvent::TouchScrollStarted,
2004 WebInputEvent::NoModifiers, GetCurrentEventTimeSec());
2005 HandleInputEventOnViewOrPopup(event);
2006 }
2007
2008 void EventSender::LeapForward(int milliseconds) {
2009 if (is_drag_mode_ &&
2010 current_pointer_state_[kRawMousePointerId].pressed_button_ ==
2011 WebMouseEvent::Button::Left &&
2012 !replaying_saved_events_) {
2013 SavedEvent saved_event;
2014 saved_event.type = SavedEvent::TYPE_LEAP_FORWARD;
2015 saved_event.milliseconds = milliseconds;
2016 mouse_event_queue_.push_back(saved_event);
2017 } else {
2018 DoLeapForward(milliseconds);
2019 }
2020 }
2021
2022 void EventSender::BeginDragWithFiles(const std::vector<std::string>& files) {
2023 if (!current_drag_data_.isNull()) {
2024 // Nested dragging not supported, fuzzer code a likely culprit.
2025 // Cancel the current drag operation and throw an error.
2026 KeyDown("Escape", 0, DOMKeyLocationStandard);
2027 v8::Isolate* isolate = blink::mainThreadIsolate();
2028 isolate->ThrowException(v8::Exception::Error(
2029 gin::StringToV8(isolate,
2030 "Nested beginDragWithFiles() not supported.")));
2031 return;
2032 }
2033 current_drag_data_.initialize();
2034 WebVector<WebString> absolute_filenames(files.size());
2035 for (size_t i = 0; i < files.size(); ++i) {
2036 WebDragData::Item item;
2037 item.storageType = WebDragData::Item::StorageTypeFilename;
2038 item.filenameData = delegate()->GetAbsoluteWebStringFromUTF8Path(files[i]);
2039 current_drag_data_.addItem(item);
2040 absolute_filenames[i] = item.filenameData;
2041 }
2042 current_drag_data_.setFilesystemId(
2043 delegate()->RegisterIsolatedFileSystem(absolute_filenames));
2044 current_drag_effects_allowed_ = blink::WebDragOperationCopy;
2045
2046 const WebPoint& last_pos =
2047 current_pointer_state_[kRawMousePointerId].last_pos_;
2048 float scale = delegate()->GetWindowToViewportScale();
2049 WebPoint scaled_last_pos(last_pos.x * scale, last_pos.y * scale);
2050
2051 // Provide a drag source.
2052 mainFrameWidget()->dragTargetDragEnter(
2053 current_drag_data_, scaled_last_pos, scaled_last_pos,
2054 current_drag_effects_allowed_, 0);
2055 // |is_drag_mode_| saves events and then replays them later. We don't
2056 // need/want that.
2057 is_drag_mode_ = false;
2058
2059 // Make the rest of eventSender think a drag is in progress.
2060 current_pointer_state_[kRawMousePointerId].pressed_button_ =
2061 WebMouseEvent::Button::Left;
2062 current_pointer_state_[kRawMousePointerId].current_buttons_ |=
2063 GetWebMouseEventModifierForButton(
2064 current_pointer_state_[kRawMousePointerId].pressed_button_);
2065 }
2066
2067 void EventSender::AddTouchPoint(float x, float y, gin::Arguments* args) {
2068 WebTouchPoint touch_point;
2069 touch_point.pointerType = WebPointerProperties::PointerType::Touch;
2070 touch_point.state = WebTouchPoint::StatePressed;
2071 touch_point.position = WebFloatPoint(x, y);
2072 touch_point.screenPosition = touch_point.position;
2073
2074 int highest_id = -1;
2075 for (size_t i = 0; i < touch_points_.size(); i++) {
2076 if (touch_points_[i].id > highest_id)
2077 highest_id = touch_points_[i].id;
2078 }
2079 touch_point.id = highest_id + 1;
2080
2081 InitPointerProperties(args, &touch_point, &touch_point.radiusX,
2082 &touch_point.radiusY);
2083
2084 // Set the touch point pressure to zero if it was not set by the caller
2085 if (std::isnan(touch_point.force))
2086 touch_point.force = 0.0;
2087
2088 touch_points_.push_back(touch_point);
2089 }
2090
2091 void EventSender::GestureScrollBegin(gin::Arguments* args) {
2092 GestureEvent(WebInputEvent::GestureScrollBegin, args);
2093 }
2094
2095 void EventSender::GestureScrollEnd(gin::Arguments* args) {
2096 GestureEvent(WebInputEvent::GestureScrollEnd, args);
2097 }
2098
2099 void EventSender::GestureScrollUpdate(gin::Arguments* args) {
2100 GestureEvent(WebInputEvent::GestureScrollUpdate, args);
2101 }
2102
2103 void EventSender::GesturePinchBegin(gin::Arguments* args) {
2104 GestureEvent(WebInputEvent::GesturePinchBegin, args);
2105 }
2106
2107 void EventSender::GesturePinchEnd(gin::Arguments* args) {
2108 GestureEvent(WebInputEvent::GesturePinchEnd, args);
2109 }
2110
2111 void EventSender::GesturePinchUpdate(gin::Arguments* args) {
2112 GestureEvent(WebInputEvent::GesturePinchUpdate, args);
2113 }
2114
2115 void EventSender::GestureTap(gin::Arguments* args) {
2116 GestureEvent(WebInputEvent::GestureTap, args);
2117 }
2118
2119 void EventSender::GestureTapDown(gin::Arguments* args) {
2120 GestureEvent(WebInputEvent::GestureTapDown, args);
2121 }
2122
2123 void EventSender::GestureShowPress(gin::Arguments* args) {
2124 GestureEvent(WebInputEvent::GestureShowPress, args);
2125 }
2126
2127 void EventSender::GestureTapCancel(gin::Arguments* args) {
2128 GestureEvent(WebInputEvent::GestureTapCancel, args);
2129 }
2130
2131 void EventSender::GestureLongPress(gin::Arguments* args) {
2132 GestureEvent(WebInputEvent::GestureLongPress, args);
2133 }
2134
2135 void EventSender::GestureLongTap(gin::Arguments* args) {
2136 GestureEvent(WebInputEvent::GestureLongTap, args);
2137 }
2138
2139 void EventSender::GestureTwoFingerTap(gin::Arguments* args) {
2140 GestureEvent(WebInputEvent::GestureTwoFingerTap, args);
2141 }
2142
2143 void EventSender::MouseScrollBy(gin::Arguments* args,
2144 MouseScrollType scroll_type) {
2145 // TODO(dtapuska): Gestures really should be sent by the MouseWheelEventQueue
2146 // class in the browser. But since the event doesn't propogate up into
2147 // the browser generate the events here. See crbug.com/596095.
2148 bool send_gestures = true;
2149 WebMouseWheelEvent wheel_event =
2150 GetMouseWheelEvent(args, scroll_type, &send_gestures);
2151 if (wheel_event.type() != WebInputEvent::Undefined &&
2152 HandleInputEventOnViewOrPopup(wheel_event) ==
2153 WebInputEventResult::NotHandled &&
2154 send_gestures) {
2155 SendGesturesForMouseWheelEvent(wheel_event);
2156 }
2157 }
2158
2159 void EventSender::MouseMoveTo(gin::Arguments* args) {
2160 if (force_layout_on_events_)
2161 widget()->updateAllLifecyclePhases();
2162
2163 double x;
2164 double y;
2165 if (!args->GetNext(&x) || !args->GetNext(&y)) {
2166 args->ThrowError();
2167 return;
2168 }
2169 WebPoint mouse_pos(static_cast<int>(x), static_cast<int>(y));
2170
2171 int modifiers = 0;
2172 if (!args->PeekNext().IsEmpty()) {
2173 modifiers = GetKeyModifiersFromV8(args->isolate(), args->PeekNext());
2174 args->Skip();
2175 }
2176
2177 WebPointerProperties::PointerType pointerType =
2178 WebPointerProperties::PointerType::Mouse;
2179 int pointerId = 0;
2180 float pressure = 0;
2181 int tiltX = 0;
2182 int tiltY = 0;
2183 if (!getMousePenPointerProperties(args, pointerType, pointerId, pressure,
2184 tiltX, tiltY))
2185 return;
2186
2187 if (pointerType == WebPointerProperties::PointerType::Mouse &&
2188 is_drag_mode_ && !replaying_saved_events_ &&
2189 current_pointer_state_[kRawMousePointerId].pressed_button_ ==
2190 WebMouseEvent::Button::Left) {
2191 SavedEvent saved_event;
2192 saved_event.type = SavedEvent::TYPE_MOUSE_MOVE;
2193 saved_event.pos = mouse_pos;
2194 saved_event.modifiers = modifiers;
2195 mouse_event_queue_.push_back(saved_event);
2196 } else {
2197 current_pointer_state_[pointerId].last_pos_ = mouse_pos;
2198 current_pointer_state_[pointerId].modifiers_ = modifiers;
2199 WebMouseEvent event(WebInputEvent::MouseMove,
2200 ModifiersForPointer(pointerId),
2201 GetCurrentEventTimeSec());
2202 int click_count = pointerType == WebPointerProperties::PointerType::Mouse
2203 ? click_count_
2204 : 0;
2205 InitMouseEventGeneric(
2206 current_pointer_state_[kRawMousePointerId].pressed_button_,
2207 current_pointer_state_[kRawMousePointerId].current_buttons_, mouse_pos,
2208 click_count, pointerType, pointerId, pressure, tiltX, tiltY, &event);
2209 HandleInputEventOnViewOrPopup(event);
2210 if (pointerType == WebPointerProperties::PointerType::Mouse)
2211 DoDragAfterMouseMove(event);
2212 }
2213 }
2214
2215 void EventSender::MouseLeave() {
2216 if (force_layout_on_events_)
2217 widget()->updateAllLifecyclePhases();
2218
2219 WebMouseEvent event(WebInputEvent::MouseLeave,
2220 ModifiersForPointer(kRawMousePointerId),
2221 GetCurrentEventTimeSec());
2222 InitMouseEvent(WebMouseEvent::Button::NoButton, 0,
2223 current_pointer_state_[kRawMousePointerId].last_pos_,
2224 click_count_, &event);
2225 HandleInputEventOnViewOrPopup(event);
2226 }
2227
2228
2229 void EventSender::ScheduleAsynchronousClick(int button_number, int modifiers) {
2230 delegate()->PostTask(base::Bind(&EventSender::MouseDown,
2231 weak_factory_.GetWeakPtr(), button_number,
2232 modifiers));
2233 delegate()->PostTask(base::Bind(&EventSender::MouseUp,
2234 weak_factory_.GetWeakPtr(), button_number,
2235 modifiers));
2236 }
2237
2238 void EventSender::ScheduleAsynchronousKeyDown(const std::string& code_str,
2239 int modifiers,
2240 KeyLocationCode location) {
2241 delegate()->PostTask(base::Bind(&EventSender::KeyDown,
2242 weak_factory_.GetWeakPtr(), code_str,
2243 modifiers, location));
2244 }
2245
2246 double EventSender::GetCurrentEventTimeSec() {
2247 return (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF() +
2248 time_offset_ms_ / 1000.0;
2249 }
2250
2251 void EventSender::DoLeapForward(int milliseconds) {
2252 time_offset_ms_ += milliseconds;
2253 }
2254
2255 uint32_t EventSender::GetUniqueTouchEventId(gin::Arguments* args) {
2256 uint32_t unique_touch_event_id;
2257 if(!args->PeekNext().IsEmpty() && args->GetNext(&unique_touch_event_id))
2258 return unique_touch_event_id;
2259
2260 return 0;
2261 }
2262
2263 void EventSender::SendCurrentTouchEvent(WebInputEvent::Type type,
2264 gin::Arguments* args) {
2265 uint32_t unique_touch_event_id = GetUniqueTouchEventId(args);
2266
2267 DCHECK_GT(static_cast<unsigned>(WebTouchEvent::kTouchesLengthCap),
2268 touch_points_.size());
2269 if (force_layout_on_events_)
2270 widget()->updateAllLifecyclePhases();
2271
2272 WebTouchEvent touch_event(type, touch_modifiers_, GetCurrentEventTimeSec());
2273 touch_event.dispatchType = touch_cancelable_
2274 ? WebInputEvent::Blocking
2275 : WebInputEvent::EventNonBlocking;
2276 touch_event.movedBeyondSlopRegion = true;
2277 touch_event.uniqueTouchEventId = unique_touch_event_id;
2278 touch_event.touchesLength = touch_points_.size();
2279 for (size_t i = 0; i < touch_points_.size(); ++i)
2280 touch_event.touches[i] = touch_points_[i];
2281 HandleInputEventOnViewOrPopup(touch_event);
2282
2283 for (size_t i = 0; i < touch_points_.size(); ++i) {
2284 WebTouchPoint* touch_point = &touch_points_[i];
2285 if (touch_point->state == WebTouchPoint::StateReleased
2286 || touch_point->state == WebTouchPoint::StateCancelled) {
2287 touch_points_.erase(touch_points_.begin() + i);
2288 --i;
2289 } else {
2290 touch_point->state = WebTouchPoint::StateStationary;
2291 }
2292 }
2293 }
2294
2295 void EventSender::GestureEvent(WebInputEvent::Type type,
2296 gin::Arguments* args) {
2297 WebGestureEvent event(type, WebInputEvent::NoModifiers,
2298 GetCurrentEventTimeSec());
2299
2300 // If the first argument is a string, it is to specify the device, otherwise
2301 // the device is assumed to be a touchscreen (since most tests were written
2302 // assuming this).
2303 event.sourceDevice = blink::WebGestureDeviceTouchscreen;
2304 if (!args->PeekNext().IsEmpty() && args->PeekNext()->IsString()) {
2305 std::string device_string;
2306 if (!args->GetNext(&device_string)) {
2307 args->ThrowError();
2308 return;
2309 }
2310 if (device_string == kSourceDeviceStringTouchpad) {
2311 event.sourceDevice = blink::WebGestureDeviceTouchpad;
2312 } else if (device_string == kSourceDeviceStringTouchscreen) {
2313 event.sourceDevice = blink::WebGestureDeviceTouchscreen;
2314 } else {
2315 args->ThrowError();
2316 return;
2317 }
2318 }
2319
2320 double x;
2321 double y;
2322 if (!args->GetNext(&x) || !args->GetNext(&y)) {
2323 args->ThrowError();
2324 return;
2325 }
2326
2327 switch (type) {
2328 case WebInputEvent::GestureScrollUpdate:
2329 {
2330 bool preventPropagation = false;
2331 if (!args->PeekNext().IsEmpty()) {
2332 if (!args->GetNext(&preventPropagation)) {
2333 args->ThrowError();
2334 return;
2335 }
2336 }
2337 if (!GetScrollUnits(args, &event.data.scrollUpdate.deltaUnits))
2338 return;
2339
2340 event.data.scrollUpdate.deltaX = static_cast<float>(x);
2341 event.data.scrollUpdate.deltaY = static_cast<float>(y);
2342 event.data.scrollUpdate.preventPropagation = preventPropagation;
2343 event.x = current_gesture_location_.x;
2344 event.y = current_gesture_location_.y;
2345 current_gesture_location_.x =
2346 current_gesture_location_.x + event.data.scrollUpdate.deltaX;
2347 current_gesture_location_.y =
2348 current_gesture_location_.y + event.data.scrollUpdate.deltaY;
2349 break;
2350 }
2351 case WebInputEvent::GestureScrollBegin:
2352 current_gesture_location_ = WebPoint(x, y);
2353 event.x = current_gesture_location_.x;
2354 event.y = current_gesture_location_.y;
2355 break;
2356 case WebInputEvent::GestureScrollEnd:
2357 case WebInputEvent::GestureFlingStart:
2358 event.x = current_gesture_location_.x;
2359 event.y = current_gesture_location_.y;
2360 break;
2361 case WebInputEvent::GesturePinchBegin:
2362 case WebInputEvent::GesturePinchEnd:
2363 current_gesture_location_ = WebPoint(x, y);
2364 event.x = current_gesture_location_.x;
2365 event.y = current_gesture_location_.y;
2366 break;
2367 case WebInputEvent::GesturePinchUpdate:
2368 {
2369 float scale = 1;
2370 if (!args->PeekNext().IsEmpty()) {
2371 if (!args->GetNext(&scale)) {
2372 args->ThrowError();
2373 return;
2374 }
2375 }
2376 event.data.pinchUpdate.scale = scale;
2377 current_gesture_location_ = WebPoint(x, y);
2378 event.x = current_gesture_location_.x;
2379 event.y = current_gesture_location_.y;
2380 break;
2381 }
2382 case WebInputEvent::GestureTap:
2383 {
2384 float tap_count = 1;
2385 float width = 30;
2386 float height = 30;
2387 if (!args->PeekNext().IsEmpty()) {
2388 if (!args->GetNext(&tap_count)) {
2389 args->ThrowError();
2390 return;
2391 }
2392 }
2393 if (!args->PeekNext().IsEmpty()) {
2394 if (!args->GetNext(&width)) {
2395 args->ThrowError();
2396 return;
2397 }
2398 }
2399 if (!args->PeekNext().IsEmpty()) {
2400 if (!args->GetNext(&height)) {
2401 args->ThrowError();
2402 return;
2403 }
2404 }
2405 event.data.tap.tapCount = tap_count;
2406 event.data.tap.width = width;
2407 event.data.tap.height = height;
2408 event.x = x;
2409 event.y = y;
2410 break;
2411 }
2412 case WebInputEvent::GestureTapUnconfirmed:
2413 if (!args->PeekNext().IsEmpty()) {
2414 float tap_count;
2415 if (!args->GetNext(&tap_count)) {
2416 args->ThrowError();
2417 return;
2418 }
2419 event.data.tap.tapCount = tap_count;
2420 } else {
2421 event.data.tap.tapCount = 1;
2422 }
2423 event.x = x;
2424 event.y = y;
2425 break;
2426 case WebInputEvent::GestureTapDown:
2427 {
2428 float width = 30;
2429 float height = 30;
2430 if (!args->PeekNext().IsEmpty()) {
2431 if (!args->GetNext(&width)) {
2432 args->ThrowError();
2433 return;
2434 }
2435 }
2436 if (!args->PeekNext().IsEmpty()) {
2437 if (!args->GetNext(&height)) {
2438 args->ThrowError();
2439 return;
2440 }
2441 }
2442 event.x = x;
2443 event.y = y;
2444 event.data.tapDown.width = width;
2445 event.data.tapDown.height = height;
2446 break;
2447 }
2448 case WebInputEvent::GestureShowPress:
2449 {
2450 float width = 30;
2451 float height = 30;
2452 if (!args->PeekNext().IsEmpty()) {
2453 if (!args->GetNext(&width)) {
2454 args->ThrowError();
2455 return;
2456 }
2457 if (!args->PeekNext().IsEmpty()) {
2458 if (!args->GetNext(&height)) {
2459 args->ThrowError();
2460 return;
2461 }
2462 }
2463 }
2464 event.x = x;
2465 event.y = y;
2466 event.data.showPress.width = width;
2467 event.data.showPress.height = height;
2468 break;
2469 }
2470 case WebInputEvent::GestureTapCancel:
2471 event.x = x;
2472 event.y = y;
2473 break;
2474 case WebInputEvent::GestureLongPress:
2475 case WebInputEvent::GestureLongTap:
2476 event.x = x;
2477 event.y = y;
2478 if (!args->PeekNext().IsEmpty()) {
2479 float width;
2480 if (!args->GetNext(&width)) {
2481 args->ThrowError();
2482 return;
2483 }
2484 event.data.longPress.width = width;
2485 if (!args->PeekNext().IsEmpty()) {
2486 float height;
2487 if (!args->GetNext(&height)) {
2488 args->ThrowError();
2489 return;
2490 }
2491 event.data.longPress.height = height;
2492 }
2493 }
2494 break;
2495 case WebInputEvent::GestureTwoFingerTap:
2496 event.x = x;
2497 event.y = y;
2498 if (!args->PeekNext().IsEmpty()) {
2499 float first_finger_width;
2500 if (!args->GetNext(&first_finger_width)) {
2501 args->ThrowError();
2502 return;
2503 }
2504 event.data.twoFingerTap.firstFingerWidth = first_finger_width;
2505 if (!args->PeekNext().IsEmpty()) {
2506 float first_finger_height;
2507 if (!args->GetNext(&first_finger_height)) {
2508 args->ThrowError();
2509 return;
2510 }
2511 event.data.twoFingerTap.firstFingerHeight = first_finger_height;
2512 }
2513 }
2514 break;
2515 default:
2516 NOTREACHED();
2517 }
2518
2519 event.uniqueTouchEventId = GetUniqueTouchEventId(args);
2520
2521 event.globalX = event.x;
2522 event.globalY = event.y;
2523
2524 if (force_layout_on_events_)
2525 widget()->updateAllLifecyclePhases();
2526
2527 WebInputEventResult result = HandleInputEventOnViewOrPopup(event);
2528
2529 // Long press might start a drag drop session. Complete it if so.
2530 if (type == WebInputEvent::GestureLongPress && !current_drag_data_.isNull()) {
2531 WebMouseEvent mouse_event(WebInputEvent::MouseDown,
2532 ModifiersForPointer(kRawMousePointerId),
2533 GetCurrentEventTimeSec());
2534
2535 InitMouseEvent(current_pointer_state_[kRawMousePointerId].pressed_button_,
2536 current_pointer_state_[kRawMousePointerId].current_buttons_,
2537 WebPoint(x, y), click_count_, &mouse_event);
2538
2539 FinishDragAndDrop(mouse_event, blink::WebDragOperationNone);
2540 }
2541 args->Return(result != WebInputEventResult::NotHandled);
2542 }
2543
2544 void EventSender::UpdateClickCountForButton(
2545 WebMouseEvent::Button button_type) {
2546 if ((GetCurrentEventTimeSec() - last_click_time_sec_ <
2547 kMultipleClickTimeSec) &&
2548 (!OutsideMultiClickRadius(
2549 current_pointer_state_[kRawMousePointerId].last_pos_,
2550 last_click_pos_)) &&
2551 (button_type == last_button_type_)) {
2552 ++click_count_;
2553 } else {
2554 click_count_ = 1;
2555 last_button_type_ = button_type;
2556 }
2557 }
2558
2559 WebMouseWheelEvent EventSender::GetMouseWheelEvent(gin::Arguments* args,
2560 MouseScrollType scroll_type,
2561 bool* send_gestures) {
2562 // Force a layout here just to make sure every position has been
2563 // determined before we send events (as well as all the other methods
2564 // that send an event do).
2565 if (force_layout_on_events_)
2566 widget()->updateAllLifecyclePhases();
2567
2568 double horizontal;
2569 double vertical;
2570 if (!args->GetNext(&horizontal) || !args->GetNext(&vertical)) {
2571 args->ThrowError();
2572 return WebMouseWheelEvent();
2573 }
2574
2575 bool paged = false;
2576 bool has_precise_scrolling_deltas = false;
2577 int modifiers = 0;
2578 WebMouseWheelEvent::Phase phase = WebMouseWheelEvent::PhaseNone;
2579 if (!args->PeekNext().IsEmpty()) {
2580 args->GetNext(&paged);
2581 if (!args->PeekNext().IsEmpty()) {
2582 args->GetNext(&has_precise_scrolling_deltas);
2583 if (!args->PeekNext().IsEmpty()) {
2584 v8::Local<v8::Value> value;
2585 args->GetNext(&value);
2586 modifiers = GetKeyModifiersFromV8(args->isolate(), value);
2587 if (!args->PeekNext().IsEmpty()) {
2588 args->GetNext(send_gestures);
2589 if (!args->PeekNext().IsEmpty()) {
2590 v8::Local<v8::Value> phase_value;
2591 args->GetNext(&phase_value);
2592 phase = GetMouseWheelEventPhaseFromV8(phase_value);
2593 }
2594 }
2595 }
2596 }
2597 }
2598
2599 current_pointer_state_[kRawMousePointerId].modifiers_ = modifiers;
2600 WebMouseWheelEvent event(WebInputEvent::MouseWheel,
2601 ModifiersForPointer(kRawMousePointerId),
2602 GetCurrentEventTimeSec());
2603 InitMouseEvent(current_pointer_state_[kRawMousePointerId].pressed_button_,
2604 current_pointer_state_[kRawMousePointerId].current_buttons_,
2605 current_pointer_state_[kRawMousePointerId].last_pos_,
2606 click_count_, &event);
2607 event.wheelTicksX = static_cast<float>(horizontal);
2608 event.wheelTicksY = static_cast<float>(vertical);
2609 event.deltaX = event.wheelTicksX;
2610 event.deltaY = event.wheelTicksY;
2611 event.scrollByPage = paged;
2612 event.hasPreciseScrollingDeltas = has_precise_scrolling_deltas;
2613 event.phase = phase;
2614 if (scroll_type == MouseScrollType::PIXEL) {
2615 event.wheelTicksX /= kScrollbarPixelsPerTick;
2616 event.wheelTicksY /= kScrollbarPixelsPerTick;
2617 } else {
2618 event.deltaX *= kScrollbarPixelsPerTick;
2619 event.deltaY *= kScrollbarPixelsPerTick;
2620 }
2621 return event;
2622 }
2623
2624 // Radius fields radius_x and radius_y should eventually be moved to
2625 // WebPointerProperties.
2626 // TODO(e_hakkinen): Drop radius_{x,y}_pointer parameters once that happens.
2627 void EventSender::InitPointerProperties(gin::Arguments* args,
2628 WebPointerProperties* e,
2629 float* radius_x_pointer,
2630 float* radius_y_pointer) {
2631 if (!args->PeekNext().IsEmpty()) {
2632 double radius_x;
2633 if (!args->GetNext(&radius_x)) {
2634 args->ThrowError();
2635 return;
2636 }
2637
2638 double radius_y = radius_x;
2639 if (!args->PeekNext().IsEmpty()) {
2640 if (!args->GetNext(&radius_y)) {
2641 args->ThrowError();
2642 return;
2643 }
2644 }
2645
2646 *radius_x_pointer = static_cast<float>(radius_x);
2647 *radius_y_pointer = static_cast<float>(radius_y);
2648 }
2649
2650 if (!args->PeekNext().IsEmpty()) {
2651 double force;
2652 if (!args->GetNext(&force)) {
2653 args->ThrowError();
2654 return;
2655 }
2656 e->force = static_cast<float>(force);
2657 }
2658
2659 if (!args->PeekNext().IsEmpty()) {
2660 int tiltX, tiltY;
2661 if (!args->GetNext(&tiltX) || !args->GetNext(&tiltY)) {
2662 args->ThrowError();
2663 return;
2664 }
2665 e->tiltX = tiltX;
2666 e->tiltY = tiltY;
2667 }
2668
2669 if (!getPointerType(args, false, e->pointerType))
2670 return;
2671 }
2672
2673 void EventSender::FinishDragAndDrop(const WebMouseEvent& raw_event,
2674 blink::WebDragOperation drag_effect) {
2675 std::unique_ptr<WebInputEvent> widget_event =
2676 TransformScreenToWidgetCoordinates(raw_event);
2677 const WebMouseEvent* event =
2678 widget_event.get() ? static_cast<WebMouseEvent*>(widget_event.get())
2679 : &raw_event;
2680
2681 WebPoint client_point(event->x, event->y);
2682 WebPoint screen_point(event->globalX, event->globalY);
2683 current_drag_effect_ = drag_effect;
2684 if (current_drag_effect_) {
2685 // Specifically pass any keyboard modifiers to the drop method. This allows
2686 // tests to control the drop type (i.e. copy or move).
2687 mainFrameWidget()->dragTargetDrop(current_drag_data_, client_point,
2688 screen_point, event->modifiers());
2689 } else {
2690 mainFrameWidget()->dragTargetDragLeave(blink::WebPoint(),
2691 blink::WebPoint());
2692 }
2693 current_drag_data_.reset();
2694 mainFrameWidget()->dragSourceEndedAt(client_point, screen_point,
2695 current_drag_effect_);
2696 mainFrameWidget()->dragSourceSystemDragEnded();
2697 }
2698
2699 void EventSender::DoDragAfterMouseUp(const WebMouseEvent& raw_event) {
2700 std::unique_ptr<WebInputEvent> widget_event =
2701 TransformScreenToWidgetCoordinates(raw_event);
2702 const WebMouseEvent* event =
2703 widget_event.get() ? static_cast<WebMouseEvent*>(widget_event.get())
2704 : &raw_event;
2705
2706 last_click_time_sec_ = event->timeStampSeconds();
2707 last_click_pos_ = current_pointer_state_[kRawMousePointerId].last_pos_;
2708
2709 // If we're in a drag operation, complete it.
2710 if (current_drag_data_.isNull())
2711 return;
2712
2713 WebPoint client_point(event->x, event->y);
2714 WebPoint screen_point(event->globalX, event->globalY);
2715 blink::WebDragOperation drag_effect = mainFrameWidget()->dragTargetDragOver(
2716 client_point, screen_point, current_drag_effects_allowed_,
2717 event->modifiers());
2718
2719 // Bail if dragover caused cancellation.
2720 if (current_drag_data_.isNull())
2721 return;
2722
2723 FinishDragAndDrop(raw_event, drag_effect);
2724 }
2725
2726 void EventSender::DoDragAfterMouseMove(const WebMouseEvent& raw_event) {
2727 if (current_pointer_state_[kRawMousePointerId].pressed_button_ ==
2728 WebMouseEvent::Button::NoButton ||
2729 current_drag_data_.isNull()) {
2730 return;
2731 }
2732
2733 std::unique_ptr<WebInputEvent> widget_event =
2734 TransformScreenToWidgetCoordinates(raw_event);
2735 const WebMouseEvent* event =
2736 widget_event.get() ? static_cast<WebMouseEvent*>(widget_event.get())
2737 : &raw_event;
2738
2739 WebPoint client_point(event->x, event->y);
2740 WebPoint screen_point(event->globalX, event->globalY);
2741 current_drag_effect_ = mainFrameWidget()->dragTargetDragOver(
2742 client_point, screen_point, current_drag_effects_allowed_,
2743 event->modifiers());
2744 }
2745
2746 void EventSender::ReplaySavedEvents() {
2747 replaying_saved_events_ = true;
2748 while (!mouse_event_queue_.empty()) {
2749 SavedEvent e = mouse_event_queue_.front();
2750 mouse_event_queue_.pop_front();
2751
2752 switch (e.type) {
2753 case SavedEvent::TYPE_MOUSE_MOVE: {
2754 current_pointer_state_[kRawMousePointerId].modifiers_ = e.modifiers;
2755 WebMouseEvent event(WebInputEvent::MouseMove,
2756 ModifiersForPointer(kRawMousePointerId),
2757 GetCurrentEventTimeSec());
2758 InitMouseEvent(
2759 current_pointer_state_[kRawMousePointerId].pressed_button_,
2760 current_pointer_state_[kRawMousePointerId].current_buttons_, e.pos,
2761 click_count_, &event);
2762 current_pointer_state_[kRawMousePointerId].last_pos_ =
2763 WebPoint(event.x, event.y);
2764 HandleInputEventOnViewOrPopup(event);
2765 DoDragAfterMouseMove(event);
2766 break;
2767 }
2768 case SavedEvent::TYPE_LEAP_FORWARD:
2769 DoLeapForward(e.milliseconds);
2770 break;
2771 case SavedEvent::TYPE_MOUSE_UP: {
2772 current_pointer_state_[kRawMousePointerId].current_buttons_ &=
2773 ~GetWebMouseEventModifierForButton(e.button_type);
2774 current_pointer_state_[kRawMousePointerId].pressed_button_ =
2775 WebMouseEvent::Button::NoButton;
2776 current_pointer_state_[kRawMousePointerId].modifiers_ = e.modifiers;
2777
2778 WebMouseEvent event(WebInputEvent::MouseUp,
2779 ModifiersForPointer(kRawMousePointerId),
2780 GetCurrentEventTimeSec());
2781 InitMouseEvent(
2782 e.button_type,
2783 current_pointer_state_[kRawMousePointerId].current_buttons_,
2784 current_pointer_state_[kRawMousePointerId].last_pos_, click_count_,
2785 &event);
2786 HandleInputEventOnViewOrPopup(event);
2787 DoDragAfterMouseUp(event);
2788 break;
2789 }
2790 default:
2791 NOTREACHED();
2792 }
2793 }
2794
2795 replaying_saved_events_ = false;
2796 }
2797
2798 WebInputEventResult EventSender::HandleInputEventOnViewOrPopup(
2799 const WebInputEvent& raw_event) {
2800 last_event_timestamp_ = raw_event.timeStampSeconds();
2801
2802 WebPagePopup* popup = widget()->pagePopup();
2803 if (popup && !WebInputEvent::isKeyboardEventType(raw_event.type())) {
2804 // ui::ScaleWebInputEvent returns nullptr when the scale is 1.0f as the
2805 // event does not have to be converted.
2806 std::unique_ptr<WebInputEvent> scaled_event = ui::ScaleWebInputEvent(
2807 raw_event, delegate()->GetWindowToViewportScale());
2808 const WebInputEvent* popup_friendly_event =
2809 scaled_event.get() ? scaled_event.get() : &raw_event;
2810 return popup->handleInputEvent(
2811 blink::WebCoalescedInputEvent(*popup_friendly_event));
2812 }
2813
2814 std::unique_ptr<WebInputEvent> widget_event =
2815 TransformScreenToWidgetCoordinates(raw_event);
2816 const WebInputEvent* event =
2817 widget_event.get() ? static_cast<WebMouseEvent*>(widget_event.get())
2818 : &raw_event;
2819 return widget()->handleInputEvent(blink::WebCoalescedInputEvent(*event));
2820 }
2821
2822 void EventSender::SendGesturesForMouseWheelEvent(
2823 const WebMouseWheelEvent wheel_event) {
2824 WebGestureEvent begin_event(WebInputEvent::GestureScrollBegin,
2825 wheel_event.modifiers(),
2826 GetCurrentEventTimeSec());
2827 InitGestureEventFromMouseWheel(wheel_event, &begin_event);
2828 begin_event.data.scrollBegin.deltaXHint = wheel_event.deltaX;
2829 begin_event.data.scrollBegin.deltaYHint = wheel_event.deltaY;
2830 if (wheel_event.scrollByPage) {
2831 begin_event.data.scrollBegin.deltaHintUnits = blink::WebGestureEvent::Page;
2832 if (begin_event.data.scrollBegin.deltaXHint) {
2833 begin_event.data.scrollBegin.deltaXHint =
2834 begin_event.data.scrollBegin.deltaXHint > 0 ? 1 : -1;
2835 }
2836 if (begin_event.data.scrollBegin.deltaYHint) {
2837 begin_event.data.scrollBegin.deltaYHint =
2838 begin_event.data.scrollBegin.deltaYHint > 0 ? 1 : -1;
2839 }
2840 } else {
2841 begin_event.data.scrollBegin.deltaHintUnits =
2842 wheel_event.hasPreciseScrollingDeltas
2843 ? blink::WebGestureEvent::PrecisePixels
2844 : blink::WebGestureEvent::Pixels;
2845 }
2846
2847 if (force_layout_on_events_)
2848 widget()->updateAllLifecyclePhases();
2849
2850 HandleInputEventOnViewOrPopup(begin_event);
2851
2852 WebGestureEvent update_event(WebInputEvent::GestureScrollUpdate,
2853 wheel_event.modifiers(),
2854 GetCurrentEventTimeSec());
2855 InitGestureEventFromMouseWheel(wheel_event, &update_event);
2856 update_event.data.scrollUpdate.deltaX =
2857 begin_event.data.scrollBegin.deltaXHint;
2858 update_event.data.scrollUpdate.deltaY =
2859 begin_event.data.scrollBegin.deltaYHint;
2860 update_event.data.scrollUpdate.deltaUnits =
2861 begin_event.data.scrollBegin.deltaHintUnits;
2862
2863 if (force_layout_on_events_)
2864 widget()->updateAllLifecyclePhases();
2865 HandleInputEventOnViewOrPopup(update_event);
2866
2867 WebGestureEvent end_event(WebInputEvent::GestureScrollEnd,
2868 wheel_event.modifiers(), GetCurrentEventTimeSec());
2869 InitGestureEventFromMouseWheel(wheel_event, &end_event);
2870 end_event.data.scrollEnd.deltaUnits =
2871 begin_event.data.scrollBegin.deltaHintUnits;
2872
2873 if (force_layout_on_events_)
2874 widget()->updateAllLifecyclePhases();
2875 HandleInputEventOnViewOrPopup(end_event);
2876 }
2877
2878 TestInterfaces* EventSender::interfaces() {
2879 return web_widget_test_proxy_base_->web_view_test_proxy_base()
2880 ->test_interfaces();
2881 }
2882
2883 WebTestDelegate* EventSender::delegate() {
2884 return web_widget_test_proxy_base_->web_view_test_proxy_base()->delegate();
2885 }
2886
2887 const blink::WebView* EventSender::view() const {
2888 return web_widget_test_proxy_base_->web_view_test_proxy_base()->web_view();
2889 }
2890
2891 blink::WebView* EventSender::view() {
2892 return web_widget_test_proxy_base_->web_view_test_proxy_base()->web_view();
2893 }
2894
2895 blink::WebWidget* EventSender::widget() {
2896 return web_widget_test_proxy_base_->web_widget();
2897 }
2898
2899 blink::WebFrameWidget* EventSender::mainFrameWidget() {
2900 return view()->mainFrame()->toWebLocalFrame()->frameWidget();
2901 }
2902
2903 std::unique_ptr<WebInputEvent> EventSender::TransformScreenToWidgetCoordinates(
2904 const WebInputEvent& event) {
2905 return delegate()->TransformScreenToWidgetCoordinates(
2906 web_widget_test_proxy_base_, event);
2907 }
2908
2909 } // namespace test_runner
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698