/* 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 ); }