/*
* Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "EventSendingController.h"
#include "InjectedBundle.h"
#include "InjectedBundlePage.h"
#include "JSEventSendingController.h"
#include <WebKit2/WKBundleFrame.h>
#include <WebKit2/WKBundlePagePrivate.h>
#include <WebKit2/WKBundlePrivate.h>
namespace WTR {
static const float ZoomMultiplierRatio = 1.2f;
static bool operator==(const WKPoint& a, const WKPoint& b)
{
return a.x == b.x && a.y == b.y;
}
static WKEventModifiers parseModifier(JSStringRef modifier)
{
if (JSStringIsEqualToUTF8CString(modifier, "ctrlKey"))
return kWKEventModifiersControlKey;
if (JSStringIsEqualToUTF8CString(modifier, "shiftKey") || JSStringIsEqualToUTF8CString(modifier, "rangeSelectionKey"))
return kWKEventModifiersShiftKey;
if (JSStringIsEqualToUTF8CString(modifier, "altKey"))
return kWKEventModifiersAltKey;
if (JSStringIsEqualToUTF8CString(modifier, "metaKey") || JSStringIsEqualToUTF8CString(modifier, "addSelectionKey"))
return kWKEventModifiersMetaKey;
return 0;
}
static unsigned arrayLength(JSContextRef context, JSObjectRef array)
{
JSRetainPtr<JSStringRef> lengthString(Adopt, JSStringCreateWithUTF8CString("length"));
JSValueRef lengthValue = JSObjectGetProperty(context, array, lengthString.get(), 0);
if (!lengthValue)
return 0;
return static_cast<unsigned>(JSValueToNumber(context, lengthValue, 0));
}
static WKEventModifiers parseModifierArray(JSContextRef context, JSValueRef arrayValue)
{
if (!arrayValue)
return 0;
if (!JSValueIsObject(context, arrayValue))
return 0;
JSObjectRef array = const_cast<JSObjectRef>(arrayValue);
unsigned length = arrayLength(context, array);
WKEventModifiers modifiers = 0;
for (unsigned i = 0; i < length; i++) {
JSValueRef exception = 0;
JSValueRef value = JSObjectGetPropertyAtIndex(context, array, i, &exception);
if (exception)
continue;
JSRetainPtr<JSStringRef> string(Adopt, JSValueToStringCopy(context, value, &exception));
if (exception)
continue;
modifiers |= parseModifier(string.get());
}
return modifiers;
}
PassRefPtr<EventSendingController> EventSendingController::create()
{
return adoptRef(new EventSendingController);
}
EventSendingController::EventSendingController()
: m_time(0)
, m_position()
, m_clickCount(0)
, m_clickTime(0)
, m_clickPosition()
, m_clickButton(kWKEventMouseButtonNoButton)
{
}
EventSendingController::~EventSendingController()
{
}
JSClassRef EventSendingController::wrapperClass()
{
return JSEventSendingController::eventSendingControllerClass();
}
void EventSendingController::mouseDown(int button, JSValueRef modifierArray)
{
WKBundlePageRef page = InjectedBundle::shared().page()->page();
WKBundleFrameRef frame = WKBundlePageGetMainFrame(page);
JSContextRef context = WKBundleFrameGetJavaScriptContext(frame);
WKEventModifiers modifiers = parseModifierArray(context, modifierArray);
updateClickCount(button);
WKBundlePageSimulateMouseDown(page, button, m_position, m_clickCount, modifiers, m_time);
}
void EventSendingController::mouseUp(int button, JSValueRef modifierArray)
{
WKBundlePageRef page = InjectedBundle::shared().page()->page();
WKBundleFrameRef frame = WKBundlePageGetMainFrame(page);
JSContextRef context = WKBundleFrameGetJavaScriptContext(frame);
WKEventModifiers modifiers = parseModifierArray(context, modifierArray);
updateClickCount(button);
WKBundlePageSimulateMouseUp(page, button, m_position, m_clickCount, modifiers, m_time);
}
void EventSendingController::mouseMoveTo(int x, int y)
{
m_position.x = x;
m_position.y = y;
WKBundlePageSimulateMouseMotion(InjectedBundle::shared().page()->page(), m_position, m_time);
}
void EventSendingController::leapForward(int milliseconds)
{
m_time += milliseconds / 1000.0;
}
void EventSendingController::updateClickCount(WKEventMouseButton button)
{
if (m_time - m_clickTime < 1 && m_position == m_clickPosition && button == m_clickButton) {
++m_clickCount;
m_clickTime = m_time;
return;
}
m_clickCount = 1;
m_clickTime = m_time;
m_clickPosition = m_position;
m_clickButton = button;
}
void EventSendingController::textZoomIn()
{
// Ensure page zoom is reset.
WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), 1);
double zoomFactor = WKBundlePageGetTextZoomFactor(InjectedBundle::shared().page()->page());
WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor * ZoomMultiplierRatio);
}
void EventSendingController::textZoomOut()
{
// Ensure page zoom is reset.
WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), 1);
double zoomFactor = WKBundlePageGetTextZoomFactor(InjectedBundle::shared().page()->page());
WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor / ZoomMultiplierRatio);
}
void EventSendingController::zoomPageIn()
{
// Ensure text zoom is reset.
WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), 1);
double zoomFactor = WKBundlePageGetPageZoomFactor(InjectedBundle::shared().page()->page());
WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor * ZoomMultiplierRatio);
}
void EventSendingController::zoomPageOut()
{
// Ensure text zoom is reset.
WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), 1);
double zoomFactor = WKBundlePageGetPageZoomFactor(InjectedBundle::shared().page()->page());
WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor / ZoomMultiplierRatio);
}
void EventSendingController::scalePageBy(double scale, double x, double y)
{
WKPoint origin = { x, y };
WKBundlePageSetScaleAtOrigin(InjectedBundle::shared().page()->page(), scale, origin);
}
// Object Creation
void EventSendingController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
{
setProperty(context, windowObject, "eventSender", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
}
} // namespace WTR