⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 268793 in webkit


Ignore:
Timestamp:
Oct 21, 2020, 5:36:18 AM (6 years ago)
Author:
Carlos Garcia Campos
Message:

WebDriver: add support for wheel actions
https://bugs.webkit.org/show_bug.cgi?id=217174

Reviewed by Brian Burg.

.:

Enable WEBDRIVER_WHEEL_INTERACTIONS for GTK and WPE ports.

  • Source/cmake/OptionsGTK.cmake:
  • Source/cmake/OptionsWPE.cmake:
  • Source/cmake/WebKitFeatures.cmake:

Source/WebDriver:

Handle wheel actions.

  • Actions.h:
  • Session.cpp:

(WebDriver::automationSourceType): Handle InputSource::Type::Wheel.
(WebDriver::Session::performActions): Handle Action::Type::Wheel.

  • WebDriverService.cpp:

(WebDriver::processKeyAction): Assert if Action::Subtype::Scroll.
(WebDriver::processPointerMoveAction): Move this code to a helper to be used by both pointer move and scroll actions.
(WebDriver::processPointerAction): Use processPointerMoveAction().
(WebDriver::processWheelAction): Call processPointerMoveAction() and process the scroll delta too.
(WebDriver::processInputActionSequence): Handle InputSource::Type::Wheel.

Source/WebKit:

  • UIProcess/Automation/Automation.json: Add scroll delta to action state.
  • UIProcess/Automation/SimulatedInputDispatcher.cpp:

(WebKit::SimulatedInputSourceState::emptyStateForSourceType): Initialize scrollDelta for wheel actions.
(WebKit::SimulatedInputDispatcher::transitionInputSourceToState): Handle SimulatedInputSourceType::Wheel.

  • UIProcess/Automation/SimulatedInputDispatcher.h:
  • UIProcess/Automation/WebAutomationSession.cpp:

(WebKit::WebAutomationSession::WebAutomationSession): Add SimulatedInputSourceType::Wheel.
(WebKit::WebAutomationSession::terminate): Handle pending wheel events.
(WebKit::WebAutomationSession::willShowJavaScriptDialog): Ditto.
(WebKit::WebAutomationSession::wheelEventsFlushedForPage): Ditto.
(WebKit::WebAutomationSession::willClosePage): Ditto.
(WebKit::WebAutomationSession::isSimulatingUserInteraction const): Return true if there are pending wheel events too.
(WebKit::WebAutomationSession::simulateWheelInteraction): Handle the wheel action.
(WebKit::simulatedInputSourceTypeFromProtocolSourceType): Handle Inspector::Protocol::Automation::InputSourceType::Wheel.
(WebKit::WebAutomationSession::performInteractionSequence): Initialize the scroll delta for wheel action.

  • UIProcess/Automation/WebAutomationSession.h:
  • UIProcess/Automation/gtk/WebAutomationSessionGtk.cpp:

(WebKit::WebAutomationSession::platformSimulateWheelInteraction): Synthesize a wheel event.

  • UIProcess/Automation/wpe/WebAutomationSessionWPE.cpp:

(WebKit::WebAutomationSession::platformSimulateWheelInteraction): Ditto.

  • UIProcess/WebPageProxy.cpp:

(WebKit::WebPageProxy::isProcessingWheelEvents const): Return whether page has pending wheel events.
(WebKit::WebPageProxy::didReceiveEvent): Notify automation that pending wheel events have been processed.

  • UIProcess/WebPageProxy.h:
  • config.h:

Tools:

Add webdriver-wheel-interactions option.

  • Scripts/webkitperl/FeatureList.pm:

WebDriverTests:

Remove expectations for wheel actions test.

Location:
trunk
Files:
23 edited

Legend:

Unmodified
Added
Removed
  • trunk/ChangeLog

    r268751 r268793  
     12020-10-21  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        WebDriver: add support for wheel actions
     4        https://bugs.webkit.org/show_bug.cgi?id=217174
     5
     6        Reviewed by Brian Burg.
     7
     8        Enable WEBDRIVER_WHEEL_INTERACTIONS for GTK and WPE ports.
     9
     10        * Source/cmake/OptionsGTK.cmake:
     11        * Source/cmake/OptionsWPE.cmake:
     12        * Source/cmake/WebKitFeatures.cmake:
     13
    1142020-10-20  Michael Catanzaro  <mcatanzaro@gnome.org>
    215
  • trunk/Source/WebDriver/Actions.h

    r239427 r268793  
    3434
    3535struct InputSource {
    36     enum class Type { None, Key, Pointer };
     36    enum class Type { None, Key, Pointer, Wheel };
    3737
    3838    Type type;
     
    5252
    5353struct Action {
    54     enum class Type { None, Key, Pointer };
    55     enum class Subtype { Pause, PointerUp, PointerDown, PointerMove, PointerCancel, KeyUp, KeyDown };
     54    enum class Type { None, Key, Pointer, Wheel };
     55    enum class Subtype { Pause, PointerUp, PointerDown, PointerMove, PointerCancel, KeyUp, KeyDown, Scroll };
    5656
    5757    Action(const String& id, Type type, Subtype subtype)
     
    7272    Optional<int64_t> x;
    7373    Optional<int64_t> y;
     74    Optional<int64_t> deltaX;
     75    Optional<int64_t> deltaY;
    7476
    7577    Optional<String> key;
  • trunk/Source/WebDriver/ChangeLog

    r268717 r268793  
     12020-10-21  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        WebDriver: add support for wheel actions
     4        https://bugs.webkit.org/show_bug.cgi?id=217174
     5
     6        Reviewed by Brian Burg.
     7
     8        Handle wheel actions.
     9
     10        * Actions.h:
     11        * Session.cpp:
     12        (WebDriver::automationSourceType): Handle InputSource::Type::Wheel.
     13        (WebDriver::Session::performActions): Handle Action::Type::Wheel.
     14        * WebDriverService.cpp:
     15        (WebDriver::processKeyAction): Assert if Action::Subtype::Scroll.
     16        (WebDriver::processPointerMoveAction): Move this code to a helper to be used by both pointer move and scroll actions.
     17        (WebDriver::processPointerAction): Use processPointerMoveAction().
     18        (WebDriver::processWheelAction): Call processPointerMoveAction() and process the scroll delta too.
     19        (WebDriver::processInputActionSequence): Handle InputSource::Type::Wheel.
     20
    1212020-10-20  Carlos Garcia Campos  <cgarcia@igalia.com>
    222
  • trunk/Source/WebDriver/Session.cpp

    r268717 r268793  
    26202620    case InputSource::Type::Key:
    26212621        return "Keyboard";
     2622    case InputSource::Type::Wheel:
     2623        return "Wheel";
    26222624    }
    26232625    RELEASE_ASSERT_NOT_REACHED();
     
    27102712                    case Action::Subtype::KeyUp:
    27112713                    case Action::Subtype::KeyDown:
     2714                    case Action::Subtype::Scroll:
    27122715                        ASSERT_NOT_REACHED();
    27132716                    }
     
    27442747                    case Action::Subtype::PointerMove:
    27452748                    case Action::Subtype::PointerCancel:
     2749                    case Action::Subtype::Scroll:
    27462750                        ASSERT_NOT_REACHED();
    27472751                    }
     
    27562760                    }
    27572761                    break;
     2762                case Action::Type::Wheel:
     2763                    switch (action.subtype) {
     2764                    case Action::Subtype::Scroll: {
     2765                        state->setString("origin"_s, automationOriginType(action.origin->type));
     2766                        auto location = JSON::Object::create();
     2767                        location->setInteger("x"_s, action.x.value());
     2768                        location->setInteger("y"_s, action.y.value());
     2769                        state->setObject("location"_s, WTFMove(location));
     2770
     2771                        auto delta = JSON::Object::create();
     2772                        delta->setInteger("width"_s, action.deltaX.value());
     2773                        delta->setInteger("height"_s, action.deltaY.value());
     2774                        state->setObject("delta"_s, WTFMove(delta));
     2775
     2776                        if (action.origin->type == PointerOrigin::Type::Element)
     2777                            state->setString("nodeHandle"_s, action.origin->elementID.value());
     2778                        FALLTHROUGH;
     2779                    }
     2780                    case Action::Subtype::Pause:
     2781                        if (action.duration)
     2782                            state->setDouble("duration"_s, action.duration.value());
     2783                        break;
     2784                    case Action::Subtype::PointerUp:
     2785                    case Action::Subtype::PointerDown:
     2786                    case Action::Subtype::PointerMove:
     2787                    case Action::Subtype::PointerCancel:
     2788                    case Action::Subtype::KeyUp:
     2789                    case Action::Subtype::KeyDown:
     2790                        ASSERT_NOT_REACHED();
     2791                    }
    27582792                }
    27592793                states->pushObject(WTFMove(state));
  • trunk/Source/WebDriver/WebDriverService.cpp

    r267919 r268793  
    19101910    case Action::Subtype::PointerMove:
    19111911    case Action::Subtype::PointerCancel:
     1912    case Action::Subtype::Scroll:
    19121913        ASSERT_NOT_REACHED();
    19131914    }
     
    19301931
    19311932    return MouseButton::None;
     1933}
     1934
     1935static bool processPointerMoveAction(JSON::Object& actionItem, Action& action, Optional<String>& errorMessage)
     1936{
     1937    if (auto durationValue = actionItem.getValue("duration"_s)) {
     1938        auto duration = unsignedValue(*durationValue);
     1939        if (!duration) {
     1940            errorMessage = String("The parameter 'duration' is invalid in action");
     1941            return false;
     1942        }
     1943        action.duration = duration.value();
     1944    }
     1945
     1946    if (auto originValue = actionItem.getValue("origin"_s)) {
     1947        if (auto originObject = originValue->asObject()) {
     1948            auto elementID = originObject->getString(Session::webElementIdentifier());
     1949            if (!elementID) {
     1950                errorMessage = String("The parameter 'origin' is not a valid web element object in action");
     1951                return false;
     1952            }
     1953            action.origin = PointerOrigin { PointerOrigin::Type::Element, elementID };
     1954        } else {
     1955            auto origin = originValue->asString();
     1956            if (origin == "viewport")
     1957                action.origin = PointerOrigin { PointerOrigin::Type::Viewport, WTF::nullopt };
     1958            else if (origin == "pointer")
     1959                action.origin = PointerOrigin { PointerOrigin::Type::Pointer, WTF::nullopt };
     1960            else {
     1961                errorMessage = String("The parameter 'origin' is invalid in action");
     1962                return false;
     1963            }
     1964        }
     1965    } else
     1966        action.origin = PointerOrigin { PointerOrigin::Type::Viewport, WTF::nullopt };
     1967
     1968    if (auto xValue = actionItem.getValue("x"_s)) {
     1969        auto x = valueAsNumberInRange(*xValue, INT_MIN);
     1970        if (!x) {
     1971            errorMessage = String("The paramater 'x' is invalid for action");
     1972            return false;
     1973        }
     1974        action.x = x.value();
     1975    }
     1976
     1977    if (auto yValue = actionItem.getValue("y"_s)) {
     1978        auto y = valueAsNumberInRange(*yValue, INT_MIN);
     1979        if (!y) {
     1980            errorMessage = String("The paramater 'y' is invalid for action");
     1981            return false;
     1982        }
     1983        action.y = y.value();
     1984    }
     1985
     1986    return true;
    19321987}
    19331988
     
    19742029        break;
    19752030    }
    1976     case Action::Subtype::PointerMove: {
    1977         if (auto durationValue = actionItem.getValue("duration"_s)) {
    1978             auto duration = unsignedValue(*durationValue);
    1979             if (!duration) {
    1980                 errorMessage = String("The parameter 'duration' is invalid in pointer move action");
    1981                 return WTF::nullopt;
    1982             }
    1983             action.duration = duration.value();
    1984         }
    1985 
    1986         if (auto originValue = actionItem.getValue("origin"_s)) {
    1987             if (auto originObject = originValue->asObject()) {
    1988                 auto elementID = originObject->getString(Session::webElementIdentifier());
    1989                 if (!elementID) {
    1990                     errorMessage = String("The parameter 'origin' is not a valid web element object in pointer move action");
    1991                     return WTF::nullopt;
    1992                 }
    1993                 action.origin = PointerOrigin { PointerOrigin::Type::Element, elementID };
    1994             } else {
    1995                 auto origin = originValue->asString();
    1996                 if (origin == "viewport")
    1997                     action.origin = PointerOrigin { PointerOrigin::Type::Viewport, WTF::nullopt };
    1998                 else if (origin == "pointer")
    1999                     action.origin = PointerOrigin { PointerOrigin::Type::Pointer, WTF::nullopt };
    2000                 else {
    2001                     errorMessage = String("The parameter 'origin' is invalid in pointer move action");
    2002                     return WTF::nullopt;
    2003                 }
    2004             }
    2005         } else
    2006             action.origin = PointerOrigin { PointerOrigin::Type::Viewport, WTF::nullopt };
    2007 
    2008         if (auto xValue = actionItem.getValue("x"_s)) {
    2009             auto x = valueAsNumberInRange(*xValue, INT_MIN);
    2010             if (!x) {
    2011                 errorMessage = String("The paramater 'x' is invalid for pointer move action");
    2012                 return WTF::nullopt;
    2013             }
    2014             action.x = x.value();
    2015         }
    2016 
    2017         if (auto yValue = actionItem.getValue("y"_s)) {
    2018             auto y = valueAsNumberInRange(*yValue, INT_MIN);
    2019             if (!y) {
    2020                 errorMessage = String("The paramater 'y' is invalid for pointer move action");
    2021                 return WTF::nullopt;
    2022             }
    2023             action.y = y.value();
    2024         }
     2031    case Action::Subtype::PointerMove:
     2032        if (!processPointerMoveAction(actionItem, action, errorMessage))
     2033            return WTF::nullopt;
    20252034        break;
    2026     }
    20272035    case Action::Subtype::PointerCancel:
    20282036        break;
    20292037    case Action::Subtype::KeyUp:
    20302038    case Action::Subtype::KeyDown:
     2039    case Action::Subtype::Scroll:
     2040        ASSERT_NOT_REACHED();
     2041    }
     2042
     2043    return action;
     2044}
     2045
     2046static Optional<Action> processWheelAction(const String& id, JSON::Object& actionItem, Optional<String>& errorMessage)
     2047{
     2048    Action::Subtype actionSubtype;
     2049    auto subtype = actionItem.getString("type"_s);
     2050    if (subtype == "pause")
     2051        actionSubtype = Action::Subtype::Pause;
     2052    else if (subtype == "scroll")
     2053        actionSubtype = Action::Subtype::Scroll;
     2054    else {
     2055        errorMessage = String("The parameter 'type' of wheel action is invalid");
     2056        return WTF::nullopt;
     2057    }
     2058
     2059    Action action(id, Action::Type::Wheel, actionSubtype);
     2060
     2061    switch (actionSubtype) {
     2062    case Action::Subtype::Pause:
     2063        if (!processPauseAction(actionItem, action, errorMessage))
     2064            return WTF::nullopt;
     2065        break;
     2066    case Action::Subtype::Scroll:
     2067        if (!processPointerMoveAction(actionItem, action, errorMessage))
     2068            return WTF::nullopt;
     2069
     2070        if (auto deltaXValue = actionItem.getValue("deltaX"_s)) {
     2071            auto deltaX = valueAsNumberInRange(*deltaXValue, INT_MIN);
     2072            if (!deltaX) {
     2073                errorMessage = String("The paramater 'deltaX' is invalid for action");
     2074                return WTF::nullopt;
     2075            }
     2076            action.deltaX = deltaX.value();
     2077        }
     2078
     2079        if (auto deltaYValue = actionItem.getValue("deltaY"_s)) {
     2080            auto deltaY = valueAsNumberInRange(*deltaYValue, INT_MIN);
     2081            if (!deltaY) {
     2082                errorMessage = String("The paramater 'deltaY' is invalid for action");
     2083                return WTF::nullopt;
     2084            }
     2085            action.deltaY = deltaY.value();
     2086        }
     2087        break;
     2088    case Action::Subtype::KeyUp:
     2089    case Action::Subtype::KeyDown:
     2090    case Action::Subtype::PointerUp:
     2091    case Action::Subtype::PointerDown:
     2092    case Action::Subtype::PointerMove:
     2093    case Action::Subtype::PointerCancel:
    20312094        ASSERT_NOT_REACHED();
    20322095    }
     
    20812144    else if (type == "pointer")
    20822145        inputSourceType = InputSource::Type::Pointer;
     2146    else if (type == "wheel")
     2147        inputSourceType = InputSource::Type::Wheel;
    20832148    else if (type == "none")
    20842149        inputSourceType = InputSource::Type::None;
     
    21372202        else if (inputSourceType == InputSource::Type::Pointer)
    21382203            action = processPointerAction(id, parameters.value(), *actionItem, errorMessage);
     2204        else if (inputSourceType == InputSource::Type::Wheel)
     2205            action = processWheelAction(id, *actionItem, errorMessage);
    21392206        if (!action)
    21402207            return WTF::nullopt;
  • trunk/Source/WebKit/ChangeLog

    r268758 r268793  
     12020-10-21  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        WebDriver: add support for wheel actions
     4        https://bugs.webkit.org/show_bug.cgi?id=217174
     5
     6        Reviewed by Brian Burg.
     7
     8        * UIProcess/Automation/Automation.json: Add scroll delta to action state.
     9        * UIProcess/Automation/SimulatedInputDispatcher.cpp:
     10        (WebKit::SimulatedInputSourceState::emptyStateForSourceType): Initialize scrollDelta for wheel actions.
     11        (WebKit::SimulatedInputDispatcher::transitionInputSourceToState): Handle SimulatedInputSourceType::Wheel.
     12        * UIProcess/Automation/SimulatedInputDispatcher.h:
     13        * UIProcess/Automation/WebAutomationSession.cpp:
     14        (WebKit::WebAutomationSession::WebAutomationSession): Add SimulatedInputSourceType::Wheel.
     15        (WebKit::WebAutomationSession::terminate): Handle pending wheel events.
     16        (WebKit::WebAutomationSession::willShowJavaScriptDialog): Ditto.
     17        (WebKit::WebAutomationSession::wheelEventsFlushedForPage): Ditto.
     18        (WebKit::WebAutomationSession::willClosePage): Ditto.
     19        (WebKit::WebAutomationSession::isSimulatingUserInteraction const): Return true if there are pending wheel events too.
     20        (WebKit::WebAutomationSession::simulateWheelInteraction): Handle the wheel action.
     21        (WebKit::simulatedInputSourceTypeFromProtocolSourceType): Handle Inspector::Protocol::Automation::InputSourceType::Wheel.
     22        (WebKit::WebAutomationSession::performInteractionSequence): Initialize the scroll delta for wheel action.
     23        * UIProcess/Automation/WebAutomationSession.h:
     24        * UIProcess/Automation/gtk/WebAutomationSessionGtk.cpp:
     25        (WebKit::WebAutomationSession::platformSimulateWheelInteraction): Synthesize a wheel event.
     26        * UIProcess/Automation/wpe/WebAutomationSessionWPE.cpp:
     27        (WebKit::WebAutomationSession::platformSimulateWheelInteraction): Ditto.
     28        * UIProcess/WebPageProxy.cpp:
     29        (WebKit::WebPageProxy::isProcessingWheelEvents const): Return whether page has pending wheel events.
     30        (WebKit::WebPageProxy::didReceiveEvent): Notify automation that pending wheel events have been processed.
     31        * UIProcess/WebPageProxy.h:
     32        * config.h:
     33
    1342020-10-20  Peng Liu  <peng.liu6@apple.com>
    235
  • trunk/Source/WebKit/UIProcess/Automation/Automation.json

    r268717 r268793  
    290290                "Mouse",
    291291                "Keyboard",
    292                 "Touch"
     292                "Touch",
     293                "Wheel"
    293294            ]
    294295        },
     
    328329                { "name": "pressedVirtualKeys", "type": "array", "items": { "$ref": "VirtualKey" }, "optional": true, "description": "For 'keyboard' input sources, specifies virtual keys that have a 'pressed' state. Unmentioned virtual keys are assumed to have a 'released' state." },
    329330                { "name": "pressedButton", "$ref": "MouseButton", "optional": true, "description": "For 'mouse' input sources, specifies which mouse button has a 'pressed' state. Unmentioned mouse buttons are assumed to have a 'released' state. For 'touch' input sources, passing MouseButton::Left denotes a touch-down state." },
    330                 { "name": "origin", "$ref": "MouseMoveOrigin", "optional": true, "description": "For 'mouse' input sources, specifies the origin type of a mouse move transition. Defaults to 'Viewport' if omitted."},
     331                { "name": "origin", "$ref": "MouseMoveOrigin", "optional": true, "description": "For 'mouse' or 'wheel' input sources, specifies the origin type of a mouse move transition. Defaults to 'Viewport' if omitted."},
    331332                { "name": "nodeHandle", "$ref": "NodeHandle", "optional": true, "description": "The handle of the element to use as origin when origin type is 'Element'."},
    332                 { "name": "location", "$ref": "Point", "optional": true, "description": "For 'mouse' or 'touch' input sources, specifies a location in view coordinates to which the input source should transition. Transitioning to this state may interpolate intemediate input source states to better simulate real user movements and gestures." },
     333                { "name": "location", "$ref": "Point", "optional": true, "description": "For 'mouse', 'wheel' or 'touch' input sources, specifies a location in view coordinates to which the input source should transition. Transitioning to this state may interpolate intemediate input source states to better simulate real user movements and gestures." },
     334                { "name": "delta", "$ref": "Size", "optional": true, "description": "For 'wheel' input sources, specifies a scroll delta."},
    333335                { "name": "duration", "type": "integer", "optional": true, "description": "The minimum number of milliseconds that must elapse while the relevant input source transitions to this state." }
    334336            ]
  • trunk/Source/WebKit/UIProcess/Automation/SimulatedInputDispatcher.cpp

    r268717 r268793  
    4444    case SimulatedInputSourceType::Keyboard:
    4545        break;
     46    case SimulatedInputSourceType::Wheel:
     47        result.scrollDelta = WebCore::IntSize();
     48        FALLTHROUGH;
    4649    case SimulatedInputSourceType::Mouse:
    4750    case SimulatedInputSourceType::Touch:
     
    381384#endif // !ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
    382385        break;
     386    case SimulatedInputSourceType::Wheel:
     387#if !ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     388        RELEASE_ASSERT_NOT_REACHED();
     389#else
     390        resolveLocation(a.location.valueOr(WebCore::IntPoint()), b.location, b.origin.valueOr(MouseMoveOrigin::Viewport), b.nodeHandle, [this, &a, &b, eventDispatchFinished = WTFMove(eventDispatchFinished)](Optional<WebCore::IntPoint> location, Optional<AutomationCommandError> error) mutable {
     391            if (error) {
     392                eventDispatchFinished(error);
     393                return;
     394            }
     395
     396            if (!location) {
     397                eventDispatchFinished(AUTOMATION_COMMAND_ERROR_WITH_NAME(ElementNotInteractable));
     398                return;
     399            }
     400
     401            b.location = location;
     402
     403            if (!a.scrollDelta->isZero())
     404                b.scrollDelta->contract(a.scrollDelta->width(), a.scrollDelta->height());
     405
     406            if (!b.scrollDelta->isZero()) {
     407                LOG(Automation, "SimulatedInputDispatcher[%p]: simulating Wheel from (%d, %d) to (%d, %d) for transition to %d.%d", this, a.scrollDelta->width(), a.scrollDelta->height(), b.scrollDelta->width(), b.scrollDelta->height(), m_keyframeIndex, m_inputSourceStateIndex);
     408                // FIXME: This does not interpolate mouse scrolls per the "perform a scroll" algorithm (§15.4.4 Wheel actions).
     409                m_client.simulateWheelInteraction(m_page, b.location.value(), b.scrollDelta.value(), WTFMove(eventDispatchFinished));
     410            } else
     411                eventDispatchFinished(WTF::nullopt);
     412        });
     413#endif // !ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     414        break;
    383415    }
    384416}
  • trunk/Source/WebKit/UIProcess/Automation/SimulatedInputDispatcher.h

    r268717 r268793  
    3030#include <WebCore/FrameIdentifier.h>
    3131#include <WebCore/IntPoint.h>
     32#include <WebCore/IntSize.h>
    3233#include <wtf/CompletionHandler.h>
    3334#include <wtf/HashSet.h>
     
    6869    Mouse,
    6970    Touch,
     71    Wheel,
    7072};
    7173
     
    8385    Optional<String> nodeHandle;
    8486    Optional<WebCore::IntPoint> location;
     87    Optional<WebCore::IntSize> scrollDelta;
    8588    Optional<Seconds> duration;
    8689
     
    134137#if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
    135138        virtual void simulateKeyboardInteraction(WebPageProxy&, KeyboardInteraction, WTF::Variant<VirtualKey, CharKey>&&, AutomationCompletionHandler&&) = 0;
     139#endif
     140#if ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     141        virtual void simulateWheelInteraction(WebPageProxy&, const WebCore::IntPoint& locationInView, const WebCore::IntSize& delta, AutomationCompletionHandler&&) = 0;
    136142#endif
    137143        virtual void viewportInViewCenterPointOfElement(WebPageProxy&, Optional<WebCore::FrameIdentifier>, const String& nodeHandle, Function<void (Optional<WebCore::IntPoint>, Optional<AutomationCommandError>)>&&) = 0;
  • trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.cpp

    r268717 r268793  
    9393    m_inputSources.add(SimulatedInputSource::create(SimulatedInputSourceType::Keyboard));
    9494#endif
     95#if ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     96    m_inputSources.add(SimulatedInputSource::create(SimulatedInputSourceType::Wheel));
     97#endif
    9598    m_inputSources.add(SimulatedInputSource::create(SimulatedInputSourceType::Null));
    9699#endif // ENABLE(WEBDRIVER_ACTIONS_API)
     
    165168    }
    166169#endif // ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
     170
     171#if ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     172    for (auto& identifier : copyToVector(m_pendingWheelEventsFlushedCallbacksPerPage.keys())) {
     173        auto callback = m_pendingWheelEventsFlushedCallbacksPerPage.take(identifier);
     174        callback(AUTOMATION_COMMAND_ERROR_WITH_NAME(InternalError));
     175    }
     176#endif // ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
    167177
    168178#if ENABLE(REMOTE_INSPECTOR)
     
    677687#endif // ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
    678688    });
     689
     690#if ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     691        if (!m_pendingWheelEventsFlushedCallbacksPerPage.isEmpty()) {
     692            for (auto key : copyToVector(m_pendingWheelEventsFlushedCallbacksPerPage.keys())) {
     693                auto callback = m_pendingWheelEventsFlushedCallbacksPerPage.take(key);
     694                callback(WTF::nullopt);
     695            }
     696        }
     697#endif // ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
    679698}
    680699   
     
    817836}
    818837
     838void WebAutomationSession::wheelEventsFlushedForPage(const WebPageProxy& page)
     839{
     840#if ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     841    if (auto callback = m_pendingWheelEventsFlushedCallbacksPerPage.take(page.identifier()))
     842        callback(WTF::nullopt);
     843#else
     844    UNUSED_PARAM(page);
     845#endif
     846}
     847
    819848void WebAutomationSession::willClosePage(const WebPageProxy& page)
    820849{
     
    830859#if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
    831860    if (auto callback = m_pendingKeyboardEventsFlushedCallbacksPerPage.take(page.identifier()))
     861        callback(AUTOMATION_COMMAND_ERROR_WITH_NAME(WindowNotFound));
     862#endif
     863#if ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     864    if (auto callback = m_pendingWheelEventsFlushedCallbacksPerPage.take(page.identifier()))
    832865        callback(AUTOMATION_COMMAND_ERROR_WITH_NAME(WindowNotFound));
    833866#endif
     
    15261559        return true;
    15271560#endif
     1561#if ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     1562    if (!m_pendingWheelEventsFlushedCallbacksPerPage.isEmpty())
     1563        return true;
     1564#endif
    15281565#if ENABLE(WEBDRIVER_TOUCH_INTERACTIONS)
    15291566    if (m_simulatingTouchInteraction)
     
    16721709}
    16731710#endif // ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
     1711
     1712#if ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     1713void WebAutomationSession::simulateWheelInteraction(WebPageProxy& page, const WebCore::IntPoint& locationInViewport, const WebCore::IntSize& delta, AutomationCompletionHandler&& completionHandler)
     1714{
     1715    page.getWindowFrameWithCallback([this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler), page = makeRef(page), locationInViewport, delta](WebCore::FloatRect windowFrame) mutable {
     1716        auto clippedX = std::min(std::max(0.0f, static_cast<float>(locationInViewport.x())), windowFrame.size().width());
     1717        auto clippedY = std::min(std::max(0.0f, static_cast<float>(locationInViewport.y())), windowFrame.size().height());
     1718        if (clippedX != locationInViewport.x() || clippedY != locationInViewport.y()) {
     1719            completionHandler(AUTOMATION_COMMAND_ERROR_WITH_NAME(TargetOutOfBounds));
     1720            return;
     1721        }
     1722
     1723        // Bridge the flushed callback to our command's completion handler.
     1724        auto wheelEventsFlushedCallback = [completionHandler = WTFMove(completionHandler)](Optional<AutomationCommandError> error) mutable {
     1725            completionHandler(error);
     1726        };
     1727
     1728        auto& callbackInMap = m_pendingWheelEventsFlushedCallbacksPerPage.add(page->identifier(), nullptr).iterator->value;
     1729        if (callbackInMap)
     1730            callbackInMap(AUTOMATION_COMMAND_ERROR_WITH_NAME(Timeout));
     1731        callbackInMap = WTFMove(wheelEventsFlushedCallback);
     1732
     1733        platformSimulateWheelInteraction(page, locationInViewport, delta);
     1734
     1735        // If the event does not hit test anything in the window, then it may not have been delivered.
     1736        if (callbackInMap && !page->isProcessingWheelEvents()) {
     1737            auto callbackToCancel = m_pendingWheelEventsFlushedCallbacksPerPage.take(page->identifier());
     1738            callbackToCancel(WTF::nullopt);
     1739        }
     1740
     1741        // Otherwise, wait for wheelEventsFlushedCallback to run when all events are handled.
     1742    });
     1743}
     1744#endif
    16741745#endif // ENABLE(WEBDRIVER_ACTIONS_API)
    16751746
     
    18551926    case Inspector::Protocol::Automation::InputSourceType::Touch:
    18561927        return SimulatedInputSourceType::Touch;
     1928    case Inspector::Protocol::Automation::InputSourceType::Wheel:
     1929        return SimulatedInputSourceType::Wheel;
    18571930    }
    18581931
     
    19662039            ASYNC_FAIL_WITH_PREDEFINED_ERROR_AND_DETAILS(NotImplemented, "Keyboard input sources are not yet supported.");
    19672040#endif
     2041#if !ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     2042        if (inputSourceType == SimulatedInputSourceType::Wheel)
     2043            ASYNC_FAIL_WITH_PREDEFINED_ERROR_AND_DETAILS(NotImplemented, "Wheel input sources are not yet supported.");
     2044#endif
    19682045        if (typeToSourceIdMap.contains(inputSourceType))
    19692046            ASYNC_FAIL_WITH_PREDEFINED_ERROR_AND_DETAILS(InvalidParameter, "Two input sources with the same type were specified.");
     
    20512128                if (x && y)
    20522129                    sourceState.location = WebCore::IntPoint(*x, *y);
     2130            }
     2131
     2132            if (auto deltaObject = stateObject->getObject("delta"_s)) {
     2133                auto deltaX = deltaObject->getInteger("width"_s);
     2134                auto deltaY = deltaObject->getInteger("height"_s);
     2135                if (deltaX && deltaY)
     2136                    sourceState.scrollDelta = WebCore::IntSize(*deltaX, *deltaY);
    20532137            }
    20542138
  • trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.h

    r267918 r268793  
    126126    void keyboardEventsFlushedForPage(const WebPageProxy&);
    127127    void mouseEventsFlushedForPage(const WebPageProxy&);
     128    void wheelEventsFlushedForPage(const WebPageProxy&);
    128129    void willClosePage(const WebPageProxy&);
    129130    void handleRunOpenPanel(const WebPageProxy&, const WebFrameProxy&, const API::OpenPanelParameters&, WebOpenPanelResultListenerProxy&);
     
    154155#if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
    155156    void simulateKeyboardInteraction(WebPageProxy&, KeyboardInteraction, WTF::Variant<VirtualKey, CharKey>&&, AutomationCompletionHandler&&);
     157#endif
     158#if ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     159    void simulateWheelInteraction(WebPageProxy&, const WebCore::IntPoint& locationInView, const WebCore::IntSize& delta, AutomationCompletionHandler&&);
    156160#endif
    157161    void viewportInViewCenterPointOfElement(WebPageProxy&, Optional<WebCore::FrameIdentifier>, const Inspector::Protocol::Automation::NodeHandle&, Function<void(Optional<WebCore::IntPoint>, Optional<AutomationCommandError>)>&&);
     
    264268    void platformSimulateKeySequence(WebPageProxy&, const String&);
    265269#endif // ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
     270#if ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     271    void platformSimulateWheelInteraction(WebPageProxy&, const WebCore::IntPoint& locationInViewport, const WebCore::IntSize& delta);
     272#endif // ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
    266273
    267274    // Get base64-encoded PNG data from a bitmap.
     
    307314    HashMap<WebPageProxyIdentifier, Function<void(Optional<AutomationCommandError>)>> m_pendingMouseEventsFlushedCallbacksPerPage;
    308315#endif
     316#if ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     317    HashMap<WebPageProxyIdentifier, Function<void(Optional<AutomationCommandError>)>> m_pendingWheelEventsFlushedCallbacksPerPage;
     318#endif
    309319
    310320    uint64_t m_nextEvaluateJavaScriptCallbackID { 1 };
  • trunk/Source/WebKit/UIProcess/Automation/gtk/WebAutomationSessionGtk.cpp

    r268717 r268793  
    3232#include <WebCore/GtkUtilities.h>
    3333#include <WebCore/GtkVersioning.h>
     34#include <WebCore/Scrollbar.h>
    3435
    3536namespace WebKit {
     
    329330#endif // ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
    330331
     332#if ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     333void WebAutomationSession::platformSimulateWheelInteraction(WebPageProxy& page, const WebCore::IntPoint& locationInViewport, const WebCore::IntSize& delta)
     334{
     335    auto* viewWidget = reinterpret_cast<WebKitWebViewBase*>(page.viewWidget());
     336    FloatSize scrollDelta(delta);
     337    scrollDelta.scale(1 / static_cast<float>(Scrollbar::pixelsPerLineStep()));
     338    webkitWebViewBaseSynthesizeWheelEvent(viewWidget, -scrollDelta.width(), -scrollDelta.height(), locationInViewport.x(), locationInViewport.y(), WheelEventPhase::NoPhase, WheelEventPhase::NoPhase);
     339}
     340#endif // ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     341
    331342} // namespace WebKit
  • trunk/Source/WebKit/UIProcess/Automation/wpe/WebAutomationSessionWPE.cpp

    r268717 r268793  
    365365#endif // ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
    366366
     367#if ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     368void WebAutomationSession::platformSimulateWheelInteraction(WebPageProxy& page, const WebCore::IntPoint& locationInView, const WebCore::IntSize& delta)
     369{
     370#if WPE_CHECK_VERSION(1, 5, 0)
     371    struct wpe_input_axis_2d_event event;
     372    memset(&event, 0, sizeof(event));
     373    event.base.type = static_cast<wpe_input_axis_event_type>(wpe_input_axis_event_type_mask_2d | wpe_input_axis_event_type_motion_smooth);
     374    event.base.x = locationInView.x();
     375    event.base.y = locationInView.y();
     376    event.x_axis = -delta.width();
     377    event.y_axis = -delta.height();
     378    wpe_view_backend_dispatch_axis_event(page.viewBackend(), &event.base);
     379#else
     380    if (auto deltaX = delta.width()) {
     381        struct wpe_input_axis_event event = { wpe_input_axis_event_type_motion, 0, locationInView.x(), locationInView.y(), 1, -deltaX, 0 };
     382        wpe_view_backend_dispatch_axis_event(page.viewBackend(), &event);
     383    }
     384    if (auto deltaY = delta.height()) {
     385        struct wpe_input_axis_event event = { wpe_input_axis_event_type_motion, 0, locationInView.x(), locationInView.y(), 0, -deltaY, 0 };
     386        wpe_view_backend_dispatch_axis_event(page.viewBackend(), &event);
     387    }
     388#endif
     389}
     390#endif // ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
     391
    367392} // namespace WebKit
    368393
  • trunk/Source/WebKit/UIProcess/WebPageProxy.cpp

    r268497 r268793  
    64276427}
    64286428
     6429bool WebPageProxy::isProcessingWheelEvents() const
     6430{
     6431    return m_wheelEventCoalescer && m_wheelEventCoalescer->hasEventsBeingProcessed();
     6432}
     6433
    64296434NativeWebMouseEvent* WebPageProxy::currentlyProcessedMouseDownEvent()
    64306435{
     
    69436948        if (auto eventToSend = wheelEventCoalescer().nextEventToDispatch())
    69446949            sendWheelEvent(*eventToSend);
     6950        else if (auto* automationSession = process().processPool().automationSession())
     6951            automationSession->wheelEventsFlushedForPage(*this);
    69456952        break;
    69466953    }
  • trunk/Source/WebKit/UIProcess/WebPageProxy.h

    r268635 r268793  
    944944    void flushPendingMouseEventCallbacks();
    945945
     946    bool isProcessingWheelEvents() const;
    946947    void handleWheelEvent(const NativeWebWheelEvent&);
    947948
  • trunk/Source/WebKit/config.h

    r257619 r268793  
    6161#endif
    6262
    63 // ENABLE_WEBDRIVER_ACTIONS_API represents whether mouse, keyboard or touch interactions are defined
    64 #if ENABLE(WEBDRIVER_MOUSE_INTERACTIONS) || ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS) || ENABLE(WEBDRIVER_TOUCH_INTERACTIONS)
     63// ENABLE_WEBDRIVER_ACTIONS_API represents whether mouse, keyboard, touch or wheel interactions are defined
     64#if ENABLE(WEBDRIVER_MOUSE_INTERACTIONS) || ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS) || ENABLE(WEBDRIVER_TOUCH_INTERACTIONS) || ENABLE(WEBDRIVER_WHEEL_INTERACTIONS)
    6565#define ENABLE_WEBDRIVER_ACTIONS_API 1
    6666#endif
  • trunk/Source/cmake/OptionsGTK.cmake

    r268751 r268793  
    272272    SET_AND_EXPOSE_TO_BUILD(ENABLE_WEBDRIVER_MOUSE_INTERACTIONS ON)
    273273    SET_AND_EXPOSE_TO_BUILD(ENABLE_WEBDRIVER_TOUCH_INTERACTIONS OFF)
     274    SET_AND_EXPOSE_TO_BUILD(ENABLE_WEBDRIVER_WHEEL_INTERACTIONS ON)
    274275endif ()
    275276
  • trunk/Source/cmake/OptionsWPE.cmake

    r268453 r268793  
    166166    SET_AND_EXPOSE_TO_BUILD(ENABLE_WEBDRIVER_MOUSE_INTERACTIONS ON)
    167167    SET_AND_EXPOSE_TO_BUILD(ENABLE_WEBDRIVER_TOUCH_INTERACTIONS OFF)
     168    SET_AND_EXPOSE_TO_BUILD(ENABLE_WEBDRIVER_WHEEL_INTERACTIONS ON)
    168169endif ()
    169170
  • trunk/Source/cmake/WebKitFeatures.cmake

    r268599 r268793  
    220220    WEBKIT_OPTION_DEFINE(ENABLE_WEBDRIVER_MOUSE_INTERACTIONS "Toggle WebDriver mouse interactions" PRIVATE OFF)
    221221    WEBKIT_OPTION_DEFINE(ENABLE_WEBDRIVER_TOUCH_INTERACTIONS "Toggle WebDriver touch interactions" PRIVATE OFF)
     222    WEBKIT_OPTION_DEFINE(ENABLE_WEBDRIVER_WHEEL_INTERACTIONS "Toggle WebDriver wheel interactions" PRIVATE OFF)
    222223    WEBKIT_OPTION_DEFINE(ENABLE_WEBGL "Toggle WebGL support" PRIVATE ON)
    223224    WEBKIT_OPTION_DEFINE(ENABLE_WEBGL2 "Toggle WebGL2 support" PRIVATE OFF)
  • trunk/Tools/ChangeLog

    r268787 r268793  
     12020-10-21  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        WebDriver: add support for wheel actions
     4        https://bugs.webkit.org/show_bug.cgi?id=217174
     5
     6        Reviewed by Brian Burg.
     7
     8        Add webdriver-wheel-interactions option.
     9
     10        * Scripts/webkitperl/FeatureList.pm:
     11
    1122020-10-21  Lauro Moura  <lmoura@igalia.com>
    213
  • trunk/Tools/Scripts/webkitperl/FeatureList.pm

    r268453 r268793  
    183183    $webdriverSupport,
    184184    $webdriverTouchInteractionsSupport,
     185    $webdriverWheelInteractionsSupport,
    185186    $webgl2Support,
    186187    $webglSupport,
     
    554555      define => "ENABLE_WEBDRIVER_TOUCH_INTERACTIONS", value => \$webdriverTouchInteractionsSupport },
    555556
     557    { option => "webdriver-wheel-interactions", desc => "Toggle WebDriver wheel interactions",
     558      define => "ENABLE_WEBDRIVER_WHEEL_INTERACTIONS", value => \$webdriverWheelInteractionsSupport },
     559
    556560    { option => "webgl", desc => "Toggle WebGL support",
    557561      define => "ENABLE_WEBGL", value => \$webglSupport },
  • trunk/WebDriverTests/ChangeLog

    r268784 r268793  
     12020-10-21  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        WebDriver: add support for wheel actions
     4        https://bugs.webkit.org/show_bug.cgi?id=217174
     5
     6        Reviewed by Brian Burg.
     7
     8        Remove expectations for wheel actions test.
     9
     10        * TestExpectations.json:
     11
    1122020-10-20  Lauro Moura  <lmoura@igalia.com>
    213
  • trunk/WebDriverTests/TestExpectations.json

    r268784 r268793  
    471471        "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/184967"}}
    472472    },
    473     "imported/w3c/webdriver/tests/perform_actions/wheel.py": {
    474         "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/217174"}}
    475     },
    476473
    477474    "imported/w3c/webdriver/tests/close_window/close.py": {
Note: See TracChangeset for help on using the changeset viewer.