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 <WebKit2/WKBundleFrame.h> 33 #include <WebKit2/WKBundlePagePrivate.h> 34 #include <WebKit2/WKBundlePrivate.h> 35 36 namespace WTR { 37 38 static const float ZoomMultiplierRatio = 1.2f; 39 40 static bool operator==(const WKPoint& a, const WKPoint& b) 41 { 42 return a.x == b.x && a.y == b.y; 43 } 44 45 static WKEventModifiers parseModifier(JSStringRef modifier) 46 { 47 if (JSStringIsEqualToUTF8CString(modifier, "ctrlKey")) 48 return kWKEventModifiersControlKey; 49 if (JSStringIsEqualToUTF8CString(modifier, "shiftKey") || JSStringIsEqualToUTF8CString(modifier, "rangeSelectionKey")) 50 return kWKEventModifiersShiftKey; 51 if (JSStringIsEqualToUTF8CString(modifier, "altKey")) 52 return kWKEventModifiersAltKey; 53 if (JSStringIsEqualToUTF8CString(modifier, "metaKey") || JSStringIsEqualToUTF8CString(modifier, "addSelectionKey")) 54 return kWKEventModifiersMetaKey; 55 return 0; 56 } 57 58 static unsigned arrayLength(JSContextRef context, JSObjectRef array) 59 { 60 JSRetainPtr<JSStringRef> lengthString(Adopt, JSStringCreateWithUTF8CString("length")); 61 JSValueRef lengthValue = JSObjectGetProperty(context, array, lengthString.get(), 0); 62 if (!lengthValue) 63 return 0; 64 return static_cast<unsigned>(JSValueToNumber(context, lengthValue, 0)); 65 } 66 67 static WKEventModifiers parseModifierArray(JSContextRef context, JSValueRef arrayValue) 68 { 69 if (!arrayValue) 70 return 0; 71 if (!JSValueIsObject(context, arrayValue)) 72 return 0; 73 JSObjectRef array = const_cast<JSObjectRef>(arrayValue); 74 unsigned length = arrayLength(context, array); 75 WKEventModifiers modifiers = 0; 76 for (unsigned i = 0; i < length; i++) { 77 JSValueRef exception = 0; 78 JSValueRef value = JSObjectGetPropertyAtIndex(context, array, i, &exception); 79 if (exception) 80 continue; 81 JSRetainPtr<JSStringRef> string(Adopt, JSValueToStringCopy(context, value, &exception)); 82 if (exception) 83 continue; 84 modifiers |= parseModifier(string.get()); 85 } 86 return modifiers; 87 } 88 89 PassRefPtr<EventSendingController> EventSendingController::create() 90 { 91 return adoptRef(new EventSendingController); 92 } 93 94 EventSendingController::EventSendingController() 95 : m_time(0) 96 , m_position() 97 , m_clickCount(0) 98 , m_clickTime(0) 99 , m_clickPosition() 100 , m_clickButton(kWKEventMouseButtonNoButton) 101 { 102 } 103 104 EventSendingController::~EventSendingController() 105 { 106 } 107 108 JSClassRef EventSendingController::wrapperClass() 109 { 110 return JSEventSendingController::eventSendingControllerClass(); 111 } 112 113 void EventSendingController::mouseDown(int button, JSValueRef modifierArray) 114 { 115 WKBundlePageRef page = InjectedBundle::shared().page()->page(); 116 WKBundleFrameRef frame = WKBundlePageGetMainFrame(page); 117 JSContextRef context = WKBundleFrameGetJavaScriptContext(frame); 118 WKEventModifiers modifiers = parseModifierArray(context, modifierArray); 119 updateClickCount(button); 120 WKBundlePageSimulateMouseDown(page, button, m_position, m_clickCount, modifiers, m_time); 121 } 122 123 void EventSendingController::mouseUp(int button, JSValueRef modifierArray) 124 { 125 WKBundlePageRef page = InjectedBundle::shared().page()->page(); 126 WKBundleFrameRef frame = WKBundlePageGetMainFrame(page); 127 JSContextRef context = WKBundleFrameGetJavaScriptContext(frame); 128 WKEventModifiers modifiers = parseModifierArray(context, modifierArray); 129 updateClickCount(button); 130 WKBundlePageSimulateMouseUp(page, button, m_position, m_clickCount, modifiers, m_time); 131 } 132 133 void EventSendingController::mouseMoveTo(int x, int y) 134 { 135 m_position.x = x; 136 m_position.y = y; 137 WKBundlePageSimulateMouseMotion(InjectedBundle::shared().page()->page(), m_position, m_time); 138 } 139 140 void EventSendingController::leapForward(int milliseconds) 141 { 142 m_time += milliseconds / 1000.0; 143 } 144 145 void EventSendingController::updateClickCount(WKEventMouseButton button) 146 { 147 if (m_time - m_clickTime < 1 && m_position == m_clickPosition && button == m_clickButton) { 148 ++m_clickCount; 149 m_clickTime = m_time; 150 return; 151 } 152 153 m_clickCount = 1; 154 m_clickTime = m_time; 155 m_clickPosition = m_position; 156 m_clickButton = button; 157 } 158 159 void EventSendingController::textZoomIn() 160 { 161 // Ensure page zoom is reset. 162 WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), 1); 163 164 double zoomFactor = WKBundlePageGetTextZoomFactor(InjectedBundle::shared().page()->page()); 165 WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor * ZoomMultiplierRatio); 166 } 167 168 void EventSendingController::textZoomOut() 169 { 170 // Ensure page zoom is reset. 171 WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), 1); 172 173 double zoomFactor = WKBundlePageGetTextZoomFactor(InjectedBundle::shared().page()->page()); 174 WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor / ZoomMultiplierRatio); 175 } 176 177 void EventSendingController::zoomPageIn() 178 { 179 // Ensure text zoom is reset. 180 WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), 1); 181 182 double zoomFactor = WKBundlePageGetPageZoomFactor(InjectedBundle::shared().page()->page()); 183 WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor * ZoomMultiplierRatio); 184 } 185 186 void EventSendingController::zoomPageOut() 187 { 188 // Ensure text zoom is reset. 189 WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), 1); 190 191 double zoomFactor = WKBundlePageGetPageZoomFactor(InjectedBundle::shared().page()->page()); 192 WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor / ZoomMultiplierRatio); 193 } 194 195 void EventSendingController::scalePageBy(double scale, double x, double y) 196 { 197 WKPoint origin = { x, y }; 198 WKBundlePageSetScaleAtOrigin(InjectedBundle::shared().page()->page(), scale, origin); 199 } 200 201 // Object Creation 202 203 void EventSendingController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception) 204 { 205 setProperty(context, windowObject, "eventSender", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception); 206 } 207 208 } // namespace WTR 209