• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007, 2008 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "config.h"
30 #include "EventSender.h"
31 
32 #include "DraggingInfo.h"
33 #include "DumpRenderTree.h"
34 
35 #include <WebCore/COMPtr.h>
36 #include <wtf/ASCIICType.h>
37 #include <wtf/Platform.h>
38 #include <JavaScriptCore/JavaScriptCore.h>
39 #include <JavaScriptCore/Assertions.h>
40 #include <WebKit/WebKit.h>
41 #include <windows.h>
42 
43 #define WM_DRT_SEND_QUEUED_EVENT (WM_APP+1)
44 
45 static bool down;
46 static bool dragMode = true;
47 static bool replayingSavedEvents;
48 static int timeOffset;
49 static POINT lastMousePosition;
50 
51 struct DelayedMessage {
52     MSG msg;
53     unsigned delay;
54 };
55 
56 static DelayedMessage msgQueue[1024];
57 static unsigned endOfQueue;
58 static unsigned startOfQueue;
59 
60 static bool didDragEnter;
61 DraggingInfo* draggingInfo = 0;
62 
getDragModeCallback(JSContextRef context,JSObjectRef object,JSStringRef propertyName,JSValueRef * exception)63 static JSValueRef getDragModeCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
64 {
65     return JSValueMakeBoolean(context, dragMode);
66 }
67 
setDragModeCallback(JSContextRef context,JSObjectRef object,JSStringRef propertyName,JSValueRef value,JSValueRef * exception)68 static bool setDragModeCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
69 {
70     dragMode = JSValueToBoolean(context, value);
71     return true;
72 }
73 
getConstantCallback(JSContextRef context,JSObjectRef object,JSStringRef propertyName,JSValueRef * exception)74 static JSValueRef getConstantCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
75 {
76     if (JSStringIsEqualToUTF8CString(propertyName, "WM_KEYDOWN"))
77         return JSValueMakeNumber(context, WM_KEYDOWN);
78     if (JSStringIsEqualToUTF8CString(propertyName, "WM_KEYUP"))
79         return JSValueMakeNumber(context, WM_KEYUP);
80     if (JSStringIsEqualToUTF8CString(propertyName, "WM_CHAR"))
81         return JSValueMakeNumber(context, WM_CHAR);
82     if (JSStringIsEqualToUTF8CString(propertyName, "WM_DEADCHAR"))
83         return JSValueMakeNumber(context, WM_DEADCHAR);
84     if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSKEYDOWN"))
85         return JSValueMakeNumber(context, WM_SYSKEYDOWN);
86     if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSKEYUP"))
87         return JSValueMakeNumber(context, WM_SYSKEYUP);
88     if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSCHAR"))
89         return JSValueMakeNumber(context, WM_SYSCHAR);
90     if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSDEADCHAR"))
91         return JSValueMakeNumber(context, WM_SYSDEADCHAR);
92     ASSERT_NOT_REACHED();
93     return JSValueMakeUndefined(context);
94 }
95 
leapForwardCallback(JSContextRef context,JSObjectRef function,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)96 static JSValueRef leapForwardCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
97 {
98     if (argumentCount > 0) {
99         msgQueue[endOfQueue].delay = JSValueToNumber(context, arguments[0], exception);
100         ASSERT(!exception || !*exception);
101     }
102 
103     return JSValueMakeUndefined(context);
104 }
105 
currentEventTime()106 static DWORD currentEventTime()
107 {
108     return ::GetTickCount() + timeOffset;
109 }
110 
makeMsg(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)111 static MSG makeMsg(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
112 {
113     MSG result = {0};
114     result.hwnd = hwnd;
115     result.message = message;
116     result.wParam = wParam;
117     result.lParam = lParam;
118     result.time = currentEventTime();
119     result.pt = lastMousePosition;
120 
121     return result;
122 }
123 
dispatchMessage(const MSG * msg)124 static LRESULT dispatchMessage(const MSG* msg)
125 {
126     ASSERT(msg);
127     ::TranslateMessage(msg);
128     return ::DispatchMessage(msg);
129 }
130 
contextClickCallback(JSContextRef context,JSObjectRef function,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)131 static JSValueRef contextClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
132 {
133     COMPtr<IWebFramePrivate> framePrivate;
134     if (SUCCEEDED(frame->QueryInterface(&framePrivate)))
135         framePrivate->layout();
136 
137     down = true;
138     MSG msg = makeMsg(webViewWindow, WM_RBUTTONDOWN, 0, MAKELPARAM(lastMousePosition.x, lastMousePosition.y));
139     dispatchMessage(&msg);
140     down = false;
141     msg = makeMsg(webViewWindow, WM_RBUTTONUP, 0, MAKELPARAM(lastMousePosition.x, lastMousePosition.y));
142     dispatchMessage(&msg);
143 
144     return JSValueMakeUndefined(context);
145 }
146 
mouseDownCallback(JSContextRef context,JSObjectRef function,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)147 static JSValueRef mouseDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
148 {
149     COMPtr<IWebFramePrivate> framePrivate;
150     if (SUCCEEDED(frame->QueryInterface(&framePrivate)))
151         framePrivate->layout();
152 
153     down = true;
154     MSG msg = makeMsg(webViewWindow, WM_LBUTTONDOWN, 0, MAKELPARAM(lastMousePosition.x, lastMousePosition.y));
155     if (!msgQueue[endOfQueue].delay)
156         dispatchMessage(&msg);
157     else {
158         // replaySavedEvents has the required logic to make leapForward delays work
159         msgQueue[endOfQueue++].msg = msg;
160         replaySavedEvents();
161     }
162 
163     return JSValueMakeUndefined(context);
164 }
165 
pointl(const POINT & point)166 static inline POINTL pointl(const POINT& point)
167 {
168     POINTL result;
169     result.x = point.x;
170     result.y = point.y;
171     return result;
172 }
173 
doMouseUp(MSG msg)174 static void doMouseUp(MSG msg)
175 {
176     COMPtr<IWebFramePrivate> framePrivate;
177     if (SUCCEEDED(frame->QueryInterface(&framePrivate)))
178         framePrivate->layout();
179 
180     dispatchMessage(&msg);
181     down = false;
182 
183     if (draggingInfo) {
184         COMPtr<IWebView> webView;
185         COMPtr<IDropTarget> webViewDropTarget;
186         if (SUCCEEDED(frame->webView(&webView)) && SUCCEEDED(webView->QueryInterface(IID_IDropTarget, (void**)&webViewDropTarget))) {
187             POINT screenPoint = msg.pt;
188             DWORD effect = 0;
189             ::ClientToScreen(webViewWindow, &screenPoint);
190             if (!didDragEnter) {
191                 webViewDropTarget->DragEnter(draggingInfo->dataObject(), 0, pointl(screenPoint), &effect);
192                 didDragEnter = true;
193             }
194             HRESULT hr = draggingInfo->dropSource()->QueryContinueDrag(0, 0);
195             webViewDropTarget->DragOver(0, pointl(screenPoint), &effect);
196             if (hr == DRAGDROP_S_DROP && effect != DROPEFFECT_NONE) {
197                 DWORD effect = 0;
198                 webViewDropTarget->Drop(draggingInfo->dataObject(), 0, pointl(screenPoint), &effect);
199             } else
200                 webViewDropTarget->DragLeave();
201 
202             delete draggingInfo;
203             draggingInfo = 0;
204         }
205     }
206 }
207 
mouseUpCallback(JSContextRef context,JSObjectRef function,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)208 static JSValueRef mouseUpCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
209 {
210     MSG msg = makeMsg(webViewWindow, WM_LBUTTONUP, 0, MAKELPARAM(lastMousePosition.x, lastMousePosition.y));
211 
212     if ((dragMode && !replayingSavedEvents) || msgQueue[endOfQueue].delay) {
213         msgQueue[endOfQueue++].msg = msg;
214         replaySavedEvents();
215     } else
216         doMouseUp(msg);
217 
218     return JSValueMakeUndefined(context);
219 }
220 
doMouseMove(MSG msg)221 static void doMouseMove(MSG msg)
222 {
223     COMPtr<IWebFramePrivate> framePrivate;
224     if (SUCCEEDED(frame->QueryInterface(&framePrivate)))
225         framePrivate->layout();
226 
227     dispatchMessage(&msg);
228 
229     if (down && draggingInfo) {
230         POINT screenPoint = msg.pt;
231         ::ClientToScreen(webViewWindow, &screenPoint);
232 
233         IWebView* webView;
234         COMPtr<IDropTarget> webViewDropTarget;
235         if (SUCCEEDED(frame->webView(&webView)) && SUCCEEDED(webView->QueryInterface(IID_IDropTarget, (void**)&webViewDropTarget))) {
236             DWORD effect = 0;
237             if (didDragEnter)
238                 webViewDropTarget->DragOver(MK_LBUTTON, pointl(screenPoint), &effect);
239             else {
240                 webViewDropTarget->DragEnter(draggingInfo->dataObject(), 0, pointl(screenPoint), &effect);
241                 didDragEnter = true;
242             }
243             draggingInfo->dropSource()->GiveFeedback(effect);
244         }
245     }
246 }
247 
mouseMoveToCallback(JSContextRef context,JSObjectRef function,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)248 static JSValueRef mouseMoveToCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
249 {
250     if (argumentCount < 2)
251         return JSValueMakeUndefined(context);
252 
253     lastMousePosition.x = (int)JSValueToNumber(context, arguments[0], exception);
254     ASSERT(!exception || !*exception);
255     lastMousePosition.y = (int)JSValueToNumber(context, arguments[1], exception);
256     ASSERT(!exception || !*exception);
257 
258     MSG msg = makeMsg(webViewWindow, WM_MOUSEMOVE, down ? MK_LBUTTON : 0, MAKELPARAM(lastMousePosition.x, lastMousePosition.y));
259 
260     if (dragMode && down && !replayingSavedEvents) {
261         msgQueue[endOfQueue++].msg = msg;
262         return JSValueMakeUndefined(context);
263     }
264 
265     doMouseMove(msg);
266 
267     return JSValueMakeUndefined(context);
268 }
269 
replaySavedEvents()270 void replaySavedEvents()
271 {
272     replayingSavedEvents = true;
273 
274     MSG msg = { 0 };
275 
276     while (startOfQueue < endOfQueue && !msgQueue[startOfQueue].delay) {
277         msg = msgQueue[startOfQueue++].msg;
278         switch (msg.message) {
279             case WM_LBUTTONUP:
280                 doMouseUp(msg);
281                 break;
282             case WM_MOUSEMOVE:
283                 doMouseMove(msg);
284                 break;
285             case WM_LBUTTONDOWN:
286                 dispatchMessage(&msg);
287                 break;
288             default:
289                 // Not reached
290                 break;
291         }
292     }
293 
294     int numQueuedMessages = endOfQueue - startOfQueue;
295     if (!numQueuedMessages) {
296         startOfQueue = 0;
297         endOfQueue = 0;
298         replayingSavedEvents = false;
299         ASSERT(!down);
300         return;
301     }
302 
303     if (msgQueue[startOfQueue].delay) {
304         ::Sleep(msgQueue[startOfQueue].delay);
305         msgQueue[startOfQueue].delay = 0;
306     }
307 
308     ::PostMessage(webViewWindow, WM_DRT_SEND_QUEUED_EVENT, 0, 0);
309     while (::GetMessage(&msg, webViewWindow, 0, 0)) {
310         // FIXME: Why do we get a WM_MOUSELEAVE? it breaks tests
311         if (msg.message == WM_MOUSELEAVE)
312             continue;
313         if (msg.message != WM_DRT_SEND_QUEUED_EVENT) {
314             dispatchMessage(&msg);
315             continue;
316         }
317         msg = msgQueue[startOfQueue++].msg;
318         switch (msg.message) {
319             case WM_LBUTTONUP:
320                 doMouseUp(msg);
321                 break;
322             case WM_MOUSEMOVE:
323                 doMouseMove(msg);
324                 break;
325             case WM_LBUTTONDOWN:
326                 dispatchMessage(&msg);
327                 break;
328             default:
329                 // Not reached
330                 break;
331         }
332         if (startOfQueue >= endOfQueue)
333             break;
334         ::Sleep(msgQueue[startOfQueue].delay);
335         msgQueue[startOfQueue].delay = 0;
336         ::PostMessage(webViewWindow, WM_DRT_SEND_QUEUED_EVENT, 0, 0);
337     }
338     startOfQueue = 0;
339     endOfQueue = 0;
340 
341     replayingSavedEvents = false;
342 }
343 
keyDownCallback(JSContextRef context,JSObjectRef function,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)344 static JSValueRef keyDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
345 {
346     if (argumentCount < 1)
347         return JSValueMakeUndefined(context);
348 
349     static const JSStringRef lengthProperty = JSStringCreateWithUTF8CString("length");
350 
351     COMPtr<IWebFramePrivate> framePrivate;
352     if (SUCCEEDED(frame->QueryInterface(&framePrivate)))
353         framePrivate->layout();
354 
355     JSStringRef character = JSValueToStringCopy(context, arguments[0], exception);
356     ASSERT(!*exception);
357     int virtualKeyCode;
358     int charCode = 0;
359     int keyData = 1;
360     bool needsShiftKeyModifier = false;
361     if (JSStringIsEqualToUTF8CString(character, "leftArrow")) {
362         virtualKeyCode = VK_LEFT;
363         keyData += KF_EXTENDED << 16; // In this case, extended means "not keypad".
364     } else if (JSStringIsEqualToUTF8CString(character, "rightArrow")) {
365         virtualKeyCode = VK_RIGHT;
366         keyData += KF_EXTENDED << 16;
367     } else if (JSStringIsEqualToUTF8CString(character, "upArrow")) {
368         virtualKeyCode = VK_UP;
369         keyData += KF_EXTENDED << 16;
370     } else if (JSStringIsEqualToUTF8CString(character, "downArrow")) {
371         virtualKeyCode = VK_DOWN;
372         keyData += KF_EXTENDED << 16;
373     } else if (JSStringIsEqualToUTF8CString(character, "pageUp"))
374         virtualKeyCode = VK_PRIOR;
375     else if (JSStringIsEqualToUTF8CString(character, "pageDown"))
376         virtualKeyCode = VK_NEXT;
377     else if (JSStringIsEqualToUTF8CString(character, "home"))
378         virtualKeyCode = VK_HOME;
379     else if (JSStringIsEqualToUTF8CString(character, "end"))
380         virtualKeyCode = VK_END;
381     else if (JSStringIsEqualToUTF8CString(character, "delete"))
382         virtualKeyCode = VK_BACK;
383     else {
384         charCode = JSStringGetCharactersPtr(character)[0];
385         virtualKeyCode = LOBYTE(VkKeyScan(charCode));
386         if (WTF::isASCIIUpper(charCode))
387             needsShiftKeyModifier = true;
388     }
389     JSStringRelease(character);
390 
391     BYTE keyState[256];
392     if (argumentCount > 1 || needsShiftKeyModifier) {
393         ::GetKeyboardState(keyState);
394 
395         BYTE newKeyState[256];
396         memcpy(newKeyState, keyState, sizeof(keyState));
397 
398         if (needsShiftKeyModifier)
399             newKeyState[VK_SHIFT] = 0x80;
400 
401         if (argumentCount > 1) {
402             JSObjectRef modifiersArray = JSValueToObject(context, arguments[1], 0);
403             if (modifiersArray) {
404                 int modifiersCount = JSValueToNumber(context, JSObjectGetProperty(context, modifiersArray, lengthProperty, 0), 0);
405                 for (int i = 0; i < modifiersCount; ++i) {
406                     JSValueRef value = JSObjectGetPropertyAtIndex(context, modifiersArray, i, 0);
407                     JSStringRef string = JSValueToStringCopy(context, value, 0);
408                     if (JSStringIsEqualToUTF8CString(string, "ctrlKey"))
409                         newKeyState[VK_CONTROL] = 0x80;
410                     else if (JSStringIsEqualToUTF8CString(string, "shiftKey"))
411                         newKeyState[VK_SHIFT] = 0x80;
412                     else if (JSStringIsEqualToUTF8CString(string, "altKey"))
413                         newKeyState[VK_MENU] = 0x80;
414 
415                     JSStringRelease(string);
416                 }
417             }
418         }
419 
420         ::SetKeyboardState(newKeyState);
421     }
422 
423     MSG msg = makeMsg(webViewWindow, (::GetKeyState(VK_MENU) & 0x8000) ? WM_SYSKEYDOWN : WM_KEYDOWN, virtualKeyCode, keyData);
424     if (virtualKeyCode != 255)
425         dispatchMessage(&msg);
426     else {
427         // For characters that do not exist in the active keyboard layout,
428         // ::Translate will not work, so we post an WM_CHAR event ourselves.
429         ::PostMessage(webViewWindow, WM_CHAR, charCode, 0);
430     }
431 
432     // Tests expect that all messages are processed by the time keyDown() returns.
433     if (::PeekMessage(&msg, webViewWindow, WM_CHAR, WM_CHAR, PM_REMOVE) || ::PeekMessage(&msg, webViewWindow, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
434         ::DispatchMessage(&msg);
435 
436     MSG msgUp = makeMsg(webViewWindow, (::GetKeyState(VK_MENU) & 0x8000) ? WM_SYSKEYUP : WM_KEYUP, virtualKeyCode, keyData);
437     ::DispatchMessage(&msgUp);
438 
439     if (argumentCount > 1 || needsShiftKeyModifier)
440         ::SetKeyboardState(keyState);
441 
442     return JSValueMakeUndefined(context);
443 }
444 
445 // eventSender.dispatchMessage(message, wParam, lParam, time = currentEventTime(), x = lastMousePosition.x, y = lastMousePosition.y)
dispatchMessageCallback(JSContextRef context,JSObjectRef function,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)446 static JSValueRef dispatchMessageCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
447 {
448     if (argumentCount < 3)
449         return JSValueMakeUndefined(context);
450 
451     COMPtr<IWebFramePrivate> framePrivate;
452     if (SUCCEEDED(frame->QueryInterface(&framePrivate)))
453         framePrivate->layout();
454 
455     MSG msg = {};
456     msg.hwnd = webViewWindow;
457     msg.message = JSValueToNumber(context, arguments[0], exception);
458     ASSERT(!*exception);
459     msg.wParam = JSValueToNumber(context, arguments[1], exception);
460     ASSERT(!*exception);
461     msg.lParam = static_cast<ULONG_PTR>(JSValueToNumber(context, arguments[2], exception));
462     ASSERT(!*exception);
463     if (argumentCount >= 4) {
464         msg.time = JSValueToNumber(context, arguments[3], exception);
465         ASSERT(!*exception);
466     }
467     if (!msg.time)
468         msg.time = currentEventTime();
469     if (argumentCount >= 6) {
470         msg.pt.x = JSValueToNumber(context, arguments[4], exception);
471         ASSERT(!*exception);
472         msg.pt.y = JSValueToNumber(context, arguments[5], exception);
473         ASSERT(!*exception);
474     } else
475         msg.pt = lastMousePosition;
476 
477     ::DispatchMessage(&msg);
478 
479     return JSValueMakeUndefined(context);
480 }
481 
textZoomInCallback(JSContextRef context,JSObjectRef function,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)482 static JSValueRef textZoomInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
483 {
484     COMPtr<IWebView> webView;
485     if (FAILED(frame->webView(&webView)))
486         return JSValueMakeUndefined(context);
487 
488     COMPtr<IWebIBActions> webIBActions(Query, webView);
489     if (!webIBActions)
490         return JSValueMakeUndefined(context);
491 
492     webIBActions->makeTextLarger(0);
493     return JSValueMakeUndefined(context);
494 }
495 
textZoomOutCallback(JSContextRef context,JSObjectRef function,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)496 static JSValueRef textZoomOutCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
497 {
498     COMPtr<IWebView> webView;
499     if (FAILED(frame->webView(&webView)))
500         return JSValueMakeUndefined(context);
501 
502     COMPtr<IWebIBActions> webIBActions(Query, webView);
503     if (!webIBActions)
504         return JSValueMakeUndefined(context);
505 
506     webIBActions->makeTextSmaller(0);
507     return JSValueMakeUndefined(context);
508 }
509 
zoomPageInCallback(JSContextRef context,JSObjectRef function,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)510 static JSValueRef zoomPageInCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
511 {
512     COMPtr<IWebView> webView;
513     if (FAILED(frame->webView(&webView)))
514         return JSValueMakeUndefined(context);
515 
516     COMPtr<IWebIBActions> webIBActions(Query, webView);
517     if (!webIBActions)
518         return JSValueMakeUndefined(context);
519 
520     webIBActions->zoomPageIn(0);
521     return JSValueMakeUndefined(context);
522 }
523 
zoomPageOutCallback(JSContextRef context,JSObjectRef function,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)524 static JSValueRef zoomPageOutCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
525 {
526     COMPtr<IWebView> webView;
527     if (FAILED(frame->webView(&webView)))
528         return JSValueMakeUndefined(context);
529 
530     COMPtr<IWebIBActions> webIBActions(Query, webView);
531     if (!webIBActions)
532         return JSValueMakeUndefined(context);
533 
534     webIBActions->zoomPageOut(0);
535     return JSValueMakeUndefined(context);
536 }
537 
538 static JSStaticFunction staticFunctions[] = {
539     { "contextClick", contextClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
540     { "mouseDown", mouseDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
541     { "mouseUp", mouseUpCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
542     { "mouseMoveTo", mouseMoveToCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
543     { "leapForward", leapForwardCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
544     { "keyDown", keyDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
545     { "dispatchMessage", dispatchMessageCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
546     { "textZoomIn", textZoomInCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
547     { "textZoomOut", textZoomOutCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
548     { "zoomPageIn", zoomPageInCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
549     { "zoomPageOut", zoomPageOutCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
550     { 0, 0, 0 }
551 };
552 
553 static JSStaticValue staticValues[] = {
554     { "dragMode", getDragModeCallback, setDragModeCallback, kJSPropertyAttributeNone },
555     { "WM_KEYDOWN", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone },
556     { "WM_KEYUP", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone },
557     { "WM_CHAR", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone },
558     { "WM_DEADCHAR", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone },
559     { "WM_SYSKEYDOWN", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone },
560     { "WM_SYSKEYUP", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone },
561     { "WM_SYSCHAR", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone },
562     { "WM_SYSDEADCHAR", getConstantCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeNone },
563     { 0, 0, 0, 0 }
564 };
565 
getClass(JSContextRef context)566 static JSClassRef getClass(JSContextRef context)
567 {
568     static JSClassRef eventSenderClass = 0;
569 
570     if (!eventSenderClass) {
571         JSClassDefinition classDefinition = {0};
572         classDefinition.staticFunctions = staticFunctions;
573         classDefinition.staticValues = staticValues;
574 
575         eventSenderClass = JSClassCreate(&classDefinition);
576     }
577 
578     return eventSenderClass;
579 }
580 
makeEventSender(JSContextRef context)581 JSObjectRef makeEventSender(JSContextRef context)
582 {
583     down = false;
584     dragMode = true;
585     replayingSavedEvents = false;
586     timeOffset = 0;
587     lastMousePosition.x = 0;
588     lastMousePosition.y = 0;
589 
590     endOfQueue = 0;
591     startOfQueue = 0;
592 
593     didDragEnter = false;
594     draggingInfo = 0;
595 
596     return JSObjectMake(context, getClass(context), 0);
597 }
598