Changeset 238344 in webkit


Ignore:
Timestamp:
Nov 17, 2018 1:29:52 AM (6 years ago)
Author:
graouts@webkit.org
Message:

[Pointer Events] event.isPrimary doesn't always represent the oldest active touch
https://bugs.webkit.org/show_bug.cgi?id=191752
<rdar://problem/46129270>

Reviewed by Dean Jackson.

Source/WebCore:

Provide isPrimary to the constructor so its value can be determined at the call site.

Test: pointerevents/ios/pointer-events-is-primary.html

  • dom/PointerEvent.h:
  • dom/ios/PointerEventIOS.cpp:

(WebCore::PointerEvent::create):
(WebCore::PointerEvent::PointerEvent):
(WebCore::m_isPrimary):

LayoutTests:

Add a new test that checks that adding a touch after another existing touch does not make it be
the primary touch, but that removing the first touch makes the second touch become the primary touch.

To do this we add a new ui.sequence() method that allows a series of touch actions to be performed
in a linear sequence. The test author can create a finger and call various actions on it, currently
begin(), move() and end().

When these actions are processed, we compute all "stationary" actions for each part of the sequence
so that we can provide this to the uiController.sendEventStream() function.

Finally, we add a way to track events received by the target and assert that the events that were
received match those that were expected.

  • pointerevents/ios/pointer-events-is-primary-expected.txt: Added.
  • pointerevents/ios/pointer-events-is-primary.html: Added.
  • pointerevents/utils.js:

(prototype.handleEvent):
(prototype.assertMatchesEvents):
(const.ui.new.UIController):
(const.ui.new.UIController.prototype.finger):
(const.ui.new.UIController.prototype.pinchOut):
(const.ui.new.UIController.prototype.sequence):
(const.ui.new.UIController.prototype._runEvents):
(prototype.begin):
(prototype.move):
(prototype.end):
(prototype.stationary):
(prototype._action):

Location:
trunk
Files:
2 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r238333 r238344  
     12018-11-16  Antoine Quint  <graouts@apple.com>
     2
     3        [Pointer Events] event.isPrimary doesn't always represent the oldest active touch
     4        https://bugs.webkit.org/show_bug.cgi?id=191752
     5        <rdar://problem/46129270>
     6
     7        Reviewed by Dean Jackson.
     8
     9        Add a new test that checks that adding a touch after another existing touch does not make it be
     10        the primary touch, but that removing the first touch makes the second touch become the primary touch.
     11
     12        To do this we add a new ui.sequence() method that allows a series of touch actions to be performed
     13        in a linear sequence. The test author can create a finger and call various actions on it, currently
     14        begin(), move() and end().
     15
     16        When these actions are processed, we compute all "stationary" actions for each part of the sequence
     17        so that we can provide this to the uiController.sendEventStream() function.
     18
     19        Finally, we add a way to track events received by the target and assert that the events that were
     20        received match those that were expected.
     21
     22        * pointerevents/ios/pointer-events-is-primary-expected.txt: Added.
     23        * pointerevents/ios/pointer-events-is-primary.html: Added.
     24        * pointerevents/utils.js:
     25        (prototype.handleEvent):
     26        (prototype.assertMatchesEvents):
     27        (const.ui.new.UIController):
     28        (const.ui.new.UIController.prototype.finger):
     29        (const.ui.new.UIController.prototype.pinchOut):
     30        (const.ui.new.UIController.prototype.sequence):
     31        (const.ui.new.UIController.prototype._runEvents):
     32        (prototype.begin):
     33        (prototype.move):
     34        (prototype.end):
     35        (prototype.stationary):
     36        (prototype._action):
     37
    1382018-11-16  Devin Rousso  <drousso@apple.com>
    239
  • trunk/LayoutTests/pointerevents/utils.js

    r238274 r238344  
    3333}
    3434
     35class EventTracker
     36{
     37
     38    constructor(target, eventNames)
     39    {
     40        this.target = target;
     41        this.events = [];
     42        this.pointerIdToTouchIdMap = {};
     43
     44        for (let eventName of eventNames)
     45            target.addEventListener(eventName, this);
     46    }
     47
     48    handleEvent(event)
     49    {
     50        if (!this.pointerIdToTouchIdMap[event.pointerId])
     51            this.pointerIdToTouchIdMap[event.pointerId] = Object.keys(this.pointerIdToTouchIdMap).length + 1;
     52
     53        const id = this.pointerIdToTouchIdMap[event.pointerId];
     54        this.events.push({
     55            id,
     56            type: event.type,
     57            x: event.clientX,
     58            y: event.clientY,
     59            isPrimary: event.isPrimary
     60        });
     61    }
     62
     63    assertMatchesEvents(expectedEvents)
     64    {
     65        assert_true(!!this.events.length, "Event tracker saw some events.");
     66        assert_equals(expectedEvents.length, this.events.length, "Expected events and actual events have the same length.");
     67        for (let i = 0; i < expectedEvents.length; ++i) {
     68            const expectedEvent = expectedEvents[i];
     69            const actualEvent = this.events[i];
     70            for (let property of Object.getOwnPropertyNames(expectedEvent))
     71                assert_equals(expectedEvent[property], actualEvent[property], `Property ${property} matches for event at index ${i}.`);
     72        }
     73    }
     74
     75}
     76
    3577const ui = new (class UIController {
     78
     79    constructor()
     80    {
     81        this.fingers = {};
     82    }
     83
     84    finger()
     85    {
     86        const id = Object.keys(this.fingers).length + 1;
     87        return this.fingers[id] = new Finger(id);
     88    }
    3689
    3790    beginTouches(options)
     
    93146        };
    94147
    95         return this._runEvents({
     148        return this._runEvents([{
    96149            interpolate : "linear",
    97150            timestep: 0.1,
     
    99152            startEvent: startEvent,
    100153            endEvent: endEvent
    101         });
     154        }]);
     155    }
     156
     157    sequence(touches)
     158    {
     159        const activeFingers = {};
     160
     161        return this._runEvents(touches.map((touches, index) => {
     162            if (!Array.isArray(touches))
     163                touches = [touches];
     164
     165            const processedIDs = {};
     166
     167            // Update the list of active touches.
     168            touches.forEach(touch => {
     169                processedIDs[touch.id] = true;
     170                if (touch.phase === "ended")
     171                    delete activeFingers[touch.id];
     172                else
     173                    activeFingers[touch.id] = { x: touch.x, y: touch.y };
     174            });
     175
     176            // Now go through the active touches and check that they're all listed in the new touches.
     177            for (let id in activeFingers) {
     178                if (!processedIDs[id])
     179                    touches.push(this.fingers[id].stationary(activeFingers[id]));
     180            }
     181
     182            return {
     183                inputType : "hand",
     184                timeOffset : index * 0.05,
     185                coordinateSpace : "content",
     186                touches : touches
     187            }
     188        }));
    102189    }
    103190
    104191    _runEvents(events)
    105192    {
    106         return this._run(`uiController.sendEventStream('${JSON.stringify({ events: [events] })}')`);
     193        return this._run(`uiController.sendEventStream('${JSON.stringify({ events })}')`);
    107194    }
    108195
     
    116203
    117204})();
     205
     206class Finger
     207{
     208
     209    constructor(id)
     210    {
     211        this.id = id;
     212    }
     213
     214    begin(options)
     215    {
     216        return this._action("began", options.x || 0, options.y || 0);
     217    }
     218
     219    move(options)
     220    {
     221        return this._action("moved", options.x || 0, options.y || 0);
     222    }
     223
     224    end(options)
     225    {
     226        return this._action("ended", this._lastX, this._lastY);
     227    }
     228
     229    stationary(options)
     230    {
     231        return this._action("stationary", options.x || 0, options.y || 0);
     232    }
     233
     234    _action(phase, x, y)
     235    {
     236        this._lastX = x;
     237        this._lastY = y;
     238        return { inputType: "finger", id: this.id, phase, x, y };
     239    }
     240
     241}
  • trunk/Source/WebCore/ChangeLog

    r238342 r238344  
     12018-11-16  Antoine Quint  <graouts@apple.com>
     2
     3        [Pointer Events] event.isPrimary doesn't always represent the oldest active touch
     4        https://bugs.webkit.org/show_bug.cgi?id=191752
     5        <rdar://problem/46129270>
     6
     7        Reviewed by Dean Jackson.
     8
     9        Provide isPrimary to the constructor so its value can be determined at the call site.
     10
     11        Test: pointerevents/ios/pointer-events-is-primary.html
     12
     13        * dom/PointerEvent.h:
     14        * dom/ios/PointerEventIOS.cpp:
     15        (WebCore::PointerEvent::create):
     16        (WebCore::PointerEvent::PointerEvent):
     17        (WebCore::m_isPrimary):
     18
    1192018-11-16  Alex Christensen  <achristensen@webkit.org>
    220
  • trunk/Source/WebCore/dom/PointerEvent.h

    r237816 r238344  
    6161
    6262#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY)
    63     static Ref<PointerEvent> create(const PlatformTouchEvent&, unsigned touchIndex, Ref<WindowProxy>&&);
     63    static Ref<PointerEvent> create(const PlatformTouchEvent&, unsigned touchIndex, bool isPrimary, Ref<WindowProxy>&&);
    6464#endif
    6565
     
    8585    PointerEvent(const AtomicString&, Init&&);
    8686#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY)
    87     PointerEvent(const AtomicString& type, const PlatformTouchEvent&, IsCancelable isCancelable, unsigned touchIndex, Ref<WindowProxy>&&);
     87    PointerEvent(const AtomicString& type, const PlatformTouchEvent&, IsCancelable isCancelable, unsigned touchIndex, bool isPrimary, Ref<WindowProxy>&&);
    8888#endif
    8989
  • trunk/Source/WebCore/dom/ios/PointerEventIOS.cpp

    r237816 r238344  
    5858}
    5959
    60 Ref<PointerEvent> PointerEvent::create(const PlatformTouchEvent& event, unsigned index, Ref<WindowProxy>&& view)
     60Ref<PointerEvent> PointerEvent::create(const PlatformTouchEvent& event, unsigned index, bool isPrimary, Ref<WindowProxy>&& view)
    6161{
    6262    auto phase = event.touchPhaseAtIndex(index);
    63     return adoptRef(*new PointerEvent(eventType(phase), event, phaseIsCancelable(phase), index, WTFMove(view)));
     63    return adoptRef(*new PointerEvent(eventType(phase), event, phaseIsCancelable(phase), index, isPrimary, WTFMove(view)));
    6464}
    6565
    66 PointerEvent::PointerEvent(const AtomicString& type, const PlatformTouchEvent& event, IsCancelable isCancelable, unsigned index, Ref<WindowProxy>&& view)
     66PointerEvent::PointerEvent(const AtomicString& type, const PlatformTouchEvent& event, IsCancelable isCancelable, unsigned index, bool isPrimary, Ref<WindowProxy>&& view)
    6767    : MouseEvent(type, CanBubble::Yes, isCancelable, IsComposed::Yes, event.timestamp().approximateMonotonicTime(), WTFMove(view), 0, event.touchLocationAtIndex(index), event.touchLocationAtIndex(index), { }, event.modifiers(), 0, 0, nullptr, 0, 0, nullptr, IsSimulated::No, IsTrusted::Yes)
    6868    , m_pointerId(event.touchIdentifierAtIndex(index))
     
    7070    , m_height(2 * event.radiusYAtIndex(index))
    7171    , m_pointerType(event.touchTypeAtIndex(index) == PlatformTouchPoint::TouchType::Stylus ? "pen"_s : "touch"_s)
    72     , m_isPrimary(!index)
     72    , m_isPrimary(isPrimary)
    7373{
    7474}
Note: See TracChangeset for help on using the changeset viewer.