initial import
[vuplus_webkit] / Tools / WebKitTestRunner / InjectedBundle / EventSendingController.cpp
1 /*
2  * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "EventSendingController.h"
28
29 #include "InjectedBundle.h"
30 #include "InjectedBundlePage.h"
31 #include "JSEventSendingController.h"
32 #include "StringFunctions.h"
33 #include <WebKit2/WKBundle.h>
34 #include <WebKit2/WKBundleFrame.h>
35 #include <WebKit2/WKBundlePagePrivate.h>
36 #include <WebKit2/WKBundlePrivate.h>
37 #include <WebKit2/WKMutableDictionary.h>
38 #include <WebKit2/WKNumber.h>
39
40 namespace WTR {
41
42 static const float ZoomMultiplierRatio = 1.2f;
43
44 static bool operator==(const WKPoint& a, const WKPoint& b)
45 {
46     return a.x == b.x && a.y == b.y;
47 }
48
49 static WKEventModifiers parseModifier(JSStringRef modifier)
50 {
51     if (JSStringIsEqualToUTF8CString(modifier, "ctrlKey"))
52         return kWKEventModifiersControlKey;
53     if (JSStringIsEqualToUTF8CString(modifier, "shiftKey") || JSStringIsEqualToUTF8CString(modifier, "rangeSelectionKey"))
54         return kWKEventModifiersShiftKey;
55     if (JSStringIsEqualToUTF8CString(modifier, "altKey"))
56         return kWKEventModifiersAltKey;
57     if (JSStringIsEqualToUTF8CString(modifier, "metaKey") || JSStringIsEqualToUTF8CString(modifier, "addSelectionKey"))
58         return kWKEventModifiersMetaKey;
59     return 0;
60 }
61
62 static unsigned arrayLength(JSContextRef context, JSObjectRef array)
63 {
64     JSRetainPtr<JSStringRef> lengthString(Adopt, JSStringCreateWithUTF8CString("length"));
65     JSValueRef lengthValue = JSObjectGetProperty(context, array, lengthString.get(), 0);
66     if (!lengthValue)
67         return 0;
68     return static_cast<unsigned>(JSValueToNumber(context, lengthValue, 0));
69 }
70
71 static WKEventModifiers parseModifierArray(JSContextRef context, JSValueRef arrayValue)
72 {
73     if (!arrayValue)
74         return 0;
75     if (!JSValueIsObject(context, arrayValue))
76         return 0;
77     JSObjectRef array = const_cast<JSObjectRef>(arrayValue);
78     unsigned length = arrayLength(context, array);
79     WKEventModifiers modifiers = 0;
80     for (unsigned i = 0; i < length; i++) {
81         JSValueRef exception = 0;
82         JSValueRef value = JSObjectGetPropertyAtIndex(context, array, i, &exception);
83         if (exception)
84             continue;
85         JSRetainPtr<JSStringRef> string(Adopt, JSValueToStringCopy(context, value, &exception));
86         if (exception)
87             continue;
88         modifiers |= parseModifier(string.get());
89     }
90     return modifiers;
91 }
92
93 PassRefPtr<EventSendingController> EventSendingController::create()
94 {
95     return adoptRef(new EventSendingController);
96 }
97
98 EventSendingController::EventSendingController()
99     : m_time(0)
100     , m_position()
101     , m_clickCount(0)
102     , m_clickTime(0)
103     , m_clickPosition()
104     , m_clickButton(kWKEventMouseButtonNoButton)
105 {
106 }
107
108 EventSendingController::~EventSendingController()
109 {
110 }
111
112 JSClassRef EventSendingController::wrapperClass()
113 {
114     return JSEventSendingController::eventSendingControllerClass();
115 }
116
117 void EventSendingController::mouseDown(int button, JSValueRef modifierArray)
118 {
119     WKBundlePageRef page = InjectedBundle::shared().page()->page();
120     WKBundleFrameRef frame = WKBundlePageGetMainFrame(page);
121     JSContextRef context = WKBundleFrameGetJavaScriptContext(frame);
122     WKEventModifiers modifiers = parseModifierArray(context, modifierArray);
123     updateClickCount(button);
124     WKBundlePageSimulateMouseDown(page, button, m_position, m_clickCount, modifiers, m_time);
125 }
126
127 void EventSendingController::mouseUp(int button, JSValueRef modifierArray)
128 {
129     WKBundlePageRef page = InjectedBundle::shared().page()->page();
130     WKBundleFrameRef frame = WKBundlePageGetMainFrame(page);
131     JSContextRef context = WKBundleFrameGetJavaScriptContext(frame);
132     WKEventModifiers modifiers = parseModifierArray(context, modifierArray);
133     updateClickCount(button);
134     WKBundlePageSimulateMouseUp(page, button, m_position, m_clickCount, modifiers, m_time);
135 }
136
137 void EventSendingController::mouseMoveTo(int x, int y)
138 {
139     m_position.x = x;
140     m_position.y = y;
141     WKBundlePageSimulateMouseMotion(InjectedBundle::shared().page()->page(), m_position, m_time);
142 }
143
144 void EventSendingController::leapForward(int milliseconds)
145 {
146     m_time += milliseconds / 1000.0;
147 }
148
149 void EventSendingController::updateClickCount(WKEventMouseButton button)
150 {
151     if (m_time - m_clickTime < 1 && m_position == m_clickPosition && button == m_clickButton) {
152         ++m_clickCount;
153         m_clickTime = m_time;
154         return;
155     }
156
157     m_clickCount = 1;
158     m_clickTime = m_time;
159     m_clickPosition = m_position;
160     m_clickButton = button;
161 }
162
163 void EventSendingController::textZoomIn()
164 {
165     // Ensure page zoom is reset.
166     WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), 1);
167
168     double zoomFactor = WKBundlePageGetTextZoomFactor(InjectedBundle::shared().page()->page());
169     WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor * ZoomMultiplierRatio);
170 }
171
172 void EventSendingController::textZoomOut()
173 {
174     // Ensure page zoom is reset.
175     WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), 1);
176
177     double zoomFactor = WKBundlePageGetTextZoomFactor(InjectedBundle::shared().page()->page());
178     WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor / ZoomMultiplierRatio);
179 }
180
181 void EventSendingController::zoomPageIn()
182 {
183     // Ensure text zoom is reset.
184     WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), 1);
185
186     double zoomFactor = WKBundlePageGetPageZoomFactor(InjectedBundle::shared().page()->page());
187     WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor * ZoomMultiplierRatio);
188 }
189
190 void EventSendingController::zoomPageOut()
191 {
192     // Ensure text zoom is reset.
193     WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), 1);
194
195     double zoomFactor = WKBundlePageGetPageZoomFactor(InjectedBundle::shared().page()->page());
196     WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor / ZoomMultiplierRatio);
197 }
198
199 void EventSendingController::scalePageBy(double scale, double x, double y)
200 {
201     WKPoint origin = { x, y };
202     WKBundlePageSetScaleAtOrigin(InjectedBundle::shared().page()->page(), scale, origin);
203 }
204
205 // Object Creation
206
207 void EventSendingController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
208 {
209     setProperty(context, windowObject, "eventSender", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
210 }
211
212 void EventSendingController::keyDown(JSStringRef key, JSValueRef modifierArray, int location)
213 {
214     WKBundlePageRef page = InjectedBundle::shared().page()->page();
215     WKBundleFrameRef frame = WKBundlePageGetMainFrame(page);
216     JSContextRef context = WKBundleFrameGetJavaScriptContext(frame);
217     WKEventModifiers modifiers = parseModifierArray(context, modifierArray);
218
219     WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender"));
220     WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate());
221
222     WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
223     WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("KeyDown"));
224     WKDictionaryAddItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get());
225
226     WKRetainPtr<WKStringRef> keyKey = adoptWK(WKStringCreateWithUTF8CString("Key"));
227     WKDictionaryAddItem(EventSenderMessageBody.get(), keyKey.get(), toWK(key).get());
228
229     WKRetainPtr<WKStringRef> modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers"));
230     WKRetainPtr<WKUInt64Ref> modifiersRef = WKUInt64Create(modifiers);
231     WKDictionaryAddItem(EventSenderMessageBody.get(), modifiersKey.get(), modifiersRef.get());
232
233     WKRetainPtr<WKStringRef> locationKey = adoptWK(WKStringCreateWithUTF8CString("Location"));
234     WKRetainPtr<WKUInt64Ref> locationRef = WKUInt64Create(location);
235     WKDictionaryAddItem(EventSenderMessageBody.get(), locationKey.get(), locationRef.get());
236
237     WKRetainPtr<WKStringRef> timestampKey = adoptWK(WKStringCreateWithUTF8CString("Timestamp"));
238     WKRetainPtr<WKDoubleRef> timeRef = WKDoubleCreate(m_time);
239     WKDictionaryAddItem(EventSenderMessageBody.get(), timestampKey.get(), timeRef.get());
240
241     WKBundlePostSynchronousMessage(InjectedBundle::shared().bundle(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
242 }
243
244 } // namespace WTR