Revert "Consolidate pointer attribute testing"
diff --git a/pointerevents/pointerevent_attributes.html b/pointerevents/pointerevent_attributes.html
deleted file mode 100644
index 7675dd5..0000000
--- a/pointerevents/pointerevent_attributes.html
+++ /dev/null
@@ -1,295 +0,0 @@
-<!doctype html>
-<html>
-<head>
- <title>Pointer Events properties tests</title>
- <meta name="viewport" content="width=device-width">
- <meta name="variant" content="?mouse">
- <meta name="variant" content="?pen">
- <meta name="variant" content="?mouse-right">
- <meta name="variant" content="?pen-right">
- <meta name="variant" content="?touch">
- <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
- <style>
- html {
- touch-action: none;
- }
-
- div {
- padding: 0;
- }
-
- #square1 {
- background-color: green;
- border: 1px solid black;
- height: 50px;
- width: 50px;
- margin-bottom: 3px;
- display: inline-block;
- }
-
- #innerFrame {
- position: relative;
- margin-bottom: 3px;
- margin-left: 0;
- top: 0;
- left: 0;
- }
- </style>
-</head>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
-<script src="/resources/testdriver-actions.js"></script>
-<script src="/resources/testdriver-vendor.js"></script>
-<!-- Additional helper script for common checks across event types -->
-<script type="text/javascript" src="pointerevent_support.js"></script>
-<script>
-let frameLoaded = undefined;
-const frameLoadedPromise = new Promise(resolve => {
- frameLoaded = resolve;
-});
-</script>
-<body>
- <div id="square1"></div>
- <div>
- <iframe onLoad = "frameLoaded()" id="innerFrame" srcdoc='
- <style>
- html {
- touch-action: none;
- }
- #square2 {
- background-color: green;
- border: 1px solid black;
- height: 50px;
- width: 50px;
- display: inline-block;
- }
- </style>
- <body>
- <div id="square2"></div>
- </body>
- '></iframe>
- </div>
- <!-- Used to detect a sentinel event. Once triggered, all other events must
- have been processed. -->
- <div>
- <button id="done">done</button>
- </div>
-</body>
-<script>
- window.onload = runTests();
-
- async function runTests() {
-
- const queryStringFragments = location.search.substring(1).split('-');
- const pointerType = queryStringFragments[0];
- const button = queryStringFragments[1];
-
- const eventList = [
- 'pointerover',
- 'pointerenter',
- 'pointerdown',
- 'pointerup',
- 'pointerout',
- 'pointerleave',
- 'pointermove'
- ];
-
- function injectScrubGesture(element) {
- const doneButton = document.getElementById('done');
- const actions = new test_driver.Actions();
-
- let buttonArguments =
- (button == 'right') ? { button: actions.ButtonType.RIGHT }
- : undefined;
-
- // The following comments refer to the first event of each type since
- // that is what is being validated in the test.
- return actions
- .addPointer('pointer1', pointerType)
- // The pointermove, pointerover and pointerenter events will be
- // triggered here with a hover pointer.
- .pointerMove(0, -20, { origin: element })
- // Pointerdown triggers pointerover, pointerenter with a non-hover
- // pointer type.
- .pointerDown(buttonArguments)
- // This move triggers pointermove with a non-hover pointer-type.
- .pointerMove(0, 20, { origin: element })
- // The pointerout and pointerleave events are triggered here with a
- // touch pointer.
- .pointerUp(buttonArguments)
- // An addition move outside of the target bounds is required to trigger
- // pointerout & pointerleave events with a hover pointer.
- .pointerMove(0, 0)
- .send();
- }
-
- // Processing a click or tap on the done button is used to signal that all
- // other events should have beem handled. This is used to catch unhandled
- // events that would otherwise result in a timeout.
- function clickOrTapDone() {
- const doneButton = document.getElementById('done');
- const pointerupPromise = getEvent('pointerup', doneButton);
- const actionPromise = new test_driver.Actions()
- .addPointer('pointer1', 'touch')
- .pointerMove(0, 0, {origin: doneButton})
- .pointerDown()
- .pointerUp()
- .send();
- return actionPromise.then(pointerupPromise);
- }
-
- function verifyButtonAttributes(event) {
- let downButton, upButton, downButtons, upButtons;
- if (button == 'right') {
- downButton = 2;
- downButtons = 2;
- upButton = 2;
- upButtons = 0;
- } else {
- // defaults to left button click
- downButton = 0;
- downButtons = 1;
- upButton = 0;
- upButtons = 0;
- }
- const expectationsHover = {
- // Pointer over, enter, and move are processed before the button press.
- pointerover: { button: -1, buttons: 0 },
- pointerenter: { button: -1, buttons: 0 },
- pointermove: { button: -1, buttons: 0 },
- // Button status changes on pointer down and up.
- pointerdown: { button: downButton, buttons: downButtons },
- pointerup: { button: upButton, buttons: upButtons },
- // Pointer out and leave are processed after the button release.
- pointerout: { button: -1, buttons: 0 },
- pointerleave: { button: -1, buttons: 0 }
- };
- const expectationsNoHover = {
- // We don't see pointer events except during a touch gesture.
- // Move is the only pointer event where the "button" click state is not
- // changing. All other pointer events are associated with the start or
- // end of a touch gesture.
- pointerover: { button: 0, buttons: 1 },
- pointerenter: { button: 0, buttons: 1 },
- pointerdown: { button: 0, buttons: 1 },
- pointermove: { button: -1, buttons: 1 },
- pointerup: { button: 0, buttons: 0 },
- pointerout: { button: 0, buttons: 0 },
- pointerleave: { button: 0, buttons: 0 }
- };
- const expectations =
- (pointerType == 'touch') ? expectationsNoHover : expectationsHover;
-
- assert_equals(event.button, expectations[event.type].button,
- `Button attribute on ${event.type}`);
- assert_equals(event.buttons, expectations[event.type].buttons,
- `Buttons attribute on ${event.type}`);
- }
-
- function verifyPosition(event) {
- const boundingRect = event.target.getBoundingClientRect();
-
- // With a touch pointer type, the pointerout and pointerleave will trigger
- // on pointerup while clientX and clientY are still within the target's
- // bounds. With a hover pointer, these events will be triggered only after
- // clientX or clientY are out of the target's bounds.
- if (pointerType != 'touch' &&
- (event.type == 'pointerout' || event.type == 'pointerleave')) {
- assert_true(
- boundingRect.left > event.clientX ||
- boundingRect.right < event.clientX ||
- boundingRect.top > event.clientY ||
- boundingRect.bottom < event.clientY,
- `clientX/clientY is outside the element bounds for ${event.type} event`);
- } else {
- assert_true(
- boundingRect.left <= event.clientX &&
- boundingRect.right >= event.clientX,
- `clientX is within the expected range for ${event.type} event`);
- assert_true(
- boundingRect.top <= event.clientY &&
- boundingRect.bottom >= event.clientY,
- `clientY is within the expected range for ${event.type} event`);
- }
- }
-
- function verifyEventAttributes(event, testNamePrefix) {
- verifyButtonAttributes(event);
- verifyPosition(event);
- assert_true(event.isPrimary, 'isPrimary attribute is true');
- check_PointerEvent(event, testNamePrefix);
- }
-
- function pointerPromise(test, testNamePrefix, type, target) {
- let rejectCallback = undefined;
- promise = new Promise((resolve, reject) => {
- // Store a reference to the promise rejection functions, which would
- // otherwise not be visible outside the promise object. If the callback
- // remains set when the deadline is reached, it means that the promise
- // will not get resolved and should be rejected.
- rejectCallback = reject;
- const pointerEventListener = event => {
- rejectCallback = undefined;
- assert_equals(event.type, type, `type attribute for ${type} event`);
- event.preventDefault();
- resolve(event);
- };
- target.addEventListener(type, pointerEventListener, { once: true });
- test.add_cleanup(() => {
- // Just in case of an assert prior to the events being triggered.
- document.removeEventListener(type, pointerEventListener,
- { once: true });
- });
- }).then(result => { verifyEventAttributes(result, testNamePrefix); },
- error => { assert_unreached(error); });
- promise.deadlineReached = () => {
- // If the event has not been received, the promise will not be
- // fulfilled, leading to a timeout. Reject the promise if still pending.
- if (rejectCallback) {
- rejectCallback(`missing ${type} event`);
- }
- }
- return promise;
- }
-
- async function runPointerEventsTest(test, testNamePrefix, target) {
- assert_true(['mouse', 'pen', 'touch'].indexOf(pointerType) >= 0,
- `Unexpected pointer type (${pointerType})`);
-
- const promises = [];
- eventList.forEach(type => {
- // Create a promise for each event type. If clicking on the done button
- // is detected before an event's promise is resolved, then the promise
- // will be rejected. Otherwise, the attributes for the event are
- // verified.
- promises.push(pointerPromise(test, testNamePrefix, type, target));
- });
-
- await injectScrubGesture(target);
-
- // The injected gestures consist of a shrub on a button followed by a
- // click on the done button. The promise is only resolved after the
- // done click is detected. At this stage all other events must have been
- // processed. Any unresolved promises in the list will be rejected to
- // avoid a test timeout. The rejection will trigger a test failure.
- await clickOrTapDone().then(promises.map(p => p.deadlineReached()));
-
- // Once all promises are resolved, all event attributes have been
- // successfully verified.
- return Promise.all(promises);
- }
-
- promise_test(t => {
- const square1 = document.getElementById('square1');
- return runPointerEventsTest(t, '', square1);
- }, 'Test pointer events in the main document');
-
- promise_test(async t => {
- const innerFrame = document.getElementById('innerFrame');
- await frameLoadedPromise;
- const square2 = innerFrame.contentDocument.getElementById('square2');
- return runPointerEventsTest(t, 'Inner Frame', square2);
- }, 'Test pointer events in an iframe');
- }
-</script>
diff --git a/pointerevents/pointerevent_attributes_hoverable_pointers.html b/pointerevents/pointerevent_attributes_hoverable_pointers.html
new file mode 100644
index 0000000..c8443d9
--- /dev/null
+++ b/pointerevents/pointerevent_attributes_hoverable_pointers.html
@@ -0,0 +1,158 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Pointer Events properties tests</title>
+ <meta name="viewport" content="width=device-width">
+ <meta name="variant" content="?mouse">
+ <meta name="variant" content="?pen">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <!-- Additional helper script for common checks across event types -->
+ <script type="text/javascript" src="pointerevent_support.js"></script>
+ <script>
+ var input_pointertype = location.search.substring(1);
+ var detected_pointertypes = {};
+ var detected_eventTypes = {};
+ var eventList = ['pointerover', 'pointerenter', 'pointermove', 'pointerdown', 'pointerup', 'pointerout', 'pointerleave'];
+ var expectedPointerId = NaN;
+
+ function resetTestState() {
+ detected_eventTypes = {};
+ document.getElementById("square1").style.visibility = 'visible';
+ document.getElementById('innerFrame').contentDocument.getElementById("square2").style.visibility = 'hidden';
+ expectedPointerId = NaN;
+ }
+ function checkPointerEventAttributes(event, targetBoundingClientRect, testNamePrefix) {
+ if (detected_eventTypes[event.type])
+ return;
+ var expectedEventType = eventList[Object.keys(detected_eventTypes).length];
+ detected_eventTypes[event.type] = true;
+ var pointerTestName = (testNamePrefix ? testNamePrefix + ' ' : '')
+ + expectedPointerType + ' ' + expectedEventType;
+
+ detected_pointertypes[event.pointerType] = true;
+
+ test(function() {
+ assert_equals(event.type, expectedEventType);
+ }, pointerTestName + ".type should be " + expectedEventType);
+
+ // Test button and buttons
+ if (event.type == 'pointerdown') {
+ test(function() {
+ assert_equals(event.button, 0);
+ }, pointerTestName + ".button attribute is 0 when left mouse button is pressed.");
+ test(function() {
+ assert_equals(event.buttons, 1);
+ }, pointerTestName + ".buttons attribute is 1 when left mouse button is pressed.");
+ } else if (event.type == 'pointerup') {
+ test(function() {
+ assert_equals(event.button, 0);
+ }, pointerTestName + ".button attribute is 0 when left mouse button is just released.");
+ test(function() {
+ assert_equals(event.buttons, 0);
+ }, pointerTestName + ".buttons attribute is 0 when left mouse button is just released.");
+ } else {
+ test(function() {
+ assert_equals(event.button, -1);
+ }, pointerTestName + ".button is -1 when mouse buttons are in released state.");
+ test(function() {
+ assert_equals(event.buttons, 0);
+ }, pointerTestName + ".buttons is 0 when mouse buttons are in released state.");
+ }
+
+ // Test clientX and clientY
+ if (event.type != 'pointerout' && event.type != 'pointerleave' ) {
+ test(function () {
+ assert_greater_than_equal(event.clientX, targetBoundingClientRect.left, "clientX should be greater or equal than left of the box");
+ assert_greater_than_equal(event.clientY, targetBoundingClientRect.top, "clientY should be greater or equal than top of the box");
+ assert_less_than_equal(event.clientX, targetBoundingClientRect.right, "clientX should be less or equal than right of the box");
+ assert_less_than_equal(event.clientY, targetBoundingClientRect.bottom, "clientY should be less or equal than bottom of the box");
+ }, pointerTestName + ".clientX and .clientY attributes are correct.");
+ } else {
+ test(function () {
+ assert_true(event.clientX < targetBoundingClientRect.left || event.clientX >= targetBoundingClientRect.right || event.clientY < targetBoundingClientRect.top || event.clientY >= targetBoundingClientRect.bottom);
+ }, pointerTestName + ".clientX and .clientY attributes are correct.");
+ }
+
+ check_PointerEvent(event, testNamePrefix);
+
+ // Test isPrimary
+ test(function () {
+ assert_equals(event.isPrimary, true);
+ }, pointerTestName + ".isPrimary attribute is true.");
+
+ // Test pointerId value
+ if (isNaN(expectedPointerId)) {
+ expectedPointerId = event.pointerId;
+ } else {
+ test(function () {
+ assert_equals(event.pointerId, expectedPointerId);
+ }, pointerTestName + ".pointerId should be the same as previous pointer events for this active pointer.");
+ }
+ }
+
+ async function run() {
+ var test_pointerEvent = setup_pointerevent_test("pointerevent attributes", [input_pointertype]);
+ var square1 = document.getElementById("square1");
+ var rectSquare1 = square1.getBoundingClientRect();
+ var innerFrame = document.getElementById('innerFrame');
+ var square2 = innerFrame.contentDocument.getElementById('square2');
+ var rectSquare2 = square2.getBoundingClientRect();
+
+ eventList.forEach(function(eventName) {
+ on_event(square1, eventName, function (event) {
+ if (square1.style.visibility == 'hidden')
+ return;
+ checkPointerEventAttributes(event, rectSquare1, "");
+ if (Object.keys(detected_eventTypes).length == eventList.length) {
+ square1.style.visibility = 'hidden';
+ detected_eventTypes = {};
+ square2.style.visibility = 'visible';
+ expectedPointerId = NaN;
+ }
+ });
+ on_event(square2, eventName, function (event) {
+ checkPointerEventAttributes(event, rectSquare2, "Inner frame ");
+ if (Object.keys(detected_eventTypes).length == eventList.length) {
+ square2.style.visibility = 'hidden';
+ test_pointerEvent.done();
+ }
+ });
+ });
+
+ // Inject mouse or pen inputs.
+ await clickInTarget(input_pointertype, square1);
+ await moveToDocument(input_pointertype);
+ await clickInTarget(input_pointertype, square2);
+ await moveToDocument(input_pointertype);
+ }
+ </script>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events hoverable pointer attributes test</h1>
+ <h2 id="pointerTypeDescription"></h2>
+ <h4>
+ Test Description: This test checks the properties of hoverable pointer events. If you are using hoverable pen don't leave the range of digitizer while doing the instructions.
+ <ol>
+ <li>Move your pointer over the black square and click on it.</li>
+ <li>Then move it off the black square so that it disappears.</li>
+ <li>When red square appears move your pointer over the red square and click on it.</li>
+ <li>Then move it off the red square.</li>
+ </ol>
+
+ Test passes if the proper behavior of the events is observed.
+ </h4>
+ <div id="square1" class="square"></div>
+ <iframe id="innerFrame" src="resources/pointerevent_attributes_hoverable_pointers-iframe.html"></iframe>
+ <div class="spacer"></div>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ <p>Refresh the page to run the tests again with a different pointer type.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/pointerevents/pointerevent_attributes_hoverable_rightbutton.html b/pointerevents/pointerevent_attributes_hoverable_rightbutton.html
new file mode 100644
index 0000000..9a449ed
--- /dev/null
+++ b/pointerevents/pointerevent_attributes_hoverable_rightbutton.html
@@ -0,0 +1,168 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Pointer Events properties tests</title>
+ <meta name="viewport" content="width=device-width">
+ <meta name="variant" content="?mouse">
+ <meta name="variant" content="?pen">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <!-- Additional helper script for common checks across event types -->
+ <script type="text/javascript" src="pointerevent_support.js"></script>
+ <script>
+ var input_pointertype = location.search.substring(1);
+ var detected_eventTypes = {};
+ var eventList = [
+ 'pointerover', 'pointerenter', 'pointermove', 'pointerdown',
+ 'pointerup', 'pointerout', 'pointerleave'
+ ];
+ var expectedPointerId = NaN;
+
+ function resetTestState() {
+ detected_eventTypes = {};
+ document.getElementById("square1").style.visibility = 'visible';
+ document.getElementById('innerFrame').contentDocument
+ .getElementById("square2").style.visibility = 'hidden';
+ expectedPointerId = NaN;
+ }
+ function checkPointerEventAttributes(
+ event, targetBoundingClientRect, testNamePrefix) {
+ if (detected_eventTypes[event.type])
+ return;
+ var expectedEventType =
+ eventList[Object.keys(detected_eventTypes).length];
+ detected_eventTypes[event.type] = true;
+ var pointerTestName = (testNamePrefix ? testNamePrefix + ' ' : '')
+ + expectedPointerType + ' ' + expectedEventType;
+
+ test(function() {
+ assert_equals(event.type, expectedEventType);
+ }, pointerTestName + "'s type should be " + expectedEventType);
+
+ // Test button and buttons
+ if (event.type == 'pointerdown') {
+ test(function() {
+ assert_equals(event.button, 2);
+ }, pointerTestName + "'s button attribute is 2 when right mouse "
+ + "button is pressed.");
+ test(function() {
+ assert_equals(event.buttons, 2);
+ }, pointerTestName + "'s buttons attribute is 2 when right mouse "
+ + "button is pressed.");
+ } else if (event.type == 'pointerup') {
+ test(function() {
+ assert_equals(event.button, 2);
+ }, pointerTestName + "'s button attribute is 0 when right mouse "
+ + "button is just released.");
+ test(function() {
+ assert_equals(event.buttons, 0);
+ }, pointerTestName + "'s buttons attribute is 0 when right mouse "
+ + "button is just released.");
+ } else {
+ test(function() {
+ assert_equals(event.button, -1);
+ }, pointerTestName + "'s button is -1 when mouse buttons are in "
+ + "released state.");
+ test(function() {
+ assert_equals(event.buttons, 0);
+ }, pointerTestName + "'s buttons is 0 when mouse buttons are in "
+ + "released state.");
+ }
+
+ // Test clientX and clientY
+ if (event.type != 'pointerout' && event.type != 'pointerleave' ) {
+ test(function () {
+ assert_greater_than_equal(
+ event.clientX, targetBoundingClientRect.left,
+ "clientX should be greater or equal than left of the box");
+ assert_greater_than_equal(
+ event.clientY, targetBoundingClientRect.top,
+ "clientY should be greater or equal than top of the box");
+ assert_less_than_equal(
+ event.clientX, targetBoundingClientRect.right,
+ "clientX should be less or equal than right of the box");
+ assert_less_than_equal(
+ event.clientY, targetBoundingClientRect.bottom,
+ "clientY should be less or equal than bottom of the box");
+ }, pointerTestName + "'s ClientX and ClientY attributes are correct.");
+ } else {
+ test(function () {
+ assert_true(
+ event.clientX < targetBoundingClientRect.left
+ || event.clientX >= targetBoundingClientRect.right
+ || event.clientY < targetBoundingClientRect.top
+ || event.clientY >= targetBoundingClientRect.bottom,
+ "ClientX/Y should be out of the boundaries of the box");
+ }, pointerTestName + "'s ClientX and ClientY attributes are correct.");
+ }
+
+ check_PointerEvent(event, testNamePrefix);
+
+ // Test isPrimary
+ test(function () {
+ assert_equals(event.isPrimary, true);
+ }, pointerTestName + ".isPrimary attribute is correct.");
+
+ // Test pointerId value
+ if (isNaN(expectedPointerId)) {
+ expectedPointerId = event.pointerId;
+ } else {
+ test(function () {
+ assert_equals(event.pointerId, expectedPointerId);
+ }, pointerTestName + ".pointerId should be the same as previous "
+ + "pointer events for this active pointer.");
+ }
+ }
+
+ async function run() {
+ var test_pointerEvent = setup_pointerevent_test(
+ "pointerevent attributes", [input_pointertype]);
+ var square1 = document.getElementById("square1");
+ var rectSquare1 = square1.getBoundingClientRect();
+ var innerFrame = document.getElementById('innerFrame');
+ var square2 = innerFrame.contentDocument.getElementById('square2');
+ var rectSquare2 = square2.getBoundingClientRect();
+ var actions_promise;
+
+ eventList.forEach(function(eventName) {
+ on_event(square1, eventName, function (event) {
+ if (square1.style.visibility == 'hidden')
+ return;
+ checkPointerEventAttributes(event, rectSquare1, "");
+ if (Object.keys(detected_eventTypes).length == eventList.length) {
+ square1.style.visibility = 'hidden';
+ detected_eventTypes = {};
+ square2.style.visibility = 'visible';
+ expectedPointerId = NaN;
+ }
+ });
+ on_event(square2, eventName, function (event) {
+ checkPointerEventAttributes(event, rectSquare2, "Inner frame");
+ if (Object.keys(detected_eventTypes).length == eventList.length) {
+ square2.style.visibility = 'hidden';
+ test_pointerEvent.done();
+ }
+ });
+ });
+
+ // Inject mouse or pen inputs.
+ await rightClickInTarget(input_pointertype, square1);
+ await moveToDocument(input_pointertype);
+ await rightClickInTarget(input_pointertype, square2);
+ await moveToDocument(input_pointertype);
+ }
+ </script>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events hoverable pointer attributes test</h1>
+ <h2 id="pointerTypeDescription"></h2>
+ <div id="square1" class="square"></div>
+ <iframe id="innerFrame"
+ src="resources/pointerevent_attributes_hoverable_pointers-iframe.html">
+ </iframe>
+ </body>
+</html>
diff --git a/pointerevents/pointerevent_attributes_nohover_pointers.html b/pointerevents/pointerevent_attributes_nohover_pointers.html
new file mode 100644
index 0000000..3441417
--- /dev/null
+++ b/pointerevents/pointerevent_attributes_nohover_pointers.html
@@ -0,0 +1,200 @@
+<!doctype html>
+<html>
+<head>
+ <title>Pointer Events properties tests</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <style>
+ html {
+ touch-action: none;
+ }
+
+ div {
+ padding: 0;
+ }
+
+ #square1 {
+ background-color: green;
+ border: 1px solid black;
+ height: 50px;
+ width: 50px;
+ margin-bottom: 3px;
+ display: inline-block;
+ }
+
+ #innerFrame {
+ position: relative;
+ margin-bottom: 3px;
+ margin-left: 0;
+ top: 0;
+ left: 0;
+ }
+ </style>
+</head>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<!-- Additional helper script for common checks across event types -->
+<script type="text/javascript" src="pointerevent_support.js"></script>
+<script>
+
+ window.onload = async () => {
+ const event_list = [
+ 'pointerover',
+ 'pointerenter',
+ 'pointerdown',
+ 'pointerup',
+ 'pointerout',
+ 'pointerleave',
+ 'pointermove'
+ ];
+
+ function checkPointerEventAttributes(testPrefix, event, expectations) {
+ const pointerTestName =
+ `${testPrefix} touch.${expectations.type}`;
+
+ test(function() {
+ assert_equals(event.type, expectations.type);
+ }, `${pointerTestName}.type should be ${expectations.type}`);
+
+ test(function() {
+ assert_equals(event.button, expectations.button);
+ }, `${pointerTestName}.button should be ${expectations.button}`);
+
+ test(function() {
+ assert_equals(event.buttons, expectations.buttons);
+ }, `${pointerTestName}.buttons should be ${expectations.buttons}`);
+
+ // Bounding rect of the event target must contain (clienX, clientY).
+ const boundingRect = event.target.getBoundingClientRect();
+ test(function() {
+ assert_true(
+ boundingRect.left <= event.clientX &&
+ boundingRect.right >= event.clientX);
+ }, `${pointerTestName}.clientX is within the expected range`);
+ test(function() {
+ assert_true(
+ boundingRect.top <= event.clientY &&
+ boundingRect.bottom >= event.clientY);
+ }, `${pointerTestName}.clientY is within the expected range`);
+
+ check_PointerEvent(event, testPrefix);
+
+ // Test isPrimary
+ test(function () {
+ assert_equals(event.isPrimary, true);
+ }, `${pointerTestName}: isPrimary attribute is true.`);
+ }
+
+ function injectScrub(element) {
+ return new test_driver.Actions()
+ .addPointer('pointer1', 'touch')
+ .pointerMove(0, -20, {origin: element})
+ .pointerDown()
+ .addTick()
+ .addTick()
+ .pointerMove(0, 20, {origin: element})
+ .addTick()
+ .addTick()
+ .pointerUp()
+ .send();
+ }
+
+ async function tapDone() {
+ const done_button = document.getElementById('done');
+ const pointerupPromise = getEvent('pointerup', done_button);
+ const actionPromise = new test_driver.Actions()
+ .addPointer('pointer1', 'touch')
+ .pointerMove(0, 0, {origin: done_button})
+ .pointerDown()
+ .addTick()
+ .addTick()
+ .pointerUp()
+ .send();
+ return actionPromise.then(pointerupPromise);
+ }
+
+ const test_fixture = async_test("All events handled");
+ const listeners = {};
+ const attachListener = (testPrefix, target, type, expectations,
+ elements) => {
+ expectations.type = type;
+ const pointer_ids = {};
+ const key = `${testPrefix} ${type}`;
+ const listener = (event) => {
+ if (pointer_ids[testPrefix] == undefined) {
+ pointer_ids[testPrefix] == event.pointerId;
+ } else {
+ test(() => {
+ assert_equals(event.pointerId, pointer_ids[testPrefix]);
+ }, `${testPrefix} touch.pointerId matches expectation`);
+ }
+ // Don't let the browser handle the event to help guard against
+ // potential memory leaks.
+ event.preventDefault();
+ checkPointerEventAttributes(testPrefix, event, expectations);
+ target.removeEventListener(type, listener);
+ delete listeners[key];
+ };
+ target.addEventListener(type, listener);
+ listeners[key] = listener;
+ };
+
+ const square1 = document.getElementById("square1");
+ const innerFrame = document.getElementById('innerFrame');
+ const square2 = innerFrame.contentDocument.getElementById('square2');
+ const expectations = {
+ pointerover: { button: 0, buttons: 1 },
+ pointerenter: { button: 0, buttons: 1 },
+ pointerdown: { button: 0, buttons: 1 },
+ pointermove: { button: -1, buttons: 1 },
+ pointerup: { button: 0, buttons: 0 },
+ pointerout: { button: 0, buttons: 0 },
+ pointerleave: { button: 0, buttons: 0 },
+ };
+ event_list.forEach(type => {
+ attachListener('', square1, type, expectations[type]);
+ attachListener('inner frame', square2, type, expectations[type]);
+ });
+ await injectScrub(square1);
+ await injectScrub(square2);
+ await tapDone();
+
+ test_fixture.step(() => {
+ assert_equals(
+ Object.keys(listeners).length, 0,
+ `Missing tests for ${Object.keys(listeners).join(', ')}`);
+ test_fixture.done();
+ });
+ };
+</script>
+<body>
+ <div id="square1"></div>
+ <div>
+ <iframe id="innerFrame" srcdoc='
+ <style>
+ html {
+ touch-action: none;
+ }
+ #square2 {
+ background-color: green;
+ border: 1px solid black;
+ height: 50px;
+ width: 50px;
+ display: inline-block;
+ }
+ </style>
+ <body>
+ <div id="square2"></div>
+ </body>
+ '></iframe>
+ </div>
+ <!-- Used to detect a sentinel event. Once triggered, all other events must
+ have been processed. -->
+ <div>
+ <button id="done">done</button>
+ </div>
+</body>
+</html>
diff --git a/pointerevents/resources/pointerevent_attributes_hoverable_pointers-iframe.html b/pointerevents/resources/pointerevent_attributes_hoverable_pointers-iframe.html
new file mode 100644
index 0000000..5e55868
--- /dev/null
+++ b/pointerevents/resources/pointerevent_attributes_hoverable_pointers-iframe.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
+ </head>
+ <body>
+ <div id="square2" class="square"></div>
+ </body>
+</html>