diff options
Diffstat (limited to 'gfx/layers/apz/test/mochitest/helper_hittest_overscroll.html')
-rw-r--r-- | gfx/layers/apz/test/mochitest/helper_hittest_overscroll.html | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/gfx/layers/apz/test/mochitest/helper_hittest_overscroll.html b/gfx/layers/apz/test/mochitest/helper_hittest_overscroll.html new file mode 100644 index 0000000000..c245258b68 --- /dev/null +++ b/gfx/layers/apz/test/mochitest/helper_hittest_overscroll.html @@ -0,0 +1,249 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test APZ hit-testing while overscrolled</title> + <script type="application/javascript" src="apz_test_utils.js"></script> + <script type="application/javascript" src="apz_test_native_event_utils.js"></script> + <script src="/tests/SimpleTest/paint_listener.js"></script> + <meta name="viewport" content="width=device-width"/> + <style> + html, body { + margin: 0; + padding: 0; + } + .spacer { + height: 5000px; + } + #target { + margin-left: 100px; + margin-top: 2px; + height: 4px; + width: 4px; + background: red; + } + #fixedtarget { + left: 300px; + height: 20px; + width: 5px; + top: 2px; + background: green; + position: fixed; + } + #fixedtargetbutton { + height: 10px; + width: 5px; + padding: 0; + margin-top: 10; + margin-left: 0; + border: 0; + } + </style> +</head> +<body> + <div id="target"></div> + <div id="fixedtarget"> + <button id="fixedtargetbutton"> + </button> + </div> + <div id="spacer" class="spacer"></div> +</body> +<script type="application/javascript"> + +// Some helper functions for listening for click events in the browser chrome. + +// A handle used to interact with the chrome script used to implement +// [start|stop]ListeningFOrClickEventsInChrome(). +let chromeScriptHandle = null; + +function startListeningForClickEventsInChrome() { + function chromeScript() { + /* eslint-env mozilla/chrome-script */ + let topWin = Services.wm.getMostRecentWindow("navigator:browser"); + if (!topWin) { + topWin = Services.wm.getMostRecentWindow("navigator:geckoview"); + } + let chromeReceivedClick = false; + function chromeListener(e) { + chromeReceivedClick = true; + } + topWin.addEventListener("click", chromeListener); + function queryClicked() { + sendAsyncMessage("query-clicked-response", { chromeReceivedClick }); + } + function cleanup() { + topWin.removeEventListener("click", chromeListener); + removeMessageListener("query-clicked", queryClicked); + removeMessageListener("cleanup", cleanup); + } + addMessageListener("query-clicked", queryClicked); + addMessageListener("cleanup", cleanup); + } + chromeScriptHandle = SpecialPowers.loadChromeScript(chromeScript); +} + +async function didChromeReceiveClick() { + chromeScriptHandle.sendAsyncMessage("query-clicked", null); + let response = await chromeScriptHandle.promiseOneMessage("query-clicked-response"); + ok(response && ("chromeReceivedClick" in response), + "Received a well-formed response from chrome script"); + return response.chromeReceivedClick; +} + +function stopListeningForClickEventsInChrome() { + chromeScriptHandle.sendAsyncMessage("cleanup", null); + chromeScriptHandle.destroy(); +} + +async function test() { + var config = getHitTestConfig(); + var utils = config.utils; + + // Overscroll the root scroll frame at the top, creating a gutter. + // Note that the size of the gutter will only be 8px, because + // setAsyncScrollOffset() applies the overscroll as a single delta, + // and current APZ logic that transforms a delta into an overscroll + // amount limits each delta to at most 8px. + utils.setAsyncScrollOffset(document.documentElement, 0, -200); + + // Check that the event hits the root scroll frame in APZ. + // This is important because additional pan-gesture events in the gutter + // should continue to be handled and cause further overscroll (or + // relieving overscroll, depending on their direction). + let hitResult = hitTest({x: 100, y: 4}); + let rootViewId = utils.getViewId(document.documentElement); + checkHitResult(hitResult, + APZHitResultFlags.VISIBLE, + rootViewId, + utils.getLayersId(), + "APZ hit-test in the root gutter"); + + // Now, perform a click in the gutter and check that APZ prevents + // the event from reaching Gecko. + // To be sure that no event was dispatched to Gecko, install listeners + // on both the browser chrome window and the content window. + // This makes sure we catch the case where the overscroll transform causes + // the event to incorrectly target the browser chrome. + + //// Util function to perform mouse events in the gutter. Used to ensure these + //// events are not dispatched to the content. + async function clickInGutter(xOffset, yOffset) { + startListeningForClickEventsInChrome(); + let contentReceivedClick = false; + let contentListener = function(e) { + info("event clientX = " + e.clientX); + info("event clientY = " + e.clientY); + info("event target id: " + e.target.id); + contentReceivedClick = true; + }; + document.addEventListener("click", contentListener); + await synthesizeNativeMouseEventWithAPZ({ + type: "click", + target: window, + offsetX: xOffset, + offsetY: yOffset, + }); + // Wait 10 frames for the event to maybe arrive, and if it + // hasn't, assume it won't. + for (let i = 0; i < 10; i++) { + await promiseFrame(); + } + info("Finished waiting around for click event"); + let chromeReceivedClick = await didChromeReceiveClick(); + ok(!chromeReceivedClick, + "Gecko received click event in browser chrome when it shouldn't have"); + ok(!contentReceivedClick, + "Gecko received click event targeting web content when it shouldn't have"); + stopListeningForClickEventsInChrome(); + document.removeEventListener("click", contentListener); + } + + // Perform the test + await clickInGutter(100, 4); + + // Finally, while still overscrolled, perform a click not in the gutter. + // This event should successfully go through to the web content, and + // be untransformed by the overscroll transform (such that it hits the + // content that is visually under the cursor). + let clickPromise = new Promise(resolve => { + document.addEventListener("click", function(e) { + info("event clientX = " + e.clientX); + info("event clientY = " + e.clientY); + is(e.target, target, "Click while overscrolled hit intended target"); + resolve(); + }, { once: true }); + }); + await synthesizeNativeMouseEventWithAPZ({ + type: "click", + target: window, + offsetX: 102, + offsetY: 12, + }); + await clickPromise; + + // Test that mouse events targetting the fixed content are dispatched + // to the content. + async function clickFixed(yOffset, expectedTarget) { + let clickFixedPromise = new Promise(resolve => { + document.addEventListener("click", function(e) { + info("event clientX = " + e.clientX); + info("event clientY = " + e.clientY); + info("event target id: " + e.target.id); + is(e.target, expectedTarget, "Click while overscrolled hit intended target"); + resolve(); + }, { once: true }); + }); + await synthesizeNativeMouseEventWithAPZ({ + type: "click", + target: window, + offsetX: 302, + offsetY: yOffset, + }); + await clickFixedPromise; + } + + // This hit is technically in the gutter created by the overscroll, but we + // should still dispatch to gecko due to the fixed element extending into + // the gutter. + await clickFixed(4, fixedtarget, false); + // Perform various mouse events to ensure the fixed element has not moved + await clickFixed(10, fixedtarget, false); + await clickFixed(14, fixedtargetbutton, false); + await clickFixed(18, fixedtargetbutton, false); + + let clickFixedPromise = new Promise(resolve => { + document.addEventListener("click", function(e) { + info("event clientX = " + e.clientX); + info("event clientY = " + e.clientY); + info("event target id: " + e.target.id); + // TODO(dlrobertson): What exists directly below the fixed element? + // Should there be a gutter below the fixed element? Or should events + // directed below the fixed element be dispatched normally. In the + // transform of the mouse event, the hit will not have any side bits + // set and we will transform the hit result. As a result, 25 will be + // transformed to ~17, and the event will be dispatched to the fixed + // element. + todo(false, + "Click while overscrolled hit intended target below fixed content"); + resolve(); + }, { once: true }); + }); + await synthesizeNativeMouseEventWithAPZ({ + type: "click", + target: window, + offsetX: 302, + offsetY: 25, + }); + await clickFixedPromise; + + // Click above the fixed element, but in the gutter. + await clickInGutter(302, 1); + // Click left of the the fixed element, but in the gutter. + await clickInGutter(298, 4); +} + +waitUntilApzStable() +.then(test) +.then(subtestDone, subtestFailed); + +</script> +</html> |