Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / shell / renderer / test_runner / event_sender.cc
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 "content/shell/renderer/test_runner/event_sender.h"
6
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "base/strings/stringprintf.h"
10 #include "content/public/common/page_zoom.h"
11 #include "content/shell/renderer/test_runner/mock_spell_check.h"
12 #include "content/shell/renderer/test_runner/test_interfaces.h"
13 #include "content/shell/renderer/test_runner/web_test_delegate.h"
14 #include "content/shell/renderer/test_runner/web_test_proxy.h"
15 #include "gin/handle.h"
16 #include "gin/object_template_builder.h"
17 #include "gin/wrappable.h"
18 #include "third_party/WebKit/public/platform/WebString.h"
19 #include "third_party/WebKit/public/platform/WebVector.h"
20 #include "third_party/WebKit/public/web/WebContextMenuData.h"
21 #include "third_party/WebKit/public/web/WebFrame.h"
22 #include "third_party/WebKit/public/web/WebKit.h"
23 #include "third_party/WebKit/public/web/WebView.h"
24 #include "ui/events/keycodes/keyboard_codes.h"
25 #include "v8/include/v8.h"
26
27 using blink::WebContextMenuData;
28 using blink::WebDragData;
29 using blink::WebDragOperationsMask;
30 using blink::WebFloatPoint;
31 using blink::WebFrame;
32 using blink::WebGestureEvent;
33 using blink::WebInputEvent;
34 using blink::WebKeyboardEvent;
35 using blink::WebMenuItemInfo;
36 using blink::WebMouseEvent;
37 using blink::WebMouseWheelEvent;
38 using blink::WebPoint;
39 using blink::WebString;
40 using blink::WebTouchEvent;
41 using blink::WebTouchPoint;
42 using blink::WebVector;
43 using blink::WebView;
44
45 namespace content {
46
47 namespace {
48
49 void InitMouseEvent(WebInputEvent::Type t,
50                     WebMouseEvent::Button b,
51                     const WebPoint& pos,
52                     double time_stamp,
53                     int click_count,
54                     int modifiers,
55                     WebMouseEvent* e) {
56   e->type = t;
57   e->button = b;
58   e->modifiers = modifiers;
59   e->x = pos.x;
60   e->y = pos.y;
61   e->globalX = pos.x;
62   e->globalY = pos.y;
63   e->timeStampSeconds = time_stamp;
64   e->clickCount = click_count;
65 }
66
67 int GetKeyModifier(const std::string& modifier_name) {
68   const char* characters = modifier_name.c_str();
69   if (!strcmp(characters, "ctrlKey")
70 #ifndef __APPLE__
71       || !strcmp(characters, "addSelectionKey")
72 #endif
73       ) {
74     return WebInputEvent::ControlKey;
75   } else if (!strcmp(characters, "shiftKey") ||
76              !strcmp(characters, "rangeSelectionKey")) {
77     return WebInputEvent::ShiftKey;
78   } else if (!strcmp(characters, "altKey")) {
79     return WebInputEvent::AltKey;
80 #ifdef __APPLE__
81   } else if (!strcmp(characters, "metaKey") ||
82              !strcmp(characters, "addSelectionKey")) {
83     return WebInputEvent::MetaKey;
84 #else
85   } else if (!strcmp(characters, "metaKey")) {
86     return WebInputEvent::MetaKey;
87 #endif
88   } else if (!strcmp(characters, "autoRepeat")) {
89     return WebInputEvent::IsAutoRepeat;
90   } else if (!strcmp(characters, "copyKey")) {
91 #ifdef __APPLE__
92     return WebInputEvent::AltKey;
93 #else
94     return WebInputEvent::ControlKey;
95 #endif
96   }
97
98   return 0;
99 }
100
101 int GetKeyModifiers(const std::vector<std::string>& modifier_names) {
102   int modifiers = 0;
103   for (std::vector<std::string>::const_iterator it = modifier_names.begin();
104        it != modifier_names.end(); ++it) {
105     modifiers |= GetKeyModifier(*it);
106   }
107   return modifiers;
108 }
109
110 int GetKeyModifiersFromV8(v8::Handle<v8::Value> value) {
111   std::vector<std::string> modifier_names;
112   if (value->IsString()) {
113     modifier_names.push_back(gin::V8ToString(value));
114   } else if (value->IsArray()) {
115     gin::Converter<std::vector<std::string> >::FromV8(
116         NULL, value, &modifier_names);
117   }
118   return GetKeyModifiers(modifier_names);
119 }
120
121 // Maximum distance (in space and time) for a mouse click to register as a
122 // double or triple click.
123 const double kMultipleClickTimeSec = 1;
124 const int kMultipleClickRadiusPixels = 5;
125 const char kSubMenuDepthIdentifier[] = "_";
126 const char kSubMenuIdentifier[] = " >";
127 const char kSeparatorIdentifier[] = "---------";
128
129 bool OutsideMultiClickRadius(const WebPoint& a, const WebPoint& b) {
130   return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)) >
131          kMultipleClickRadiusPixels * kMultipleClickRadiusPixels;
132 }
133
134 void PopulateCustomItems(const WebVector<WebMenuItemInfo>& customItems,
135     const std::string& prefix, std::vector<std::string>* strings) {
136   for (size_t i = 0; i < customItems.size(); ++i) {
137     if (customItems[i].type == blink::WebMenuItemInfo::Separator) {
138       strings->push_back(prefix + kSeparatorIdentifier);
139     } else if (customItems[i].type == blink::WebMenuItemInfo::SubMenu) {
140       strings->push_back(prefix + customItems[i].label.utf8() +
141           kSubMenuIdentifier);
142       PopulateCustomItems(customItems[i].subMenuItems, prefix +
143           kSubMenuDepthIdentifier, strings);
144     } else {
145       strings->push_back(prefix + customItems[i].label.utf8());
146     }
147   }
148 }
149
150 // Because actual context menu is implemented by the browser side,
151 // this function does only what LayoutTests are expecting:
152 // - Many test checks the count of items. So returning non-zero value makes
153 // sense.
154 // - Some test compares the count before and after some action. So changing the
155 // count based on flags also makes sense. This function is doing such for some
156 // flags.
157 // - Some test even checks actual string content. So providing it would be also
158 // helpful.
159 std::vector<std::string> MakeMenuItemStringsFor(
160     WebContextMenuData* context_menu,
161     WebTestDelegate* delegate) {
162   // These constants are based on Safari's context menu because tests are made
163   // for it.
164   static const char* kNonEditableMenuStrings[] = {
165     "Back",
166     "Reload Page",
167     "Open in Dashbaord",
168     "<separator>",
169     "View Source",
170     "Save Page As",
171     "Print Page",
172     "Inspect Element",
173     0
174   };
175   static const char* kEditableMenuStrings[] = {
176     "Cut",
177     "Copy",
178     "<separator>",
179     "Paste",
180     "Spelling and Grammar",
181     "Substitutions, Transformations",
182     "Font",
183     "Speech",
184     "Paragraph Direction",
185     "<separator>",
186     0
187   };
188
189   // This is possible because mouse events are cancelleable.
190   if (!context_menu)
191     return std::vector<std::string>();
192
193   std::vector<std::string> strings;
194
195   // Populate custom menu items if provided by blink.
196   PopulateCustomItems(context_menu->customItems, "", &strings);
197
198   if (context_menu->isEditable) {
199     for (const char** item = kEditableMenuStrings; *item; ++item) {
200       strings.push_back(*item);
201     }
202     WebVector<WebString> suggestions;
203     MockSpellCheck::FillSuggestionList(context_menu->misspelledWord,
204                                        &suggestions);
205     for (size_t i = 0; i < suggestions.size(); ++i) {
206       strings.push_back(suggestions[i].utf8());
207     }
208   } else {
209     for (const char** item = kNonEditableMenuStrings; *item; ++item) {
210       strings.push_back(*item);
211     }
212   }
213
214   return strings;
215 }
216
217 // How much we should scroll per event - the value here is chosen to match the
218 // WebKit impl and layout test results.
219 const float kScrollbarPixelsPerTick = 40.0f;
220
221 WebMouseEvent::Button GetButtonTypeFromButtonNumber(int button_code) {
222   if (!button_code)
223     return WebMouseEvent::ButtonLeft;
224   if (button_code == 2)
225     return WebMouseEvent::ButtonRight;
226   return WebMouseEvent::ButtonMiddle;
227 }
228
229 class MouseDownTask : public WebMethodTask<EventSender> {
230  public:
231   MouseDownTask(EventSender* obj, int button_number, int modifiers)
232       : WebMethodTask<EventSender>(obj),
233         button_number_(button_number),
234         modifiers_(modifiers) {}
235
236   virtual void RunIfValid() OVERRIDE {
237     object_->MouseDown(button_number_, modifiers_);
238   }
239
240  private:
241   int button_number_;
242   int modifiers_;
243 };
244
245 class MouseUpTask : public WebMethodTask<EventSender> {
246  public:
247   MouseUpTask(EventSender* obj, int button_number, int modifiers)
248       : WebMethodTask<EventSender>(obj),
249         button_number_(button_number),
250         modifiers_(modifiers) {}
251
252   virtual void RunIfValid() OVERRIDE {
253     object_->MouseUp(button_number_, modifiers_);
254   }
255
256  private:
257   int button_number_;
258   int modifiers_;
259 };
260
261 class KeyDownTask : public WebMethodTask<EventSender> {
262  public:
263   KeyDownTask(EventSender* obj,
264               const std::string code_str,
265               int modifiers,
266               KeyLocationCode location)
267       : WebMethodTask<EventSender>(obj),
268         code_str_(code_str),
269         modifiers_(modifiers),
270         location_(location) {}
271
272   virtual void RunIfValid() OVERRIDE {
273     object_->KeyDown(code_str_, modifiers_, location_);
274   }
275
276  private:
277   std::string code_str_;
278   int modifiers_;
279   KeyLocationCode location_;
280 };
281
282 bool NeedsShiftModifier(int keyCode) {
283   // If code is an uppercase letter, assign a SHIFT key to eventDown.modifier.
284   return (keyCode & 0xFF) >= 'A' && (keyCode & 0xFF) <= 'Z';
285 }
286
287 // Get the edit command corresponding to a keyboard event.
288 // Returns true if the specified event corresponds to an edit command, the name
289 // of the edit command will be stored in |*name|.
290 bool GetEditCommand(const WebKeyboardEvent& event, std::string* name) {
291 #if defined(OS_MACOSX)
292 // We only cares about Left,Right,Up,Down keys with Command or Command+Shift
293 // modifiers. These key events correspond to some special movement and
294 // selection editor commands. These keys will be marked as system key, which
295 // prevents them from being handled. Thus they must be handled specially.
296   if ((event.modifiers & ~WebKeyboardEvent::ShiftKey) !=
297       WebKeyboardEvent::MetaKey)
298     return false;
299
300   switch (event.windowsKeyCode) {
301     case ui::VKEY_LEFT:
302       *name = "MoveToBeginningOfLine";
303       break;
304     case ui::VKEY_RIGHT:
305       *name = "MoveToEndOfLine";
306       break;
307     case ui::VKEY_UP:
308       *name = "MoveToBeginningOfDocument";
309       break;
310     case ui::VKEY_DOWN:
311       *name = "MoveToEndOfDocument";
312       break;
313     default:
314       return false;
315   }
316
317   if (event.modifiers & WebKeyboardEvent::ShiftKey)
318     name->append("AndModifySelection");
319
320   return true;
321 #else
322   return false;
323 #endif
324 }
325
326 bool IsSystemKeyEvent(const WebKeyboardEvent& event) {
327 #if defined(OS_MACOSX)
328   return event.modifiers & WebInputEvent::MetaKey &&
329       event.windowsKeyCode != ui::VKEY_B &&
330       event.windowsKeyCode != ui::VKEY_I;
331 #else
332   return !!(event.modifiers & WebInputEvent::AltKey);
333 #endif
334 }
335
336 }  // namespace
337
338 class EventSenderBindings : public gin::Wrappable<EventSenderBindings> {
339  public:
340   static gin::WrapperInfo kWrapperInfo;
341
342   static void Install(base::WeakPtr<EventSender> sender,
343                       blink::WebFrame* frame);
344
345  private:
346   explicit EventSenderBindings(base::WeakPtr<EventSender> sender);
347   virtual ~EventSenderBindings();
348
349   // gin::Wrappable:
350   virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
351       v8::Isolate* isolate) OVERRIDE;
352
353   // Bound methods:
354   void EnableDOMUIEventLogging();
355   void FireKeyboardEventsToElement();
356   void ClearKillRing();
357   std::vector<std::string> ContextClick();
358   void TextZoomIn();
359   void TextZoomOut();
360   void ZoomPageIn();
361   void ZoomPageOut();
362   void SetPageZoomFactor(double factor);
363   void SetPageScaleFactor(gin::Arguments* args);
364   void ClearTouchPoints();
365   void ReleaseTouchPoint(unsigned index);
366   void UpdateTouchPoint(unsigned index, double x, double y);
367   void CancelTouchPoint(unsigned index);
368   void SetTouchModifier(const std::string& key_name, bool set_mask);
369   void SetTouchCancelable(bool cancelable);
370   void DumpFilenameBeingDragged();
371   void GestureFlingCancel();
372   void GestureFlingStart(float x, float y, float velocity_x, float velocity_y);
373   void GestureScrollFirstPoint(int x, int y);
374   void TouchStart();
375   void TouchMove();
376   void TouchCancel();
377   void TouchEnd();
378   void LeapForward(int milliseconds);
379   void BeginDragWithFiles(const std::vector<std::string>& files);
380   void AddTouchPoint(gin::Arguments* args);
381   void MouseDragBegin();
382   void MouseDragEnd();
383   void GestureScrollBegin(gin::Arguments* args);
384   void GestureScrollEnd(gin::Arguments* args);
385   void GestureScrollUpdate(gin::Arguments* args);
386   void GestureScrollUpdateWithoutPropagation(gin::Arguments* args);
387   void GestureTap(gin::Arguments* args);
388   void GestureTapDown(gin::Arguments* args);
389   void GestureShowPress(gin::Arguments* args);
390   void GestureTapCancel(gin::Arguments* args);
391   void GestureLongPress(gin::Arguments* args);
392   void GestureLongTap(gin::Arguments* args);
393   void GestureTwoFingerTap(gin::Arguments* args);
394   void ContinuousMouseScrollBy(gin::Arguments* args);
395   void MouseMoveTo(gin::Arguments* args);
396   void TrackpadScrollBegin();
397   void TrackpadScroll(gin::Arguments* args);
398   void TrackpadScrollEnd();
399   void MouseScrollBy(gin::Arguments* args);
400   // TODO(erikchen): Remove MouseMomentumBegin once CL 282743002 has landed.
401   void MouseMomentumBegin();
402   void MouseMomentumBegin2(gin::Arguments* args);
403   void MouseMomentumScrollBy(gin::Arguments* args);
404   void MouseMomentumEnd();
405   void ScheduleAsynchronousClick(gin::Arguments* args);
406   void ScheduleAsynchronousKeyDown(gin::Arguments* args);
407   void MouseDown(gin::Arguments* args);
408   void MouseUp(gin::Arguments* args);
409   void KeyDown(gin::Arguments* args);
410
411   // Binding properties:
412   bool ForceLayoutOnEvents() const;
413   void SetForceLayoutOnEvents(bool force);
414   bool IsDragMode() const;
415   void SetIsDragMode(bool drag_mode);
416
417 #if defined(OS_WIN)
418   int WmKeyDown() const;
419   void SetWmKeyDown(int key_down);
420
421   int WmKeyUp() const;
422   void SetWmKeyUp(int key_up);
423
424   int WmChar() const;
425   void SetWmChar(int wm_char);
426
427   int WmDeadChar() const;
428   void SetWmDeadChar(int dead_char);
429
430   int WmSysKeyDown() const;
431   void SetWmSysKeyDown(int key_down);
432
433   int WmSysKeyUp() const;
434   void SetWmSysKeyUp(int key_up);
435
436   int WmSysChar() const;
437   void SetWmSysChar(int sys_char);
438
439   int WmSysDeadChar() const;
440   void SetWmSysDeadChar(int sys_dead_char);
441 #endif
442
443   base::WeakPtr<EventSender> sender_;
444
445   DISALLOW_COPY_AND_ASSIGN(EventSenderBindings);
446 };
447
448 gin::WrapperInfo EventSenderBindings::kWrapperInfo = {gin::kEmbedderNativeGin};
449
450 EventSenderBindings::EventSenderBindings(base::WeakPtr<EventSender> sender)
451     : sender_(sender) {
452 }
453
454 EventSenderBindings::~EventSenderBindings() {}
455
456 // static
457 void EventSenderBindings::Install(base::WeakPtr<EventSender> sender,
458                                   WebFrame* frame) {
459   v8::Isolate* isolate = blink::mainThreadIsolate();
460   v8::HandleScope handle_scope(isolate);
461   v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
462   if (context.IsEmpty())
463     return;
464
465   v8::Context::Scope context_scope(context);
466
467   gin::Handle<EventSenderBindings> bindings =
468       gin::CreateHandle(isolate, new EventSenderBindings(sender));
469   if (bindings.IsEmpty())
470     return;
471   v8::Handle<v8::Object> global = context->Global();
472   global->Set(gin::StringToV8(isolate, "eventSender"), bindings.ToV8());
473 }
474
475 gin::ObjectTemplateBuilder
476 EventSenderBindings::GetObjectTemplateBuilder(v8::Isolate* isolate) {
477   return gin::Wrappable<EventSenderBindings>::GetObjectTemplateBuilder(isolate)
478       .SetMethod("enableDOMUIEventLogging",
479                  &EventSenderBindings::EnableDOMUIEventLogging)
480       .SetMethod("fireKeyboardEventsToElement",
481                  &EventSenderBindings::FireKeyboardEventsToElement)
482       .SetMethod("clearKillRing", &EventSenderBindings::ClearKillRing)
483       .SetMethod("contextClick", &EventSenderBindings::ContextClick)
484       .SetMethod("textZoomIn", &EventSenderBindings::TextZoomIn)
485       .SetMethod("textZoomOut", &EventSenderBindings::TextZoomOut)
486       .SetMethod("zoomPageIn", &EventSenderBindings::ZoomPageIn)
487       .SetMethod("zoomPageOut", &EventSenderBindings::ZoomPageOut)
488       .SetMethod("setPageZoomFactor", &EventSenderBindings::SetPageZoomFactor)
489       .SetMethod("setPageScaleFactor", &EventSenderBindings::SetPageScaleFactor)
490       .SetMethod("clearTouchPoints", &EventSenderBindings::ClearTouchPoints)
491       .SetMethod("releaseTouchPoint", &EventSenderBindings::ReleaseTouchPoint)
492       .SetMethod("updateTouchPoint", &EventSenderBindings::UpdateTouchPoint)
493       .SetMethod("cancelTouchPoint", &EventSenderBindings::CancelTouchPoint)
494       .SetMethod("setTouchModifier", &EventSenderBindings::SetTouchModifier)
495       .SetMethod("setTouchCancelable", &EventSenderBindings::SetTouchCancelable)
496       .SetMethod("dumpFilenameBeingDragged",
497                  &EventSenderBindings::DumpFilenameBeingDragged)
498       .SetMethod("gestureFlingCancel", &EventSenderBindings::GestureFlingCancel)
499       .SetMethod("gestureFlingStart", &EventSenderBindings::GestureFlingStart)
500       .SetMethod("gestureScrollFirstPoint",
501                  &EventSenderBindings::GestureScrollFirstPoint)
502       .SetMethod("touchStart", &EventSenderBindings::TouchStart)
503       .SetMethod("touchMove", &EventSenderBindings::TouchMove)
504       .SetMethod("touchCancel", &EventSenderBindings::TouchCancel)
505       .SetMethod("touchEnd", &EventSenderBindings::TouchEnd)
506       .SetMethod("leapForward", &EventSenderBindings::LeapForward)
507       .SetMethod("beginDragWithFiles", &EventSenderBindings::BeginDragWithFiles)
508       .SetMethod("addTouchPoint", &EventSenderBindings::AddTouchPoint)
509       .SetMethod("mouseDragBegin", &EventSenderBindings::MouseDragBegin)
510       .SetMethod("mouseDragEnd", &EventSenderBindings::MouseDragEnd)
511       .SetMethod("gestureScrollBegin", &EventSenderBindings::GestureScrollBegin)
512       .SetMethod("gestureScrollEnd", &EventSenderBindings::GestureScrollEnd)
513       .SetMethod("gestureScrollUpdate",
514                  &EventSenderBindings::GestureScrollUpdate)
515       .SetMethod("gestureScrollUpdateWithoutPropagation",
516                  &EventSenderBindings::GestureScrollUpdateWithoutPropagation)
517       .SetMethod("gestureTap", &EventSenderBindings::GestureTap)
518       .SetMethod("gestureTapDown", &EventSenderBindings::GestureTapDown)
519       .SetMethod("gestureShowPress", &EventSenderBindings::GestureShowPress)
520       .SetMethod("gestureTapCancel", &EventSenderBindings::GestureTapCancel)
521       .SetMethod("gestureLongPress", &EventSenderBindings::GestureLongPress)
522       .SetMethod("gestureLongTap", &EventSenderBindings::GestureLongTap)
523       .SetMethod("gestureTwoFingerTap",
524                  &EventSenderBindings::GestureTwoFingerTap)
525       .SetMethod("continuousMouseScrollBy",
526                  &EventSenderBindings::ContinuousMouseScrollBy)
527       .SetMethod("keyDown", &EventSenderBindings::KeyDown)
528       .SetMethod("mouseDown", &EventSenderBindings::MouseDown)
529       .SetMethod("mouseMoveTo", &EventSenderBindings::MouseMoveTo)
530       .SetMethod("trackpadScrollBegin",
531                  &EventSenderBindings::TrackpadScrollBegin)
532       .SetMethod("trackpadScroll", &EventSenderBindings::TrackpadScroll)
533       .SetMethod("trackpadScrollEnd", &EventSenderBindings::TrackpadScrollEnd)
534       .SetMethod("mouseScrollBy", &EventSenderBindings::MouseScrollBy)
535       .SetMethod("mouseUp", &EventSenderBindings::MouseUp)
536       .SetMethod("mouseMomentumBegin", &EventSenderBindings::MouseMomentumBegin)
537       .SetMethod("mouseMomentumBegin2",
538                  &EventSenderBindings::MouseMomentumBegin2)
539       .SetMethod("mouseMomentumScrollBy",
540                  &EventSenderBindings::MouseMomentumScrollBy)
541       .SetMethod("mouseMomentumEnd", &EventSenderBindings::MouseMomentumEnd)
542       .SetMethod("scheduleAsynchronousClick",
543                  &EventSenderBindings::ScheduleAsynchronousClick)
544       .SetMethod("scheduleAsynchronousKeyDown",
545                  &EventSenderBindings::ScheduleAsynchronousKeyDown)
546       .SetProperty("forceLayoutOnEvents",
547                    &EventSenderBindings::ForceLayoutOnEvents,
548                    &EventSenderBindings::SetForceLayoutOnEvents)
549       .SetProperty("dragMode",
550                    &EventSenderBindings::IsDragMode,
551                    &EventSenderBindings::SetIsDragMode)
552 #if defined(OS_WIN)
553       .SetProperty("WM_KEYDOWN",
554                    &EventSenderBindings::WmKeyDown,
555                    &EventSenderBindings::SetWmKeyDown)
556       .SetProperty("WM_KEYUP",
557                    &EventSenderBindings::WmKeyUp,
558                    &EventSenderBindings::SetWmKeyUp)
559       .SetProperty("WM_CHAR",
560                    &EventSenderBindings::WmChar,
561                    &EventSenderBindings::SetWmChar)
562       .SetProperty("WM_DEADCHAR",
563                    &EventSenderBindings::WmDeadChar,
564                    &EventSenderBindings::SetWmDeadChar)
565       .SetProperty("WM_SYSKEYDOWN",
566                    &EventSenderBindings::WmSysKeyDown,
567                    &EventSenderBindings::SetWmSysKeyDown)
568       .SetProperty("WM_SYSKEYUP",
569                    &EventSenderBindings::WmSysKeyUp,
570                    &EventSenderBindings::SetWmSysKeyUp)
571       .SetProperty("WM_SYSCHAR",
572                    &EventSenderBindings::WmSysChar,
573                    &EventSenderBindings::SetWmSysChar)
574       .SetProperty("WM_SYSDEADCHAR",
575                    &EventSenderBindings::WmSysDeadChar,
576                    &EventSenderBindings::SetWmSysDeadChar);
577 #else
578       ;
579 #endif
580 }
581
582 void EventSenderBindings::EnableDOMUIEventLogging() {
583   if (sender_)
584     sender_->EnableDOMUIEventLogging();
585 }
586
587 void EventSenderBindings::FireKeyboardEventsToElement() {
588   if (sender_)
589     sender_->FireKeyboardEventsToElement();
590 }
591
592 void EventSenderBindings::ClearKillRing() {
593   if (sender_)
594     sender_->ClearKillRing();
595 }
596
597 std::vector<std::string> EventSenderBindings::ContextClick() {
598   if (sender_)
599     return sender_->ContextClick();
600   return std::vector<std::string>();
601 }
602
603 void EventSenderBindings::TextZoomIn() {
604   if (sender_)
605     sender_->TextZoomIn();
606 }
607
608 void EventSenderBindings::TextZoomOut() {
609   if (sender_)
610     sender_->TextZoomOut();
611 }
612
613 void EventSenderBindings::ZoomPageIn() {
614   if (sender_)
615     sender_->ZoomPageIn();
616 }
617
618 void EventSenderBindings::ZoomPageOut() {
619   if (sender_)
620     sender_->ZoomPageOut();
621 }
622
623 void EventSenderBindings::SetPageZoomFactor(double factor) {
624   if (sender_)
625     sender_->SetPageZoomFactor(factor);
626 }
627
628 void EventSenderBindings::SetPageScaleFactor(gin::Arguments* args) {
629   if (!sender_)
630     return;
631   float scale_factor;
632   double x;
633   double y;
634   if (args->PeekNext().IsEmpty())
635     return;
636   args->GetNext(&scale_factor);
637   if (args->PeekNext().IsEmpty())
638     return;
639   args->GetNext(&x);
640   if (args->PeekNext().IsEmpty())
641     return;
642   args->GetNext(&y);
643   sender_->SetPageScaleFactor(scale_factor,
644                               static_cast<int>(x), static_cast<int>(y));
645 }
646
647 void EventSenderBindings::ClearTouchPoints() {
648   if (sender_)
649     sender_->ClearTouchPoints();
650 }
651
652 void EventSenderBindings::ReleaseTouchPoint(unsigned index) {
653   if (sender_)
654     sender_->ReleaseTouchPoint(index);
655 }
656
657 void EventSenderBindings::UpdateTouchPoint(unsigned index, double x, double y) {
658   if (sender_)
659     sender_->UpdateTouchPoint(index, static_cast<float>(x), static_cast<float>(y));
660 }
661
662 void EventSenderBindings::CancelTouchPoint(unsigned index) {
663   if (sender_)
664     sender_->CancelTouchPoint(index);
665 }
666
667 void EventSenderBindings::SetTouchModifier(const std::string& key_name,
668                                            bool set_mask) {
669   if (sender_)
670     sender_->SetTouchModifier(key_name, set_mask);
671 }
672
673 void EventSenderBindings::SetTouchCancelable(bool cancelable) {
674   if (sender_)
675     sender_->SetTouchCancelable(cancelable);
676 }
677
678 void EventSenderBindings::DumpFilenameBeingDragged() {
679   if (sender_)
680     sender_->DumpFilenameBeingDragged();
681 }
682
683 void EventSenderBindings::GestureFlingCancel() {
684   if (sender_)
685     sender_->GestureFlingCancel();
686 }
687
688 void EventSenderBindings::GestureFlingStart(float x,
689                                             float y,
690                                             float velocity_x,
691                                             float velocity_y) {
692   if (sender_)
693     sender_->GestureFlingStart(x, y, velocity_x, velocity_y);
694 }
695
696 void EventSenderBindings::GestureScrollFirstPoint(int x, int y) {
697   if (sender_)
698     sender_->GestureScrollFirstPoint(x, y);
699 }
700
701 void EventSenderBindings::TouchStart() {
702   if (sender_)
703     sender_->TouchStart();
704 }
705
706 void EventSenderBindings::TouchMove() {
707   if (sender_)
708     sender_->TouchMove();
709 }
710
711 void EventSenderBindings::TouchCancel() {
712   if (sender_)
713     sender_->TouchCancel();
714 }
715
716 void EventSenderBindings::TouchEnd() {
717   if (sender_)
718     sender_->TouchEnd();
719 }
720
721 void EventSenderBindings::LeapForward(int milliseconds) {
722   if (sender_)
723     sender_->LeapForward(milliseconds);
724 }
725
726 void EventSenderBindings::BeginDragWithFiles(
727     const std::vector<std::string>& files) {
728   if (sender_)
729     sender_->BeginDragWithFiles(files);
730 }
731
732 void EventSenderBindings::AddTouchPoint(gin::Arguments* args) {
733   if (sender_)
734     sender_->AddTouchPoint(args);
735 }
736
737 void EventSenderBindings::MouseDragBegin() {
738   if (sender_)
739     sender_->MouseDragBegin();
740 }
741
742 void EventSenderBindings::MouseDragEnd() {
743   if (sender_)
744     sender_->MouseDragEnd();
745 }
746
747 void EventSenderBindings::GestureScrollBegin(gin::Arguments* args) {
748   if (sender_)
749     sender_->GestureScrollBegin(args);
750 }
751
752 void EventSenderBindings::GestureScrollEnd(gin::Arguments* args) {
753   if (sender_)
754     sender_->GestureScrollEnd(args);
755 }
756
757 void EventSenderBindings::GestureScrollUpdate(gin::Arguments* args) {
758   if (sender_)
759     sender_->GestureScrollUpdate(args);
760 }
761
762 void EventSenderBindings::GestureScrollUpdateWithoutPropagation(
763     gin::Arguments* args) {
764   if (sender_)
765     sender_->GestureScrollUpdateWithoutPropagation(args);
766 }
767
768 void EventSenderBindings::GestureTap(gin::Arguments* args) {
769   if (sender_)
770     sender_->GestureTap(args);
771 }
772
773 void EventSenderBindings::GestureTapDown(gin::Arguments* args) {
774   if (sender_)
775     sender_->GestureTapDown(args);
776 }
777
778 void EventSenderBindings::GestureShowPress(gin::Arguments* args) {
779   if (sender_)
780     sender_->GestureShowPress(args);
781 }
782
783 void EventSenderBindings::GestureTapCancel(gin::Arguments* args) {
784   if (sender_)
785     sender_->GestureTapCancel(args);
786 }
787
788 void EventSenderBindings::GestureLongPress(gin::Arguments* args) {
789   if (sender_)
790     sender_->GestureLongPress(args);
791 }
792
793 void EventSenderBindings::GestureLongTap(gin::Arguments* args) {
794   if (sender_)
795     sender_->GestureLongTap(args);
796 }
797
798 void EventSenderBindings::GestureTwoFingerTap(gin::Arguments* args) {
799   if (sender_)
800     sender_->GestureTwoFingerTap(args);
801 }
802
803 void EventSenderBindings::ContinuousMouseScrollBy(gin::Arguments* args) {
804   if (sender_)
805     sender_->ContinuousMouseScrollBy(args);
806 }
807
808 void EventSenderBindings::MouseMoveTo(gin::Arguments* args) {
809   if (sender_)
810     sender_->MouseMoveTo(args);
811 }
812
813 void EventSenderBindings::TrackpadScrollBegin() {
814   if (sender_)
815     sender_->TrackpadScrollBegin();
816 }
817
818 void EventSenderBindings::TrackpadScroll(gin::Arguments* args) {
819   if (sender_)
820     sender_->TrackpadScroll(args);
821 }
822
823 void EventSenderBindings::TrackpadScrollEnd() {
824   if (sender_)
825     sender_->TrackpadScrollEnd();
826 }
827
828 void EventSenderBindings::MouseScrollBy(gin::Arguments* args) {
829   if (sender_)
830     sender_->MouseScrollBy(args);
831 }
832
833 void EventSenderBindings::MouseMomentumBegin() {
834   if (sender_)
835     sender_->MouseMomentumBegin();
836 }
837
838 void EventSenderBindings::MouseMomentumBegin2(gin::Arguments* args) {
839   if (sender_)
840     sender_->MouseMomentumBegin2(args);
841 }
842
843 void EventSenderBindings::MouseMomentumScrollBy(gin::Arguments* args) {
844   if (sender_)
845     sender_->MouseMomentumScrollBy(args);
846 }
847
848 void EventSenderBindings::MouseMomentumEnd() {
849   if (sender_)
850     sender_->MouseMomentumEnd();
851 }
852
853 void EventSenderBindings::ScheduleAsynchronousClick(gin::Arguments* args) {
854   if (!sender_)
855     return;
856
857   int button_number = 0;
858   int modifiers = 0;
859   if (!args->PeekNext().IsEmpty()) {
860     args->GetNext(&button_number);
861     if (!args->PeekNext().IsEmpty())
862       modifiers = GetKeyModifiersFromV8(args->PeekNext());
863   }
864   sender_->ScheduleAsynchronousClick(button_number, modifiers);
865 }
866
867 void EventSenderBindings::ScheduleAsynchronousKeyDown(gin::Arguments* args) {
868   if (!sender_)
869     return;
870
871   std::string code_str;
872   int modifiers = 0;
873   int location = DOMKeyLocationStandard;
874   args->GetNext(&code_str);
875   if (!args->PeekNext().IsEmpty()) {
876     v8::Handle<v8::Value> value;
877     args->GetNext(&value);
878     modifiers = GetKeyModifiersFromV8(value);
879     if (!args->PeekNext().IsEmpty())
880       args->GetNext(&location);
881   }
882   sender_->ScheduleAsynchronousKeyDown(code_str, modifiers,
883                                        static_cast<KeyLocationCode>(location));
884 }
885
886 void EventSenderBindings::MouseDown(gin::Arguments* args) {
887   if (!sender_)
888     return;
889
890   int button_number = 0;
891   int modifiers = 0;
892   if (!args->PeekNext().IsEmpty()) {
893     args->GetNext(&button_number);
894     if (!args->PeekNext().IsEmpty())
895       modifiers = GetKeyModifiersFromV8(args->PeekNext());
896   }
897   sender_->MouseDown(button_number, modifiers);
898 }
899
900 void EventSenderBindings::MouseUp(gin::Arguments* args) {
901   if (!sender_)
902     return;
903
904   int button_number = 0;
905   int modifiers = 0;
906   if (!args->PeekNext().IsEmpty()) {
907     args->GetNext(&button_number);
908     if (!args->PeekNext().IsEmpty())
909       modifiers = GetKeyModifiersFromV8(args->PeekNext());
910   }
911   sender_->MouseUp(button_number, modifiers);
912 }
913
914 void EventSenderBindings::KeyDown(gin::Arguments* args) {
915   if (!sender_)
916     return;
917
918   std::string code_str;
919   int modifiers = 0;
920   int location = DOMKeyLocationStandard;
921   args->GetNext(&code_str);
922   if (!args->PeekNext().IsEmpty()) {
923     v8::Handle<v8::Value> value;
924     args->GetNext(&value);
925     modifiers = GetKeyModifiersFromV8(value);
926     if (!args->PeekNext().IsEmpty())
927       args->GetNext(&location);
928   }
929   sender_->KeyDown(code_str, modifiers, static_cast<KeyLocationCode>(location));
930 }
931
932 bool EventSenderBindings::ForceLayoutOnEvents() const {
933   if (sender_)
934     return sender_->force_layout_on_events();
935   return false;
936 }
937
938 void EventSenderBindings::SetForceLayoutOnEvents(bool force) {
939   if (sender_)
940     sender_->set_force_layout_on_events(force);
941 }
942
943 bool EventSenderBindings::IsDragMode() const {
944   if (sender_)
945     return sender_->is_drag_mode();
946   return true;
947 }
948
949 void EventSenderBindings::SetIsDragMode(bool drag_mode) {
950   if (sender_)
951     sender_->set_is_drag_mode(drag_mode);
952 }
953
954 #if defined(OS_WIN)
955 int EventSenderBindings::WmKeyDown() const {
956   if (sender_)
957     return sender_->wm_key_down();
958   return 0;
959 }
960
961 void EventSenderBindings::SetWmKeyDown(int key_down) {
962   if (sender_)
963     sender_->set_wm_key_down(key_down);
964 }
965
966 int EventSenderBindings::WmKeyUp() const {
967   if (sender_)
968     return sender_->wm_key_up();
969   return 0;
970 }
971
972 void EventSenderBindings::SetWmKeyUp(int key_up) {
973   if (sender_)
974     sender_->set_wm_key_up(key_up);
975 }
976
977 int EventSenderBindings::WmChar() const {
978   if (sender_)
979     return sender_->wm_char();
980   return 0;
981 }
982
983 void EventSenderBindings::SetWmChar(int wm_char) {
984   if (sender_)
985     sender_->set_wm_char(wm_char);
986 }
987
988 int EventSenderBindings::WmDeadChar() const {
989   if (sender_)
990     return sender_->wm_dead_char();
991   return 0;
992 }
993
994 void EventSenderBindings::SetWmDeadChar(int dead_char) {
995   if (sender_)
996     sender_->set_wm_dead_char(dead_char);
997 }
998
999 int EventSenderBindings::WmSysKeyDown() const {
1000   if (sender_)
1001     return sender_->wm_sys_key_down();
1002   return 0;
1003 }
1004
1005 void EventSenderBindings::SetWmSysKeyDown(int key_down) {
1006   if (sender_)
1007     sender_->set_wm_sys_key_down(key_down);
1008 }
1009
1010 int EventSenderBindings::WmSysKeyUp() const {
1011   if (sender_)
1012     return sender_->wm_sys_key_up();
1013   return 0;
1014 }
1015
1016 void EventSenderBindings::SetWmSysKeyUp(int key_up) {
1017   if (sender_)
1018     sender_->set_wm_sys_key_up(key_up);
1019 }
1020
1021 int EventSenderBindings::WmSysChar() const {
1022   if (sender_)
1023     return sender_->wm_sys_char();
1024   return 0;
1025 }
1026
1027 void EventSenderBindings::SetWmSysChar(int sys_char) {
1028   if (sender_)
1029     sender_->set_wm_sys_char(sys_char);
1030 }
1031
1032 int EventSenderBindings::WmSysDeadChar() const {
1033   if (sender_)
1034     return sender_->wm_sys_dead_char();
1035   return 0;
1036 }
1037
1038 void EventSenderBindings::SetWmSysDeadChar(int sys_dead_char) {
1039   if (sender_)
1040     sender_->set_wm_sys_dead_char(sys_dead_char);
1041 }
1042 #endif
1043
1044 // EventSender -----------------------------------------------------------------
1045
1046 WebMouseEvent::Button EventSender::pressed_button_ = WebMouseEvent::ButtonNone;
1047
1048 WebPoint EventSender::last_mouse_pos_;
1049
1050 WebMouseEvent::Button EventSender::last_button_type_ =
1051     WebMouseEvent::ButtonNone;
1052
1053 EventSender::SavedEvent::SavedEvent()
1054     : type(TYPE_UNSPECIFIED),
1055       button_type(WebMouseEvent::ButtonNone),
1056       milliseconds(0),
1057       modifiers(0) {}
1058
1059 EventSender::EventSender(TestInterfaces* interfaces)
1060     : interfaces_(interfaces),
1061       delegate_(NULL),
1062       view_(NULL),
1063       force_layout_on_events_(false),
1064       is_drag_mode_(true),
1065       touch_modifiers_(0),
1066       touch_cancelable_(true),
1067       replaying_saved_events_(false),
1068       current_drag_effects_allowed_(blink::WebDragOperationNone),
1069       last_click_time_sec_(0),
1070       current_drag_effect_(blink::WebDragOperationNone),
1071       time_offset_ms_(0),
1072       click_count_(0),
1073 #if defined(OS_WIN)
1074       wm_key_down_(0),
1075       wm_key_up_(0),
1076       wm_char_(0),
1077       wm_dead_char_(0),
1078       wm_sys_key_down_(0),
1079       wm_sys_key_up_(0),
1080       wm_sys_char_(0),
1081       wm_sys_dead_char_(0),
1082 #endif
1083       weak_factory_(this) {}
1084
1085 EventSender::~EventSender() {}
1086
1087 void EventSender::Reset() {
1088   DCHECK(current_drag_data_.isNull());
1089   current_drag_data_.reset();
1090   current_drag_effect_ = blink::WebDragOperationNone;
1091   current_drag_effects_allowed_ = blink::WebDragOperationNone;
1092   if (view_ && pressed_button_ != WebMouseEvent::ButtonNone)
1093     view_->mouseCaptureLost();
1094   pressed_button_ = WebMouseEvent::ButtonNone;
1095   is_drag_mode_ = true;
1096   force_layout_on_events_ = true;
1097
1098 #if defined(OS_WIN)
1099   wm_key_down_ = WM_KEYDOWN;
1100   wm_key_up_ = WM_KEYUP;
1101   wm_char_ = WM_CHAR;
1102   wm_dead_char_ = WM_DEADCHAR;
1103   wm_sys_key_down_ = WM_SYSKEYDOWN;
1104   wm_sys_key_up_ = WM_SYSKEYUP;
1105   wm_sys_char_ = WM_SYSCHAR;
1106   wm_sys_dead_char_ = WM_SYSDEADCHAR;
1107 #endif
1108
1109   last_mouse_pos_ = WebPoint(0, 0);
1110   last_click_time_sec_ = 0;
1111   last_click_pos_ = WebPoint(0, 0);
1112   last_button_type_ = WebMouseEvent::ButtonNone;
1113   touch_points_.clear();
1114   last_context_menu_data_.reset();
1115   task_list_.RevokeAll();
1116   current_gesture_location_ = WebPoint(0, 0);
1117   mouse_event_queue_.clear();
1118
1119   time_offset_ms_ = 0;
1120   click_count_ = 0;
1121
1122   touch_modifiers_ = 0;
1123   touch_cancelable_ = true;
1124   touch_points_.clear();
1125 }
1126
1127 void EventSender::Install(WebFrame* frame) {
1128   EventSenderBindings::Install(weak_factory_.GetWeakPtr(), frame);
1129 }
1130
1131 void EventSender::SetDelegate(WebTestDelegate* delegate) {
1132   delegate_ = delegate;
1133 }
1134
1135 void EventSender::SetWebView(WebView* view) {
1136   view_ = view;
1137 }
1138
1139 void EventSender::SetContextMenuData(const WebContextMenuData& data) {
1140   last_context_menu_data_.reset(new WebContextMenuData(data));
1141 }
1142
1143 void EventSender::DoDragDrop(const WebDragData& drag_data,
1144                               WebDragOperationsMask mask) {
1145   WebMouseEvent event;
1146   InitMouseEvent(WebInputEvent::MouseDown,
1147                  pressed_button_,
1148                  last_mouse_pos_,
1149                  GetCurrentEventTimeSec(),
1150                  click_count_,
1151                  0,
1152                  &event);
1153   WebPoint client_point(event.x, event.y);
1154   WebPoint screen_point(event.globalX, event.globalY);
1155   current_drag_data_ = drag_data;
1156   current_drag_effects_allowed_ = mask;
1157   current_drag_effect_ = view_->dragTargetDragEnter(
1158       drag_data, client_point, screen_point, current_drag_effects_allowed_, 0);
1159
1160   // Finish processing events.
1161   ReplaySavedEvents();
1162 }
1163
1164 void EventSender::MouseDown(int button_number, int modifiers) {
1165   if (force_layout_on_events_)
1166     view_->layout();
1167
1168   DCHECK_NE(-1, button_number);
1169
1170   WebMouseEvent::Button button_type =
1171       GetButtonTypeFromButtonNumber(button_number);
1172
1173   UpdateClickCountForButton(button_type);
1174
1175   pressed_button_ = button_type;
1176
1177   WebMouseEvent event;
1178   InitMouseEvent(WebInputEvent::MouseDown,
1179                  button_type,
1180                  last_mouse_pos_,
1181                  GetCurrentEventTimeSec(),
1182                  click_count_,
1183                  modifiers,
1184                  &event);
1185   view_->handleInputEvent(event);
1186 }
1187
1188 void EventSender::MouseUp(int button_number, int modifiers) {
1189   if (force_layout_on_events_)
1190     view_->layout();
1191
1192   DCHECK_NE(-1, button_number);
1193
1194   WebMouseEvent::Button button_type =
1195       GetButtonTypeFromButtonNumber(button_number);
1196
1197   if (is_drag_mode_ && !replaying_saved_events_) {
1198     SavedEvent saved_event;
1199     saved_event.type = SavedEvent::TYPE_MOUSE_UP;
1200     saved_event.button_type = button_type;
1201     saved_event.modifiers = modifiers;
1202     mouse_event_queue_.push_back(saved_event);
1203     ReplaySavedEvents();
1204   } else {
1205     WebMouseEvent event;
1206     InitMouseEvent(WebInputEvent::MouseUp,
1207                    button_type,
1208                    last_mouse_pos_,
1209                    GetCurrentEventTimeSec(),
1210                    click_count_,
1211                    modifiers,
1212                    &event);
1213     DoMouseUp(event);
1214   }
1215 }
1216
1217 void EventSender::KeyDown(const std::string& code_str,
1218                           int modifiers,
1219                           KeyLocationCode location) {
1220   // FIXME: I'm not exactly sure how we should convert the string to a key
1221   // event. This seems to work in the cases I tested.
1222   // FIXME: Should we also generate a KEY_UP?
1223
1224   bool generate_char = false;
1225
1226   // Convert \n -> VK_RETURN. Some layout tests use \n to mean "Enter", when
1227   // Windows uses \r for "Enter".
1228   int code = 0;
1229   int text = 0;
1230   bool needs_shift_key_modifier = false;
1231
1232   if ("\n" == code_str) {
1233     generate_char = true;
1234     text = code = ui::VKEY_RETURN;
1235   } else if ("rightArrow" == code_str) {
1236     code = ui::VKEY_RIGHT;
1237   } else if ("downArrow" == code_str) {
1238     code = ui::VKEY_DOWN;
1239   } else if ("leftArrow" == code_str) {
1240     code = ui::VKEY_LEFT;
1241   } else if ("upArrow" == code_str) {
1242     code = ui::VKEY_UP;
1243   } else if ("insert" == code_str) {
1244     code = ui::VKEY_INSERT;
1245   } else if ("delete" == code_str) {
1246     code = ui::VKEY_DELETE;
1247   } else if ("pageUp" == code_str) {
1248     code = ui::VKEY_PRIOR;
1249   } else if ("pageDown" == code_str) {
1250     code = ui::VKEY_NEXT;
1251   } else if ("home" == code_str) {
1252     code = ui::VKEY_HOME;
1253   } else if ("end" == code_str) {
1254     code = ui::VKEY_END;
1255   } else if ("printScreen" == code_str) {
1256     code = ui::VKEY_SNAPSHOT;
1257   } else if ("menu" == code_str) {
1258     code = ui::VKEY_APPS;
1259   } else if ("leftControl" == code_str) {
1260     code = ui::VKEY_LCONTROL;
1261   } else if ("rightControl" == code_str) {
1262     code = ui::VKEY_RCONTROL;
1263   } else if ("leftShift" == code_str) {
1264     code = ui::VKEY_LSHIFT;
1265   } else if ("rightShift" == code_str) {
1266     code = ui::VKEY_RSHIFT;
1267   } else if ("leftAlt" == code_str) {
1268     code = ui::VKEY_LMENU;
1269   } else if ("rightAlt" == code_str) {
1270     code = ui::VKEY_RMENU;
1271   } else if ("numLock" == code_str) {
1272     code = ui::VKEY_NUMLOCK;
1273   } else if ("backspace" == code_str) {
1274     code = ui::VKEY_BACK;
1275   } else if ("escape" == code_str) {
1276     code = ui::VKEY_ESCAPE;
1277   } else {
1278     // Compare the input string with the function-key names defined by the
1279     // DOM spec (i.e. "F1",...,"F24"). If the input string is a function-key
1280     // name, set its key code.
1281     for (int i = 1; i <= 24; ++i) {
1282       std::string function_key_name = base::StringPrintf("F%d", i);
1283       if (function_key_name == code_str) {
1284         code = ui::VKEY_F1 + (i - 1);
1285         break;
1286       }
1287     }
1288     if (!code) {
1289       WebString web_code_str =
1290           WebString::fromUTF8(code_str.data(), code_str.size());
1291       DCHECK_EQ(1u, web_code_str.length());
1292       text = code = web_code_str.at(0);
1293       needs_shift_key_modifier = NeedsShiftModifier(code);
1294       if ((code & 0xFF) >= 'a' && (code & 0xFF) <= 'z')
1295         code -= 'a' - 'A';
1296       generate_char = true;
1297     }
1298
1299     if ("(" == code_str) {
1300       code = '9';
1301       needs_shift_key_modifier = true;
1302     }
1303   }
1304
1305   // For one generated keyboard event, we need to generate a keyDown/keyUp
1306   // pair;
1307   // On Windows, we might also need to generate a char event to mimic the
1308   // Windows event flow; on other platforms we create a merged event and test
1309   // the event flow that that platform provides.
1310   WebKeyboardEvent event_down;
1311   event_down.type = WebInputEvent::RawKeyDown;
1312   event_down.modifiers = modifiers;
1313   event_down.windowsKeyCode = code;
1314
1315   if (generate_char) {
1316     event_down.text[0] = text;
1317     event_down.unmodifiedText[0] = text;
1318   }
1319
1320   event_down.setKeyIdentifierFromWindowsKeyCode();
1321
1322   if (event_down.modifiers != 0)
1323     event_down.isSystemKey = IsSystemKeyEvent(event_down);
1324
1325   if (needs_shift_key_modifier)
1326     event_down.modifiers |= WebInputEvent::ShiftKey;
1327
1328   // See if KeyLocation argument is given.
1329   if (location == DOMKeyLocationNumpad)
1330     event_down.modifiers |= WebInputEvent::IsKeyPad;
1331
1332   WebKeyboardEvent event_up;
1333   event_up = event_down;
1334   event_up.type = WebInputEvent::KeyUp;
1335   // EventSender.m forces a layout here, with at least one
1336   // test (fast/forms/focus-control-to-page.html) relying on this.
1337   if (force_layout_on_events_)
1338     view_->layout();
1339
1340   // In the browser, if a keyboard event corresponds to an editor command,
1341   // the command will be dispatched to the renderer just before dispatching
1342   // the keyboard event, and then it will be executed in the
1343   // RenderView::handleCurrentKeyboardEvent() method.
1344   // We just simulate the same behavior here.
1345   std::string edit_command;
1346   if (GetEditCommand(event_down, &edit_command))
1347     delegate_->SetEditCommand(edit_command, "");
1348
1349   view_->handleInputEvent(event_down);
1350
1351   if (code == ui::VKEY_ESCAPE && !current_drag_data_.isNull()) {
1352     WebMouseEvent event;
1353     InitMouseEvent(WebInputEvent::MouseDown,
1354                    pressed_button_,
1355                    last_mouse_pos_,
1356                    GetCurrentEventTimeSec(),
1357                    click_count_,
1358                    0,
1359                    &event);
1360     FinishDragAndDrop(event, blink::WebDragOperationNone);
1361   }
1362
1363   delegate_->ClearEditCommand();
1364
1365   if (generate_char) {
1366     WebKeyboardEvent event_char = event_up;
1367     event_char.type = WebInputEvent::Char;
1368     event_char.keyIdentifier[0] = '\0';
1369     view_->handleInputEvent(event_char);
1370   }
1371
1372   view_->handleInputEvent(event_up);
1373 }
1374
1375 void EventSender::EnableDOMUIEventLogging() {}
1376
1377 void EventSender::FireKeyboardEventsToElement() {}
1378
1379 void EventSender::ClearKillRing() {}
1380
1381 std::vector<std::string> EventSender::ContextClick() {
1382   if (force_layout_on_events_) {
1383     view_->layout();
1384   }
1385
1386   UpdateClickCountForButton(WebMouseEvent::ButtonRight);
1387
1388   // Clears last context menu data because we need to know if the context menu
1389   // be requested after following mouse events.
1390   last_context_menu_data_.reset();
1391
1392   // Generate right mouse down and up.
1393   WebMouseEvent event;
1394   // This is a hack to work around only allowing a single pressed button since
1395   // we want to test the case where both the left and right mouse buttons are
1396   // pressed.
1397   if (pressed_button_ == WebMouseEvent::ButtonNone) {
1398     pressed_button_ = WebMouseEvent::ButtonRight;
1399   }
1400   InitMouseEvent(WebInputEvent::MouseDown,
1401                  WebMouseEvent::ButtonRight,
1402                  last_mouse_pos_,
1403                  GetCurrentEventTimeSec(),
1404                  click_count_,
1405                  0,
1406                  &event);
1407   view_->handleInputEvent(event);
1408
1409 #if defined(OS_WIN)
1410   InitMouseEvent(WebInputEvent::MouseUp,
1411                  WebMouseEvent::ButtonRight,
1412                  last_mouse_pos_,
1413                  GetCurrentEventTimeSec(),
1414                  click_count_,
1415                  0,
1416                  &event);
1417   view_->handleInputEvent(event);
1418
1419   pressed_button_= WebMouseEvent::ButtonNone;
1420 #endif
1421
1422   std::vector<std::string> menu_items = MakeMenuItemStringsFor(last_context_menu_data_.get(), delegate_);
1423   last_context_menu_data_.reset();
1424   return menu_items;
1425 }
1426
1427 void EventSender::TextZoomIn() {
1428   view_->setTextZoomFactor(view_->textZoomFactor() * 1.2f);
1429 }
1430
1431 void EventSender::TextZoomOut() {
1432   view_->setTextZoomFactor(view_->textZoomFactor() / 1.2f);
1433 }
1434
1435 void EventSender::ZoomPageIn() {
1436   const std::vector<WebTestProxyBase*>& window_list =
1437       interfaces_->GetWindowList();
1438
1439   for (size_t i = 0; i < window_list.size(); ++i) {
1440     window_list.at(i)->GetWebView()->setZoomLevel(
1441         window_list.at(i)->GetWebView()->zoomLevel() + 1);
1442   }
1443 }
1444
1445 void EventSender::ZoomPageOut() {
1446   const std::vector<WebTestProxyBase*>& window_list =
1447       interfaces_->GetWindowList();
1448
1449   for (size_t i = 0; i < window_list.size(); ++i) {
1450     window_list.at(i)->GetWebView()->setZoomLevel(
1451         window_list.at(i)->GetWebView()->zoomLevel() - 1);
1452   }
1453 }
1454
1455 void EventSender::SetPageZoomFactor(double zoom_factor) {
1456   const std::vector<WebTestProxyBase*>& window_list =
1457       interfaces_->GetWindowList();
1458
1459   for (size_t i = 0; i < window_list.size(); ++i) {
1460     window_list.at(i)->GetWebView()->setZoomLevel(
1461         ZoomFactorToZoomLevel(zoom_factor));
1462   }
1463 }
1464
1465 void EventSender::SetPageScaleFactor(float scale_factor, int x, int y) {
1466   view_->setPageScaleFactorLimits(scale_factor, scale_factor);
1467   view_->setPageScaleFactor(scale_factor, WebPoint(x, y));
1468 }
1469
1470 void EventSender::ClearTouchPoints() {
1471   touch_points_.clear();
1472 }
1473
1474 void EventSender::ThrowTouchPointError() {
1475   v8::Isolate* isolate = blink::mainThreadIsolate();
1476   isolate->ThrowException(v8::Exception::TypeError(
1477       gin::StringToV8(isolate, "Invalid touch point.")));
1478 }
1479
1480 void EventSender::ReleaseTouchPoint(unsigned index) {
1481   if (index >= touch_points_.size()) {
1482     ThrowTouchPointError();
1483     return;
1484   }
1485
1486   WebTouchPoint* touch_point = &touch_points_[index];
1487   touch_point->state = WebTouchPoint::StateReleased;
1488 }
1489
1490 void EventSender::UpdateTouchPoint(unsigned index, float x, float y) {
1491   if (index >= touch_points_.size()) {
1492     ThrowTouchPointError();
1493     return;
1494   }
1495
1496   WebTouchPoint* touch_point = &touch_points_[index];
1497   touch_point->state = WebTouchPoint::StateMoved;
1498   touch_point->position = WebFloatPoint(x, y);
1499   touch_point->screenPosition = touch_point->position;
1500 }
1501
1502 void EventSender::CancelTouchPoint(unsigned index) {
1503   if (index >= touch_points_.size()) {
1504     ThrowTouchPointError();
1505     return;
1506   }
1507
1508   WebTouchPoint* touch_point = &touch_points_[index];
1509   touch_point->state = WebTouchPoint::StateCancelled;
1510 }
1511
1512 void EventSender::SetTouchModifier(const std::string& key_name,
1513                                     bool set_mask) {
1514   int mask = 0;
1515   if (key_name == "shift")
1516     mask = WebInputEvent::ShiftKey;
1517   else if (key_name == "alt")
1518     mask = WebInputEvent::AltKey;
1519   else if (key_name == "ctrl")
1520     mask = WebInputEvent::ControlKey;
1521   else if (key_name == "meta")
1522     mask = WebInputEvent::MetaKey;
1523
1524   if (set_mask)
1525     touch_modifiers_ |= mask;
1526   else
1527     touch_modifiers_ &= ~mask;
1528 }
1529
1530 void EventSender::SetTouchCancelable(bool cancelable) {
1531   touch_cancelable_ = cancelable;
1532 }
1533
1534 void EventSender::DumpFilenameBeingDragged() {
1535   WebString filename;
1536   WebVector<WebDragData::Item> items = current_drag_data_.items();
1537   for (size_t i = 0; i < items.size(); ++i) {
1538     if (items[i].storageType == WebDragData::Item::StorageTypeBinaryData) {
1539       filename = items[i].title;
1540       break;
1541     }
1542   }
1543   delegate_->PrintMessage(std::string("Filename being dragged: ") +
1544                           filename.utf8().data() + "\n");
1545 }
1546
1547 void EventSender::GestureFlingCancel() {
1548   WebGestureEvent event;
1549   event.type = WebInputEvent::GestureFlingCancel;
1550   event.timeStampSeconds = GetCurrentEventTimeSec();
1551
1552   if (force_layout_on_events_)
1553     view_->layout();
1554
1555   view_->handleInputEvent(event);
1556 }
1557
1558 void EventSender::GestureFlingStart(float x,
1559                                      float y,
1560                                      float velocity_x,
1561                                      float velocity_y) {
1562   WebGestureEvent event;
1563   event.type = WebInputEvent::GestureFlingStart;
1564
1565   event.x = x;
1566   event.y = y;
1567   event.globalX = event.x;
1568   event.globalY = event.y;
1569
1570   event.data.flingStart.velocityX = velocity_x;
1571   event.data.flingStart.velocityY = velocity_y;
1572   event.timeStampSeconds = GetCurrentEventTimeSec();
1573
1574   if (force_layout_on_events_)
1575     view_->layout();
1576
1577   view_->handleInputEvent(event);
1578 }
1579
1580 void EventSender::GestureScrollFirstPoint(int x, int y) {
1581   current_gesture_location_ = WebPoint(x, y);
1582 }
1583
1584 void EventSender::TouchStart() {
1585   SendCurrentTouchEvent(WebInputEvent::TouchStart);
1586 }
1587
1588 void EventSender::TouchMove() {
1589   SendCurrentTouchEvent(WebInputEvent::TouchMove);
1590 }
1591
1592 void EventSender::TouchCancel() {
1593   SendCurrentTouchEvent(WebInputEvent::TouchCancel);
1594 }
1595
1596 void EventSender::TouchEnd() {
1597   SendCurrentTouchEvent(WebInputEvent::TouchEnd);
1598 }
1599
1600 void EventSender::LeapForward(int milliseconds) {
1601   if (is_drag_mode_ && pressed_button_ == WebMouseEvent::ButtonLeft &&
1602       !replaying_saved_events_) {
1603     SavedEvent saved_event;
1604     saved_event.type = SavedEvent::TYPE_LEAP_FORWARD;
1605     saved_event.milliseconds = milliseconds;
1606     mouse_event_queue_.push_back(saved_event);
1607   } else {
1608     DoLeapForward(milliseconds);
1609   }
1610 }
1611
1612 void EventSender::BeginDragWithFiles(const std::vector<std::string>& files) {
1613   current_drag_data_.initialize();
1614   WebVector<WebString> absolute_filenames(files.size());
1615   for (size_t i = 0; i < files.size(); ++i) {
1616     WebDragData::Item item;
1617     item.storageType = WebDragData::Item::StorageTypeFilename;
1618     item.filenameData = delegate_->GetAbsoluteWebStringFromUTF8Path(files[i]);
1619     current_drag_data_.addItem(item);
1620     absolute_filenames[i] = item.filenameData;
1621   }
1622   current_drag_data_.setFilesystemId(
1623       delegate_->RegisterIsolatedFileSystem(absolute_filenames));
1624   current_drag_effects_allowed_ = blink::WebDragOperationCopy;
1625
1626   // Provide a drag source.
1627   view_->dragTargetDragEnter(current_drag_data_,
1628                              last_mouse_pos_,
1629                              last_mouse_pos_,
1630                              current_drag_effects_allowed_,
1631                              0);
1632   // |is_drag_mode_| saves events and then replays them later. We don't
1633   // need/want that.
1634   is_drag_mode_ = false;
1635
1636   // Make the rest of eventSender think a drag is in progress.
1637   pressed_button_ = WebMouseEvent::ButtonLeft;
1638 }
1639
1640 void EventSender::AddTouchPoint(gin::Arguments* args) {
1641   double x;
1642   double y;
1643   if (!args->GetNext(&x) || !args->GetNext(&y)) {
1644     args->ThrowError();
1645     return;
1646   }
1647
1648   WebTouchPoint touch_point;
1649   touch_point.state = WebTouchPoint::StatePressed;
1650   touch_point.position = WebFloatPoint(static_cast<float>(x),
1651                                        static_cast<float>(y));
1652   touch_point.screenPosition = touch_point.position;
1653
1654   if (!args->PeekNext().IsEmpty()) {
1655     double radius_x;
1656     if (!args->GetNext(&radius_x)) {
1657       args->ThrowError();
1658       return;
1659     }
1660
1661     double radius_y = radius_x;
1662     if (!args->PeekNext().IsEmpty()) {
1663       if (!args->GetNext(&radius_y)) {
1664         args->ThrowError();
1665         return;
1666       }
1667     }
1668
1669     touch_point.radiusX = static_cast<float>(radius_x);
1670     touch_point.radiusY = static_cast<float>(radius_y);
1671   }
1672
1673   int lowest_id = 0;
1674   for (size_t i = 0; i < touch_points_.size(); i++) {
1675     if (touch_points_[i].id == lowest_id)
1676       lowest_id++;
1677   }
1678   touch_point.id = lowest_id;
1679   touch_points_.push_back(touch_point);
1680 }
1681
1682 void EventSender::MouseDragBegin() {
1683   WebMouseWheelEvent event;
1684   InitMouseEvent(WebInputEvent::MouseWheel,
1685                  WebMouseEvent::ButtonNone,
1686                  last_mouse_pos_,
1687                  GetCurrentEventTimeSec(),
1688                  click_count_,
1689                  0,
1690                  &event);
1691   event.phase = WebMouseWheelEvent::PhaseBegan;
1692   event.hasPreciseScrollingDeltas = true;
1693   view_->handleInputEvent(event);
1694 }
1695
1696 void EventSender::MouseDragEnd() {
1697   WebMouseWheelEvent event;
1698   InitMouseEvent(WebInputEvent::MouseWheel,
1699                  WebMouseEvent::ButtonNone,
1700                  last_mouse_pos_,
1701                  GetCurrentEventTimeSec(),
1702                  click_count_,
1703                  0,
1704                  &event);
1705   event.phase = WebMouseWheelEvent::PhaseEnded;
1706   event.hasPreciseScrollingDeltas = true;
1707   view_->handleInputEvent(event);
1708 }
1709
1710 void EventSender::GestureScrollBegin(gin::Arguments* args) {
1711   GestureEvent(WebInputEvent::GestureScrollBegin, args);
1712 }
1713
1714 void EventSender::GestureScrollEnd(gin::Arguments* args) {
1715   GestureEvent(WebInputEvent::GestureScrollEnd, args);
1716 }
1717
1718 void EventSender::GestureScrollUpdate(gin::Arguments* args) {
1719   GestureEvent(WebInputEvent::GestureScrollUpdate, args);
1720 }
1721
1722 void EventSender::GestureScrollUpdateWithoutPropagation(gin::Arguments* args) {
1723   GestureEvent(WebInputEvent::GestureScrollUpdateWithoutPropagation, args);
1724 }
1725
1726 void EventSender::GestureTap(gin::Arguments* args) {
1727   GestureEvent(WebInputEvent::GestureTap, args);
1728 }
1729
1730 void EventSender::GestureTapDown(gin::Arguments* args) {
1731   GestureEvent(WebInputEvent::GestureTapDown, args);
1732 }
1733
1734 void EventSender::GestureShowPress(gin::Arguments* args) {
1735   GestureEvent(WebInputEvent::GestureShowPress, args);
1736 }
1737
1738 void EventSender::GestureTapCancel(gin::Arguments* args) {
1739   GestureEvent(WebInputEvent::GestureTapCancel, args);
1740 }
1741
1742 void EventSender::GestureLongPress(gin::Arguments* args) {
1743   GestureEvent(WebInputEvent::GestureLongPress, args);
1744 }
1745
1746 void EventSender::GestureLongTap(gin::Arguments* args) {
1747   GestureEvent(WebInputEvent::GestureLongTap, args);
1748 }
1749
1750 void EventSender::GestureTwoFingerTap(gin::Arguments* args) {
1751   GestureEvent(WebInputEvent::GestureTwoFingerTap, args);
1752 }
1753
1754 void EventSender::ContinuousMouseScrollBy(gin::Arguments* args) {
1755   WebMouseWheelEvent event;
1756   InitMouseWheelEvent(args, true, &event);
1757   view_->handleInputEvent(event);
1758 }
1759
1760 void EventSender::MouseMoveTo(gin::Arguments* args) {
1761   if (force_layout_on_events_)
1762     view_->layout();
1763
1764   double x;
1765   double y;
1766   if (!args->GetNext(&x) || !args->GetNext(&y)) {
1767     args->ThrowError();
1768     return;
1769   }
1770   WebPoint mouse_pos(static_cast<int>(x), static_cast<int>(y));
1771
1772   int modifiers = 0;
1773   if (!args->PeekNext().IsEmpty())
1774     modifiers = GetKeyModifiersFromV8(args->PeekNext());
1775
1776   if (is_drag_mode_ && pressed_button_ == WebMouseEvent::ButtonLeft &&
1777       !replaying_saved_events_) {
1778     SavedEvent saved_event;
1779     saved_event.type = SavedEvent::TYPE_MOUSE_MOVE;
1780     saved_event.pos = mouse_pos;
1781     saved_event.modifiers = modifiers;
1782     mouse_event_queue_.push_back(saved_event);
1783   } else {
1784     WebMouseEvent event;
1785     InitMouseEvent(WebInputEvent::MouseMove,
1786                    pressed_button_,
1787                    mouse_pos,
1788                    GetCurrentEventTimeSec(),
1789                    click_count_,
1790                    modifiers,
1791                    &event);
1792     DoMouseMove(event);
1793   }
1794 }
1795
1796 void EventSender::TrackpadScrollBegin() {
1797   WebMouseWheelEvent event;
1798   InitMouseEvent(WebInputEvent::MouseWheel,
1799                  WebMouseEvent::ButtonNone,
1800                  last_mouse_pos_,
1801                  GetCurrentEventTimeSec(),
1802                  click_count_,
1803                  0,
1804                  &event);
1805   event.phase = blink::WebMouseWheelEvent::PhaseBegan;
1806   event.hasPreciseScrollingDeltas = true;
1807   view_->handleInputEvent(event);
1808 }
1809
1810 void EventSender::TrackpadScroll(gin::Arguments* args) {
1811   WebMouseWheelEvent event;
1812   InitMouseWheelEvent(args, true, &event);
1813   event.phase = blink::WebMouseWheelEvent::PhaseChanged;
1814   event.hasPreciseScrollingDeltas = true;
1815   view_->handleInputEvent(event);
1816 }
1817
1818 void EventSender::TrackpadScrollEnd() {
1819   WebMouseWheelEvent event;
1820   InitMouseEvent(WebInputEvent::MouseWheel,
1821                  WebMouseEvent::ButtonNone,
1822                  last_mouse_pos_,
1823                  GetCurrentEventTimeSec(),
1824                  click_count_,
1825                  0,
1826                  &event);
1827   event.phase = WebMouseWheelEvent::PhaseEnded;
1828   event.hasPreciseScrollingDeltas = true;
1829   view_->handleInputEvent(event);
1830 }
1831
1832 void EventSender::MouseScrollBy(gin::Arguments* args) {
1833    WebMouseWheelEvent event;
1834   InitMouseWheelEvent(args, false, &event);
1835   view_->handleInputEvent(event);
1836 }
1837
1838 void EventSender::MouseMomentumBegin() {
1839   WebMouseWheelEvent event;
1840   InitMouseEvent(WebInputEvent::MouseWheel,
1841                  WebMouseEvent::ButtonNone,
1842                  last_mouse_pos_,
1843                  GetCurrentEventTimeSec(),
1844                  click_count_,
1845                  0,
1846                  &event);
1847   event.momentumPhase = WebMouseWheelEvent::PhaseBegan;
1848   event.hasPreciseScrollingDeltas = true;
1849   view_->handleInputEvent(event);
1850 }
1851
1852 void EventSender::MouseMomentumBegin2(gin::Arguments* args) {
1853   WebMouseWheelEvent event;
1854   InitMouseWheelEvent(args, true, &event);
1855   event.momentumPhase = WebMouseWheelEvent::PhaseBegan;
1856   event.hasPreciseScrollingDeltas = true;
1857   view_->handleInputEvent(event);
1858 }
1859
1860 void EventSender::MouseMomentumScrollBy(gin::Arguments* args) {
1861   WebMouseWheelEvent event;
1862   InitMouseWheelEvent(args, true, &event);
1863   event.momentumPhase = WebMouseWheelEvent::PhaseChanged;
1864   event.hasPreciseScrollingDeltas = true;
1865   view_->handleInputEvent(event);
1866 }
1867
1868 void EventSender::MouseMomentumEnd() {
1869   WebMouseWheelEvent event;
1870   InitMouseEvent(WebInputEvent::MouseWheel,
1871                  WebMouseEvent::ButtonNone,
1872                  last_mouse_pos_,
1873                  GetCurrentEventTimeSec(),
1874                  click_count_,
1875                  0,
1876                  &event);
1877   event.momentumPhase = WebMouseWheelEvent::PhaseEnded;
1878   event.hasPreciseScrollingDeltas = true;
1879   view_->handleInputEvent(event);
1880 }
1881
1882 void EventSender::ScheduleAsynchronousClick(int button_number, int modifiers) {
1883   delegate_->PostTask(new MouseDownTask(this, button_number, modifiers));
1884   delegate_->PostTask(new MouseUpTask(this, button_number, modifiers));
1885 }
1886
1887 void EventSender::ScheduleAsynchronousKeyDown(const std::string& code_str,
1888                                               int modifiers,
1889                                               KeyLocationCode location) {
1890   delegate_->PostTask(new KeyDownTask(this, code_str, modifiers, location));
1891 }
1892
1893 double EventSender::GetCurrentEventTimeSec() {
1894   return (delegate_->GetCurrentTimeInMillisecond() + time_offset_ms_) / 1000.0;
1895 }
1896
1897 void EventSender::DoLeapForward(int milliseconds) {
1898   time_offset_ms_ += milliseconds;
1899 }
1900
1901 void EventSender::SendCurrentTouchEvent(WebInputEvent::Type type) {
1902   DCHECK_GT(static_cast<unsigned>(WebTouchEvent::touchesLengthCap),
1903             touch_points_.size());
1904   if (force_layout_on_events_)
1905     view_->layout();
1906
1907   WebTouchEvent touch_event;
1908   touch_event.type = type;
1909   touch_event.modifiers = touch_modifiers_;
1910   touch_event.cancelable = touch_cancelable_;
1911   touch_event.timeStampSeconds = GetCurrentEventTimeSec();
1912   touch_event.touchesLength = touch_points_.size();
1913   for (size_t i = 0; i < touch_points_.size(); ++i)
1914     touch_event.touches[i] = touch_points_[i];
1915   view_->handleInputEvent(touch_event);
1916
1917   for (size_t i = 0; i < touch_points_.size(); ++i) {
1918     WebTouchPoint* touch_point = &touch_points_[i];
1919     if (touch_point->state == WebTouchPoint::StateReleased) {
1920       touch_points_.erase(touch_points_.begin() + i);
1921       --i;
1922     } else
1923       touch_point->state = WebTouchPoint::StateStationary;
1924   }
1925 }
1926
1927 void EventSender::GestureEvent(WebInputEvent::Type type,
1928                                gin::Arguments* args) {
1929   double x;
1930   double y;
1931   if (!args->GetNext(&x) || !args->GetNext(&y)) {
1932     args->ThrowError();
1933     return;
1934   }
1935
1936   WebGestureEvent event;
1937   event.type = type;
1938
1939   switch (type) {
1940     case WebInputEvent::GestureScrollUpdate:
1941     case WebInputEvent::GestureScrollUpdateWithoutPropagation:
1942       event.data.scrollUpdate.deltaX = static_cast<float>(x);
1943       event.data.scrollUpdate.deltaY = static_cast<float>(y);
1944       event.x = current_gesture_location_.x;
1945       event.y = current_gesture_location_.y;
1946       current_gesture_location_.x =
1947           current_gesture_location_.x + event.data.scrollUpdate.deltaX;
1948       current_gesture_location_.y =
1949           current_gesture_location_.y + event.data.scrollUpdate.deltaY;
1950       break;
1951     case WebInputEvent::GestureScrollBegin:
1952       current_gesture_location_ = WebPoint(x, y);
1953       event.x = current_gesture_location_.x;
1954       event.y = current_gesture_location_.y;
1955       break;
1956     case WebInputEvent::GestureScrollEnd:
1957     case WebInputEvent::GestureFlingStart:
1958       event.x = current_gesture_location_.x;
1959       event.y = current_gesture_location_.y;
1960       break;
1961     case WebInputEvent::GestureTap:
1962     {
1963       float tap_count = 1;
1964       float width = 30;
1965       float height = 30;
1966       if (!args->PeekNext().IsEmpty()) {
1967         if (!args->GetNext(&tap_count)) {
1968           args->ThrowError();
1969           return;
1970         }
1971       }
1972       if (!args->PeekNext().IsEmpty()) {
1973         if (!args->GetNext(&width)) {
1974           args->ThrowError();
1975           return;
1976         }
1977       }
1978       if (!args->PeekNext().IsEmpty()) {
1979         if (!args->GetNext(&height)) {
1980           args->ThrowError();
1981           return;
1982         }
1983       }
1984       event.data.tap.tapCount = tap_count;
1985       event.data.tap.width = width;
1986       event.data.tap.height = height;
1987       event.x = x;
1988       event.y = y;
1989       break;
1990     }
1991     case WebInputEvent::GestureTapUnconfirmed:
1992       if (!args->PeekNext().IsEmpty()) {
1993         float tap_count;
1994         if (!args->GetNext(&tap_count)) {
1995           args->ThrowError();
1996           return;
1997         }
1998         event.data.tap.tapCount = tap_count;
1999       } else {
2000         event.data.tap.tapCount = 1;
2001       }
2002       event.x = x;
2003       event.y = y;
2004       break;
2005     case WebInputEvent::GestureTapDown:
2006     {
2007       float width = 30;
2008       float height = 30;
2009       if (!args->PeekNext().IsEmpty()) {
2010         if (!args->GetNext(&width)) {
2011           args->ThrowError();
2012           return;
2013         }
2014       }
2015       if (!args->PeekNext().IsEmpty()) {
2016         if (!args->GetNext(&height)) {
2017           args->ThrowError();
2018           return;
2019         }
2020       }
2021       event.x = x;
2022       event.y = y;
2023       event.data.tapDown.width = width;
2024       event.data.tapDown.height = height;
2025       break;
2026     }
2027     case WebInputEvent::GestureShowPress:
2028     {
2029       float width = 30;
2030       float height = 30;
2031       if (!args->PeekNext().IsEmpty()) {
2032         if (!args->GetNext(&width)) {
2033           args->ThrowError();
2034           return;
2035         }
2036         if (!args->PeekNext().IsEmpty()) {
2037           if (!args->GetNext(&height)) {
2038             args->ThrowError();
2039             return;
2040           }
2041         }
2042       }
2043       event.x = x;
2044       event.y = y;
2045       event.data.showPress.width = width;
2046       event.data.showPress.height = height;
2047       break;
2048     }
2049     case WebInputEvent::GestureTapCancel:
2050       event.x = x;
2051       event.y = y;
2052       break;
2053     case WebInputEvent::GestureLongPress:
2054       event.x = x;
2055       event.y = y;
2056       if (!args->PeekNext().IsEmpty()) {
2057         float width;
2058         if (!args->GetNext(&width)) {
2059           args->ThrowError();
2060           return;
2061         }
2062         event.data.longPress.width = width;
2063         if (!args->PeekNext().IsEmpty()) {
2064           float height;
2065           if (!args->GetNext(&height)) {
2066             args->ThrowError();
2067             return;
2068           }
2069           event.data.longPress.height = height;
2070         }
2071       }
2072       break;
2073     case WebInputEvent::GestureLongTap:
2074       event.x = x;
2075       event.y = y;
2076       if (!args->PeekNext().IsEmpty()) {
2077         float width;
2078         if (!args->GetNext(&width)) {
2079           args->ThrowError();
2080           return;
2081         }
2082         event.data.longPress.width = width;
2083         if (!args->PeekNext().IsEmpty()) {
2084           float height;
2085           if (!args->GetNext(&height)) {
2086             args->ThrowError();
2087             return;
2088           }
2089           event.data.longPress.height = height;
2090         }
2091       }
2092       break;
2093     case WebInputEvent::GestureTwoFingerTap:
2094       event.x = x;
2095       event.y = y;
2096       if (!args->PeekNext().IsEmpty()) {
2097         float first_finger_width;
2098         if (!args->GetNext(&first_finger_width)) {
2099           args->ThrowError();
2100           return;
2101         }
2102         event.data.twoFingerTap.firstFingerWidth = first_finger_width;
2103         if (!args->PeekNext().IsEmpty()) {
2104           float first_finger_height;
2105           if (!args->GetNext(&first_finger_height)) {
2106             args->ThrowError();
2107             return;
2108           }
2109           event.data.twoFingerTap.firstFingerHeight = first_finger_height;
2110         }
2111       }
2112       break;
2113     default:
2114       NOTREACHED();
2115   }
2116
2117   event.globalX = event.x;
2118   event.globalY = event.y;
2119   event.timeStampSeconds = GetCurrentEventTimeSec();
2120
2121   if (force_layout_on_events_)
2122     view_->layout();
2123
2124   bool result = view_->handleInputEvent(event);
2125
2126   // Long press might start a drag drop session. Complete it if so.
2127   if (type == WebInputEvent::GestureLongPress && !current_drag_data_.isNull()) {
2128     WebMouseEvent mouse_event;
2129     InitMouseEvent(WebInputEvent::MouseDown,
2130                    pressed_button_,
2131                    WebPoint(x, y),
2132                    GetCurrentEventTimeSec(),
2133                    click_count_,
2134                    0,
2135                    &mouse_event);
2136
2137     FinishDragAndDrop(mouse_event, blink::WebDragOperationNone);
2138   }
2139   args->Return(result);
2140 }
2141
2142 void EventSender::UpdateClickCountForButton(
2143     WebMouseEvent::Button button_type) {
2144   if ((GetCurrentEventTimeSec() - last_click_time_sec_ <
2145        kMultipleClickTimeSec) &&
2146       (!OutsideMultiClickRadius(last_mouse_pos_, last_click_pos_)) &&
2147       (button_type == last_button_type_)) {
2148     ++click_count_;
2149   } else {
2150     click_count_ = 1;
2151     last_button_type_ = button_type;
2152   }
2153 }
2154
2155 void EventSender::InitMouseWheelEvent(gin::Arguments* args,
2156                                       bool continuous,
2157                                       WebMouseWheelEvent* event) {
2158   // Force a layout here just to make sure every position has been
2159   // determined before we send events (as well as all the other methods
2160   // that send an event do).
2161   if (force_layout_on_events_)
2162     view_->layout();
2163
2164   double horizontal;
2165   if (!args->GetNext(&horizontal)) {
2166     args->ThrowError();
2167     return;
2168   }
2169   double vertical;
2170   if (!args->GetNext(&vertical)) {
2171     args->ThrowError();
2172     return;
2173   }
2174
2175   bool paged = false;
2176   bool has_precise_scrolling_deltas = false;
2177   int modifiers = 0;
2178   if (!args->PeekNext().IsEmpty()) {
2179     args->GetNext(&paged);
2180     if (!args->PeekNext().IsEmpty()) {
2181       args->GetNext(&has_precise_scrolling_deltas);
2182       if (!args->PeekNext().IsEmpty())
2183         modifiers = GetKeyModifiersFromV8(args->PeekNext());
2184     }
2185   }
2186
2187   InitMouseEvent(WebInputEvent::MouseWheel,
2188                  pressed_button_,
2189                  last_mouse_pos_,
2190                  GetCurrentEventTimeSec(),
2191                  click_count_,
2192                  modifiers,
2193                  event);
2194   event->wheelTicksX = static_cast<float>(horizontal);
2195   event->wheelTicksY = static_cast<float>(vertical);
2196   event->deltaX = event->wheelTicksX;
2197   event->deltaY = event->wheelTicksY;
2198   event->scrollByPage = paged;
2199   event->hasPreciseScrollingDeltas = has_precise_scrolling_deltas;
2200
2201   if (continuous) {
2202     event->wheelTicksX /= kScrollbarPixelsPerTick;
2203     event->wheelTicksY /= kScrollbarPixelsPerTick;
2204   } else {
2205     event->deltaX *= kScrollbarPixelsPerTick;
2206     event->deltaY *= kScrollbarPixelsPerTick;
2207   }
2208 }
2209
2210 void EventSender::FinishDragAndDrop(const WebMouseEvent& e,
2211                                      blink::WebDragOperation drag_effect) {
2212   WebPoint client_point(e.x, e.y);
2213   WebPoint screen_point(e.globalX, e.globalY);
2214   current_drag_effect_ = drag_effect;
2215   if (current_drag_effect_) {
2216     // Specifically pass any keyboard modifiers to the drop method. This allows
2217     // tests to control the drop type (i.e. copy or move).
2218     view_->dragTargetDrop(client_point, screen_point, e.modifiers);
2219   } else {
2220     view_->dragTargetDragLeave();
2221   }
2222   view_->dragSourceEndedAt(client_point, screen_point, current_drag_effect_);
2223   view_->dragSourceSystemDragEnded();
2224
2225   current_drag_data_.reset();
2226 }
2227
2228 void EventSender::DoMouseUp(const WebMouseEvent& e) {
2229   view_->handleInputEvent(e);
2230
2231   pressed_button_ = WebMouseEvent::ButtonNone;
2232   last_click_time_sec_ = e.timeStampSeconds;
2233   last_click_pos_ = last_mouse_pos_;
2234
2235   // If we're in a drag operation, complete it.
2236   if (current_drag_data_.isNull())
2237     return;
2238
2239   WebPoint client_point(e.x, e.y);
2240   WebPoint screen_point(e.globalX, e.globalY);
2241   FinishDragAndDrop(
2242       e,
2243       view_->dragTargetDragOver(
2244           client_point, screen_point, current_drag_effects_allowed_, 0));
2245 }
2246
2247 void EventSender::DoMouseMove(const WebMouseEvent& e) {
2248   last_mouse_pos_ = WebPoint(e.x, e.y);
2249
2250   view_->handleInputEvent(e);
2251
2252   if (pressed_button_ == WebMouseEvent::ButtonNone ||
2253       current_drag_data_.isNull()) {
2254     return;
2255   }
2256
2257   WebPoint client_point(e.x, e.y);
2258   WebPoint screen_point(e.globalX, e.globalY);
2259   current_drag_effect_ = view_->dragTargetDragOver(
2260       client_point, screen_point, current_drag_effects_allowed_, 0);
2261 }
2262
2263 void EventSender::ReplaySavedEvents() {
2264   replaying_saved_events_ = true;
2265   while (!mouse_event_queue_.empty()) {
2266     SavedEvent e = mouse_event_queue_.front();
2267     mouse_event_queue_.pop_front();
2268
2269     switch (e.type) {
2270       case SavedEvent::TYPE_MOUSE_MOVE: {
2271         WebMouseEvent event;
2272         InitMouseEvent(WebInputEvent::MouseMove,
2273                        pressed_button_,
2274                        e.pos,
2275                        GetCurrentEventTimeSec(),
2276                        click_count_,
2277                        e.modifiers,
2278                        &event);
2279         DoMouseMove(event);
2280         break;
2281       }
2282       case SavedEvent::TYPE_LEAP_FORWARD:
2283         DoLeapForward(e.milliseconds);
2284         break;
2285       case SavedEvent::TYPE_MOUSE_UP: {
2286         WebMouseEvent event;
2287         InitMouseEvent(WebInputEvent::MouseUp,
2288                        e.button_type,
2289                        last_mouse_pos_,
2290                        GetCurrentEventTimeSec(),
2291                        click_count_,
2292                        e.modifiers,
2293                        &event);
2294         DoMouseUp(event);
2295         break;
2296       }
2297       default:
2298         NOTREACHED();
2299     }
2300   }
2301
2302   replaying_saved_events_ = false;
2303 }
2304
2305 }  // namespace content