Extension syncing: Introduce a NeedsSync pref
[chromium-blink-merge.git] / components / test_runner / event_sender.cc
blob0b1c78b59f23da4647f8eed50811f635b17b5920
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.
5 #include "components/test_runner/event_sender.h"
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "components/test_runner/mock_spell_check.h"
12 #include "components/test_runner/test_interfaces.h"
13 #include "components/test_runner/web_test_delegate.h"
14 #include "components/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/WebPagePopup.h"
24 #include "third_party/WebKit/public/web/WebView.h"
25 #include "ui/events/keycodes/dom/keycode_converter.h"
26 #include "ui/events/keycodes/keyboard_codes.h"
27 #include "v8/include/v8.h"
29 using blink::WebContextMenuData;
30 using blink::WebDragData;
31 using blink::WebDragOperationsMask;
32 using blink::WebFloatPoint;
33 using blink::WebFrame;
34 using blink::WebGestureEvent;
35 using blink::WebInputEvent;
36 using blink::WebKeyboardEvent;
37 using blink::WebMenuItemInfo;
38 using blink::WebMouseEvent;
39 using blink::WebMouseWheelEvent;
40 using blink::WebPagePopup;
41 using blink::WebPoint;
42 using blink::WebString;
43 using blink::WebTouchEvent;
44 using blink::WebTouchPoint;
45 using blink::WebVector;
46 using blink::WebView;
48 namespace test_runner {
50 namespace {
52 void InitMouseEvent(WebInputEvent::Type t,
53 WebMouseEvent::Button b,
54 const WebPoint& pos,
55 double time_stamp,
56 int click_count,
57 int modifiers,
58 WebMouseEvent* e) {
59 e->type = t;
60 e->button = b;
61 e->modifiers = modifiers;
62 e->x = pos.x;
63 e->y = pos.y;
64 e->globalX = pos.x;
65 e->globalY = pos.y;
66 e->timeStampSeconds = time_stamp;
67 e->clickCount = click_count;
70 int GetKeyModifier(const std::string& modifier_name) {
71 const char* characters = modifier_name.c_str();
72 if (!strcmp(characters, "ctrlKey")
73 #ifndef __APPLE__
74 || !strcmp(characters, "addSelectionKey")
75 #endif
76 ) {
77 return WebInputEvent::ControlKey;
78 } else if (!strcmp(characters, "shiftKey") ||
79 !strcmp(characters, "rangeSelectionKey")) {
80 return WebInputEvent::ShiftKey;
81 } else if (!strcmp(characters, "altKey")) {
82 return WebInputEvent::AltKey;
83 #ifdef __APPLE__
84 } else if (!strcmp(characters, "metaKey") ||
85 !strcmp(characters, "addSelectionKey")) {
86 return WebInputEvent::MetaKey;
87 #else
88 } else if (!strcmp(characters, "metaKey")) {
89 return WebInputEvent::MetaKey;
90 #endif
91 } else if (!strcmp(characters, "autoRepeat")) {
92 return WebInputEvent::IsAutoRepeat;
93 } else if (!strcmp(characters, "copyKey")) {
94 #ifdef __APPLE__
95 return WebInputEvent::AltKey;
96 #else
97 return WebInputEvent::ControlKey;
98 #endif
99 } else if (!strcmp(characters, "leftButton")) {
100 return WebInputEvent::LeftButtonDown;
101 } else if (!strcmp(characters, "middleButton")) {
102 return WebInputEvent::MiddleButtonDown;
103 } else if (!strcmp(characters, "rightButton")) {
104 return WebInputEvent::RightButtonDown;
107 return 0;
110 int GetKeyModifiers(const std::vector<std::string>& modifier_names) {
111 int modifiers = 0;
112 for (std::vector<std::string>::const_iterator it = modifier_names.begin();
113 it != modifier_names.end(); ++it) {
114 modifiers |= GetKeyModifier(*it);
116 return modifiers;
119 int GetKeyModifiersFromV8(v8::Isolate* isolate, v8::Local<v8::Value> value) {
120 std::vector<std::string> modifier_names;
121 if (value->IsString()) {
122 modifier_names.push_back(gin::V8ToString(value));
123 } else if (value->IsArray()) {
124 gin::Converter<std::vector<std::string> >::FromV8(
125 isolate, value, &modifier_names);
127 return GetKeyModifiers(modifier_names);
130 // Maximum distance (in space and time) for a mouse click to register as a
131 // double or triple click.
132 const double kMultipleClickTimeSec = 1;
133 const int kMultipleClickRadiusPixels = 5;
134 const char kSubMenuDepthIdentifier[] = "_";
135 const char kSubMenuIdentifier[] = " >";
136 const char kSeparatorIdentifier[] = "---------";
137 const char kDisabledIdentifier[] = "#";
138 const char kCheckedIdentifier[] = "*";
140 bool OutsideMultiClickRadius(const WebPoint& a, const WebPoint& b) {
141 return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)) >
142 kMultipleClickRadiusPixels * kMultipleClickRadiusPixels;
145 void PopulateCustomItems(const WebVector<WebMenuItemInfo>& customItems,
146 const std::string& prefix, std::vector<std::string>* strings) {
147 for (size_t i = 0; i < customItems.size(); ++i) {
148 std::string prefixCopy = prefix;
149 if (!customItems[i].enabled)
150 prefixCopy = kDisabledIdentifier + prefix;
151 if (customItems[i].checked)
152 prefixCopy = kCheckedIdentifier + prefix;
153 if (customItems[i].type == blink::WebMenuItemInfo::Separator) {
154 strings->push_back(prefixCopy + kSeparatorIdentifier);
155 } else if (customItems[i].type == blink::WebMenuItemInfo::SubMenu) {
156 strings->push_back(prefixCopy + customItems[i].label.utf8() +
157 customItems[i].icon.utf8() + kSubMenuIdentifier);
158 PopulateCustomItems(customItems[i].subMenuItems, prefixCopy +
159 kSubMenuDepthIdentifier, strings);
160 } else {
161 strings->push_back(prefixCopy + customItems[i].label.utf8() +
162 customItems[i].icon.utf8());
167 // Because actual context menu is implemented by the browser side,
168 // this function does only what LayoutTests are expecting:
169 // - Many test checks the count of items. So returning non-zero value makes
170 // sense.
171 // - Some test compares the count before and after some action. So changing the
172 // count based on flags also makes sense. This function is doing such for some
173 // flags.
174 // - Some test even checks actual string content. So providing it would be also
175 // helpful.
176 std::vector<std::string> MakeMenuItemStringsFor(
177 WebContextMenuData* context_menu,
178 WebTestDelegate* delegate) {
179 // These constants are based on Safari's context menu because tests are made
180 // for it.
181 static const char* kNonEditableMenuStrings[] = {
182 "Back",
183 "Reload Page",
184 "Open in Dashbaord",
185 "<separator>",
186 "View Source",
187 "Save Page As",
188 "Print Page",
189 "Inspect Element",
192 static const char* kEditableMenuStrings[] = {
193 "Cut",
194 "Copy",
195 "<separator>",
196 "Paste",
197 "Spelling and Grammar",
198 "Substitutions, Transformations",
199 "Font",
200 "Speech",
201 "Paragraph Direction",
202 "<separator>",
206 // This is possible because mouse events are cancelleable.
207 if (!context_menu)
208 return std::vector<std::string>();
210 std::vector<std::string> strings;
212 // Populate custom menu items if provided by blink.
213 PopulateCustomItems(context_menu->customItems, "", &strings);
215 if (context_menu->isEditable) {
216 for (const char** item = kEditableMenuStrings; *item; ++item) {
217 strings.push_back(*item);
219 WebVector<WebString> suggestions;
220 MockSpellCheck::FillSuggestionList(context_menu->misspelledWord,
221 &suggestions);
222 for (size_t i = 0; i < suggestions.size(); ++i) {
223 strings.push_back(suggestions[i].utf8());
225 } else {
226 for (const char** item = kNonEditableMenuStrings; *item; ++item) {
227 strings.push_back(*item);
231 return strings;
234 // How much we should scroll per event - the value here is chosen to match the
235 // WebKit impl and layout test results.
236 const float kScrollbarPixelsPerTick = 40.0f;
238 WebMouseEvent::Button GetButtonTypeFromButtonNumber(int button_code) {
239 if (!button_code)
240 return WebMouseEvent::ButtonLeft;
241 if (button_code == 2)
242 return WebMouseEvent::ButtonRight;
243 return WebMouseEvent::ButtonMiddle;
246 class MouseDownTask : public WebMethodTask<EventSender> {
247 public:
248 MouseDownTask(EventSender* obj, int button_number, int modifiers)
249 : WebMethodTask<EventSender>(obj),
250 button_number_(button_number),
251 modifiers_(modifiers) {}
253 void RunIfValid() override { object_->MouseDown(button_number_, modifiers_); }
255 private:
256 int button_number_;
257 int modifiers_;
260 class MouseUpTask : public WebMethodTask<EventSender> {
261 public:
262 MouseUpTask(EventSender* obj, int button_number, int modifiers)
263 : WebMethodTask<EventSender>(obj),
264 button_number_(button_number),
265 modifiers_(modifiers) {}
267 void RunIfValid() override { object_->MouseUp(button_number_, modifiers_); }
269 private:
270 int button_number_;
271 int modifiers_;
274 class KeyDownTask : public WebMethodTask<EventSender> {
275 public:
276 KeyDownTask(EventSender* obj,
277 const std::string code_str,
278 int modifiers,
279 KeyLocationCode location)
280 : WebMethodTask<EventSender>(obj),
281 code_str_(code_str),
282 modifiers_(modifiers),
283 location_(location) {}
285 void RunIfValid() override {
286 object_->KeyDown(code_str_, modifiers_, location_);
289 private:
290 std::string code_str_;
291 int modifiers_;
292 KeyLocationCode location_;
295 bool NeedsShiftModifier(int keyCode) {
296 // If code is an uppercase letter, assign a SHIFT key to eventDown.modifier.
297 return (keyCode & 0xFF) >= 'A' && (keyCode & 0xFF) <= 'Z';
300 // Get the edit command corresponding to a keyboard event.
301 // Returns true if the specified event corresponds to an edit command, the name
302 // of the edit command will be stored in |*name|.
303 bool GetEditCommand(const WebKeyboardEvent& event, std::string* name) {
304 #if defined(OS_MACOSX)
305 // We only cares about Left,Right,Up,Down keys with Command or Command+Shift
306 // modifiers. These key events correspond to some special movement and
307 // selection editor commands. These keys will be marked as system key, which
308 // prevents them from being handled. Thus they must be handled specially.
309 if ((event.modifiers & ~WebKeyboardEvent::ShiftKey) !=
310 WebKeyboardEvent::MetaKey)
311 return false;
313 switch (event.windowsKeyCode) {
314 case ui::VKEY_LEFT:
315 *name = "MoveToBeginningOfLine";
316 break;
317 case ui::VKEY_RIGHT:
318 *name = "MoveToEndOfLine";
319 break;
320 case ui::VKEY_UP:
321 *name = "MoveToBeginningOfDocument";
322 break;
323 case ui::VKEY_DOWN:
324 *name = "MoveToEndOfDocument";
325 break;
326 default:
327 return false;
330 if (event.modifiers & WebKeyboardEvent::ShiftKey)
331 name->append("AndModifySelection");
333 return true;
334 #else
335 return false;
336 #endif
339 bool IsSystemKeyEvent(const WebKeyboardEvent& event) {
340 #if defined(OS_MACOSX)
341 return event.modifiers & WebInputEvent::MetaKey &&
342 event.windowsKeyCode != ui::VKEY_B &&
343 event.windowsKeyCode != ui::VKEY_I;
344 #else
345 return !!(event.modifiers & WebInputEvent::AltKey);
346 #endif
349 const char* kSourceDeviceStringTouchpad = "touchpad";
350 const char* kSourceDeviceStringTouchscreen = "touchscreen";
352 } // namespace
354 class EventSenderBindings : public gin::Wrappable<EventSenderBindings> {
355 public:
356 static gin::WrapperInfo kWrapperInfo;
358 static void Install(base::WeakPtr<EventSender> sender,
359 blink::WebFrame* frame);
361 private:
362 explicit EventSenderBindings(base::WeakPtr<EventSender> sender);
363 ~EventSenderBindings() override;
365 // gin::Wrappable:
366 gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
367 v8::Isolate* isolate) override;
369 // Bound methods:
370 void EnableDOMUIEventLogging();
371 void FireKeyboardEventsToElement();
372 void ClearKillRing();
373 std::vector<std::string> ContextClick();
374 void TextZoomIn();
375 void TextZoomOut();
376 void ZoomPageIn();
377 void ZoomPageOut();
378 void SetPageZoomFactor(double factor);
379 void ClearTouchPoints();
380 void ReleaseTouchPoint(unsigned index);
381 void UpdateTouchPoint(unsigned index, double x, double y);
382 void CancelTouchPoint(unsigned index);
383 void SetTouchModifier(const std::string& key_name, bool set_mask);
384 void SetTouchCancelable(bool cancelable);
385 void DumpFilenameBeingDragged();
386 void GestureFlingCancel();
387 void GestureFlingStart(float x,
388 float y,
389 float velocity_x,
390 float velocity_y,
391 gin::Arguments* args);
392 void GestureScrollFirstPoint(int x, int y);
393 void TouchStart();
394 void TouchMove();
395 void TouchMoveCausingScrollIfUncanceled();
396 void TouchCancel();
397 void TouchEnd();
398 void LeapForward(int milliseconds);
399 void BeginDragWithFiles(const std::vector<std::string>& files);
400 void AddTouchPoint(gin::Arguments* args);
401 void MouseDragBegin();
402 void MouseDragEnd();
403 void GestureScrollBegin(gin::Arguments* args);
404 void GestureScrollEnd(gin::Arguments* args);
405 void GestureScrollUpdate(gin::Arguments* args);
406 void GesturePinchBegin(gin::Arguments* args);
407 void GesturePinchEnd(gin::Arguments* args);
408 void GesturePinchUpdate(gin::Arguments* args);
409 void GestureTap(gin::Arguments* args);
410 void GestureTapDown(gin::Arguments* args);
411 void GestureShowPress(gin::Arguments* args);
412 void GestureTapCancel(gin::Arguments* args);
413 void GestureLongPress(gin::Arguments* args);
414 void GestureLongTap(gin::Arguments* args);
415 void GestureTwoFingerTap(gin::Arguments* args);
416 void ContinuousMouseScrollBy(gin::Arguments* args);
417 void MouseMoveTo(gin::Arguments* args);
418 void MouseLeave();
419 void TrackpadScrollBegin();
420 void TrackpadScroll(gin::Arguments* args);
421 void TrackpadScrollEnd();
422 void MouseScrollBy(gin::Arguments* args);
423 // TODO(erikchen): Remove MouseMomentumBegin once CL 282743002 has landed.
424 void MouseMomentumBegin();
425 void MouseMomentumBegin2(gin::Arguments* args);
426 void MouseMomentumScrollBy(gin::Arguments* args);
427 void MouseMomentumEnd();
428 void ScheduleAsynchronousClick(gin::Arguments* args);
429 void ScheduleAsynchronousKeyDown(gin::Arguments* args);
430 void MouseDown(gin::Arguments* args);
431 void MouseUp(gin::Arguments* args);
432 void KeyDown(gin::Arguments* args);
434 // Binding properties:
435 bool ForceLayoutOnEvents() const;
436 void SetForceLayoutOnEvents(bool force);
437 bool IsDragMode() const;
438 void SetIsDragMode(bool drag_mode);
440 #if defined(OS_WIN)
441 int WmKeyDown() const;
442 void SetWmKeyDown(int key_down);
444 int WmKeyUp() const;
445 void SetWmKeyUp(int key_up);
447 int WmChar() const;
448 void SetWmChar(int wm_char);
450 int WmDeadChar() const;
451 void SetWmDeadChar(int dead_char);
453 int WmSysKeyDown() const;
454 void SetWmSysKeyDown(int key_down);
456 int WmSysKeyUp() const;
457 void SetWmSysKeyUp(int key_up);
459 int WmSysChar() const;
460 void SetWmSysChar(int sys_char);
462 int WmSysDeadChar() const;
463 void SetWmSysDeadChar(int sys_dead_char);
464 #endif
466 base::WeakPtr<EventSender> sender_;
468 DISALLOW_COPY_AND_ASSIGN(EventSenderBindings);
471 gin::WrapperInfo EventSenderBindings::kWrapperInfo = {gin::kEmbedderNativeGin};
473 EventSenderBindings::EventSenderBindings(base::WeakPtr<EventSender> sender)
474 : sender_(sender) {
477 EventSenderBindings::~EventSenderBindings() {}
479 // static
480 void EventSenderBindings::Install(base::WeakPtr<EventSender> sender,
481 WebFrame* frame) {
482 v8::Isolate* isolate = blink::mainThreadIsolate();
483 v8::HandleScope handle_scope(isolate);
484 v8::Local<v8::Context> context = frame->mainWorldScriptContext();
485 if (context.IsEmpty())
486 return;
488 v8::Context::Scope context_scope(context);
490 gin::Handle<EventSenderBindings> bindings =
491 gin::CreateHandle(isolate, new EventSenderBindings(sender));
492 if (bindings.IsEmpty())
493 return;
494 v8::Local<v8::Object> global = context->Global();
495 global->Set(gin::StringToV8(isolate, "eventSender"), bindings.ToV8());
498 gin::ObjectTemplateBuilder
499 EventSenderBindings::GetObjectTemplateBuilder(v8::Isolate* isolate) {
500 return gin::Wrappable<EventSenderBindings>::GetObjectTemplateBuilder(isolate)
501 .SetMethod("enableDOMUIEventLogging",
502 &EventSenderBindings::EnableDOMUIEventLogging)
503 .SetMethod("fireKeyboardEventsToElement",
504 &EventSenderBindings::FireKeyboardEventsToElement)
505 .SetMethod("clearKillRing", &EventSenderBindings::ClearKillRing)
506 .SetMethod("contextClick", &EventSenderBindings::ContextClick)
507 .SetMethod("textZoomIn", &EventSenderBindings::TextZoomIn)
508 .SetMethod("textZoomOut", &EventSenderBindings::TextZoomOut)
509 .SetMethod("zoomPageIn", &EventSenderBindings::ZoomPageIn)
510 .SetMethod("zoomPageOut", &EventSenderBindings::ZoomPageOut)
511 .SetMethod("setPageZoomFactor", &EventSenderBindings::SetPageZoomFactor)
512 .SetMethod("clearTouchPoints", &EventSenderBindings::ClearTouchPoints)
513 .SetMethod("releaseTouchPoint", &EventSenderBindings::ReleaseTouchPoint)
514 .SetMethod("updateTouchPoint", &EventSenderBindings::UpdateTouchPoint)
515 .SetMethod("cancelTouchPoint", &EventSenderBindings::CancelTouchPoint)
516 .SetMethod("setTouchModifier", &EventSenderBindings::SetTouchModifier)
517 .SetMethod("setTouchCancelable", &EventSenderBindings::SetTouchCancelable)
518 .SetMethod("dumpFilenameBeingDragged",
519 &EventSenderBindings::DumpFilenameBeingDragged)
520 .SetMethod("gestureFlingCancel", &EventSenderBindings::GestureFlingCancel)
521 .SetMethod("gestureFlingStart", &EventSenderBindings::GestureFlingStart)
522 .SetMethod("gestureScrollFirstPoint",
523 &EventSenderBindings::GestureScrollFirstPoint)
524 .SetMethod("touchStart", &EventSenderBindings::TouchStart)
525 .SetMethod("touchMove", &EventSenderBindings::TouchMove)
526 .SetMethod("touchMoveCausingScrollIfUncanceled",
527 &EventSenderBindings::TouchMoveCausingScrollIfUncanceled)
528 .SetMethod("touchCancel", &EventSenderBindings::TouchCancel)
529 .SetMethod("touchEnd", &EventSenderBindings::TouchEnd)
530 .SetMethod("leapForward", &EventSenderBindings::LeapForward)
531 .SetMethod("beginDragWithFiles", &EventSenderBindings::BeginDragWithFiles)
532 .SetMethod("addTouchPoint", &EventSenderBindings::AddTouchPoint)
533 .SetMethod("mouseDragBegin", &EventSenderBindings::MouseDragBegin)
534 .SetMethod("mouseDragEnd", &EventSenderBindings::MouseDragEnd)
535 .SetMethod("gestureScrollBegin", &EventSenderBindings::GestureScrollBegin)
536 .SetMethod("gestureScrollEnd", &EventSenderBindings::GestureScrollEnd)
537 .SetMethod("gestureScrollUpdate",
538 &EventSenderBindings::GestureScrollUpdate)
539 .SetMethod("gesturePinchBegin", &EventSenderBindings::GesturePinchBegin)
540 .SetMethod("gesturePinchEnd", &EventSenderBindings::GesturePinchEnd)
541 .SetMethod("gesturePinchUpdate", &EventSenderBindings::GesturePinchUpdate)
542 .SetMethod("gestureTap", &EventSenderBindings::GestureTap)
543 .SetMethod("gestureTapDown", &EventSenderBindings::GestureTapDown)
544 .SetMethod("gestureShowPress", &EventSenderBindings::GestureShowPress)
545 .SetMethod("gestureTapCancel", &EventSenderBindings::GestureTapCancel)
546 .SetMethod("gestureLongPress", &EventSenderBindings::GestureLongPress)
547 .SetMethod("gestureLongTap", &EventSenderBindings::GestureLongTap)
548 .SetMethod("gestureTwoFingerTap",
549 &EventSenderBindings::GestureTwoFingerTap)
550 .SetMethod("continuousMouseScrollBy",
551 &EventSenderBindings::ContinuousMouseScrollBy)
552 .SetMethod("keyDown", &EventSenderBindings::KeyDown)
553 .SetMethod("mouseDown", &EventSenderBindings::MouseDown)
554 .SetMethod("mouseMoveTo", &EventSenderBindings::MouseMoveTo)
555 .SetMethod("mouseLeave", &EventSenderBindings::MouseLeave)
556 .SetMethod("trackpadScrollBegin",
557 &EventSenderBindings::TrackpadScrollBegin)
558 .SetMethod("trackpadScroll", &EventSenderBindings::TrackpadScroll)
559 .SetMethod("trackpadScrollEnd", &EventSenderBindings::TrackpadScrollEnd)
560 .SetMethod("mouseScrollBy", &EventSenderBindings::MouseScrollBy)
561 .SetMethod("mouseUp", &EventSenderBindings::MouseUp)
562 .SetMethod("mouseMomentumBegin", &EventSenderBindings::MouseMomentumBegin)
563 .SetMethod("mouseMomentumBegin2",
564 &EventSenderBindings::MouseMomentumBegin2)
565 .SetMethod("mouseMomentumScrollBy",
566 &EventSenderBindings::MouseMomentumScrollBy)
567 .SetMethod("mouseMomentumEnd", &EventSenderBindings::MouseMomentumEnd)
568 .SetMethod("scheduleAsynchronousClick",
569 &EventSenderBindings::ScheduleAsynchronousClick)
570 .SetMethod("scheduleAsynchronousKeyDown",
571 &EventSenderBindings::ScheduleAsynchronousKeyDown)
572 .SetProperty("forceLayoutOnEvents",
573 &EventSenderBindings::ForceLayoutOnEvents,
574 &EventSenderBindings::SetForceLayoutOnEvents)
575 .SetProperty("dragMode", &EventSenderBindings::IsDragMode,
576 &EventSenderBindings::SetIsDragMode)
577 #if defined(OS_WIN)
578 .SetProperty("WM_KEYDOWN", &EventSenderBindings::WmKeyDown,
579 &EventSenderBindings::SetWmKeyDown)
580 .SetProperty("WM_KEYUP", &EventSenderBindings::WmKeyUp,
581 &EventSenderBindings::SetWmKeyUp)
582 .SetProperty("WM_CHAR", &EventSenderBindings::WmChar,
583 &EventSenderBindings::SetWmChar)
584 .SetProperty("WM_DEADCHAR", &EventSenderBindings::WmDeadChar,
585 &EventSenderBindings::SetWmDeadChar)
586 .SetProperty("WM_SYSKEYDOWN", &EventSenderBindings::WmSysKeyDown,
587 &EventSenderBindings::SetWmSysKeyDown)
588 .SetProperty("WM_SYSKEYUP", &EventSenderBindings::WmSysKeyUp,
589 &EventSenderBindings::SetWmSysKeyUp)
590 .SetProperty("WM_SYSCHAR", &EventSenderBindings::WmSysChar,
591 &EventSenderBindings::SetWmSysChar)
592 .SetProperty("WM_SYSDEADCHAR", &EventSenderBindings::WmSysDeadChar,
593 &EventSenderBindings::SetWmSysDeadChar);
594 #else
596 #endif
599 void EventSenderBindings::EnableDOMUIEventLogging() {
600 if (sender_)
601 sender_->EnableDOMUIEventLogging();
604 void EventSenderBindings::FireKeyboardEventsToElement() {
605 if (sender_)
606 sender_->FireKeyboardEventsToElement();
609 void EventSenderBindings::ClearKillRing() {
610 if (sender_)
611 sender_->ClearKillRing();
614 std::vector<std::string> EventSenderBindings::ContextClick() {
615 if (sender_)
616 return sender_->ContextClick();
617 return std::vector<std::string>();
620 void EventSenderBindings::TextZoomIn() {
621 if (sender_)
622 sender_->TextZoomIn();
625 void EventSenderBindings::TextZoomOut() {
626 if (sender_)
627 sender_->TextZoomOut();
630 void EventSenderBindings::ZoomPageIn() {
631 if (sender_)
632 sender_->ZoomPageIn();
635 void EventSenderBindings::ZoomPageOut() {
636 if (sender_)
637 sender_->ZoomPageOut();
640 void EventSenderBindings::SetPageZoomFactor(double factor) {
641 if (sender_)
642 sender_->SetPageZoomFactor(factor);
645 void EventSenderBindings::ClearTouchPoints() {
646 if (sender_)
647 sender_->ClearTouchPoints();
650 void EventSenderBindings::ReleaseTouchPoint(unsigned index) {
651 if (sender_)
652 sender_->ReleaseTouchPoint(index);
655 void EventSenderBindings::UpdateTouchPoint(unsigned index, double x, double y) {
656 if (sender_) {
657 sender_->UpdateTouchPoint(index, static_cast<float>(x),
658 static_cast<float>(y));
662 void EventSenderBindings::CancelTouchPoint(unsigned index) {
663 if (sender_)
664 sender_->CancelTouchPoint(index);
667 void EventSenderBindings::SetTouchModifier(const std::string& key_name,
668 bool set_mask) {
669 if (sender_)
670 sender_->SetTouchModifier(key_name, set_mask);
673 void EventSenderBindings::SetTouchCancelable(bool cancelable) {
674 if (sender_)
675 sender_->SetTouchCancelable(cancelable);
678 void EventSenderBindings::DumpFilenameBeingDragged() {
679 if (sender_)
680 sender_->DumpFilenameBeingDragged();
683 void EventSenderBindings::GestureFlingCancel() {
684 if (sender_)
685 sender_->GestureFlingCancel();
688 void EventSenderBindings::GestureFlingStart(float x,
689 float y,
690 float velocity_x,
691 float velocity_y,
692 gin::Arguments* args) {
693 if (sender_)
694 sender_->GestureFlingStart(x, y, velocity_x, velocity_y, args);
697 void EventSenderBindings::GestureScrollFirstPoint(int x, int y) {
698 if (sender_)
699 sender_->GestureScrollFirstPoint(x, y);
702 void EventSenderBindings::TouchStart() {
703 if (sender_)
704 sender_->TouchStart();
707 void EventSenderBindings::TouchMove() {
708 if (sender_)
709 sender_->TouchMove();
712 void EventSenderBindings::TouchMoveCausingScrollIfUncanceled() {
713 if (sender_)
714 sender_->TouchMoveCausingScrollIfUncanceled();
717 void EventSenderBindings::TouchCancel() {
718 if (sender_)
719 sender_->TouchCancel();
722 void EventSenderBindings::TouchEnd() {
723 if (sender_)
724 sender_->TouchEnd();
727 void EventSenderBindings::LeapForward(int milliseconds) {
728 if (sender_)
729 sender_->LeapForward(milliseconds);
732 void EventSenderBindings::BeginDragWithFiles(
733 const std::vector<std::string>& files) {
734 if (sender_)
735 sender_->BeginDragWithFiles(files);
738 void EventSenderBindings::AddTouchPoint(gin::Arguments* args) {
739 if (sender_)
740 sender_->AddTouchPoint(args);
743 void EventSenderBindings::MouseDragBegin() {
744 if (sender_)
745 sender_->MouseDragBegin();
748 void EventSenderBindings::MouseDragEnd() {
749 if (sender_)
750 sender_->MouseDragEnd();
753 void EventSenderBindings::GestureScrollBegin(gin::Arguments* args) {
754 if (sender_)
755 sender_->GestureScrollBegin(args);
758 void EventSenderBindings::GestureScrollEnd(gin::Arguments* args) {
759 if (sender_)
760 sender_->GestureScrollEnd(args);
763 void EventSenderBindings::GestureScrollUpdate(gin::Arguments* args) {
764 if (sender_)
765 sender_->GestureScrollUpdate(args);
768 void EventSenderBindings::GesturePinchBegin(gin::Arguments* args) {
769 if (sender_)
770 sender_->GesturePinchBegin(args);
773 void EventSenderBindings::GesturePinchEnd(gin::Arguments* args) {
774 if (sender_)
775 sender_->GesturePinchEnd(args);
778 void EventSenderBindings::GesturePinchUpdate(gin::Arguments* args) {
779 if (sender_)
780 sender_->GesturePinchUpdate(args);
783 void EventSenderBindings::GestureTap(gin::Arguments* args) {
784 if (sender_)
785 sender_->GestureTap(args);
788 void EventSenderBindings::GestureTapDown(gin::Arguments* args) {
789 if (sender_)
790 sender_->GestureTapDown(args);
793 void EventSenderBindings::GestureShowPress(gin::Arguments* args) {
794 if (sender_)
795 sender_->GestureShowPress(args);
798 void EventSenderBindings::GestureTapCancel(gin::Arguments* args) {
799 if (sender_)
800 sender_->GestureTapCancel(args);
803 void EventSenderBindings::GestureLongPress(gin::Arguments* args) {
804 if (sender_)
805 sender_->GestureLongPress(args);
808 void EventSenderBindings::GestureLongTap(gin::Arguments* args) {
809 if (sender_)
810 sender_->GestureLongTap(args);
813 void EventSenderBindings::GestureTwoFingerTap(gin::Arguments* args) {
814 if (sender_)
815 sender_->GestureTwoFingerTap(args);
818 void EventSenderBindings::ContinuousMouseScrollBy(gin::Arguments* args) {
819 if (sender_)
820 sender_->ContinuousMouseScrollBy(args);
823 void EventSenderBindings::MouseMoveTo(gin::Arguments* args) {
824 if (sender_)
825 sender_->MouseMoveTo(args);
828 void EventSenderBindings::MouseLeave() {
829 if (sender_)
830 sender_->MouseLeave();
833 void EventSenderBindings::TrackpadScrollBegin() {
834 if (sender_)
835 sender_->TrackpadScrollBegin();
838 void EventSenderBindings::TrackpadScroll(gin::Arguments* args) {
839 if (sender_)
840 sender_->TrackpadScroll(args);
843 void EventSenderBindings::TrackpadScrollEnd() {
844 if (sender_)
845 sender_->TrackpadScrollEnd();
848 void EventSenderBindings::MouseScrollBy(gin::Arguments* args) {
849 if (sender_)
850 sender_->MouseScrollBy(args);
853 void EventSenderBindings::MouseMomentumBegin() {
854 if (sender_)
855 sender_->MouseMomentumBegin();
858 void EventSenderBindings::MouseMomentumBegin2(gin::Arguments* args) {
859 if (sender_)
860 sender_->MouseMomentumBegin2(args);
863 void EventSenderBindings::MouseMomentumScrollBy(gin::Arguments* args) {
864 if (sender_)
865 sender_->MouseMomentumScrollBy(args);
868 void EventSenderBindings::MouseMomentumEnd() {
869 if (sender_)
870 sender_->MouseMomentumEnd();
873 void EventSenderBindings::ScheduleAsynchronousClick(gin::Arguments* args) {
874 if (!sender_)
875 return;
877 int button_number = 0;
878 int modifiers = 0;
879 if (!args->PeekNext().IsEmpty()) {
880 args->GetNext(&button_number);
881 if (!args->PeekNext().IsEmpty())
882 modifiers = GetKeyModifiersFromV8(args->isolate(), args->PeekNext());
884 sender_->ScheduleAsynchronousClick(button_number, modifiers);
887 void EventSenderBindings::ScheduleAsynchronousKeyDown(gin::Arguments* args) {
888 if (!sender_)
889 return;
891 std::string code_str;
892 int modifiers = 0;
893 int location = DOMKeyLocationStandard;
894 args->GetNext(&code_str);
895 if (!args->PeekNext().IsEmpty()) {
896 v8::Local<v8::Value> value;
897 args->GetNext(&value);
898 modifiers = GetKeyModifiersFromV8(args->isolate(), value);
899 if (!args->PeekNext().IsEmpty())
900 args->GetNext(&location);
902 sender_->ScheduleAsynchronousKeyDown(code_str, modifiers,
903 static_cast<KeyLocationCode>(location));
906 void EventSenderBindings::MouseDown(gin::Arguments* args) {
907 if (!sender_)
908 return;
910 int button_number = 0;
911 int modifiers = 0;
912 if (!args->PeekNext().IsEmpty()) {
913 args->GetNext(&button_number);
914 if (!args->PeekNext().IsEmpty())
915 modifiers = GetKeyModifiersFromV8(args->isolate(), args->PeekNext());
917 sender_->MouseDown(button_number, modifiers);
920 void EventSenderBindings::MouseUp(gin::Arguments* args) {
921 if (!sender_)
922 return;
924 int button_number = 0;
925 int modifiers = 0;
926 if (!args->PeekNext().IsEmpty()) {
927 args->GetNext(&button_number);
928 if (!args->PeekNext().IsEmpty())
929 modifiers = GetKeyModifiersFromV8(args->isolate(), args->PeekNext());
931 sender_->MouseUp(button_number, modifiers);
934 void EventSenderBindings::KeyDown(gin::Arguments* args) {
935 if (!sender_)
936 return;
938 std::string code_str;
939 int modifiers = 0;
940 int location = DOMKeyLocationStandard;
941 args->GetNext(&code_str);
942 if (!args->PeekNext().IsEmpty()) {
943 v8::Local<v8::Value> value;
944 args->GetNext(&value);
945 modifiers = GetKeyModifiersFromV8(args->isolate(), value);
946 if (!args->PeekNext().IsEmpty())
947 args->GetNext(&location);
949 sender_->KeyDown(code_str, modifiers, static_cast<KeyLocationCode>(location));
952 bool EventSenderBindings::ForceLayoutOnEvents() const {
953 if (sender_)
954 return sender_->force_layout_on_events();
955 return false;
958 void EventSenderBindings::SetForceLayoutOnEvents(bool force) {
959 if (sender_)
960 sender_->set_force_layout_on_events(force);
963 bool EventSenderBindings::IsDragMode() const {
964 if (sender_)
965 return sender_->is_drag_mode();
966 return true;
969 void EventSenderBindings::SetIsDragMode(bool drag_mode) {
970 if (sender_)
971 sender_->set_is_drag_mode(drag_mode);
974 #if defined(OS_WIN)
975 int EventSenderBindings::WmKeyDown() const {
976 if (sender_)
977 return sender_->wm_key_down();
978 return 0;
981 void EventSenderBindings::SetWmKeyDown(int key_down) {
982 if (sender_)
983 sender_->set_wm_key_down(key_down);
986 int EventSenderBindings::WmKeyUp() const {
987 if (sender_)
988 return sender_->wm_key_up();
989 return 0;
992 void EventSenderBindings::SetWmKeyUp(int key_up) {
993 if (sender_)
994 sender_->set_wm_key_up(key_up);
997 int EventSenderBindings::WmChar() const {
998 if (sender_)
999 return sender_->wm_char();
1000 return 0;
1003 void EventSenderBindings::SetWmChar(int wm_char) {
1004 if (sender_)
1005 sender_->set_wm_char(wm_char);
1008 int EventSenderBindings::WmDeadChar() const {
1009 if (sender_)
1010 return sender_->wm_dead_char();
1011 return 0;
1014 void EventSenderBindings::SetWmDeadChar(int dead_char) {
1015 if (sender_)
1016 sender_->set_wm_dead_char(dead_char);
1019 int EventSenderBindings::WmSysKeyDown() const {
1020 if (sender_)
1021 return sender_->wm_sys_key_down();
1022 return 0;
1025 void EventSenderBindings::SetWmSysKeyDown(int key_down) {
1026 if (sender_)
1027 sender_->set_wm_sys_key_down(key_down);
1030 int EventSenderBindings::WmSysKeyUp() const {
1031 if (sender_)
1032 return sender_->wm_sys_key_up();
1033 return 0;
1036 void EventSenderBindings::SetWmSysKeyUp(int key_up) {
1037 if (sender_)
1038 sender_->set_wm_sys_key_up(key_up);
1041 int EventSenderBindings::WmSysChar() const {
1042 if (sender_)
1043 return sender_->wm_sys_char();
1044 return 0;
1047 void EventSenderBindings::SetWmSysChar(int sys_char) {
1048 if (sender_)
1049 sender_->set_wm_sys_char(sys_char);
1052 int EventSenderBindings::WmSysDeadChar() const {
1053 if (sender_)
1054 return sender_->wm_sys_dead_char();
1055 return 0;
1058 void EventSenderBindings::SetWmSysDeadChar(int sys_dead_char) {
1059 if (sender_)
1060 sender_->set_wm_sys_dead_char(sys_dead_char);
1062 #endif
1064 // EventSender -----------------------------------------------------------------
1066 WebMouseEvent::Button EventSender::pressed_button_ = WebMouseEvent::ButtonNone;
1067 int EventSender::modifiers_ = 0;
1069 WebPoint EventSender::last_mouse_pos_;
1071 WebMouseEvent::Button EventSender::last_button_type_ =
1072 WebMouseEvent::ButtonNone;
1074 EventSender::SavedEvent::SavedEvent()
1075 : type(TYPE_UNSPECIFIED),
1076 button_type(WebMouseEvent::ButtonNone),
1077 milliseconds(0),
1078 modifiers(0) {}
1080 EventSender::EventSender(TestInterfaces* interfaces)
1082 #if defined(OS_WIN)
1083 wm_key_down_(0),
1084 wm_key_up_(0),
1085 wm_char_(0),
1086 wm_dead_char_(0),
1087 wm_sys_key_down_(0),
1088 wm_sys_key_up_(0),
1089 wm_sys_char_(0),
1090 wm_sys_dead_char_(0),
1091 #endif
1092 interfaces_(interfaces),
1093 delegate_(NULL),
1094 view_(NULL),
1095 force_layout_on_events_(false),
1096 is_drag_mode_(true),
1097 touch_modifiers_(0),
1098 touch_cancelable_(true),
1099 replaying_saved_events_(false),
1100 current_drag_effects_allowed_(blink::WebDragOperationNone),
1101 last_click_time_sec_(0),
1102 current_drag_effect_(blink::WebDragOperationNone),
1103 time_offset_ms_(0),
1104 click_count_(0),
1105 weak_factory_(this) {
1108 EventSender::~EventSender() {}
1110 void EventSender::Reset() {
1111 DCHECK(current_drag_data_.isNull());
1112 current_drag_data_.reset();
1113 current_drag_effect_ = blink::WebDragOperationNone;
1114 current_drag_effects_allowed_ = blink::WebDragOperationNone;
1115 if (view_ && pressed_button_ != WebMouseEvent::ButtonNone)
1116 view_->mouseCaptureLost();
1117 pressed_button_ = WebMouseEvent::ButtonNone;
1118 is_drag_mode_ = true;
1119 force_layout_on_events_ = true;
1121 #if defined(OS_WIN)
1122 wm_key_down_ = WM_KEYDOWN;
1123 wm_key_up_ = WM_KEYUP;
1124 wm_char_ = WM_CHAR;
1125 wm_dead_char_ = WM_DEADCHAR;
1126 wm_sys_key_down_ = WM_SYSKEYDOWN;
1127 wm_sys_key_up_ = WM_SYSKEYUP;
1128 wm_sys_char_ = WM_SYSCHAR;
1129 wm_sys_dead_char_ = WM_SYSDEADCHAR;
1130 #endif
1132 last_mouse_pos_ = WebPoint(0, 0);
1133 last_click_time_sec_ = 0;
1134 last_click_pos_ = WebPoint(0, 0);
1135 last_button_type_ = WebMouseEvent::ButtonNone;
1136 touch_points_.clear();
1137 last_context_menu_data_.reset();
1138 task_list_.RevokeAll();
1139 current_gesture_location_ = WebPoint(0, 0);
1140 mouse_event_queue_.clear();
1142 time_offset_ms_ = 0;
1143 click_count_ = 0;
1145 touch_modifiers_ = 0;
1146 touch_cancelable_ = true;
1147 touch_points_.clear();
1150 void EventSender::Install(WebFrame* frame) {
1151 EventSenderBindings::Install(weak_factory_.GetWeakPtr(), frame);
1154 void EventSender::SetDelegate(WebTestDelegate* delegate) {
1155 delegate_ = delegate;
1158 void EventSender::SetWebView(WebView* view) {
1159 view_ = view;
1162 void EventSender::SetContextMenuData(const WebContextMenuData& data) {
1163 last_context_menu_data_.reset(new WebContextMenuData(data));
1166 void EventSender::DoDragDrop(const WebDragData& drag_data,
1167 WebDragOperationsMask mask) {
1168 WebMouseEvent event;
1169 InitMouseEvent(WebInputEvent::MouseDown,
1170 pressed_button_,
1171 last_mouse_pos_,
1172 GetCurrentEventTimeSec(),
1173 click_count_,
1174 modifiers_,
1175 &event);
1176 WebPoint client_point(event.x, event.y);
1177 WebPoint screen_point(event.globalX, event.globalY);
1178 current_drag_data_ = drag_data;
1179 current_drag_effects_allowed_ = mask;
1180 current_drag_effect_ = view_->dragTargetDragEnter(
1181 drag_data,
1182 client_point,
1183 screen_point,
1184 current_drag_effects_allowed_,
1185 modifiers_);
1187 // Finish processing events.
1188 ReplaySavedEvents();
1191 void EventSender::MouseDown(int button_number, int modifiers) {
1192 if (force_layout_on_events_)
1193 view_->layout();
1195 DCHECK_NE(-1, button_number);
1197 WebMouseEvent::Button button_type =
1198 GetButtonTypeFromButtonNumber(button_number);
1200 UpdateClickCountForButton(button_type);
1202 pressed_button_ = button_type;
1203 modifiers_ = modifiers;
1205 WebMouseEvent event;
1206 InitMouseEvent(WebInputEvent::MouseDown,
1207 button_type,
1208 last_mouse_pos_,
1209 GetCurrentEventTimeSec(),
1210 click_count_,
1211 modifiers,
1212 &event);
1213 HandleInputEventOnViewOrPopup(event);
1216 void EventSender::MouseUp(int button_number, int modifiers) {
1217 if (force_layout_on_events_)
1218 view_->layout();
1220 DCHECK_NE(-1, button_number);
1222 WebMouseEvent::Button button_type =
1223 GetButtonTypeFromButtonNumber(button_number);
1225 if (is_drag_mode_ && !replaying_saved_events_) {
1226 SavedEvent saved_event;
1227 saved_event.type = SavedEvent::TYPE_MOUSE_UP;
1228 saved_event.button_type = button_type;
1229 saved_event.modifiers = modifiers;
1230 mouse_event_queue_.push_back(saved_event);
1231 ReplaySavedEvents();
1232 } else {
1233 WebMouseEvent event;
1234 InitMouseEvent(WebInputEvent::MouseUp,
1235 button_type,
1236 last_mouse_pos_,
1237 GetCurrentEventTimeSec(),
1238 click_count_,
1239 modifiers,
1240 &event);
1241 DoMouseUp(event);
1245 void EventSender::KeyDown(const std::string& code_str,
1246 int modifiers,
1247 KeyLocationCode location) {
1248 // FIXME: I'm not exactly sure how we should convert the string to a key
1249 // event. This seems to work in the cases I tested.
1250 // FIXME: Should we also generate a KEY_UP?
1252 bool generate_char = false;
1254 // Convert \n -> VK_RETURN. Some layout tests use \n to mean "Enter", when
1255 // Windows uses \r for "Enter".
1256 int code = 0;
1257 int text = 0;
1258 bool needs_shift_key_modifier = false;
1259 std::string domString;
1261 if ("\n" == code_str) {
1262 generate_char = true;
1263 text = code = ui::VKEY_RETURN;
1264 domString.assign("Enter");
1265 } else if ("rightArrow" == code_str) {
1266 code = ui::VKEY_RIGHT;
1267 domString.assign("ArrowRight");
1268 } else if ("downArrow" == code_str) {
1269 code = ui::VKEY_DOWN;
1270 domString.assign("ArrowDown");
1271 } else if ("leftArrow" == code_str) {
1272 code = ui::VKEY_LEFT;
1273 domString.assign("ArrowLeft");
1274 } else if ("upArrow" == code_str) {
1275 code = ui::VKEY_UP;
1276 domString.assign("ArrowUp");
1277 } else if ("insert" == code_str) {
1278 code = ui::VKEY_INSERT;
1279 domString.assign("Insert");
1280 } else if ("delete" == code_str) {
1281 code = ui::VKEY_DELETE;
1282 domString.assign("Delete");
1283 } else if ("pageUp" == code_str) {
1284 code = ui::VKEY_PRIOR;
1285 domString.assign("PageUp");
1286 } else if ("pageDown" == code_str) {
1287 code = ui::VKEY_NEXT;
1288 domString.assign("PageDown");
1289 } else if ("home" == code_str) {
1290 code = ui::VKEY_HOME;
1291 domString.assign("Home");
1292 } else if ("end" == code_str) {
1293 code = ui::VKEY_END;
1294 domString.assign("End");
1295 } else if ("printScreen" == code_str) {
1296 code = ui::VKEY_SNAPSHOT;
1297 domString.assign("PrintScreen");
1298 } else if ("menu" == code_str) {
1299 code = ui::VKEY_APPS;
1300 domString.assign("ContextMenu");
1301 } else if ("leftControl" == code_str) {
1302 code = ui::VKEY_LCONTROL;
1303 domString.assign("ControlLeft");
1304 } else if ("rightControl" == code_str) {
1305 code = ui::VKEY_RCONTROL;
1306 domString.assign("ControlRight");
1307 } else if ("leftShift" == code_str) {
1308 code = ui::VKEY_LSHIFT;
1309 domString.assign("ShiftLeft");
1310 } else if ("rightShift" == code_str) {
1311 code = ui::VKEY_RSHIFT;
1312 domString.assign("ShiftRight");
1313 } else if ("leftAlt" == code_str) {
1314 code = ui::VKEY_LMENU;
1315 domString.assign("AltLeft");
1316 } else if ("rightAlt" == code_str) {
1317 code = ui::VKEY_RMENU;
1318 domString.assign("AltRight");
1319 } else if ("numLock" == code_str) {
1320 code = ui::VKEY_NUMLOCK;
1321 domString.assign("NumLock");
1322 } else if ("backspace" == code_str) {
1323 code = ui::VKEY_BACK;
1324 domString.assign("Backspace");
1325 } else if ("escape" == code_str) {
1326 code = ui::VKEY_ESCAPE;
1327 domString.assign("Escape");
1328 } else {
1329 // Compare the input string with the function-key names defined by the
1330 // DOM spec (i.e. "F1",...,"F24"). If the input string is a function-key
1331 // name, set its key code.
1332 for (int i = 1; i <= 24; ++i) {
1333 std::string function_key_name = base::StringPrintf("F%d", i);
1334 if (function_key_name == code_str) {
1335 code = ui::VKEY_F1 + (i - 1);
1336 domString = function_key_name;
1337 break;
1340 if (!code) {
1341 WebString web_code_str =
1342 WebString::fromUTF8(code_str.data(), code_str.size());
1343 if (web_code_str.length() != 1u) {
1344 v8::Isolate* isolate = blink::mainThreadIsolate();
1345 isolate->ThrowException(v8::Exception::TypeError(
1346 gin::StringToV8(isolate, "Invalid web code.")));
1347 return;
1349 text = code = web_code_str.at(0);
1350 needs_shift_key_modifier = NeedsShiftModifier(code);
1351 if ((code & 0xFF) >= 'a' && (code & 0xFF) <= 'z')
1352 code -= 'a' - 'A';
1353 if ((code >= 'A' && code <= 'Z') || (code >= 'a' && code <= 'z')) {
1354 domString.assign("Key");
1355 domString.push_back(base::ToUpperASCII(code));
1356 } else if (code >= '0' && code <= '9') {
1357 domString.assign("Digit");
1358 domString.push_back(code);
1359 } else if (code == ' ') {
1360 domString.assign("Space");
1361 } else if (code == 9) {
1362 domString.assign("Tab");
1364 generate_char = true;
1367 if ("(" == code_str) {
1368 code = '9';
1369 needs_shift_key_modifier = true;
1373 // For one generated keyboard event, we need to generate a keyDown/keyUp
1374 // pair;
1375 // On Windows, we might also need to generate a char event to mimic the
1376 // Windows event flow; on other platforms we create a merged event and test
1377 // the event flow that that platform provides.
1378 WebKeyboardEvent event_down;
1379 event_down.type = WebInputEvent::RawKeyDown;
1380 event_down.modifiers = modifiers;
1381 event_down.windowsKeyCode = code;
1382 event_down.domCode = static_cast<int>(
1383 ui::KeycodeConverter::CodeStringToDomCode(domString.c_str()));
1385 if (generate_char) {
1386 event_down.text[0] = text;
1387 event_down.unmodifiedText[0] = text;
1390 event_down.setKeyIdentifierFromWindowsKeyCode();
1392 if (event_down.modifiers != 0)
1393 event_down.isSystemKey = IsSystemKeyEvent(event_down);
1395 if (needs_shift_key_modifier)
1396 event_down.modifiers |= WebInputEvent::ShiftKey;
1398 // See if KeyLocation argument is given.
1399 if (location == DOMKeyLocationNumpad)
1400 event_down.modifiers |= WebInputEvent::IsKeyPad;
1402 WebKeyboardEvent event_up;
1403 event_up = event_down;
1404 event_up.type = WebInputEvent::KeyUp;
1405 // EventSender.m forces a layout here, with at least one
1406 // test (fast/forms/focus-control-to-page.html) relying on this.
1407 if (force_layout_on_events_)
1408 view_->layout();
1410 // In the browser, if a keyboard event corresponds to an editor command,
1411 // the command will be dispatched to the renderer just before dispatching
1412 // the keyboard event, and then it will be executed in the
1413 // RenderView::handleCurrentKeyboardEvent() method.
1414 // We just simulate the same behavior here.
1415 std::string edit_command;
1416 if (GetEditCommand(event_down, &edit_command))
1417 delegate_->SetEditCommand(edit_command, "");
1419 HandleInputEventOnViewOrPopup(event_down);
1421 if (code == ui::VKEY_ESCAPE && !current_drag_data_.isNull()) {
1422 WebMouseEvent event;
1423 InitMouseEvent(WebInputEvent::MouseDown,
1424 pressed_button_,
1425 last_mouse_pos_,
1426 GetCurrentEventTimeSec(),
1427 click_count_,
1429 &event);
1430 FinishDragAndDrop(event, blink::WebDragOperationNone);
1433 delegate_->ClearEditCommand();
1435 if (generate_char) {
1436 WebKeyboardEvent event_char = event_up;
1437 event_char.type = WebInputEvent::Char;
1438 // keyIdentifier is an empty string, unless the Enter key was pressed.
1439 // This behavior is not standard (keyIdentifier itself is not even a
1440 // standard any more), but it matches the actual behavior in Blink.
1441 if (code != ui::VKEY_RETURN)
1442 event_char.keyIdentifier[0] = '\0';
1443 HandleInputEventOnViewOrPopup(event_char);
1446 HandleInputEventOnViewOrPopup(event_up);
1449 void EventSender::EnableDOMUIEventLogging() {}
1451 void EventSender::FireKeyboardEventsToElement() {}
1453 void EventSender::ClearKillRing() {}
1455 std::vector<std::string> EventSender::ContextClick() {
1456 if (force_layout_on_events_) {
1457 view_->layout();
1460 UpdateClickCountForButton(WebMouseEvent::ButtonRight);
1462 // Clears last context menu data because we need to know if the context menu
1463 // be requested after following mouse events.
1464 last_context_menu_data_.reset();
1466 // Generate right mouse down and up.
1467 WebMouseEvent event;
1468 // This is a hack to work around only allowing a single pressed button since
1469 // we want to test the case where both the left and right mouse buttons are
1470 // pressed.
1471 if (pressed_button_ == WebMouseEvent::ButtonNone) {
1472 pressed_button_ = WebMouseEvent::ButtonRight;
1474 InitMouseEvent(WebInputEvent::MouseDown,
1475 WebMouseEvent::ButtonRight,
1476 last_mouse_pos_,
1477 GetCurrentEventTimeSec(),
1478 click_count_,
1480 &event);
1481 HandleInputEventOnViewOrPopup(event);
1483 #if defined(OS_WIN)
1484 InitMouseEvent(WebInputEvent::MouseUp,
1485 WebMouseEvent::ButtonRight,
1486 last_mouse_pos_,
1487 GetCurrentEventTimeSec(),
1488 click_count_,
1490 &event);
1491 HandleInputEventOnViewOrPopup(event);
1493 pressed_button_= WebMouseEvent::ButtonNone;
1494 #endif
1496 std::vector<std::string> menu_items =
1497 MakeMenuItemStringsFor(last_context_menu_data_.get(), delegate_);
1498 last_context_menu_data_.reset();
1499 return menu_items;
1502 void EventSender::TextZoomIn() {
1503 view_->setTextZoomFactor(view_->textZoomFactor() * 1.2f);
1506 void EventSender::TextZoomOut() {
1507 view_->setTextZoomFactor(view_->textZoomFactor() / 1.2f);
1510 void EventSender::ZoomPageIn() {
1511 const std::vector<WebTestProxyBase*>& window_list =
1512 interfaces_->GetWindowList();
1514 for (size_t i = 0; i < window_list.size(); ++i) {
1515 window_list.at(i)->GetWebView()->setZoomLevel(
1516 window_list.at(i)->GetWebView()->zoomLevel() + 1);
1520 void EventSender::ZoomPageOut() {
1521 const std::vector<WebTestProxyBase*>& window_list =
1522 interfaces_->GetWindowList();
1524 for (size_t i = 0; i < window_list.size(); ++i) {
1525 window_list.at(i)->GetWebView()->setZoomLevel(
1526 window_list.at(i)->GetWebView()->zoomLevel() - 1);
1530 void EventSender::SetPageZoomFactor(double zoom_factor) {
1531 const std::vector<WebTestProxyBase*>& window_list =
1532 interfaces_->GetWindowList();
1534 for (size_t i = 0; i < window_list.size(); ++i) {
1535 window_list.at(i)->GetWebView()->setZoomLevel(
1536 std::log(zoom_factor) / std::log(1.2));
1540 void EventSender::ClearTouchPoints() {
1541 touch_points_.clear();
1544 void EventSender::ThrowTouchPointError() {
1545 v8::Isolate* isolate = blink::mainThreadIsolate();
1546 isolate->ThrowException(v8::Exception::TypeError(
1547 gin::StringToV8(isolate, "Invalid touch point.")));
1550 void EventSender::ReleaseTouchPoint(unsigned index) {
1551 if (index >= touch_points_.size()) {
1552 ThrowTouchPointError();
1553 return;
1556 WebTouchPoint* touch_point = &touch_points_[index];
1557 touch_point->state = WebTouchPoint::StateReleased;
1560 void EventSender::UpdateTouchPoint(unsigned index, float x, float y) {
1561 if (index >= touch_points_.size()) {
1562 ThrowTouchPointError();
1563 return;
1566 WebTouchPoint* touch_point = &touch_points_[index];
1567 touch_point->state = WebTouchPoint::StateMoved;
1568 touch_point->position = WebFloatPoint(x, y);
1569 touch_point->screenPosition = touch_point->position;
1572 void EventSender::CancelTouchPoint(unsigned index) {
1573 if (index >= touch_points_.size()) {
1574 ThrowTouchPointError();
1575 return;
1578 WebTouchPoint* touch_point = &touch_points_[index];
1579 touch_point->state = WebTouchPoint::StateCancelled;
1582 void EventSender::SetTouchModifier(const std::string& key_name,
1583 bool set_mask) {
1584 int mask = 0;
1585 if (key_name == "shift")
1586 mask = WebInputEvent::ShiftKey;
1587 else if (key_name == "alt")
1588 mask = WebInputEvent::AltKey;
1589 else if (key_name == "ctrl")
1590 mask = WebInputEvent::ControlKey;
1591 else if (key_name == "meta")
1592 mask = WebInputEvent::MetaKey;
1594 if (set_mask)
1595 touch_modifiers_ |= mask;
1596 else
1597 touch_modifiers_ &= ~mask;
1600 void EventSender::SetTouchCancelable(bool cancelable) {
1601 touch_cancelable_ = cancelable;
1604 void EventSender::DumpFilenameBeingDragged() {
1605 if (current_drag_data_.isNull())
1606 return;
1608 WebString filename;
1609 WebVector<WebDragData::Item> items = current_drag_data_.items();
1610 for (size_t i = 0; i < items.size(); ++i) {
1611 if (items[i].storageType == WebDragData::Item::StorageTypeBinaryData) {
1612 filename = items[i].title;
1613 break;
1616 delegate_->PrintMessage(std::string("Filename being dragged: ") +
1617 filename.utf8().data() + "\n");
1620 void EventSender::GestureFlingCancel() {
1621 WebGestureEvent event;
1622 event.type = WebInputEvent::GestureFlingCancel;
1623 event.timeStampSeconds = GetCurrentEventTimeSec();
1625 if (force_layout_on_events_)
1626 view_->layout();
1628 HandleInputEventOnViewOrPopup(event);
1631 void EventSender::GestureFlingStart(float x,
1632 float y,
1633 float velocity_x,
1634 float velocity_y,
1635 gin::Arguments* args) {
1636 WebGestureEvent event;
1637 event.type = WebInputEvent::GestureFlingStart;
1639 std::string device_string;
1640 if (!args->PeekNext().IsEmpty() && args->PeekNext()->IsString())
1641 args->GetNext(&device_string);
1643 if (device_string == kSourceDeviceStringTouchpad) {
1644 event.sourceDevice = blink::WebGestureDeviceTouchpad;
1645 } else if (device_string == kSourceDeviceStringTouchscreen) {
1646 event.sourceDevice = blink::WebGestureDeviceTouchscreen;
1647 } else {
1648 args->ThrowError();
1649 return;
1652 event.x = x;
1653 event.y = y;
1654 event.globalX = event.x;
1655 event.globalY = event.y;
1657 event.data.flingStart.velocityX = velocity_x;
1658 event.data.flingStart.velocityY = velocity_y;
1659 event.timeStampSeconds = GetCurrentEventTimeSec();
1661 if (force_layout_on_events_)
1662 view_->layout();
1664 HandleInputEventOnViewOrPopup(event);
1667 void EventSender::GestureScrollFirstPoint(int x, int y) {
1668 current_gesture_location_ = WebPoint(x, y);
1671 void EventSender::TouchStart() {
1672 SendCurrentTouchEvent(WebInputEvent::TouchStart, false);
1675 void EventSender::TouchMove() {
1676 SendCurrentTouchEvent(WebInputEvent::TouchMove, false);
1679 void EventSender::TouchMoveCausingScrollIfUncanceled() {
1680 SendCurrentTouchEvent(WebInputEvent::TouchMove, true);
1683 void EventSender::TouchCancel() {
1684 SendCurrentTouchEvent(WebInputEvent::TouchCancel, false);
1687 void EventSender::TouchEnd() {
1688 SendCurrentTouchEvent(WebInputEvent::TouchEnd, false);
1691 void EventSender::LeapForward(int milliseconds) {
1692 if (is_drag_mode_ && pressed_button_ == WebMouseEvent::ButtonLeft &&
1693 !replaying_saved_events_) {
1694 SavedEvent saved_event;
1695 saved_event.type = SavedEvent::TYPE_LEAP_FORWARD;
1696 saved_event.milliseconds = milliseconds;
1697 mouse_event_queue_.push_back(saved_event);
1698 } else {
1699 DoLeapForward(milliseconds);
1703 void EventSender::BeginDragWithFiles(const std::vector<std::string>& files) {
1704 current_drag_data_.initialize();
1705 WebVector<WebString> absolute_filenames(files.size());
1706 for (size_t i = 0; i < files.size(); ++i) {
1707 WebDragData::Item item;
1708 item.storageType = WebDragData::Item::StorageTypeFilename;
1709 item.filenameData = delegate_->GetAbsoluteWebStringFromUTF8Path(files[i]);
1710 current_drag_data_.addItem(item);
1711 absolute_filenames[i] = item.filenameData;
1713 current_drag_data_.setFilesystemId(
1714 delegate_->RegisterIsolatedFileSystem(absolute_filenames));
1715 current_drag_effects_allowed_ = blink::WebDragOperationCopy;
1717 // Provide a drag source.
1718 view_->dragTargetDragEnter(current_drag_data_,
1719 last_mouse_pos_,
1720 last_mouse_pos_,
1721 current_drag_effects_allowed_,
1723 // |is_drag_mode_| saves events and then replays them later. We don't
1724 // need/want that.
1725 is_drag_mode_ = false;
1727 // Make the rest of eventSender think a drag is in progress.
1728 pressed_button_ = WebMouseEvent::ButtonLeft;
1731 void EventSender::AddTouchPoint(gin::Arguments* args) {
1732 double x;
1733 double y;
1734 if (!args->GetNext(&x) || !args->GetNext(&y)) {
1735 args->ThrowError();
1736 return;
1739 WebTouchPoint touch_point;
1740 touch_point.state = WebTouchPoint::StatePressed;
1741 touch_point.position = WebFloatPoint(static_cast<float>(x),
1742 static_cast<float>(y));
1743 touch_point.screenPosition = touch_point.position;
1745 if (!args->PeekNext().IsEmpty()) {
1746 double radius_x;
1747 if (!args->GetNext(&radius_x)) {
1748 args->ThrowError();
1749 return;
1752 double radius_y = radius_x;
1753 if (!args->PeekNext().IsEmpty()) {
1754 if (!args->GetNext(&radius_y)) {
1755 args->ThrowError();
1756 return;
1760 touch_point.radiusX = static_cast<float>(radius_x);
1761 touch_point.radiusY = static_cast<float>(radius_y);
1764 int lowest_id = 0;
1765 for (size_t i = 0; i < touch_points_.size(); i++) {
1766 if (touch_points_[i].id == lowest_id)
1767 lowest_id++;
1769 touch_point.id = lowest_id;
1770 touch_points_.push_back(touch_point);
1773 void EventSender::MouseDragBegin() {
1774 WebMouseWheelEvent event;
1775 InitMouseEvent(WebInputEvent::MouseWheel,
1776 WebMouseEvent::ButtonNone,
1777 last_mouse_pos_,
1778 GetCurrentEventTimeSec(),
1779 click_count_,
1781 &event);
1782 event.phase = WebMouseWheelEvent::PhaseBegan;
1783 event.hasPreciseScrollingDeltas = true;
1784 HandleInputEventOnViewOrPopup(event);
1787 void EventSender::MouseDragEnd() {
1788 WebMouseWheelEvent event;
1789 InitMouseEvent(WebInputEvent::MouseWheel,
1790 WebMouseEvent::ButtonNone,
1791 last_mouse_pos_,
1792 GetCurrentEventTimeSec(),
1793 click_count_,
1795 &event);
1796 event.phase = WebMouseWheelEvent::PhaseEnded;
1797 event.hasPreciseScrollingDeltas = true;
1798 HandleInputEventOnViewOrPopup(event);
1801 void EventSender::GestureScrollBegin(gin::Arguments* args) {
1802 GestureEvent(WebInputEvent::GestureScrollBegin, args);
1805 void EventSender::GestureScrollEnd(gin::Arguments* args) {
1806 GestureEvent(WebInputEvent::GestureScrollEnd, args);
1809 void EventSender::GestureScrollUpdate(gin::Arguments* args) {
1810 GestureEvent(WebInputEvent::GestureScrollUpdate, args);
1813 void EventSender::GesturePinchBegin(gin::Arguments* args) {
1814 GestureEvent(WebInputEvent::GesturePinchBegin, args);
1817 void EventSender::GesturePinchEnd(gin::Arguments* args) {
1818 GestureEvent(WebInputEvent::GesturePinchEnd, args);
1821 void EventSender::GesturePinchUpdate(gin::Arguments* args) {
1822 GestureEvent(WebInputEvent::GesturePinchUpdate, args);
1825 void EventSender::GestureTap(gin::Arguments* args) {
1826 GestureEvent(WebInputEvent::GestureTap, args);
1829 void EventSender::GestureTapDown(gin::Arguments* args) {
1830 GestureEvent(WebInputEvent::GestureTapDown, args);
1833 void EventSender::GestureShowPress(gin::Arguments* args) {
1834 GestureEvent(WebInputEvent::GestureShowPress, args);
1837 void EventSender::GestureTapCancel(gin::Arguments* args) {
1838 GestureEvent(WebInputEvent::GestureTapCancel, args);
1841 void EventSender::GestureLongPress(gin::Arguments* args) {
1842 GestureEvent(WebInputEvent::GestureLongPress, args);
1845 void EventSender::GestureLongTap(gin::Arguments* args) {
1846 GestureEvent(WebInputEvent::GestureLongTap, args);
1849 void EventSender::GestureTwoFingerTap(gin::Arguments* args) {
1850 GestureEvent(WebInputEvent::GestureTwoFingerTap, args);
1853 void EventSender::ContinuousMouseScrollBy(gin::Arguments* args) {
1854 WebMouseWheelEvent event;
1855 InitMouseWheelEvent(args, true, &event);
1856 HandleInputEventOnViewOrPopup(event);
1859 void EventSender::MouseMoveTo(gin::Arguments* args) {
1860 if (force_layout_on_events_)
1861 view_->layout();
1863 double x;
1864 double y;
1865 if (!args->GetNext(&x) || !args->GetNext(&y)) {
1866 args->ThrowError();
1867 return;
1869 WebPoint mouse_pos(static_cast<int>(x), static_cast<int>(y));
1871 int modifiers = 0;
1872 if (!args->PeekNext().IsEmpty())
1873 modifiers = GetKeyModifiersFromV8(args->isolate(), args->PeekNext());
1875 if (is_drag_mode_ && pressed_button_ == WebMouseEvent::ButtonLeft &&
1876 !replaying_saved_events_) {
1877 SavedEvent saved_event;
1878 saved_event.type = SavedEvent::TYPE_MOUSE_MOVE;
1879 saved_event.pos = mouse_pos;
1880 saved_event.modifiers = modifiers;
1881 mouse_event_queue_.push_back(saved_event);
1882 } else {
1883 WebMouseEvent event;
1884 InitMouseEvent(WebInputEvent::MouseMove,
1885 pressed_button_,
1886 mouse_pos,
1887 GetCurrentEventTimeSec(),
1888 click_count_,
1889 modifiers,
1890 &event);
1891 DoMouseMove(event);
1895 void EventSender::MouseLeave() {
1896 if (force_layout_on_events_)
1897 view_->layout();
1899 WebMouseEvent event;
1900 InitMouseEvent(WebInputEvent::MouseLeave,
1901 WebMouseEvent::ButtonNone,
1902 last_mouse_pos_,
1903 GetCurrentEventTimeSec(),
1904 click_count_,
1906 &event);
1907 view_->handleInputEvent(event);
1911 void EventSender::TrackpadScrollBegin() {
1912 WebMouseWheelEvent event;
1913 InitMouseEvent(WebInputEvent::MouseWheel,
1914 WebMouseEvent::ButtonNone,
1915 last_mouse_pos_,
1916 GetCurrentEventTimeSec(),
1917 click_count_,
1919 &event);
1920 event.phase = blink::WebMouseWheelEvent::PhaseBegan;
1921 event.hasPreciseScrollingDeltas = true;
1922 HandleInputEventOnViewOrPopup(event);
1925 void EventSender::TrackpadScroll(gin::Arguments* args) {
1926 WebMouseWheelEvent event;
1927 InitMouseWheelEvent(args, true, &event);
1928 event.phase = blink::WebMouseWheelEvent::PhaseChanged;
1929 event.hasPreciseScrollingDeltas = true;
1930 HandleInputEventOnViewOrPopup(event);
1933 void EventSender::TrackpadScrollEnd() {
1934 WebMouseWheelEvent event;
1935 InitMouseEvent(WebInputEvent::MouseWheel,
1936 WebMouseEvent::ButtonNone,
1937 last_mouse_pos_,
1938 GetCurrentEventTimeSec(),
1939 click_count_,
1941 &event);
1942 event.phase = WebMouseWheelEvent::PhaseEnded;
1943 event.hasPreciseScrollingDeltas = true;
1944 HandleInputEventOnViewOrPopup(event);
1947 void EventSender::MouseScrollBy(gin::Arguments* args) {
1948 WebMouseWheelEvent event;
1949 InitMouseWheelEvent(args, false, &event);
1950 HandleInputEventOnViewOrPopup(event);
1953 void EventSender::MouseMomentumBegin() {
1954 WebMouseWheelEvent event;
1955 InitMouseEvent(WebInputEvent::MouseWheel,
1956 WebMouseEvent::ButtonNone,
1957 last_mouse_pos_,
1958 GetCurrentEventTimeSec(),
1959 click_count_,
1961 &event);
1962 event.momentumPhase = WebMouseWheelEvent::PhaseBegan;
1963 event.hasPreciseScrollingDeltas = true;
1964 HandleInputEventOnViewOrPopup(event);
1967 void EventSender::MouseMomentumBegin2(gin::Arguments* args) {
1968 WebMouseWheelEvent event;
1969 InitMouseWheelEvent(args, true, &event);
1970 event.momentumPhase = WebMouseWheelEvent::PhaseBegan;
1971 event.hasPreciseScrollingDeltas = true;
1972 HandleInputEventOnViewOrPopup(event);
1975 void EventSender::MouseMomentumScrollBy(gin::Arguments* args) {
1976 WebMouseWheelEvent event;
1977 InitMouseWheelEvent(args, true, &event);
1978 event.momentumPhase = WebMouseWheelEvent::PhaseChanged;
1979 event.hasPreciseScrollingDeltas = true;
1980 HandleInputEventOnViewOrPopup(event);
1983 void EventSender::MouseMomentumEnd() {
1984 WebMouseWheelEvent event;
1985 InitMouseEvent(WebInputEvent::MouseWheel,
1986 WebMouseEvent::ButtonNone,
1987 last_mouse_pos_,
1988 GetCurrentEventTimeSec(),
1989 click_count_,
1991 &event);
1992 event.momentumPhase = WebMouseWheelEvent::PhaseEnded;
1993 event.hasPreciseScrollingDeltas = true;
1994 HandleInputEventOnViewOrPopup(event);
1997 void EventSender::ScheduleAsynchronousClick(int button_number, int modifiers) {
1998 delegate_->PostTask(new MouseDownTask(this, button_number, modifiers));
1999 delegate_->PostTask(new MouseUpTask(this, button_number, modifiers));
2002 void EventSender::ScheduleAsynchronousKeyDown(const std::string& code_str,
2003 int modifiers,
2004 KeyLocationCode location) {
2005 delegate_->PostTask(new KeyDownTask(this, code_str, modifiers, location));
2008 double EventSender::GetCurrentEventTimeSec() {
2009 return (delegate_->GetCurrentTimeInMillisecond() + time_offset_ms_) / 1000.0;
2012 void EventSender::DoLeapForward(int milliseconds) {
2013 time_offset_ms_ += milliseconds;
2016 void EventSender::SendCurrentTouchEvent(WebInputEvent::Type type,
2017 bool causesScrollingIfUncanceled) {
2018 DCHECK_GT(static_cast<unsigned>(WebTouchEvent::touchesLengthCap),
2019 touch_points_.size());
2020 if (force_layout_on_events_)
2021 view_->layout();
2023 WebTouchEvent touch_event;
2024 touch_event.type = type;
2025 touch_event.modifiers = touch_modifiers_;
2026 touch_event.cancelable = touch_cancelable_;
2027 touch_event.timeStampSeconds = GetCurrentEventTimeSec();
2028 touch_event.causesScrollingIfUncanceled = causesScrollingIfUncanceled;
2029 touch_event.touchesLength = touch_points_.size();
2030 for (size_t i = 0; i < touch_points_.size(); ++i)
2031 touch_event.touches[i] = touch_points_[i];
2032 HandleInputEventOnViewOrPopup(touch_event);
2034 for (size_t i = 0; i < touch_points_.size(); ++i) {
2035 WebTouchPoint* touch_point = &touch_points_[i];
2036 if (touch_point->state == WebTouchPoint::StateReleased) {
2037 touch_points_.erase(touch_points_.begin() + i);
2038 --i;
2039 } else
2040 touch_point->state = WebTouchPoint::StateStationary;
2044 void EventSender::GestureEvent(WebInputEvent::Type type,
2045 gin::Arguments* args) {
2046 WebGestureEvent event;
2047 event.type = type;
2049 // If the first argument is a string, it is to specify the device, otherwise
2050 // the device is assumed to be a touchscreen (since most tests were written
2051 // assuming this).
2052 event.sourceDevice = blink::WebGestureDeviceTouchscreen;
2053 if (!args->PeekNext().IsEmpty() && args->PeekNext()->IsString()) {
2054 std::string device_string;
2055 if (!args->GetNext(&device_string)) {
2056 args->ThrowError();
2057 return;
2059 if (device_string == kSourceDeviceStringTouchpad) {
2060 event.sourceDevice = blink::WebGestureDeviceTouchpad;
2061 } else if (device_string == kSourceDeviceStringTouchscreen) {
2062 event.sourceDevice = blink::WebGestureDeviceTouchscreen;
2063 } else {
2064 args->ThrowError();
2065 return;
2069 double x;
2070 double y;
2071 if (!args->GetNext(&x) || !args->GetNext(&y)) {
2072 args->ThrowError();
2073 return;
2076 switch (type) {
2077 case WebInputEvent::GestureScrollUpdate:
2079 bool preventPropagation = false;
2080 if (!args->PeekNext().IsEmpty()) {
2081 if (!args->GetNext(&preventPropagation)) {
2082 args->ThrowError();
2083 return;
2087 event.data.scrollUpdate.deltaX = static_cast<float>(x);
2088 event.data.scrollUpdate.deltaY = static_cast<float>(y);
2089 event.data.scrollUpdate.preventPropagation = preventPropagation;
2090 event.x = current_gesture_location_.x;
2091 event.y = current_gesture_location_.y;
2092 current_gesture_location_.x =
2093 current_gesture_location_.x + event.data.scrollUpdate.deltaX;
2094 current_gesture_location_.y =
2095 current_gesture_location_.y + event.data.scrollUpdate.deltaY;
2096 break;
2098 case WebInputEvent::GestureScrollBegin:
2099 current_gesture_location_ = WebPoint(x, y);
2100 event.x = current_gesture_location_.x;
2101 event.y = current_gesture_location_.y;
2102 break;
2103 case WebInputEvent::GestureScrollEnd:
2104 case WebInputEvent::GestureFlingStart:
2105 event.x = current_gesture_location_.x;
2106 event.y = current_gesture_location_.y;
2107 break;
2108 case WebInputEvent::GesturePinchBegin:
2109 case WebInputEvent::GesturePinchEnd:
2110 current_gesture_location_ = WebPoint(x, y);
2111 event.x = current_gesture_location_.x;
2112 event.y = current_gesture_location_.y;
2113 break;
2114 case WebInputEvent::GesturePinchUpdate:
2116 float scale = 1;
2117 if (!args->PeekNext().IsEmpty()) {
2118 if (!args->GetNext(&scale)) {
2119 args->ThrowError();
2120 return;
2123 event.data.pinchUpdate.scale = scale;
2124 current_gesture_location_ = WebPoint(x, y);
2125 event.x = current_gesture_location_.x;
2126 event.y = current_gesture_location_.y;
2127 break;
2129 case WebInputEvent::GestureTap:
2131 float tap_count = 1;
2132 float width = 30;
2133 float height = 30;
2134 if (!args->PeekNext().IsEmpty()) {
2135 if (!args->GetNext(&tap_count)) {
2136 args->ThrowError();
2137 return;
2140 if (!args->PeekNext().IsEmpty()) {
2141 if (!args->GetNext(&width)) {
2142 args->ThrowError();
2143 return;
2146 if (!args->PeekNext().IsEmpty()) {
2147 if (!args->GetNext(&height)) {
2148 args->ThrowError();
2149 return;
2152 event.data.tap.tapCount = tap_count;
2153 event.data.tap.width = width;
2154 event.data.tap.height = height;
2155 event.x = x;
2156 event.y = y;
2157 break;
2159 case WebInputEvent::GestureTapUnconfirmed:
2160 if (!args->PeekNext().IsEmpty()) {
2161 float tap_count;
2162 if (!args->GetNext(&tap_count)) {
2163 args->ThrowError();
2164 return;
2166 event.data.tap.tapCount = tap_count;
2167 } else {
2168 event.data.tap.tapCount = 1;
2170 event.x = x;
2171 event.y = y;
2172 break;
2173 case WebInputEvent::GestureTapDown:
2175 float width = 30;
2176 float height = 30;
2177 if (!args->PeekNext().IsEmpty()) {
2178 if (!args->GetNext(&width)) {
2179 args->ThrowError();
2180 return;
2183 if (!args->PeekNext().IsEmpty()) {
2184 if (!args->GetNext(&height)) {
2185 args->ThrowError();
2186 return;
2189 event.x = x;
2190 event.y = y;
2191 event.data.tapDown.width = width;
2192 event.data.tapDown.height = height;
2193 break;
2195 case WebInputEvent::GestureShowPress:
2197 float width = 30;
2198 float height = 30;
2199 if (!args->PeekNext().IsEmpty()) {
2200 if (!args->GetNext(&width)) {
2201 args->ThrowError();
2202 return;
2204 if (!args->PeekNext().IsEmpty()) {
2205 if (!args->GetNext(&height)) {
2206 args->ThrowError();
2207 return;
2211 event.x = x;
2212 event.y = y;
2213 event.data.showPress.width = width;
2214 event.data.showPress.height = height;
2215 break;
2217 case WebInputEvent::GestureTapCancel:
2218 event.x = x;
2219 event.y = y;
2220 break;
2221 case WebInputEvent::GestureLongPress:
2222 event.x = x;
2223 event.y = y;
2224 if (!args->PeekNext().IsEmpty()) {
2225 float width;
2226 if (!args->GetNext(&width)) {
2227 args->ThrowError();
2228 return;
2230 event.data.longPress.width = width;
2231 if (!args->PeekNext().IsEmpty()) {
2232 float height;
2233 if (!args->GetNext(&height)) {
2234 args->ThrowError();
2235 return;
2237 event.data.longPress.height = height;
2240 break;
2241 case WebInputEvent::GestureLongTap:
2242 event.x = x;
2243 event.y = y;
2244 if (!args->PeekNext().IsEmpty()) {
2245 float width;
2246 if (!args->GetNext(&width)) {
2247 args->ThrowError();
2248 return;
2250 event.data.longPress.width = width;
2251 if (!args->PeekNext().IsEmpty()) {
2252 float height;
2253 if (!args->GetNext(&height)) {
2254 args->ThrowError();
2255 return;
2257 event.data.longPress.height = height;
2260 break;
2261 case WebInputEvent::GestureTwoFingerTap:
2262 event.x = x;
2263 event.y = y;
2264 if (!args->PeekNext().IsEmpty()) {
2265 float first_finger_width;
2266 if (!args->GetNext(&first_finger_width)) {
2267 args->ThrowError();
2268 return;
2270 event.data.twoFingerTap.firstFingerWidth = first_finger_width;
2271 if (!args->PeekNext().IsEmpty()) {
2272 float first_finger_height;
2273 if (!args->GetNext(&first_finger_height)) {
2274 args->ThrowError();
2275 return;
2277 event.data.twoFingerTap.firstFingerHeight = first_finger_height;
2280 break;
2281 default:
2282 NOTREACHED();
2285 event.globalX = event.x;
2286 event.globalY = event.y;
2287 event.timeStampSeconds = GetCurrentEventTimeSec();
2289 if (force_layout_on_events_)
2290 view_->layout();
2292 bool result = HandleInputEventOnViewOrPopup(event);
2294 // Long press might start a drag drop session. Complete it if so.
2295 if (type == WebInputEvent::GestureLongPress && !current_drag_data_.isNull()) {
2296 WebMouseEvent mouse_event;
2297 InitMouseEvent(WebInputEvent::MouseDown,
2298 pressed_button_,
2299 WebPoint(x, y),
2300 GetCurrentEventTimeSec(),
2301 click_count_,
2303 &mouse_event);
2305 FinishDragAndDrop(mouse_event, blink::WebDragOperationNone);
2307 args->Return(result);
2310 void EventSender::UpdateClickCountForButton(
2311 WebMouseEvent::Button button_type) {
2312 if ((GetCurrentEventTimeSec() - last_click_time_sec_ <
2313 kMultipleClickTimeSec) &&
2314 (!OutsideMultiClickRadius(last_mouse_pos_, last_click_pos_)) &&
2315 (button_type == last_button_type_)) {
2316 ++click_count_;
2317 } else {
2318 click_count_ = 1;
2319 last_button_type_ = button_type;
2323 void EventSender::InitMouseWheelEvent(gin::Arguments* args,
2324 bool continuous,
2325 WebMouseWheelEvent* event) {
2326 // Force a layout here just to make sure every position has been
2327 // determined before we send events (as well as all the other methods
2328 // that send an event do).
2329 if (force_layout_on_events_)
2330 view_->layout();
2332 double horizontal;
2333 if (!args->GetNext(&horizontal)) {
2334 args->ThrowError();
2335 return;
2337 double vertical;
2338 if (!args->GetNext(&vertical)) {
2339 args->ThrowError();
2340 return;
2343 bool paged = false;
2344 bool has_precise_scrolling_deltas = false;
2345 int modifiers = 0;
2346 bool can_scroll = true;
2347 if (!args->PeekNext().IsEmpty()) {
2348 args->GetNext(&paged);
2349 if (!args->PeekNext().IsEmpty()) {
2350 args->GetNext(&has_precise_scrolling_deltas);
2351 if (!args->PeekNext().IsEmpty()) {
2352 v8::Local<v8::Value> value;
2353 args->GetNext(&value);
2354 modifiers = GetKeyModifiersFromV8(args->isolate(), value);
2355 if (!args->PeekNext().IsEmpty())
2356 args->GetNext(&can_scroll);
2361 InitMouseEvent(WebInputEvent::MouseWheel,
2362 pressed_button_,
2363 last_mouse_pos_,
2364 GetCurrentEventTimeSec(),
2365 click_count_,
2366 modifiers,
2367 event);
2368 event->wheelTicksX = static_cast<float>(horizontal);
2369 event->wheelTicksY = static_cast<float>(vertical);
2370 event->deltaX = event->wheelTicksX;
2371 event->deltaY = event->wheelTicksY;
2372 event->scrollByPage = paged;
2373 event->hasPreciseScrollingDeltas = has_precise_scrolling_deltas;
2374 event->canScroll = can_scroll;
2375 if (continuous) {
2376 event->wheelTicksX /= kScrollbarPixelsPerTick;
2377 event->wheelTicksY /= kScrollbarPixelsPerTick;
2378 } else {
2379 event->deltaX *= kScrollbarPixelsPerTick;
2380 event->deltaY *= kScrollbarPixelsPerTick;
2384 void EventSender::FinishDragAndDrop(const WebMouseEvent& e,
2385 blink::WebDragOperation drag_effect) {
2386 WebPoint client_point(e.x, e.y);
2387 WebPoint screen_point(e.globalX, e.globalY);
2388 current_drag_effect_ = drag_effect;
2389 if (current_drag_effect_) {
2390 // Specifically pass any keyboard modifiers to the drop method. This allows
2391 // tests to control the drop type (i.e. copy or move).
2392 view_->dragTargetDrop(client_point, screen_point, e.modifiers);
2393 } else {
2394 view_->dragTargetDragLeave();
2396 view_->dragSourceEndedAt(client_point, screen_point, current_drag_effect_);
2397 view_->dragSourceSystemDragEnded();
2399 current_drag_data_.reset();
2402 void EventSender::DoMouseUp(const WebMouseEvent& e) {
2403 HandleInputEventOnViewOrPopup(e);
2405 pressed_button_ = WebMouseEvent::ButtonNone;
2406 last_click_time_sec_ = e.timeStampSeconds;
2407 last_click_pos_ = last_mouse_pos_;
2409 // If we're in a drag operation, complete it.
2410 if (current_drag_data_.isNull())
2411 return;
2413 WebPoint client_point(e.x, e.y);
2414 WebPoint screen_point(e.globalX, e.globalY);
2415 FinishDragAndDrop(
2417 view_->dragTargetDragOver(
2418 client_point,
2419 screen_point,
2420 current_drag_effects_allowed_,
2421 e.modifiers));
2424 void EventSender::DoMouseMove(const WebMouseEvent& e) {
2425 last_mouse_pos_ = WebPoint(e.x, e.y);
2427 HandleInputEventOnViewOrPopup(e);
2429 if (pressed_button_ == WebMouseEvent::ButtonNone ||
2430 current_drag_data_.isNull()) {
2431 return;
2434 WebPoint client_point(e.x, e.y);
2435 WebPoint screen_point(e.globalX, e.globalY);
2436 current_drag_effect_ = view_->dragTargetDragOver(
2437 client_point, screen_point, current_drag_effects_allowed_, e.modifiers);
2440 void EventSender::ReplaySavedEvents() {
2441 replaying_saved_events_ = true;
2442 while (!mouse_event_queue_.empty()) {
2443 SavedEvent e = mouse_event_queue_.front();
2444 mouse_event_queue_.pop_front();
2446 switch (e.type) {
2447 case SavedEvent::TYPE_MOUSE_MOVE: {
2448 WebMouseEvent event;
2449 InitMouseEvent(WebInputEvent::MouseMove,
2450 pressed_button_,
2451 e.pos,
2452 GetCurrentEventTimeSec(),
2453 click_count_,
2454 e.modifiers,
2455 &event);
2456 DoMouseMove(event);
2457 break;
2459 case SavedEvent::TYPE_LEAP_FORWARD:
2460 DoLeapForward(e.milliseconds);
2461 break;
2462 case SavedEvent::TYPE_MOUSE_UP: {
2463 WebMouseEvent event;
2464 InitMouseEvent(WebInputEvent::MouseUp,
2465 e.button_type,
2466 last_mouse_pos_,
2467 GetCurrentEventTimeSec(),
2468 click_count_,
2469 e.modifiers,
2470 &event);
2471 DoMouseUp(event);
2472 break;
2474 default:
2475 NOTREACHED();
2479 replaying_saved_events_ = false;
2482 bool EventSender::HandleInputEventOnViewOrPopup(const WebInputEvent& event) {
2483 if (WebPagePopup* popup = view_->pagePopup()) {
2484 if (!WebInputEvent::isKeyboardEventType(event.type))
2485 return popup->handleInputEvent(event);
2487 return view_->handleInputEvent(event);
2490 } // namespace test_runner