tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pointerevent_pointerrawupdate_changes_pointer_capture.https.html (11938B)


      1 <!doctype html>
      2 <html>
      3 <head>
      4 <meta charset="utf-8">
      5 <meta name="timeout" content="long">
      6 <meta name="viewport" content="width=device-width, initial-scale:1, user-scalable=no">
      7 <title>Test for handling of "fire a pointer event named pointerrawupdate"</title>
      8 <script src="/resources/testharness.js"></script>
      9 <script src="/resources/testharnessreport.js"></script>
     10 <script src="/resources/testdriver.js"></script>
     11 <script src="/resources/testdriver-actions.js"></script>
     12 <script src="/resources/testdriver-vendor.js"></script>
     13 <style>
     14 div#initPosition {
     15  height: 1em;
     16  margin: 50px;
     17 }
     18 div#parent, div#child {
     19  width: 200px;
     20  height: 200px;
     21  margin: 0px;
     22  padding: 0;
     23 }
     24 </style>
     25 <script>
     26 "use strict";
     27 
     28 /**
     29 * `pointerrawupdate` is defined as:
     30 * > The user agent MUST fire a pointer event named pointerrawupdate, and only
     31 * > do so within a secure context, when a pointer changes any properties that
     32 * > don't fire pointerdown or pointerup events.
     33 *
     34 * The following `pointermove` event is also defined as:
     35 * > The user agent MUST fire a pointer event named pointermove
     36 *
     37 * So, when a set of `pointerrawupdate` and `pointermove` is dispatched, the
     38 * "fire a pointer event" runs twice.
     39 *
     40 * "fire a pointer event" defines:
     41 * > If the event is not a gotpointercapture, lostpointercapture, click,
     42 * > auxclick or contextmenu event, run the process pending pointer capture
     43 * > steps for this PointerEvent.
     44 *
     45 *  And also the section defines:
     46 * > Determine the target at which the event is fired as follows:
     47 * > - If the pointer capture target override has been set for the pointer, set
     48 * >   the target to pointer capture target override object.
     49 * > - Otherwise, set the target to the object returned by normal hit test
     50 * >   mechanisms (out of scope for this specification).
     51 *
     52 * So, dispatching `pointerrawupdate` should fix the pointer capture override
     53 * and cause dispatching `gotpointercapture` and/or `lostpointercapture` and
     54 * `pointermove` event should be retarget to the new pointer capture override.
     55 */
     56 
     57 addEventListener("load", () => {
     58  const ticksToPreventCoalescedPointerMove = 300;
     59  const initDiv = document.getElementById("initPosition");
     60  const parent = document.getElementById("parent");
     61  const child = document.getElementById("child");
     62 
     63  let events;
     64  function logEvent(event) {
     65    events.push({type: event.type, target: event.target});
     66  }
     67  function stringifyEvents(arrayOfEvents) {
     68    function stringifyEvent(event) {
     69      return `${event.type}@${event.target.localName}${
     70        event.target.id ? `#${event.target.id}` : ""
     71      }`;
     72    }
     73    let str = "";
     74    for (const event of arrayOfEvents) {
     75      if (str) {
     76        str += ", ";
     77      }
     78      str += stringifyEvent(event);
     79    }
     80    return str;
     81  }
     82  for (const type of ["pointerdown", "pointerup",
     83                      "pointerrawupdate", "pointermove",
     84                      "gotpointercapture", "lostpointercapture"]) {
     85    parent.addEventListener(type, logEvent, {capture: true});
     86  }
     87 
     88  promise_test(async t => {
     89    events = [];
     90    child.addEventListener("pointerdown", pointerDownEvent => {
     91      parent.setPointerCapture(pointerDownEvent.pointerId);
     92      parent.addEventListener("pointerrawupdate", pointerRawUpdateEvent => {
     93        parent.releasePointerCapture(pointerRawUpdateEvent.pointerId);
     94      }, {once: true});
     95    }, {once: true});
     96    await new test_driver.Actions()
     97      .pointerMove(0, 0, {origin: initDiv})
     98      .pause(ticksToPreventCoalescedPointerMove)
     99      .pointerMove(0, 0, {origin: child})
    100      .pointerDown()
    101      .pointerMove(1, 1, {origin: child})
    102      .pointerUp()
    103      .pointerMove(0, 0, {origin: initDiv})
    104      .send();
    105    assert_equals(
    106      stringifyEvents(events),
    107      stringifyEvents([
    108        {type: "pointerrawupdate", target: child},
    109        {type: "pointermove", target: child},
    110        {type: "pointerdown", target: child}, // set pending pointer capture to parent
    111        // The following `pointerrawupdate` event dispatching runs the
    112        // "process pending pointer capture" steps.
    113        {type: "gotpointercapture", target: parent},
    114        {type: "pointerrawupdate", target: parent}, // set pending pointer capture to null
    115        // The following `pointermove` event dispatching runs the
    116        // "process pending pointer capture" steps again.
    117        {type: "lostpointercapture", target: parent},
    118        {type: "pointermove", target: child},
    119        {type: "pointerup", target: child},
    120      ])
    121    );
    122  }, "Setting pointer capture at `pointerdown` and releasing pointer capture at `pointerrawupdate`");
    123 
    124  promise_test(async t => {
    125    events = [];
    126    child.addEventListener("pointerdown", () => {
    127      parent.addEventListener("pointerrawupdate", pointerRawUpdateEvent => {
    128        parent.setPointerCapture(pointerRawUpdateEvent.pointerId);
    129      }, {once: true});
    130    }, {once: true});
    131    await new test_driver.Actions()
    132      .pointerMove(0, 0, {origin: initDiv})
    133      .pause(ticksToPreventCoalescedPointerMove)
    134      .pointerMove(0, 0, {origin: child})
    135      .pointerDown()
    136      .pointerMove(1, 1, {origin: child})
    137      .pointerUp()
    138      .pointerMove(0, 0, {origin: initDiv})
    139      .send();
    140    assert_equals(
    141      stringifyEvents(events),
    142      stringifyEvents([
    143        {type: "pointerrawupdate", target: child},
    144        {type: "pointermove", target: child},
    145        {type: "pointerdown", target: child},
    146        {type: "pointerrawupdate", target: child}, // set pending pointer capture to parent
    147        // The following `pointermove` event dispatching runs the
    148        // "process pending pointer capture" steps.
    149        {type: "gotpointercapture", target: parent},
    150        {type: "pointermove", target: parent},
    151        {type: "pointerup", target: parent},
    152        {type: "lostpointercapture", target: parent},
    153      ])
    154    );
    155  }, "Setting pointer capture at `pointerrawupdate`");
    156 
    157  promise_test(async t => {
    158    events = [];
    159    child.addEventListener("pointerdown", pointerDownEvent => {
    160      parent.setPointerCapture(pointerDownEvent.pointerId);
    161      parent.addEventListener("gotpointercapture", gotPointerCaptureEvent => {
    162        parent.releasePointerCapture(gotPointerCaptureEvent.pointerId);
    163      }, {once: true});
    164    }, {once: true});
    165    await new test_driver.Actions()
    166      .pointerMove(0, 0, {origin: initDiv})
    167      .pause(ticksToPreventCoalescedPointerMove)
    168      .pointerMove(0, 0, {origin: child})
    169      .pointerDown()
    170      .pointerMove(1, 1, {origin: child})
    171      .pointerUp()
    172      .pointerMove(0, 0, {origin: initDiv})
    173      .send();
    174    assert_equals(
    175      stringifyEvents(events),
    176      stringifyEvents([
    177        {type: "pointerrawupdate", target: child},
    178        {type: "pointermove", target: child},
    179        {type: "pointerdown", target: child}, // set pending pointer capture to parent
    180        // The following `pointerrawupdate` event dispatching runs the
    181        // "process pending pointer capture" steps.
    182        {type: "gotpointercapture", target: parent}, // set pending pointer capture to null
    183        {type: "pointerrawupdate", target: parent},
    184        // The following `pointermove` event dispatching runs the
    185        // "process pending pointer capture" steps again.
    186        {type: "lostpointercapture", target: parent},
    187        {type: "pointermove", target: child},
    188        {type: "pointerup", target: child},
    189      ])
    190    );
    191  }, "Setting pointer capture at `pointerdown` and releasing pointer capture at `gotpointercapture`");
    192 
    193  promise_test(async t => {
    194    events = [];
    195    child.addEventListener("pointerdown", pointerDownEvent => {
    196      parent.setPointerCapture(pointerDownEvent.pointerId);
    197      parent.addEventListener("pointermove", pointerMoveEvent => {
    198        parent.releasePointerCapture(pointerMoveEvent.pointerId);
    199        parent.addEventListener("lostpointercapture", lostPointerCaptureEvent => {
    200          parent.setPointerCapture(lostPointerCaptureEvent.pointerId);
    201        }, {once: true});
    202      }, {once: true});
    203    }, {once: true});
    204    await new test_driver.Actions()
    205      .pointerMove(0, 0, {origin: initDiv})
    206      .pause(ticksToPreventCoalescedPointerMove)
    207      .pointerMove(0, 0, {origin: child})
    208      .pointerDown()
    209      .pointerMove(1, 1, {origin: child})
    210      .pause(ticksToPreventCoalescedPointerMove)
    211      .pointerMove(2, 2, {origin: child})
    212      .pointerUp()
    213      .pointerMove(0, 0, {origin: initDiv})
    214      .send();
    215    assert_equals(
    216      stringifyEvents(events),
    217      stringifyEvents([
    218        {type: "pointerrawupdate", target: child},
    219        {type: "pointermove", target: child},
    220        {type: "pointerdown", target: child}, // set pending pointer capture to parent
    221        // The following `pointerrawupdate` event dispatching runs the
    222        // "process pending pointer capture" steps.
    223        {type: "gotpointercapture", target: parent},
    224        {type: "pointerrawupdate", target: parent},
    225        {type: "pointermove", target: parent}, // set pending pointer capture to null
    226        // The following `pointerrawupdate` event dispatching runs the
    227        // "process pending pointer capture" steps again.
    228        {type: "lostpointercapture", target: parent}, // set pending pointer capture to parent again
    229        {type: "pointerrawupdate", target: child},
    230        // The following `pointermove` event dispatching runs the
    231        // "process pending pointer capture" steps again.
    232        {type: "gotpointercapture", target: parent},
    233        {type: "pointermove", target: parent},
    234        {type: "pointerup", target: parent},
    235        {type: "lostpointercapture", target: parent},
    236      ])
    237    );
    238  }, "Setting pointer capture at `lostpointercapture`");
    239 
    240  promise_test(async () => {
    241    parent.removeEventListener("pointerrawupdate", logEvent, {capture: true});
    242    // Now, there is no `pointerrawupdate` event listener.  So, browsers should
    243    // not dispatch `pointerrawupdate` event and the "fire a pointer event" steps
    244    // including the "process pending pointer capture" steps should not run twice
    245    // per `pointermove`.
    246    assert_true(true, "There is no `pointerrawupdate` event listener anymore");
    247  });
    248 
    249  promise_test(async t => {
    250    events = [];
    251    child.addEventListener("pointerdown", pointerDownEvent => {
    252      parent.setPointerCapture(pointerDownEvent.pointerId);
    253      parent.addEventListener("gotpointercapture", gotPointerCaptureEvent => {
    254        parent.releasePointerCapture(gotPointerCaptureEvent.pointerId);
    255      }, {once: true});
    256    }, {once: true});
    257    await new test_driver.Actions()
    258      .pointerMove(0, 0, {origin: initDiv})
    259      .pause(ticksToPreventCoalescedPointerMove)
    260      .pointerMove(0, 0, {origin: child})
    261      .pointerDown()
    262      .pointerMove(1, 1, {origin: child})
    263      .pause(ticksToPreventCoalescedPointerMove)
    264      .pointerMove(2, 2, {origin: child})
    265      .pointerUp()
    266      .pointerMove(0, 0, {origin: initDiv})
    267      .send();
    268    assert_equals(
    269      stringifyEvents(events),
    270      stringifyEvents([
    271        {type: "pointermove", target: child},
    272        {type: "pointerdown", target: child}, // set pending pointer capture to parent
    273        // The following `pointermove` event dispatching runs the
    274        // "process pending pointer capture" steps.
    275        {type: "gotpointercapture", target: parent}, // set pending pointer capture to null
    276        {type: "pointermove", target: parent},
    277        // The following `pointermove` event dispatching runs the
    278        // "process pending pointer capture" steps again.
    279        {type: "lostpointercapture", target: parent},
    280        {type: "pointermove", target: child},
    281        {type: "pointerup", target: child},
    282      ])
    283    );
    284  }, "Setting pointer capture at `pointerdown` and releasing pointer capture at `gotpointercapture` when no `pointerrawupdate` event listener");
    285 }, {once: true});
    286 </script>
    287 </head>
    288 <body>
    289  <div id="initPosition"></div>
    290  <div id="parent">
    291    <div id="child">
    292    </div>
    293  </div>
    294 </body>
    295 </html>