2011-06-27 Leandro Pereira <leandro@profusion.mobi>
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 27 Jun 2011 15:10:58 +0000 (15:10 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 27 Jun 2011 15:10:58 +0000 (15:10 +0000)
        Reviewed by Kent Tamura.

        [EFL] Add an EventSender implementation to EFL's DumpRenderTree along
        with support files.
        Build system changes will be made as soon as the whole DumpRenderTree
        is upstreamed.
        https://bugs.webkit.org/show_bug.cgi?id=61962

        * DumpRenderTree/efl/EventSender.cpp: Added.
        (setEvasModifiers):
        (translateMouseButtonNumber):
        (sendMouseEvent):
        (sendClick):
        (scheduleAsynchronousClickCallback):
        (updateClickCount):
        (modifierFromJSValue):
        (modifiersFromJSValue):
        (mouseDownCallback):
        (mouseUpCallback):
        (mouseMoveToCallback):
        (evasMouseEventFromHorizontalAndVerticalOffsets):
        (mouseScrollByCallback):
        (continuousMouseScrollByCallback):
        (keyPadNameFromJSValue):
        (keyNameFromJSValue):
        (keyDownCallback):
        (scalePageByCallback):
        (getClass):
        (makeEventSender):
        * DumpRenderTree/efl/EventSender.h: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@89820 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Tools/ChangeLog
Tools/DumpRenderTree/efl/EventSender.cpp [new file with mode: 0644]
Tools/DumpRenderTree/efl/EventSender.h [new file with mode: 0644]

index 6561dba..9dd7b2a 100644 (file)
@@ -1,3 +1,36 @@
+2011-06-27  Leandro Pereira  <leandro@profusion.mobi>
+
+        Reviewed by Kent Tamura.
+
+        [EFL] Add an EventSender implementation to EFL's DumpRenderTree along
+        with support files.
+        Build system changes will be made as soon as the whole DumpRenderTree
+        is upstreamed.
+        https://bugs.webkit.org/show_bug.cgi?id=61962
+
+        * DumpRenderTree/efl/EventSender.cpp: Added.
+        (setEvasModifiers):
+        (translateMouseButtonNumber):
+        (sendMouseEvent):
+        (sendClick):
+        (scheduleAsynchronousClickCallback):
+        (updateClickCount):
+        (modifierFromJSValue):
+        (modifiersFromJSValue):
+        (mouseDownCallback):
+        (mouseUpCallback):
+        (mouseMoveToCallback):
+        (evasMouseEventFromHorizontalAndVerticalOffsets):
+        (mouseScrollByCallback):
+        (continuousMouseScrollByCallback):
+        (keyPadNameFromJSValue):
+        (keyNameFromJSValue):
+        (keyDownCallback):
+        (scalePageByCallback):
+        (getClass):
+        (makeEventSender):
+        * DumpRenderTree/efl/EventSender.h: Added.
+
 2011-06-27  Eric Seidel  <eric@webkit.org>
 
         Reviewed by Adam Barth.
diff --git a/Tools/DumpRenderTree/efl/EventSender.cpp b/Tools/DumpRenderTree/efl/EventSender.cpp
new file mode 100644 (file)
index 0000000..edd0a83
--- /dev/null
@@ -0,0 +1,503 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com>
+ * Copyright (C) 2009 Holger Hans Peter Freyther
+ * Copyright (C) 2010 Igalia S.L.
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "EventSender.h"
+
+#include "DumpRenderTree.h"
+#include "JSStringUtils.h"
+#include "NotImplemented.h"
+#include "ewk_private.h"
+#include <EWebKit.h>
+#include <JavaScriptCore/JSObjectRef.h>
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <JavaScriptCore/JSStringRef.h>
+#include <JavaScriptCore/OpaqueJSString.h>
+#include <wtf/ASCIICType.h>
+#include <wtf/Platform.h>
+#include <wtf/text/CString.h>
+
+static bool gDragMode;
+static int gTimeOffset = 0;
+
+static int gLastMousePositionX;
+static int gLastMousePositionY;
+static int gLastClickPositionX;
+static int gLastClickPositionY;
+static int gLastClickTimeOffset;
+static int gLastClickButton;
+static int gButtonCurrentlyDown;
+static int gClickCount;
+
+static const float zoomMultiplierRatio = 1.2f;
+
+// Key event location code defined in DOM Level 3.
+enum KeyLocationCode {
+    DomKeyLocationStandard,
+    DomKeyLocationLeft,
+    DomKeyLocationRight,
+    DomKeyLocationNumpad
+};
+
+enum EvasKeyModifier {
+    EvasKeyModifierNone    = 0,
+    EvasKeyModifierControl = 1 << 0,
+    EvasKeyModifierShift   = 1 << 1,
+    EvasKeyModifierAlt     = 1 << 2,
+    EvasKeyModifierMeta    = 1 << 3
+};
+
+enum EvasMouseButton {
+    EvasMouseButtonNone,
+    EvasMouseButtonLeft,
+    EvasMouseButtonMiddle,
+    EvasMouseButtonRight
+};
+
+enum EvasMouseEvent {
+    EvasMouseEventNone        = 0,
+    EvasMouseEventDown        = 1 << 0,
+    EvasMouseEventUp          = 1 << 1,
+    EvasMouseEventMove        = 1 << 2,
+    EvasMouseEventScrollUp    = 1 << 3,
+    EvasMouseEventScrollDown  = 1 << 4,
+    EvasMouseEventScrollLeft  = 1 << 5,
+    EvasMouseEventScrollRight = 1 << 6,
+    EvasMouseEventClick       = EvasMouseEventMove | EvasMouseEventDown | EvasMouseEventUp,
+};
+
+static void setEvasModifiers(Evas* evas, EvasKeyModifier modifiers)
+{
+    static const char* modifierNames[] = { "Control", "Shift", "Alt", "Super" };
+    for (unsigned modifier = 0; modifier < 4; ++modifier) {
+        if (modifiers & (1 << modifier))
+            evas_key_modifier_on(evas, modifierNames[modifier]);
+        else
+            evas_key_modifier_off(evas, modifierNames[modifier]);
+    }
+}
+
+static EvasMouseButton translateMouseButtonNumber(int eventSenderButtonNumber)
+{
+    static const EvasMouseButton translationTable[] = {
+        EvasMouseButtonLeft,
+        EvasMouseButtonMiddle,
+        EvasMouseButtonRight,
+        EvasMouseButtonMiddle // fast/events/mouse-click-events expects the 4th button to be treated as the middle button
+    };
+    static const unsigned translationTableSize = sizeof(translationTable) / sizeof(translationTable[0]);
+
+    if (eventSenderButtonNumber < translationTableSize)
+        return translationTable[eventSenderButtonNumber];
+
+    return EvasMouseButtonLeft;
+}
+
+static bool sendMouseEvent(Evas* evas, EvasMouseEvent event, int buttonNumber, EvasKeyModifier modifiers)
+{
+    unsigned timeStamp = 0;
+
+    setEvasModifiers(evas, modifiers);
+    if (event & EvasMouseEventMove)
+        evas_event_feed_mouse_move(evas, gLastMousePositionX, gLastMousePositionY, timeStamp++, 0);
+    if (event & EvasMouseEventDown)
+        evas_event_feed_mouse_down(evas, buttonNumber, EVAS_BUTTON_NONE, timeStamp++, 0);
+    if (event & EvasMouseEventUp)
+        evas_event_feed_mouse_up(evas, buttonNumber, EVAS_BUTTON_NONE, timeStamp++, 0);
+
+    const bool horizontal = !!(event & EvasMouseEventScrollLeft | event & EvasMouseEventScrollRight);
+    const bool vertical = !!(event & EvasMouseEventScrollUp | event & EvasMouseEventScrollDown);
+    if (vertical && horizontal) {
+        evas_event_feed_mouse_wheel(evas, 0, (event & EvasMouseEventScrollUp) ? 10 : -10, timeStamp, 0);
+        evas_event_feed_mouse_wheel(evas, 1, (event & EvasMouseEventScrollLeft) ? 10 : -10, timeStamp, 0);
+    } else if (vertical)
+        evas_event_feed_mouse_wheel(evas, 0, (event & EvasMouseEventScrollUp) ? 10 : -10, timeStamp, 0);
+    else if (horizontal)
+        evas_event_feed_mouse_wheel(evas, 1, (event & EvasMouseEventScrollLeft) ? 10 : -10, timeStamp, 0);
+
+    setEvasModifiers(evas, EvasKeyModifierNone);
+
+    return true;
+}
+
+static Eina_Bool sendClick(void*)
+{
+    return !!sendMouseEvent(evas_object_evas_get(mainFrame), EvasMouseEventClick, EvasMouseButtonLeft, EvasKeyModifierNone);
+}
+
+static JSValueRef scheduleAsynchronousClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    ecore_idler_add(sendClick, 0);
+    return JSValueMakeUndefined(context);
+}
+
+static void updateClickCount(int button)
+{
+    if (gLastClickPositionX != gLastMousePositionX
+        || gLastClickPositionY != gLastMousePositionY
+        || gLastClickButton != button
+        || gTimeOffset - gLastClickTimeOffset >= 1)
+        gClickCount = 1;
+    else
+        gClickCount++;
+}
+
+static EvasKeyModifier modifierFromJSValue(JSContextRef context, const JSValueRef value)
+{
+    JSRetainPtr<JSStringRef> jsKeyValue(Adopt, JSValueToStringCopy(context, value, 0));
+
+    if (equals(jsKeyValue, "ctrlKey") || equals(jsKeyValue, "addSelectionKey"))
+        return EvasKeyModifierControl;
+    if (equals(jsKeyValue, "shiftKey") || equals(jsKeyValue, "rangeSelectionKey"))
+        return EvasKeyModifierShift;
+    if (equals(jsKeyValue, "altKey"))
+        return EvasKeyModifierAlt;
+    if (equals(jsKeyValue, "metaKey"))
+        return EvasKeyModifierMeta;
+
+    return EvasKeyModifierNone;
+}
+
+static EvasKeyModifier modifiersFromJSValue(JSContextRef context, const JSValueRef modifiers)
+{
+    // The value may either be a string with a single modifier or an array of modifiers.
+    if (JSValueIsString(context, modifiers))
+        return modifierFromJSValue(context, modifiers);
+
+    JSObjectRef modifiersArray = JSValueToObject(context, modifiers, 0);
+    if (!modifiersArray)
+        return EvasKeyModifierNone;
+
+    unsigned modifier = 0;
+    int modifiersCount = JSValueToNumber(context, JSObjectGetProperty(context, modifiersArray, JSStringCreateWithUTF8CString("length"), 0), 0);
+    for (int i = 0; i < modifiersCount; ++i)
+        modifier |= static_cast<unsigned>(modifierFromJSValue(context, JSObjectGetPropertyAtIndex(context, modifiersArray, i, 0)));
+    return static_cast<EvasKeyModifier>(modifier);
+}
+
+static JSValueRef mouseDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    int button = 0;
+    if (argumentCount == 1) {
+        button = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
+
+        if (exception && *exception)
+            return JSValueMakeUndefined(context);
+    }
+
+    button = translateMouseButtonNumber(button);
+    // If the same mouse button is already in the down position don't send another event as it may confuse Xvfb.
+    if (gButtonCurrentlyDown == button)
+        return JSValueMakeUndefined(context);
+
+    updateClickCount(button);
+
+    EvasKeyModifier modifiers = argumentCount >= 2 ? modifiersFromJSValue(context, arguments[1]) : EvasKeyModifierNone;
+    if (!sendMouseEvent(evas_object_evas_get(mainFrame), EvasMouseEventDown, button, modifiers))
+        return JSValueMakeUndefined(context);
+
+    gButtonCurrentlyDown = button;
+    return JSValueMakeUndefined(context);
+}
+
+static JSValueRef mouseUpCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    int button = 0;
+    if (argumentCount == 1) {
+        button = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
+        if (exception && *exception)
+            return JSValueMakeUndefined(context);
+    }
+
+    gLastClickPositionX = gLastMousePositionX;
+    gLastClickPositionY = gLastMousePositionY;
+    gLastClickButton = gButtonCurrentlyDown;
+    gLastClickTimeOffset = gTimeOffset;
+    gButtonCurrentlyDown = 0;
+
+    EvasKeyModifier modifiers = argumentCount >= 2 ? modifiersFromJSValue(context, arguments[1]) : EvasKeyModifierNone;
+    sendMouseEvent(evas_object_evas_get(mainFrame), EvasMouseEventUp, translateMouseButtonNumber(button), modifiers);
+    return JSValueMakeUndefined(context);
+}
+
+static JSValueRef mouseMoveToCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    if (argumentCount < 2)
+        return JSValueMakeUndefined(context);
+
+    gLastMousePositionX = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
+    if (exception && *exception)
+        return JSValueMakeUndefined(context);
+    gLastMousePositionY = static_cast<int>(JSValueToNumber(context, arguments[1], exception));
+    if (exception && *exception)
+        return JSValueMakeUndefined(context);
+
+    sendMouseEvent(evas_object_evas_get(mainFrame), EvasMouseEventMove, EvasMouseButtonNone, EvasKeyModifierNone);
+    return JSValueMakeUndefined(context);
+}
+
+static EvasMouseEvent evasMouseEventFromHorizontalAndVerticalOffsets(int horizontalOffset, int verticalOffset)
+{
+    unsigned mouseEvent = 0;
+
+    if (verticalOffset > 0)
+        mouseEvent |= EvasMouseEventScrollUp;
+    else if (verticalOffset < 0)
+        mouseEvent |= EvasMouseEventScrollDown;
+
+    if (horizontalOffset > 0)
+        mouseEvent |= EvasMouseEventScrollRight;
+    else if (horizontalOffset < 0)
+        mouseEvent |= EvasMouseEventScrollLeft;
+
+    return static_cast<EvasMouseEvent>(mouseEvent);
+}
+
+static JSValueRef mouseScrollByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    if (argumentCount < 2)
+        return JSValueMakeUndefined(context);
+
+    const int horizontal = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
+    if (exception && *exception)
+        return JSValueMakeUndefined(context);
+    const int vertical = static_cast<int>(JSValueToNumber(context, arguments[1], exception));
+    if (exception && *exception)
+        return JSValueMakeUndefined(context);
+
+    sendMouseEvent(evas_object_evas_get(mainFrame), evasMouseEventFromHorizontalAndVerticalOffsets(horizontal, vertical), EvasMouseButtonNone, EvasKeyModifierNone);
+    return JSValueMakeUndefined(context);
+}
+
+static JSValueRef continuousMouseScrollByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    return JSValueMakeUndefined(context);
+}
+
+static const char* keyPadNameFromJSValue(JSStringRef character)
+{
+    if (equals(character, "leftArrow"))
+        return "KP_Left";
+    if (equals(character, "rightArrow"))
+        return "KP_Right";
+    if (equals(character, "upArrow"))
+        return "KP_Up";
+    if (equals(character, "downArrow"))
+        return "KP_Down";
+    if (equals(character, "pageUp"))
+        return "KP_Page_Up";
+    if (equals(character, "pageDown"))
+        return "KP_Page_Down";
+    if (equals(character, "home"))
+        return "KP_Home";
+    if (equals(character, "end"))
+        return "KP_End";
+    if (equals(character, "insert"))
+        return "KP_Insert";
+    if (equals(character, "delete"))
+        return "KP_Delete";
+
+    // If we get some other key specified with the numpad location,
+    // crash here, so we add it sooner rather than later.
+    fprintf(stderr, "numeric pad key not handled: %s\n", character->ustring().utf8().data());
+    abort();
+}
+
+static const char* keyNameFromJSValue(JSStringRef character)
+{
+    if (equals(character, "leftArrow"))
+        return "Left";
+    if (equals(character, "rightArrow"))
+        return "Right";
+    if (equals(character, "upArrow"))
+        return "Up";
+    if (equals(character, "downArrow"))
+        return "Down";
+    if (equals(character, "pageUp"))
+        return "Page_Up";
+    if (equals(character, "pageDown"))
+        return "Page_Down";
+    if (equals(character, "home"))
+        return "Home";
+    if (equals(character, "end"))
+        return "End";
+    if (equals(character, "insert"))
+        return "Insert";
+    if (equals(character, "delete"))
+        return "Delete";
+    if (equals(character, "printScreen"))
+        return "Print";
+    if (equals(character, "menu"))
+        return "Menu";
+    if (equals(character, "F1"))
+        return "F1";
+    if (equals(character, "F2"))
+        return "F2";
+    if (equals(character, "F3"))
+        return "F3";
+    if (equals(character, "F4"))
+        return "F4";
+    if (equals(character, "F5"))
+        return "F5";
+    if (equals(character, "F6"))
+        return "F6";
+    if (equals(character, "F7"))
+        return "F7";
+    if (equals(character, "F8"))
+        return "F8";
+    if (equals(character, "F9"))
+        return "F9";
+    if (equals(character, "F10"))
+        return "F10";
+    if (equals(character, "F11"))
+        return "F11";
+    if (equals(character, "F12"))
+        return "F12";
+
+    int charCode = JSStringGetCharactersPtr(character)[0];
+    if (charCode == '\n' || charCode == '\r')
+        return "Return";
+    if (charCode == '\t')
+        return "Tab";
+    if (charCode == '\x8')
+        return "BackSpace";
+
+    // FIXME: See other implementations and obtain the key name by
+    // the Unicode character code.
+    fprintf(stderr, "key not handled: %s\n", character->ustring().utf8().data());
+    abort();
+}
+
+static JSValueRef keyDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    Evas_Object* view = ewk_frame_view_get(mainFrame);
+    if (!view)
+        return JSValueMakeUndefined(context);
+
+    if (argumentCount < 1)
+        return JSValueMakeUndefined(context);
+
+    // handle location argument.
+    int location = DomKeyLocationStandard;
+    if (argumentCount > 2)
+        location = static_cast<int>(JSValueToNumber(context, arguments[2], exception));
+
+    JSRetainPtr<JSStringRef> character(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+    if (exception && *exception)
+        return JSValueMakeUndefined(context);
+
+    // send the event
+    Evas* evas = evas_object_evas_get(view);
+    if (argumentCount >= 2)
+        setEvasModifiers(evas, modifiersFromJSValue(context, arguments[1]));
+
+    const char* keyName = (location == DomKeyLocationNumpad) ? keyPadNameFromJSValue(character.get()) : keyNameFromJSValue(character.get());
+    evas_event_feed_key_down(evas, keyName, keyName, 0, 0, 0, 0);
+    evas_event_feed_key_up(evas, keyName, keyName, 0, 0, 1, 0);
+
+    setEvasModifiers(evas, EvasKeyModifierNone);
+
+    return JSValueMakeUndefined(context);
+}
+
+static JSValueRef scalePageByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    if (argumentCount < 3)
+        return JSValueMakeUndefined(context);
+
+    Evas_Object* view = ewk_frame_view_get(mainFrame);
+    if (!view)
+        return JSValueMakeUndefined(context);
+
+    float scaleFactor = JSValueToNumber(context, arguments[0], exception);
+    float x = JSValueToNumber(context, arguments[1], exception);
+    float y = JSValueToNumber(context, arguments[2], exception);
+    ewk_view_page_scale(view, scaleFactor, x, y);
+
+    return JSValueMakeUndefined(context);
+}
+
+static JSStaticFunction staticFunctions[] = {
+    { "mouseScrollBy", mouseScrollByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+    { "continuousMouseScrollBy", continuousMouseScrollByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+    { "mouseDown", mouseDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+    { "mouseUp", mouseUpCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+    { "mouseMoveTo", mouseMoveToCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+    { "keyDown", keyDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+    { "scheduleAsynchronousClick", scheduleAsynchronousClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+    { "scalePageBy", scalePageByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+    { 0, 0, 0 }
+};
+
+static JSStaticValue staticValues[] = {
+    { 0, 0, 0, 0 }
+};
+
+static JSClassRef getClass(JSContextRef context)
+{
+    static JSClassRef eventSenderClass = 0;
+
+    if (!eventSenderClass) {
+        JSClassDefinition classDefinition = {
+                0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+        classDefinition.staticFunctions = staticFunctions;
+        classDefinition.staticValues = staticValues;
+
+        eventSenderClass = JSClassCreate(&classDefinition);
+    }
+
+    return eventSenderClass;
+}
+
+JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame)
+{
+    if (isTopFrame) {
+        gDragMode = true;
+
+        // Fly forward in time one second when the main frame loads. This will
+        // ensure that when a test begins clicking in the same location as
+        // a previous test, those clicks won't be interpreted as continuations
+        // of the previous test's click sequences.
+        gTimeOffset += 1000;
+
+        gLastMousePositionX = gLastMousePositionY = 0;
+        gLastClickPositionX = gLastClickPositionY = 0;
+        gLastClickTimeOffset = 0;
+        gLastClickButton = 0;
+        gButtonCurrentlyDown = 0;
+        gClickCount = 0;
+    }
+
+    return JSObjectMake(context, getClass(context), 0);
+}
diff --git a/Tools/DumpRenderTree/efl/EventSender.h b/Tools/DumpRenderTree/efl/EventSender.h
new file mode 100644 (file)
index 0000000..bded655
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2007 Apple Inc.  All rights reserved.
+ * Copyright (C) 2009 Holger Hans Peter Freyther
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
+ */
+
+#ifndef EventSender_h
+#define EventSender_h
+
+typedef const struct OpaqueJSContext* JSContextRef;
+typedef struct OpaqueJSValue* JSObjectRef;
+
+// The boolean parameter refers to whether this is being called from a top-level frame.
+JSObjectRef makeEventSender(JSContextRef, bool);
+
+#endif // EventSender_h