From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../content/test/general/browser_gestureSupport.js | 1132 ++++++++++++++++++++ 1 file changed, 1132 insertions(+) create mode 100644 browser/base/content/test/general/browser_gestureSupport.js (limited to 'browser/base/content/test/general/browser_gestureSupport.js') diff --git a/browser/base/content/test/general/browser_gestureSupport.js b/browser/base/content/test/general/browser_gestureSupport.js new file mode 100644 index 0000000000..d8f0331268 --- /dev/null +++ b/browser/base/content/test/general/browser_gestureSupport.js @@ -0,0 +1,1132 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/gfx/layers/apz/test/mochitest/apz_test_utils.js", + this +); + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js", + this +); + +// Simple gestures tests +// +// Some of these tests require the ability to disable the fact that the +// Firefox chrome intentionally prevents "simple gesture" events from +// reaching web content. + +var test_utils; +var test_commandset; +var test_prefBranch = "browser.gesture."; +var test_normalTab; + +async function test() { + waitForExplicitFinish(); + + // Disable the default gestures support during this part of the test + gGestureSupport.init(false); + + test_utils = window.windowUtils; + + // Run the tests of "simple gesture" events generally + test_EnsureConstantsAreDisjoint(); + test_TestEventListeners(); + test_TestEventCreation(); + + // Reenable the default gestures support. The remaining tests target + // the Firefox gesture functionality. + gGestureSupport.init(true); + + const aPage = "about:about"; + test_normalTab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + aPage, + true /* waitForLoad */ + ); + + // Test Firefox's gestures support. + test_commandset = document.getElementById("mainCommandSet"); + await test_swipeGestures(); + await test_latchedGesture("pinch", "out", "in", "MozMagnifyGesture"); + await test_thresholdGesture("pinch", "out", "in", "MozMagnifyGesture"); + test_rotateGestures(); +} + +var test_eventCount = 0; +var test_expectedType; +var test_expectedDirection; +var test_expectedDelta; +var test_expectedModifiers; +var test_expectedClickCount; +var test_imageTab; + +function test_gestureListener(evt) { + is( + evt.type, + test_expectedType, + "evt.type (" + evt.type + ") does not match expected value" + ); + is( + evt.target, + test_utils.elementFromPoint(60, 60, false, false), + "evt.target (" + evt.target + ") does not match expected value" + ); + is( + evt.clientX, + 60, + "evt.clientX (" + evt.clientX + ") does not match expected value" + ); + is( + evt.clientY, + 60, + "evt.clientY (" + evt.clientY + ") does not match expected value" + ); + isnot( + evt.screenX, + 0, + "evt.screenX (" + evt.screenX + ") does not match expected value" + ); + isnot( + evt.screenY, + 0, + "evt.screenY (" + evt.screenY + ") does not match expected value" + ); + + is( + evt.direction, + test_expectedDirection, + "evt.direction (" + evt.direction + ") does not match expected value" + ); + is( + evt.delta, + test_expectedDelta, + "evt.delta (" + evt.delta + ") does not match expected value" + ); + + is( + evt.shiftKey, + (test_expectedModifiers & Event.SHIFT_MASK) != 0, + "evt.shiftKey did not match expected value" + ); + is( + evt.ctrlKey, + (test_expectedModifiers & Event.CONTROL_MASK) != 0, + "evt.ctrlKey did not match expected value" + ); + is( + evt.altKey, + (test_expectedModifiers & Event.ALT_MASK) != 0, + "evt.altKey did not match expected value" + ); + is( + evt.metaKey, + (test_expectedModifiers & Event.META_MASK) != 0, + "evt.metaKey did not match expected value" + ); + + if (evt.type == "MozTapGesture") { + is( + evt.clickCount, + test_expectedClickCount, + "evt.clickCount does not match" + ); + } + + test_eventCount++; +} + +function test_helper1(type, direction, delta, modifiers) { + // Setup the expected values + test_expectedType = type; + test_expectedDirection = direction; + test_expectedDelta = delta; + test_expectedModifiers = modifiers; + + let expectedEventCount = test_eventCount + 1; + + document.addEventListener(type, test_gestureListener, true); + test_utils.sendSimpleGestureEvent(type, 60, 60, direction, delta, modifiers); + document.removeEventListener(type, test_gestureListener, true); + + is( + expectedEventCount, + test_eventCount, + "Event (" + type + ") was never received by event listener" + ); +} + +function test_clicks(type, clicks) { + // Setup the expected values + test_expectedType = type; + test_expectedDirection = 0; + test_expectedDelta = 0; + test_expectedModifiers = 0; + test_expectedClickCount = clicks; + + let expectedEventCount = test_eventCount + 1; + + document.addEventListener(type, test_gestureListener, true); + test_utils.sendSimpleGestureEvent(type, 60, 60, 0, 0, 0, clicks); + document.removeEventListener(type, test_gestureListener, true); + + is( + expectedEventCount, + test_eventCount, + "Event (" + type + ") was never received by event listener" + ); +} + +function test_TestEventListeners() { + let e = test_helper1; // easier to type this name + + // Swipe gesture animation events + e("MozSwipeGestureStart", 0, -0.7, 0); + e("MozSwipeGestureUpdate", 0, -0.4, 0); + e("MozSwipeGestureEnd", 0, 0, 0); + e("MozSwipeGestureStart", 0, 0.6, 0); + e("MozSwipeGestureUpdate", 0, 0.3, 0); + e("MozSwipeGestureEnd", 0, 1, 0); + + // Swipe gesture event + e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_LEFT, 0.0, 0); + e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_RIGHT, 0.0, 0); + e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_UP, 0.0, 0); + e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_DOWN, 0.0, 0); + e( + "MozSwipeGesture", + SimpleGestureEvent.DIRECTION_UP | SimpleGestureEvent.DIRECTION_LEFT, + 0.0, + 0 + ); + e( + "MozSwipeGesture", + SimpleGestureEvent.DIRECTION_DOWN | SimpleGestureEvent.DIRECTION_RIGHT, + 0.0, + 0 + ); + e( + "MozSwipeGesture", + SimpleGestureEvent.DIRECTION_UP | SimpleGestureEvent.DIRECTION_RIGHT, + 0.0, + 0 + ); + e( + "MozSwipeGesture", + SimpleGestureEvent.DIRECTION_DOWN | SimpleGestureEvent.DIRECTION_LEFT, + 0.0, + 0 + ); + + // magnify gesture events + e("MozMagnifyGestureStart", 0, 50.0, 0); + e("MozMagnifyGestureUpdate", 0, -25.0, 0); + e("MozMagnifyGestureUpdate", 0, 5.0, 0); + e("MozMagnifyGesture", 0, 30.0, 0); + + // rotate gesture events + e("MozRotateGestureStart", SimpleGestureEvent.ROTATION_CLOCKWISE, 33.0, 0); + e( + "MozRotateGestureUpdate", + SimpleGestureEvent.ROTATION_COUNTERCLOCKWISE, + -13.0, + 0 + ); + e("MozRotateGestureUpdate", SimpleGestureEvent.ROTATION_CLOCKWISE, 13.0, 0); + e("MozRotateGesture", SimpleGestureEvent.ROTATION_CLOCKWISE, 33.0, 0); + + // Tap and presstap gesture events + test_clicks("MozTapGesture", 1); + test_clicks("MozTapGesture", 2); + test_clicks("MozTapGesture", 3); + test_clicks("MozPressTapGesture", 1); + + // simple delivery test for edgeui gestures + e("MozEdgeUIStarted", 0, 0, 0); + e("MozEdgeUICanceled", 0, 0, 0); + e("MozEdgeUICompleted", 0, 0, 0); + + // event.shiftKey + let modifier = Event.SHIFT_MASK; + e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_RIGHT, 0, modifier); + + // event.metaKey + modifier = Event.META_MASK; + e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_RIGHT, 0, modifier); + + // event.altKey + modifier = Event.ALT_MASK; + e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_RIGHT, 0, modifier); + + // event.ctrlKey + modifier = Event.CONTROL_MASK; + e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_RIGHT, 0, modifier); +} + +function test_eventDispatchListener(evt) { + test_eventCount++; + evt.stopPropagation(); +} + +function test_helper2( + type, + direction, + delta, + altKey, + ctrlKey, + shiftKey, + metaKey +) { + let event = null; + let successful; + + try { + event = document.createEvent("SimpleGestureEvent"); + successful = true; + } catch (ex) { + successful = false; + } + ok(successful, "Unable to create SimpleGestureEvent"); + + try { + event.initSimpleGestureEvent( + type, + true, + true, + window, + 1, + 10, + 10, + 10, + 10, + ctrlKey, + altKey, + shiftKey, + metaKey, + 1, + window, + 0, + direction, + delta, + 0 + ); + successful = true; + } catch (ex) { + successful = false; + } + ok(successful, "event.initSimpleGestureEvent should not fail"); + + // Make sure the event fields match the expected values + is(event.type, type, "Mismatch on evt.type"); + is(event.direction, direction, "Mismatch on evt.direction"); + is(event.delta, delta, "Mismatch on evt.delta"); + is(event.altKey, altKey, "Mismatch on evt.altKey"); + is(event.ctrlKey, ctrlKey, "Mismatch on evt.ctrlKey"); + is(event.shiftKey, shiftKey, "Mismatch on evt.shiftKey"); + is(event.metaKey, metaKey, "Mismatch on evt.metaKey"); + is(event.view, window, "Mismatch on evt.view"); + is(event.detail, 1, "Mismatch on evt.detail"); + is(event.clientX, 10, "Mismatch on evt.clientX"); + is(event.clientY, 10, "Mismatch on evt.clientY"); + is(event.screenX, 10, "Mismatch on evt.screenX"); + is(event.screenY, 10, "Mismatch on evt.screenY"); + is(event.button, 1, "Mismatch on evt.button"); + is(event.relatedTarget, window, "Mismatch on evt.relatedTarget"); + + // Test event dispatch + let expectedEventCount = test_eventCount + 1; + document.addEventListener(type, test_eventDispatchListener, true); + document.dispatchEvent(event); + document.removeEventListener(type, test_eventDispatchListener, true); + is( + expectedEventCount, + test_eventCount, + "Dispatched event was never received by listener" + ); +} + +function test_TestEventCreation() { + // Event creation + test_helper2( + "MozMagnifyGesture", + SimpleGestureEvent.DIRECTION_RIGHT, + 20.0, + true, + false, + true, + false + ); + test_helper2( + "MozMagnifyGesture", + SimpleGestureEvent.DIRECTION_LEFT, + -20.0, + false, + true, + false, + true + ); +} + +function test_EnsureConstantsAreDisjoint() { + let up = SimpleGestureEvent.DIRECTION_UP; + let down = SimpleGestureEvent.DIRECTION_DOWN; + let left = SimpleGestureEvent.DIRECTION_LEFT; + let right = SimpleGestureEvent.DIRECTION_RIGHT; + + let clockwise = SimpleGestureEvent.ROTATION_CLOCKWISE; + let cclockwise = SimpleGestureEvent.ROTATION_COUNTERCLOCKWISE; + + ok(up ^ down, "DIRECTION_UP and DIRECTION_DOWN are not bitwise disjoint"); + ok(up ^ left, "DIRECTION_UP and DIRECTION_LEFT are not bitwise disjoint"); + ok(up ^ right, "DIRECTION_UP and DIRECTION_RIGHT are not bitwise disjoint"); + ok(down ^ left, "DIRECTION_DOWN and DIRECTION_LEFT are not bitwise disjoint"); + ok( + down ^ right, + "DIRECTION_DOWN and DIRECTION_RIGHT are not bitwise disjoint" + ); + ok( + left ^ right, + "DIRECTION_LEFT and DIRECTION_RIGHT are not bitwise disjoint" + ); + ok( + clockwise ^ cclockwise, + "ROTATION_CLOCKWISE and ROTATION_COUNTERCLOCKWISE are not bitwise disjoint" + ); +} + +// Helper for test of latched event processing. Emits the actual +// gesture events to test whether the commands associated with the +// gesture will only trigger once for each direction of movement. +async function test_emitLatchedEvents(eventPrefix, initialDelta, cmd) { + let cumulativeDelta = 0; + let isIncreasing = initialDelta > 0; + + let expect = {}; + // Reset the call counters and initialize expected values + for (let dir in cmd) { + cmd[dir].callCount = expect[dir] = 0; + } + + let check = (aDir, aMsg) => ok(cmd[aDir].callCount == expect[aDir], aMsg); + let checkBoth = function (aNum, aInc, aDec) { + let prefix = "Step " + aNum + ": "; + check("inc", prefix + aInc); + check("dec", prefix + aDec); + }; + + // Send the "Start" event. + await synthesizeSimpleGestureEvent( + test_normalTab.linkedBrowser, + eventPrefix + "Start", + 10, + 10, + 0, + initialDelta, + 0, + 0 + ); + cumulativeDelta += initialDelta; + if (isIncreasing) { + expect.inc++; + checkBoth( + 1, + "Increasing command was not triggered", + "Decreasing command was triggered" + ); + } else { + expect.dec++; + checkBoth( + 1, + "Increasing command was triggered", + "Decreasing command was not triggered" + ); + } + + // Send random values in the same direction and ensure neither + // command triggers. + for (let i = 0; i < 5; i++) { + let delta = Math.random() * (isIncreasing ? 100 : -100); + + await synthesizeSimpleGestureEvent( + test_normalTab.linkedBrowser, + eventPrefix + "Update", + 10, + 10, + 0, + delta, + 0, + 0 + ); + cumulativeDelta += delta; + checkBoth( + 2, + "Increasing command was triggered", + "Decreasing command was triggered" + ); + } + + // Now go back in the opposite direction. + await synthesizeSimpleGestureEvent( + test_normalTab.linkedBrowser, + eventPrefix + "Update", + 10, + 10, + 0, + -initialDelta, + 0, + 0 + ); + cumulativeDelta += -initialDelta; + if (isIncreasing) { + expect.dec++; + checkBoth( + 3, + "Increasing command was triggered", + "Decreasing command was not triggered" + ); + } else { + expect.inc++; + checkBoth( + 3, + "Increasing command was not triggered", + "Decreasing command was triggered" + ); + } + + // Send random values in the opposite direction and ensure neither + // command triggers. + for (let i = 0; i < 5; i++) { + let delta = Math.random() * (isIncreasing ? -100 : 100); + await synthesizeSimpleGestureEvent( + test_normalTab.linkedBrowser, + eventPrefix + "Update", + 10, + 10, + 0, + delta, + 0, + 0 + ); + cumulativeDelta += delta; + checkBoth( + 4, + "Increasing command was triggered", + "Decreasing command was triggered" + ); + } + + // Go back to the original direction. The original command should trigger. + await synthesizeSimpleGestureEvent( + test_normalTab.linkedBrowser, + eventPrefix + "Update", + 10, + 10, + 0, + initialDelta, + 0, + 0 + ); + cumulativeDelta += initialDelta; + if (isIncreasing) { + expect.inc++; + checkBoth( + 5, + "Increasing command was not triggered", + "Decreasing command was triggered" + ); + } else { + expect.dec++; + checkBoth( + 5, + "Increasing command was triggered", + "Decreasing command was not triggered" + ); + } + + // Send the wrap-up event. No commands should be triggered. + await synthesizeSimpleGestureEvent( + test_normalTab.linkedBrowser, + eventPrefix, + 10, + 10, + 0, + cumulativeDelta, + 0, + 0 + ); + checkBoth( + 6, + "Increasing command was triggered", + "Decreasing command was triggered" + ); +} + +function test_addCommand(prefName, id) { + let cmd = test_commandset.appendChild(document.createXULElement("command")); + cmd.setAttribute("id", id); + cmd.setAttribute("oncommand", "this.callCount++;"); + + cmd.origPrefName = prefName; + cmd.origPrefValue = Services.prefs.getCharPref(prefName); + Services.prefs.setCharPref(prefName, id); + + return cmd; +} + +function test_removeCommand(cmd) { + Services.prefs.setCharPref(cmd.origPrefName, cmd.origPrefValue); + test_commandset.removeChild(cmd); +} + +// Test whether latched events are only called once per direction of motion. +async function test_latchedGesture(gesture, inc, dec, eventPrefix) { + let branch = test_prefBranch + gesture + "."; + + // Put the gesture into latched mode. + let oldLatchedValue = Services.prefs.getBoolPref(branch + "latched"); + Services.prefs.setBoolPref(branch + "latched", true); + + // Install the test commands for increasing and decreasing motion. + let cmd = { + inc: test_addCommand(branch + inc, "test:incMotion"), + dec: test_addCommand(branch + dec, "test:decMotion"), + }; + + // Test the gestures in each direction. + await test_emitLatchedEvents(eventPrefix, 500, cmd); + await test_emitLatchedEvents(eventPrefix, -500, cmd); + + // Restore the gesture to its original configuration. + Services.prefs.setBoolPref(branch + "latched", oldLatchedValue); + for (let dir in cmd) { + test_removeCommand(cmd[dir]); + } +} + +// Test whether non-latched events are triggered upon sufficient motion. +async function test_thresholdGesture(gesture, inc, dec, eventPrefix) { + let branch = test_prefBranch + gesture + "."; + + // Disable latched mode for this gesture. + let oldLatchedValue = Services.prefs.getBoolPref(branch + "latched"); + Services.prefs.setBoolPref(branch + "latched", false); + + // Set the triggering threshold value to 50. + let oldThresholdValue = Services.prefs.getIntPref(branch + "threshold"); + Services.prefs.setIntPref(branch + "threshold", 50); + + // Install the test commands for increasing and decreasing motion. + let cmdInc = test_addCommand(branch + inc, "test:incMotion"); + let cmdDec = test_addCommand(branch + dec, "test:decMotion"); + + // Send the start event but stop short of triggering threshold. + cmdInc.callCount = cmdDec.callCount = 0; + await synthesizeSimpleGestureEvent( + test_normalTab.linkedBrowser, + eventPrefix + "Start", + 10, + 10, + 0, + 49.5, + 0, + 0 + ); + ok(cmdInc.callCount == 0, "Increasing command was triggered"); + ok(cmdDec.callCount == 0, "Decreasing command was triggered"); + + // Now trigger the threshold. + cmdInc.callCount = cmdDec.callCount = 0; + await synthesizeSimpleGestureEvent( + test_normalTab.linkedBrowser, + eventPrefix + "Update", + 10, + 10, + 0, + 1, + 0, + 0 + ); + ok(cmdInc.callCount == 1, "Increasing command was not triggered"); + ok(cmdDec.callCount == 0, "Decreasing command was triggered"); + + // The tracking counter should go to zero. Go back the other way and + // stop short of triggering the threshold. + cmdInc.callCount = cmdDec.callCount = 0; + await synthesizeSimpleGestureEvent( + test_normalTab.linkedBrowser, + eventPrefix + "Update", + 10, + 10, + 0, + -49.5, + 0, + 0 + ); + ok(cmdInc.callCount == 0, "Increasing command was triggered"); + ok(cmdDec.callCount == 0, "Decreasing command was triggered"); + + // Now cross the threshold and trigger the decreasing command. + cmdInc.callCount = cmdDec.callCount = 0; + await synthesizeSimpleGestureEvent( + test_normalTab.linkedBrowser, + eventPrefix + "Update", + 10, + 10, + 0, + -1.5, + 0, + 0 + ); + ok(cmdInc.callCount == 0, "Increasing command was triggered"); + ok(cmdDec.callCount == 1, "Decreasing command was not triggered"); + + // Send the wrap-up event. No commands should trigger. + cmdInc.callCount = cmdDec.callCount = 0; + await synthesizeSimpleGestureEvent( + test_normalTab.linkedBrowser, + eventPrefix, + 0, + 0, + 0, + -0.5, + 0, + 0 + ); + ok(cmdInc.callCount == 0, "Increasing command was triggered"); + ok(cmdDec.callCount == 0, "Decreasing command was triggered"); + + // Restore the gesture to its original configuration. + Services.prefs.setBoolPref(branch + "latched", oldLatchedValue); + Services.prefs.setIntPref(branch + "threshold", oldThresholdValue); + test_removeCommand(cmdInc); + test_removeCommand(cmdDec); +} + +async function test_swipeGestures() { + // easier to type names for the direction constants + let up = SimpleGestureEvent.DIRECTION_UP; + let down = SimpleGestureEvent.DIRECTION_DOWN; + let left = SimpleGestureEvent.DIRECTION_LEFT; + let right = SimpleGestureEvent.DIRECTION_RIGHT; + + let branch = test_prefBranch + "swipe."; + + // Install the test commands for the swipe gestures. + let cmdUp = test_addCommand(branch + "up", "test:swipeUp"); + let cmdDown = test_addCommand(branch + "down", "test:swipeDown"); + let cmdLeft = test_addCommand(branch + "left", "test:swipeLeft"); + let cmdRight = test_addCommand(branch + "right", "test:swipeRight"); + + function resetCounts() { + cmdUp.callCount = 0; + cmdDown.callCount = 0; + cmdLeft.callCount = 0; + cmdRight.callCount = 0; + } + + // UP + resetCounts(); + await synthesizeSimpleGestureEvent( + test_normalTab.linkedBrowser, + "MozSwipeGesture", + 10, + 10, + up, + 0, + 0, + 0 + ); + ok(cmdUp.callCount == 1, "Step 1: Up command was not triggered"); + ok(cmdDown.callCount == 0, "Step 1: Down command was triggered"); + ok(cmdLeft.callCount == 0, "Step 1: Left command was triggered"); + ok(cmdRight.callCount == 0, "Step 1: Right command was triggered"); + + // DOWN + resetCounts(); + await synthesizeSimpleGestureEvent( + test_normalTab.linkedBrowser, + "MozSwipeGesture", + 10, + 10, + down, + 0, + 0, + 0 + ); + ok(cmdUp.callCount == 0, "Step 2: Up command was triggered"); + ok(cmdDown.callCount == 1, "Step 2: Down command was not triggered"); + ok(cmdLeft.callCount == 0, "Step 2: Left command was triggered"); + ok(cmdRight.callCount == 0, "Step 2: Right command was triggered"); + + // LEFT + resetCounts(); + await synthesizeSimpleGestureEvent( + test_normalTab.linkedBrowser, + "MozSwipeGesture", + 10, + 10, + left, + 0, + 0, + 0 + ); + ok(cmdUp.callCount == 0, "Step 3: Up command was triggered"); + ok(cmdDown.callCount == 0, "Step 3: Down command was triggered"); + ok(cmdLeft.callCount == 1, "Step 3: Left command was not triggered"); + ok(cmdRight.callCount == 0, "Step 3: Right command was triggered"); + + // RIGHT + resetCounts(); + await synthesizeSimpleGestureEvent( + test_normalTab.linkedBrowser, + "MozSwipeGesture", + 10, + 10, + right, + 0, + 0, + 0 + ); + ok(cmdUp.callCount == 0, "Step 4: Up command was triggered"); + ok(cmdDown.callCount == 0, "Step 4: Down command was triggered"); + ok(cmdLeft.callCount == 0, "Step 4: Left command was triggered"); + ok(cmdRight.callCount == 1, "Step 4: Right command was not triggered"); + + // Make sure combinations do not trigger events. + let combos = [up | left, up | right, down | left, down | right]; + for (let i = 0; i < combos.length; i++) { + resetCounts(); + await synthesizeSimpleGestureEvent( + test_normalTab.linkedBrowser, + "MozSwipeGesture", + 10, + 10, + combos[i], + 0, + 0, + 0 + ); + ok(cmdUp.callCount == 0, "Step 5-" + i + ": Up command was triggered"); + ok(cmdDown.callCount == 0, "Step 5-" + i + ": Down command was triggered"); + ok(cmdLeft.callCount == 0, "Step 5-" + i + ": Left command was triggered"); + ok( + cmdRight.callCount == 0, + "Step 5-" + i + ": Right command was triggered" + ); + } + + // Remove the test commands. + test_removeCommand(cmdUp); + test_removeCommand(cmdDown); + test_removeCommand(cmdLeft); + test_removeCommand(cmdRight); +} + +function test_rotateHelperGetImageRotation(aImageElement) { + // Get the true image rotation from the transform matrix, bounded + // to 0 <= result < 360 + let transformValue = content.window.getComputedStyle(aImageElement).transform; + if (transformValue == "none") { + return 0; + } + + transformValue = transformValue.split("(")[1].split(")")[0].split(","); + var rotation = Math.round( + Math.atan2(transformValue[1], transformValue[0]) * (180 / Math.PI) + ); + return rotation < 0 ? rotation + 360 : rotation; +} + +async function test_rotateHelperOneGesture( + aImageElement, + aCurrentRotation, + aDirection, + aAmount, + aStop +) { + if (aAmount <= 0 || aAmount > 90) { + // Bound to 0 < aAmount <= 90 + return; + } + + // easier to type names for the direction constants + let clockwise = SimpleGestureEvent.ROTATION_CLOCKWISE; + + let delta = aAmount * (aDirection == clockwise ? 1 : -1); + + // Kill transition time on image so test isn't wrong and doesn't take 10 seconds + aImageElement.style.transitionDuration = "0s"; + + // Start the gesture, perform an update, and force flush + await synthesizeSimpleGestureEvent( + test_imageTab.linkedBrowser, + "MozRotateGestureStart", + 10, + 10, + aDirection, + 0.001, + 0, + 0 + ); + await synthesizeSimpleGestureEvent( + test_imageTab.linkedBrowser, + "MozRotateGestureUpdate", + 10, + 10, + aDirection, + delta, + 0, + 0 + ); + aImageElement.clientTop; + + // If stop, check intermediate + if (aStop) { + // Send near-zero-delta to stop, and force flush + await synthesizeSimpleGestureEvent( + test_imageTab.linkedBrowser, + "MozRotateGestureUpdate", + 10, + 10, + aDirection, + 0.001, + 0, + 0 + ); + aImageElement.clientTop; + + let stopExpectedRotation = (aCurrentRotation + delta) % 360; + if (stopExpectedRotation < 0) { + stopExpectedRotation += 360; + } + + is( + stopExpectedRotation, + test_rotateHelperGetImageRotation(aImageElement), + "Image rotation at gesture stop/hold: expected=" + + stopExpectedRotation + + ", observed=" + + test_rotateHelperGetImageRotation(aImageElement) + + ", init=" + + aCurrentRotation + + ", amt=" + + aAmount + + ", dir=" + + (aDirection == clockwise ? "cl" : "ccl") + ); + } + // End it and force flush + await synthesizeSimpleGestureEvent( + test_imageTab.linkedBrowser, + "MozRotateGesture", + 10, + 10, + aDirection, + 0, + 0, + 0 + ); + aImageElement.clientTop; + + let finalExpectedRotation; + + if (aAmount < 45 && aStop) { + // Rotate a bit, then stop. Expect no change at end of gesture. + finalExpectedRotation = aCurrentRotation; + } else { + // Either not stopping (expect 90 degree change in aDirection), OR + // stopping but after 45, (expect 90 degree change in aDirection) + finalExpectedRotation = + (aCurrentRotation + (aDirection == clockwise ? 1 : -1) * 90) % 360; + if (finalExpectedRotation < 0) { + finalExpectedRotation += 360; + } + } + + is( + finalExpectedRotation, + test_rotateHelperGetImageRotation(aImageElement), + "Image rotation gesture end: expected=" + + finalExpectedRotation + + ", observed=" + + test_rotateHelperGetImageRotation(aImageElement) + + ", init=" + + aCurrentRotation + + ", amt=" + + aAmount + + ", dir=" + + (aDirection == clockwise ? "cl" : "ccl") + ); +} + +async function test_rotateGesturesOnTab() { + gBrowser.selectedBrowser.removeEventListener( + "load", + test_rotateGesturesOnTab, + true + ); + + if (!ImageDocument.isInstance(content.document)) { + ok(false, "Image document failed to open for rotation testing"); + gBrowser.removeTab(test_imageTab); + BrowserTestUtils.removeTab(test_normalTab); + test_imageTab = null; + test_normalTab = null; + finish(); + return; + } + + // easier to type names for the direction constants + let cl = SimpleGestureEvent.ROTATION_CLOCKWISE; + let ccl = SimpleGestureEvent.ROTATION_COUNTERCLOCKWISE; + + let imgElem = + content.document.body && content.document.body.firstElementChild; + + if (!imgElem) { + ok(false, "Could not get image element on ImageDocument for rotation!"); + gBrowser.removeTab(test_imageTab); + BrowserTestUtils.removeTab(test_normalTab); + test_imageTab = null; + test_normalTab = null; + finish(); + return; + } + + // Quick function to normalize rotation to 0 <= r < 360 + var normRot = function (rotation) { + rotation = rotation % 360; + if (rotation < 0) { + rotation += 360; + } + return rotation; + }; + + for (var initRot = 0; initRot < 360; initRot += 90) { + // Test each case: at each 90 degree snap; cl/ccl; + // amount more or less than 45; stop and hold or don't (32 total tests) + // The amount added to the initRot is where it is expected to be + await test_rotateHelperOneGesture( + imgElem, + normRot(initRot + 0), + cl, + 35, + true + ); + await test_rotateHelperOneGesture( + imgElem, + normRot(initRot + 0), + cl, + 35, + false + ); + await test_rotateHelperOneGesture( + imgElem, + normRot(initRot + 90), + cl, + 55, + true + ); + await test_rotateHelperOneGesture( + imgElem, + normRot(initRot + 180), + cl, + 55, + false + ); + await test_rotateHelperOneGesture( + imgElem, + normRot(initRot + 270), + ccl, + 35, + true + ); + await test_rotateHelperOneGesture( + imgElem, + normRot(initRot + 270), + ccl, + 35, + false + ); + await test_rotateHelperOneGesture( + imgElem, + normRot(initRot + 180), + ccl, + 55, + true + ); + await test_rotateHelperOneGesture( + imgElem, + normRot(initRot + 90), + ccl, + 55, + false + ); + + // Manually rotate it 90 degrees clockwise to prepare for next iteration, + // and force flush + await synthesizeSimpleGestureEvent( + test_imageTab.linkedBrowser, + "MozRotateGestureStart", + 10, + 10, + cl, + 0.001, + 0, + 0 + ); + await synthesizeSimpleGestureEvent( + test_imageTab.linkedBrowser, + "MozRotateGestureUpdate", + 10, + 10, + cl, + 90, + 0, + 0 + ); + await synthesizeSimpleGestureEvent( + test_imageTab.linkedBrowser, + "MozRotateGestureUpdate", + 10, + 10, + cl, + 0.001, + 0, + 0 + ); + await synthesizeSimpleGestureEvent( + test_imageTab.linkedBrowser, + "MozRotateGesture", + 10, + 10, + cl, + 0, + 0, + 0 + ); + imgElem.clientTop; + } + + gBrowser.removeTab(test_imageTab); + BrowserTestUtils.removeTab(test_normalTab); + test_imageTab = null; + test_normalTab = null; + finish(); +} + +function test_rotateGestures() { + test_imageTab = BrowserTestUtils.addTab( + gBrowser, + "chrome://branding/content/about-logo.png" + ); + gBrowser.selectedTab = test_imageTab; + + gBrowser.selectedBrowser.addEventListener( + "load", + test_rotateGesturesOnTab, + true + ); +} -- cgit v1.2.3