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