Home | History | Annotate | Download | only in test_runner
      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
   2306