/* * Copyright (C) 2010, 2011, 2014-2015 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 "StringFunctions.h" #include #include #include #include #include #include #include #include namespace WTR { static const float ZoomMultiplierRatio = 1.2f; struct MenuItemPrivateData { MenuItemPrivateData(WKBundlePageRef page, WKContextMenuItemRef item) : m_page(page), m_item(item) { } WKBundlePageRef m_page; WKRetainPtr m_item; }; #if ENABLE(CONTEXT_MENUS) static JSValueRef menuItemClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { MenuItemPrivateData* privateData = static_cast(JSObjectGetPrivate(thisObject)); WKBundlePageClickMenuItem(privateData->m_page, privateData->m_item.get()); return JSValueMakeUndefined(context); } static JSValueRef getMenuItemTitleCallback(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) { MenuItemPrivateData* privateData = static_cast(JSObjectGetPrivate(object)); WKRetainPtr wkTitle(AdoptWK, WKContextMenuItemCopyTitle(privateData->m_item.get())); return JSValueMakeString(context, toJS(wkTitle).get()); } static JSStaticFunction staticMenuItemFunctions[] = { { "click", menuItemClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { 0, 0, 0 } }; static JSStaticValue staticMenuItemValues[] = { { "title", getMenuItemTitleCallback, 0, kJSPropertyAttributeReadOnly }, { 0, 0, 0, 0 } }; static void staticMenuItemFinalize(JSObjectRef object) { delete static_cast(JSObjectGetPrivate(object)); } static JSValueRef staticConvertMenuItemToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception) { if (kJSTypeString == type) return getMenuItemTitleCallback(context, object, 0, 0); return 0; } static JSClassRef getMenuItemClass() { static JSClassRef menuItemClass = 0; if (!menuItemClass) { JSClassDefinition classDefinition = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; classDefinition.staticFunctions = staticMenuItemFunctions; classDefinition.staticValues = staticMenuItemValues; classDefinition.finalize = staticMenuItemFinalize; classDefinition.convertToType = staticConvertMenuItemToType; menuItemClass = JSClassCreate(&classDefinition); } return menuItemClass; } #endif 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")) return kWKEventModifiersMetaKey; if (JSStringIsEqualToUTF8CString(modifier, "addSelectionKey")) { #if OS(MAC_OS_X) return kWKEventModifiersMetaKey; #else return kWKEventModifiersControlKey; #endif } return 0; } static unsigned arrayLength(JSContextRef context, JSObjectRef array) { JSRetainPtr lengthString(Adopt, JSStringCreateWithUTF8CString("length")); JSValueRef lengthValue = JSObjectGetProperty(context, array, lengthString.get(), 0); if (!lengthValue) return 0; return static_cast(JSValueToNumber(context, lengthValue, 0)); } static WKEventModifiers parseModifierArray(JSContextRef context, JSValueRef arrayValue) { if (!arrayValue) return 0; // The value may either be a string with a single modifier or an array of modifiers. if (JSValueIsString(context, arrayValue)) { JSRetainPtr string(Adopt, JSValueToStringCopy(context, arrayValue, 0)); return parseModifier(string.get()); } if (!JSValueIsObject(context, arrayValue)) return 0; JSObjectRef array = const_cast(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 string(Adopt, JSValueToStringCopy(context, value, &exception)); if (exception) continue; modifiers |= parseModifier(string.get()); } return modifiers; } PassRefPtr EventSendingController::create() { return adoptRef(new EventSendingController); } EventSendingController::EventSendingController() { } EventSendingController::~EventSendingController() { } JSClassRef EventSendingController::wrapperClass() { return JSEventSendingController::eventSendingControllerClass(); } enum MouseState { MouseUp, MouseDown }; static WKMutableDictionaryRef createMouseMessageBody(MouseState state, int button, WKEventModifiers modifiers) { WKMutableDictionaryRef EventSenderMessageBody = WKMutableDictionaryCreate(); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString(state == MouseUp ? "MouseUp" : "MouseDown")); WKDictionarySetItem(EventSenderMessageBody, subMessageKey.get(), subMessageName.get()); WKRetainPtr buttonKey = adoptWK(WKStringCreateWithUTF8CString("Button")); WKRetainPtr buttonRef = adoptWK(WKUInt64Create(button)); WKDictionarySetItem(EventSenderMessageBody, buttonKey.get(), buttonRef.get()); WKRetainPtr modifiersKey = adoptWK(WKStringCreateWithUTF8CString("Modifiers")); WKRetainPtr modifiersRef = adoptWK(WKUInt64Create(modifiers)); WKDictionarySetItem(EventSenderMessageBody, modifiersKey.get(), modifiersRef.get()); return EventSenderMessageBody; } void EventSendingController::mouseDown(int button, JSValueRef modifierArray) { auto& injectedBundle = InjectedBundle::singleton(); WKBundlePageRef page = injectedBundle.page()->page(); WKBundleFrameRef frame = WKBundlePageGetMainFrame(page); JSContextRef context = WKBundleFrameGetJavaScriptContext(frame); WKEventModifiers modifiers = parseModifierArray(context, modifierArray); WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, createMouseMessageBody(MouseDown, button, modifiers)); WKBundlePagePostSynchronousMessageForTesting(page, EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::mouseUp(int button, JSValueRef modifierArray) { WKBundlePageRef page = InjectedBundle::singleton().page()->page(); WKBundleFrameRef frame = WKBundlePageGetMainFrame(page); JSContextRef context = WKBundleFrameGetJavaScriptContext(frame); WKEventModifiers modifiers = parseModifierArray(context, modifierArray); WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, createMouseMessageBody(MouseUp, button, modifiers)); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::mouseMoveTo(int x, int y) { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseMoveTo")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKRetainPtr xKey(AdoptWK, WKStringCreateWithUTF8CString("X")); WKRetainPtr xRef(AdoptWK, WKDoubleCreate(x)); WKDictionarySetItem(EventSenderMessageBody.get(), xKey.get(), xRef.get()); WKRetainPtr yKey(AdoptWK, WKStringCreateWithUTF8CString("Y")); WKRetainPtr yRef(AdoptWK, WKDoubleCreate(y)); WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get()); m_position = WKPointMake(x, y); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::mouseForceClick() { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseForceClick")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::startAndCancelMouseForceClick() { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("StartAndCancelMouseForceClick")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::mouseForceDown() { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseForceDown")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::mouseForceUp() { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseForceUp")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::mouseForceChanged(double force) { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseForceChanged")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKRetainPtr forceKey(AdoptWK, WKStringCreateWithUTF8CString("Force")); WKRetainPtr forceRef(AdoptWK, WKDoubleCreate(force)); WKDictionarySetItem(EventSenderMessageBody.get(), forceKey.get(), forceRef.get()); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::leapForward(int milliseconds) { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("LeapForward")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKRetainPtr timeKey(AdoptWK, WKStringCreateWithUTF8CString("TimeInMilliseconds")); WKRetainPtr timeRef(AdoptWK, WKUInt64Create(milliseconds)); WKDictionarySetItem(EventSenderMessageBody.get(), timeKey.get(), timeRef.get()); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::scheduleAsynchronousClick() { WKEventModifiers modifiers = 0; int button = 0; WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); // Asynchronous mouse down. WKRetainPtr mouseDownMessageBody(AdoptWK, createMouseMessageBody(MouseDown, button, modifiers)); WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), mouseDownMessageBody.get()); // Asynchronous mouse up. WKRetainPtr mouseUpMessageBody(AdoptWK, createMouseMessageBody(MouseUp, button, modifiers)); WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), mouseUpMessageBody.get()); } static WKRetainPtr createKeyDownMessageBody(JSStringRef key, WKEventModifiers modifiers, int location) { WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("KeyDown")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKRetainPtr keyKey(AdoptWK, WKStringCreateWithUTF8CString("Key")); WKDictionarySetItem(EventSenderMessageBody.get(), keyKey.get(), toWK(key).get()); WKRetainPtr modifiersKey(AdoptWK, WKStringCreateWithUTF8CString("Modifiers")); WKRetainPtr modifiersRef(AdoptWK, WKUInt64Create(modifiers)); WKDictionarySetItem(EventSenderMessageBody.get(), modifiersKey.get(), modifiersRef.get()); WKRetainPtr locationKey(AdoptWK, WKStringCreateWithUTF8CString("Location")); WKRetainPtr locationRef(AdoptWK, WKUInt64Create(location)); WKDictionarySetItem(EventSenderMessageBody.get(), locationKey.get(), locationRef.get()); return EventSenderMessageBody; } void EventSendingController::keyDown(JSStringRef key, JSValueRef modifierArray, int location) { WKBundlePageRef page = InjectedBundle::singleton().page()->page(); WKBundleFrameRef frame = WKBundlePageGetMainFrame(page); JSContextRef context = WKBundleFrameGetJavaScriptContext(frame); WKEventModifiers modifiers = parseModifierArray(context, modifierArray); WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr keyDownMessageBody = createKeyDownMessageBody(key, modifiers, location); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), keyDownMessageBody.get(), 0); } void EventSendingController::scheduleAsynchronousKeyDown(JSStringRef key) { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr keyDownMessageBody = createKeyDownMessageBody(key, 0 /* modifiers */, 0 /* location */); WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), keyDownMessageBody.get()); } void EventSendingController::mouseScrollBy(int x, int y) { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseScrollBy")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKRetainPtr xKey(AdoptWK, WKStringCreateWithUTF8CString("X")); WKRetainPtr xRef(AdoptWK, WKDoubleCreate(x)); WKDictionarySetItem(EventSenderMessageBody.get(), xKey.get(), xRef.get()); WKRetainPtr yKey(AdoptWK, WKStringCreateWithUTF8CString("Y")); WKRetainPtr yRef(AdoptWK, WKDoubleCreate(y)); WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get()); WKBundlePageForceRepaint(InjectedBundle::singleton().page()->page()); // Triggers a scrolling tree commit. WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get()); } static uint64_t cgEventPhaseFromString(JSStringRef phaseStr) { if (JSStringIsEqualToUTF8CString(phaseStr, "none")) return 0; if (JSStringIsEqualToUTF8CString(phaseStr, "began")) return 1; // kCGScrollPhaseBegan if (JSStringIsEqualToUTF8CString(phaseStr, "changed")) return 2; // kCGScrollPhaseChanged if (JSStringIsEqualToUTF8CString(phaseStr, "ended")) return 4; // kCGScrollPhaseEnded if (JSStringIsEqualToUTF8CString(phaseStr, "cancelled")) return 8; // kCGScrollPhaseCancelled if (JSStringIsEqualToUTF8CString(phaseStr, "maybegin")) return 128; // kCGScrollPhaseMayBegin ASSERT_NOT_REACHED(); return 0; } static uint64_t cgEventMomentumPhaseFromString(JSStringRef phaseStr) { if (JSStringIsEqualToUTF8CString(phaseStr, "none")) return 0; // kCGMomentumScrollPhaseNone if (JSStringIsEqualToUTF8CString(phaseStr, "begin")) return 1; // kCGMomentumScrollPhaseBegin if (JSStringIsEqualToUTF8CString(phaseStr, "continue")) return 2; // kCGMomentumScrollPhaseContinue if (JSStringIsEqualToUTF8CString(phaseStr, "end")) return 3; // kCGMomentumScrollPhaseEnd ASSERT_NOT_REACHED(); return 0; } void EventSendingController::mouseScrollByWithWheelAndMomentumPhases(int x, int y, JSStringRef phaseStr, JSStringRef momentumStr) { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseScrollByWithWheelAndMomentumPhases")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKRetainPtr xKey(AdoptWK, WKStringCreateWithUTF8CString("X")); WKRetainPtr xRef(AdoptWK, WKDoubleCreate(x)); WKDictionarySetItem(EventSenderMessageBody.get(), xKey.get(), xRef.get()); WKRetainPtr yKey(AdoptWK, WKStringCreateWithUTF8CString("Y")); WKRetainPtr yRef(AdoptWK, WKDoubleCreate(y)); WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get()); uint64_t phase = cgEventPhaseFromString(phaseStr); uint64_t momentum = cgEventMomentumPhaseFromString(momentumStr); WKRetainPtr phaseKey(AdoptWK, WKStringCreateWithUTF8CString("Phase")); WKRetainPtr phaseRef(AdoptWK, WKUInt64Create(phase)); WKDictionarySetItem(EventSenderMessageBody.get(), phaseKey.get(), phaseRef.get()); WKRetainPtr momentumKey(AdoptWK, WKStringCreateWithUTF8CString("Momentum")); WKRetainPtr momentumRef(AdoptWK, WKUInt64Create(momentum)); WKDictionarySetItem(EventSenderMessageBody.get(), momentumKey.get(), momentumRef.get()); WKBundlePageForceRepaint(InjectedBundle::singleton().page()->page()); // Triggers a scrolling tree commit. WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get()); } void EventSendingController::swipeGestureWithWheelAndMomentumPhases(int x, int y, JSStringRef phaseStr, JSStringRef momentumStr) { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("SwipeGestureWithWheelAndMomentumPhases")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKRetainPtr xKey(AdoptWK, WKStringCreateWithUTF8CString("X")); WKRetainPtr xRef(AdoptWK, WKDoubleCreate(x)); WKDictionarySetItem(EventSenderMessageBody.get(), xKey.get(), xRef.get()); WKRetainPtr yKey(AdoptWK, WKStringCreateWithUTF8CString("Y")); WKRetainPtr yRef(AdoptWK, WKDoubleCreate(y)); WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get()); uint64_t phase = cgEventPhaseFromString(phaseStr); uint64_t momentum = cgEventMomentumPhaseFromString(momentumStr); WKRetainPtr phaseKey(AdoptWK, WKStringCreateWithUTF8CString("Phase")); WKRetainPtr phaseRef(AdoptWK, WKUInt64Create(phase)); WKDictionarySetItem(EventSenderMessageBody.get(), phaseKey.get(), phaseRef.get()); WKRetainPtr momentumKey(AdoptWK, WKStringCreateWithUTF8CString("Momentum")); WKRetainPtr momentumRef(AdoptWK, WKUInt64Create(momentum)); WKDictionarySetItem(EventSenderMessageBody.get(), momentumKey.get(), momentumRef.get()); WKBundlePageForceRepaint(InjectedBundle::singleton().page()->page()); // Triggers a scrolling tree commit. WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get()); } void EventSendingController::continuousMouseScrollBy(int x, int y, bool paged) { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("ContinuousMouseScrollBy")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKRetainPtr xKey(AdoptWK, WKStringCreateWithUTF8CString("X")); WKRetainPtr xRef(AdoptWK, WKDoubleCreate(x)); WKDictionarySetItem(EventSenderMessageBody.get(), xKey.get(), xRef.get()); WKRetainPtr yKey(AdoptWK, WKStringCreateWithUTF8CString("Y")); WKRetainPtr yRef(AdoptWK, WKDoubleCreate(y)); WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get()); WKRetainPtr pagedKey(AdoptWK, WKStringCreateWithUTF8CString("Paged")); WKRetainPtr pagedRef(AdoptWK, WKUInt64Create(paged)); WKDictionarySetItem(EventSenderMessageBody.get(), pagedKey.get(), pagedRef.get()); // FIXME: This message should be asynchronous, as scrolling is intrinsically asynchronous. // See also: . WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } JSValueRef EventSendingController::contextClick() { WKBundlePageRef page = InjectedBundle::singleton().page()->page(); WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page); JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); #if ENABLE(CONTEXT_MENUS) #if PLATFORM(GTK) || PLATFORM(EFL) // Do mouse context click. mouseDown(2, 0); mouseUp(2, 0); WKRetainPtr menuEntries = adoptWK(WKBundlePageCopyContextMenuItems(page)); #else WKRetainPtr menuEntries = adoptWK(WKBundlePageCopyContextMenuAtPointInWindow(page, m_position)); #endif JSValueRef arrayResult = JSObjectMakeArray(context, 0, 0, 0); if (!menuEntries) return arrayResult; JSObjectRef arrayObj = JSValueToObject(context, arrayResult, 0); size_t entriesSize = WKArrayGetSize(menuEntries.get()); for (size_t i = 0; i < entriesSize; ++i) { ASSERT(WKGetTypeID(WKArrayGetItemAtIndex(menuEntries.get(), i)) == WKContextMenuItemGetTypeID()); WKContextMenuItemRef item = static_cast(WKArrayGetItemAtIndex(menuEntries.get(), i)); MenuItemPrivateData* privateData = new MenuItemPrivateData(page, item); JSObjectSetPropertyAtIndex(context, arrayObj, i, JSObjectMake(context, getMenuItemClass(), privateData), 0); } return arrayResult; #else return JSValueMakeUndefined(context); #endif } void EventSendingController::textZoomIn() { auto& injectedBundle = InjectedBundle::singleton(); // Ensure page zoom is reset. WKBundlePageSetPageZoomFactor(injectedBundle.page()->page(), 1); double zoomFactor = WKBundlePageGetTextZoomFactor(injectedBundle.page()->page()); WKBundlePageSetTextZoomFactor(injectedBundle.page()->page(), zoomFactor * ZoomMultiplierRatio); } void EventSendingController::textZoomOut() { auto& injectedBundle = InjectedBundle::singleton(); // Ensure page zoom is reset. WKBundlePageSetPageZoomFactor(injectedBundle.page()->page(), 1); double zoomFactor = WKBundlePageGetTextZoomFactor(injectedBundle.page()->page()); WKBundlePageSetTextZoomFactor(injectedBundle.page()->page(), zoomFactor / ZoomMultiplierRatio); } void EventSendingController::zoomPageIn() { auto& injectedBundle = InjectedBundle::singleton(); // Ensure text zoom is reset. WKBundlePageSetTextZoomFactor(injectedBundle.page()->page(), 1); double zoomFactor = WKBundlePageGetPageZoomFactor(injectedBundle.page()->page()); WKBundlePageSetPageZoomFactor(injectedBundle.page()->page(), zoomFactor * ZoomMultiplierRatio); } void EventSendingController::zoomPageOut() { auto& injectedBundle = InjectedBundle::singleton(); // Ensure text zoom is reset. WKBundlePageSetTextZoomFactor(injectedBundle.page()->page(), 1); double zoomFactor = WKBundlePageGetPageZoomFactor(injectedBundle.page()->page()); WKBundlePageSetPageZoomFactor(injectedBundle.page()->page(), zoomFactor / ZoomMultiplierRatio); } void EventSendingController::scalePageBy(double scale, double x, double y) { WKPoint origin = { x, y }; WKBundlePageSetScaleAtOrigin(InjectedBundle::singleton().page()->page(), scale, origin); } void EventSendingController::monitorWheelEvents() { WKBundlePageRef page = InjectedBundle::singleton().page()->page(); WKBundlePageStartMonitoringScrollOperations(page); } struct ScrollCompletionCallbackData { JSContextRef m_context; JSObjectRef m_function; ScrollCompletionCallbackData(JSContextRef context, JSObjectRef function) : m_context(context), m_function(function) { } }; static void executeCallback(void* context) { if (!context) return; std::unique_ptr callBackData(reinterpret_cast(context)); JSObjectCallAsFunction(callBackData->m_context, callBackData->m_function, nullptr, 0, nullptr, nullptr); JSValueUnprotect(callBackData->m_context, callBackData->m_function); } void EventSendingController::callAfterScrollingCompletes(JSValueRef functionCallback) { if (!functionCallback) return; WKBundlePageRef page = InjectedBundle::singleton().page()->page(); WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(page); JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); JSObjectRef functionCallbackObject = JSValueToObject(context, functionCallback, nullptr); if (!functionCallbackObject) return; JSValueProtect(context, functionCallbackObject); auto scrollCompletionCallbackData = std::make_unique(context, functionCallbackObject); WKBundlePageRegisterScrollOperationCompletionCallback(page, executeCallback, scrollCompletionCallbackData.release()); } #if ENABLE(TOUCH_EVENTS) void EventSendingController::addTouchPoint(int x, int y) { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("AddTouchPoint")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKRetainPtr xKey(AdoptWK, WKStringCreateWithUTF8CString("X")); WKRetainPtr xRef(AdoptWK, WKUInt64Create(x)); WKDictionarySetItem(EventSenderMessageBody.get(), xKey.get(), xRef.get()); WKRetainPtr yKey(AdoptWK, WKStringCreateWithUTF8CString("Y")); WKRetainPtr yRef(AdoptWK, WKUInt64Create(y)); WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get()); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::updateTouchPoint(int index, int x, int y) { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("UpdateTouchPoint")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKRetainPtr indexKey(AdoptWK, WKStringCreateWithUTF8CString("Index")); WKRetainPtr indexRef(AdoptWK, WKUInt64Create(index)); WKDictionarySetItem(EventSenderMessageBody.get(), indexKey.get(), indexRef.get()); WKRetainPtr xKey(AdoptWK, WKStringCreateWithUTF8CString("X")); WKRetainPtr xRef(AdoptWK, WKUInt64Create(x)); WKDictionarySetItem(EventSenderMessageBody.get(), xKey.get(), xRef.get()); WKRetainPtr yKey(AdoptWK, WKStringCreateWithUTF8CString("Y")); WKRetainPtr yRef(AdoptWK, WKUInt64Create(y)); WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get()); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::setTouchModifier(const JSStringRef &modifier, bool enable) { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("SetTouchModifier")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKEventModifiers mod = 0; if (JSStringIsEqualToUTF8CString(modifier, "ctrl")) mod = kWKEventModifiersControlKey; if (JSStringIsEqualToUTF8CString(modifier, "shift")) mod = kWKEventModifiersShiftKey; if (JSStringIsEqualToUTF8CString(modifier, "alt")) mod = kWKEventModifiersAltKey; if (JSStringIsEqualToUTF8CString(modifier, "meta")) mod = kWKEventModifiersMetaKey; WKRetainPtr modifierKey(AdoptWK, WKStringCreateWithUTF8CString("Modifier")); WKRetainPtr modifierRef(AdoptWK, WKUInt64Create(mod)); WKDictionarySetItem(EventSenderMessageBody.get(), modifierKey.get(), modifierRef.get()); WKRetainPtr enableKey(AdoptWK, WKStringCreateWithUTF8CString("Enable")); WKRetainPtr enableRef(AdoptWK, WKUInt64Create(enable)); WKDictionarySetItem(EventSenderMessageBody.get(), enableKey.get(), enableRef.get()); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::setTouchPointRadius(int radiusX, int radiusY) { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("SetTouchPointRadius")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKRetainPtr xKey(AdoptWK, WKStringCreateWithUTF8CString("RadiusX")); WKRetainPtr xRef(AdoptWK, WKUInt64Create(radiusX)); WKDictionarySetItem(EventSenderMessageBody.get(), xKey.get(), xRef.get()); WKRetainPtr yKey(AdoptWK, WKStringCreateWithUTF8CString("RadiusY")); WKRetainPtr yRef(AdoptWK, WKUInt64Create(radiusY)); WKDictionarySetItem(EventSenderMessageBody.get(), yKey.get(), yRef.get()); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::touchStart() { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("TouchStart")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::touchMove() { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("TouchMove")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::touchEnd() { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("TouchEnd")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::touchCancel() { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("TouchCancel")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::clearTouchPoints() { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("ClearTouchPoints")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::releaseTouchPoint(int index) { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("ReleaseTouchPoint")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKRetainPtr indexKey(AdoptWK, WKStringCreateWithUTF8CString("Index")); WKRetainPtr indexRef(AdoptWK, WKUInt64Create(index)); WKDictionarySetItem(EventSenderMessageBody.get(), indexKey.get(), indexRef.get()); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } void EventSendingController::cancelTouchPoint(int index) { WKRetainPtr EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender")); WKRetainPtr EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate()); WKRetainPtr subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage")); WKRetainPtr subMessageName(AdoptWK, WKStringCreateWithUTF8CString("CancelTouchPoint")); WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get()); WKRetainPtr indexKey(AdoptWK, WKStringCreateWithUTF8CString("Index")); WKRetainPtr indexRef(AdoptWK, WKUInt64Create(index)); WKDictionarySetItem(EventSenderMessageBody.get(), indexKey.get(), indexRef.get()); WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0); } #endif // Object Creation void EventSendingController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception) { setProperty(context, windowObject, "eventSender", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception); } } // namespace WTR