browser_gestureSupport.js (29748B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 Services.scriptloader.loadSubScript( 6 "chrome://mochitests/content/browser/gfx/layers/apz/test/mochitest/apz_test_utils.js", 7 this 8 ); 9 10 Services.scriptloader.loadSubScript( 11 "chrome://mochitests/content/browser/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js", 12 this 13 ); 14 15 // Simple gestures tests 16 // 17 // Some of these tests require the ability to disable the fact that the 18 // Firefox chrome intentionally prevents "simple gesture" events from 19 // reaching web content. 20 21 var test_utils; 22 var test_commandset; 23 var test_prefBranch = "browser.gesture."; 24 var test_normalTab; 25 26 async function test() { 27 waitForExplicitFinish(); 28 29 await SpecialPowers.pushPrefEnv({ 30 set: [["test.wait300msAfterTabSwitch", true]], 31 }); 32 33 // Disable the default gestures support during this part of the test 34 gGestureSupport.init(false); 35 36 test_utils = window.windowUtils; 37 38 // Run the tests of "simple gesture" events generally 39 test_EnsureConstantsAreDisjoint(); 40 test_TestEventListeners(); 41 test_TestEventCreation(); 42 43 // Reenable the default gestures support. The remaining tests target 44 // the Firefox gesture functionality. 45 gGestureSupport.init(true); 46 47 const aPage = "about:about"; 48 test_normalTab = await BrowserTestUtils.openNewForegroundTab( 49 gBrowser, 50 aPage, 51 true /* waitForLoad */ 52 ); 53 54 // Test Firefox's gestures support. 55 test_commandset = document.getElementById("mainCommandSet"); 56 await test_swipeGestures(); 57 await test_latchedGesture("pinch", "out", "in", "MozMagnifyGesture"); 58 await test_thresholdGesture("pinch", "out", "in", "MozMagnifyGesture"); 59 test_rotateGestures(); 60 } 61 62 var test_eventCount = 0; 63 var test_expectedType; 64 var test_expectedDirection; 65 var test_expectedDelta; 66 var test_expectedModifiers; 67 var test_expectedClickCount; 68 var test_imageTab; 69 70 function test_gestureListener(evt) { 71 is( 72 evt.type, 73 test_expectedType, 74 "evt.type (" + evt.type + ") does not match expected value" 75 ); 76 is( 77 evt.target, 78 test_utils.elementFromPoint(60, 60, false, false), 79 "evt.target (" + evt.target + ") does not match expected value" 80 ); 81 is( 82 evt.clientX, 83 60, 84 "evt.clientX (" + evt.clientX + ") does not match expected value" 85 ); 86 is( 87 evt.clientY, 88 60, 89 "evt.clientY (" + evt.clientY + ") does not match expected value" 90 ); 91 isnot( 92 evt.screenX, 93 0, 94 "evt.screenX (" + evt.screenX + ") does not match expected value" 95 ); 96 isnot( 97 evt.screenY, 98 0, 99 "evt.screenY (" + evt.screenY + ") does not match expected value" 100 ); 101 102 is( 103 evt.direction, 104 test_expectedDirection, 105 "evt.direction (" + evt.direction + ") does not match expected value" 106 ); 107 is( 108 evt.delta, 109 test_expectedDelta, 110 "evt.delta (" + evt.delta + ") does not match expected value" 111 ); 112 113 is( 114 evt.shiftKey, 115 (test_expectedModifiers & Event.SHIFT_MASK) != 0, 116 "evt.shiftKey did not match expected value" 117 ); 118 is( 119 evt.ctrlKey, 120 (test_expectedModifiers & Event.CONTROL_MASK) != 0, 121 "evt.ctrlKey did not match expected value" 122 ); 123 is( 124 evt.altKey, 125 (test_expectedModifiers & Event.ALT_MASK) != 0, 126 "evt.altKey did not match expected value" 127 ); 128 is( 129 evt.metaKey, 130 (test_expectedModifiers & Event.META_MASK) != 0, 131 "evt.metaKey did not match expected value" 132 ); 133 134 if (evt.type == "MozTapGesture") { 135 is( 136 evt.clickCount, 137 test_expectedClickCount, 138 "evt.clickCount does not match" 139 ); 140 } 141 142 test_eventCount++; 143 } 144 145 function test_helper1(type, direction, delta, modifiers) { 146 // Setup the expected values 147 test_expectedType = type; 148 test_expectedDirection = direction; 149 test_expectedDelta = delta; 150 test_expectedModifiers = modifiers; 151 152 let expectedEventCount = test_eventCount + 1; 153 154 document.addEventListener(type, test_gestureListener, true); 155 test_utils.sendSimpleGestureEvent(type, 60, 60, direction, delta, modifiers); 156 document.removeEventListener(type, test_gestureListener, true); 157 158 is( 159 expectedEventCount, 160 test_eventCount, 161 "Event (" + type + ") was never received by event listener" 162 ); 163 } 164 165 function test_clicks(type, clicks) { 166 // Setup the expected values 167 test_expectedType = type; 168 test_expectedDirection = 0; 169 test_expectedDelta = 0; 170 test_expectedModifiers = 0; 171 test_expectedClickCount = clicks; 172 173 let expectedEventCount = test_eventCount + 1; 174 175 document.addEventListener(type, test_gestureListener, true); 176 test_utils.sendSimpleGestureEvent(type, 60, 60, 0, 0, 0, clicks); 177 document.removeEventListener(type, test_gestureListener, true); 178 179 is( 180 expectedEventCount, 181 test_eventCount, 182 "Event (" + type + ") was never received by event listener" 183 ); 184 } 185 186 function test_TestEventListeners() { 187 let e = test_helper1; // easier to type this name 188 189 // Swipe gesture animation events 190 e("MozSwipeGestureStart", 0, -0.7, 0); 191 e("MozSwipeGestureUpdate", 0, -0.4, 0); 192 e("MozSwipeGestureEnd", 0, 0, 0); 193 e("MozSwipeGestureStart", 0, 0.6, 0); 194 e("MozSwipeGestureUpdate", 0, 0.3, 0); 195 e("MozSwipeGestureEnd", 0, 1, 0); 196 197 // Swipe gesture event 198 e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_LEFT, 0.0, 0); 199 e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_RIGHT, 0.0, 0); 200 e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_UP, 0.0, 0); 201 e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_DOWN, 0.0, 0); 202 e( 203 "MozSwipeGesture", 204 SimpleGestureEvent.DIRECTION_UP | SimpleGestureEvent.DIRECTION_LEFT, 205 0.0, 206 0 207 ); 208 e( 209 "MozSwipeGesture", 210 SimpleGestureEvent.DIRECTION_DOWN | SimpleGestureEvent.DIRECTION_RIGHT, 211 0.0, 212 0 213 ); 214 e( 215 "MozSwipeGesture", 216 SimpleGestureEvent.DIRECTION_UP | SimpleGestureEvent.DIRECTION_RIGHT, 217 0.0, 218 0 219 ); 220 e( 221 "MozSwipeGesture", 222 SimpleGestureEvent.DIRECTION_DOWN | SimpleGestureEvent.DIRECTION_LEFT, 223 0.0, 224 0 225 ); 226 227 // magnify gesture events 228 e("MozMagnifyGestureStart", 0, 50.0, 0); 229 e("MozMagnifyGestureUpdate", 0, -25.0, 0); 230 e("MozMagnifyGestureUpdate", 0, 5.0, 0); 231 e("MozMagnifyGesture", 0, 30.0, 0); 232 233 // rotate gesture events 234 e("MozRotateGestureStart", SimpleGestureEvent.ROTATION_CLOCKWISE, 33.0, 0); 235 e( 236 "MozRotateGestureUpdate", 237 SimpleGestureEvent.ROTATION_COUNTERCLOCKWISE, 238 -13.0, 239 0 240 ); 241 e("MozRotateGestureUpdate", SimpleGestureEvent.ROTATION_CLOCKWISE, 13.0, 0); 242 e("MozRotateGesture", SimpleGestureEvent.ROTATION_CLOCKWISE, 33.0, 0); 243 244 // Tap and presstap gesture events 245 test_clicks("MozTapGesture", 1); 246 test_clicks("MozTapGesture", 2); 247 test_clicks("MozTapGesture", 3); 248 test_clicks("MozPressTapGesture", 1); 249 250 // simple delivery test for edgeui gestures 251 e("MozEdgeUIStarted", 0, 0, 0); 252 e("MozEdgeUICanceled", 0, 0, 0); 253 e("MozEdgeUICompleted", 0, 0, 0); 254 255 // event.shiftKey 256 let modifier = Event.SHIFT_MASK; 257 e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_RIGHT, 0, modifier); 258 259 // event.metaKey 260 modifier = Event.META_MASK; 261 e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_RIGHT, 0, modifier); 262 263 // event.altKey 264 modifier = Event.ALT_MASK; 265 e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_RIGHT, 0, modifier); 266 267 // event.ctrlKey 268 modifier = Event.CONTROL_MASK; 269 e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_RIGHT, 0, modifier); 270 } 271 272 function test_eventDispatchListener(evt) { 273 test_eventCount++; 274 evt.stopPropagation(); 275 } 276 277 function test_helper2( 278 type, 279 direction, 280 delta, 281 altKey, 282 ctrlKey, 283 shiftKey, 284 metaKey 285 ) { 286 let event = null; 287 let successful; 288 289 try { 290 event = document.createEvent("SimpleGestureEvent"); 291 successful = true; 292 } catch (ex) { 293 successful = false; 294 } 295 ok(successful, "Unable to create SimpleGestureEvent"); 296 297 try { 298 event.initSimpleGestureEvent( 299 type, 300 true, 301 true, 302 window, 303 1, 304 10, 305 10, 306 10, 307 10, 308 ctrlKey, 309 altKey, 310 shiftKey, 311 metaKey, 312 1, 313 window, 314 0, 315 direction, 316 delta, 317 0 318 ); 319 successful = true; 320 } catch (ex) { 321 successful = false; 322 } 323 ok(successful, "event.initSimpleGestureEvent should not fail"); 324 325 // Make sure the event fields match the expected values 326 is(event.type, type, "Mismatch on evt.type"); 327 is(event.direction, direction, "Mismatch on evt.direction"); 328 is(event.delta, delta, "Mismatch on evt.delta"); 329 is(event.altKey, altKey, "Mismatch on evt.altKey"); 330 is(event.ctrlKey, ctrlKey, "Mismatch on evt.ctrlKey"); 331 is(event.shiftKey, shiftKey, "Mismatch on evt.shiftKey"); 332 is(event.metaKey, metaKey, "Mismatch on evt.metaKey"); 333 is(event.view, window, "Mismatch on evt.view"); 334 is(event.detail, 1, "Mismatch on evt.detail"); 335 is(event.clientX, 10, "Mismatch on evt.clientX"); 336 is(event.clientY, 10, "Mismatch on evt.clientY"); 337 is(event.screenX, 10, "Mismatch on evt.screenX"); 338 is(event.screenY, 10, "Mismatch on evt.screenY"); 339 is(event.button, 1, "Mismatch on evt.button"); 340 is(event.relatedTarget, window, "Mismatch on evt.relatedTarget"); 341 342 // Test event dispatch 343 let expectedEventCount = test_eventCount + 1; 344 document.addEventListener(type, test_eventDispatchListener, true); 345 document.dispatchEvent(event); 346 document.removeEventListener(type, test_eventDispatchListener, true); 347 is( 348 expectedEventCount, 349 test_eventCount, 350 "Dispatched event was never received by listener" 351 ); 352 } 353 354 function test_TestEventCreation() { 355 // Event creation 356 test_helper2( 357 "MozMagnifyGesture", 358 SimpleGestureEvent.DIRECTION_RIGHT, 359 20.0, 360 true, 361 false, 362 true, 363 false 364 ); 365 test_helper2( 366 "MozMagnifyGesture", 367 SimpleGestureEvent.DIRECTION_LEFT, 368 -20.0, 369 false, 370 true, 371 false, 372 true 373 ); 374 } 375 376 function test_EnsureConstantsAreDisjoint() { 377 let up = SimpleGestureEvent.DIRECTION_UP; 378 let down = SimpleGestureEvent.DIRECTION_DOWN; 379 let left = SimpleGestureEvent.DIRECTION_LEFT; 380 let right = SimpleGestureEvent.DIRECTION_RIGHT; 381 382 let clockwise = SimpleGestureEvent.ROTATION_CLOCKWISE; 383 let cclockwise = SimpleGestureEvent.ROTATION_COUNTERCLOCKWISE; 384 385 ok(up ^ down, "DIRECTION_UP and DIRECTION_DOWN are not bitwise disjoint"); 386 ok(up ^ left, "DIRECTION_UP and DIRECTION_LEFT are not bitwise disjoint"); 387 ok(up ^ right, "DIRECTION_UP and DIRECTION_RIGHT are not bitwise disjoint"); 388 ok(down ^ left, "DIRECTION_DOWN and DIRECTION_LEFT are not bitwise disjoint"); 389 ok( 390 down ^ right, 391 "DIRECTION_DOWN and DIRECTION_RIGHT are not bitwise disjoint" 392 ); 393 ok( 394 left ^ right, 395 "DIRECTION_LEFT and DIRECTION_RIGHT are not bitwise disjoint" 396 ); 397 ok( 398 clockwise ^ cclockwise, 399 "ROTATION_CLOCKWISE and ROTATION_COUNTERCLOCKWISE are not bitwise disjoint" 400 ); 401 } 402 403 // Helper for test of latched event processing. Emits the actual 404 // gesture events to test whether the commands associated with the 405 // gesture will only trigger once for each direction of movement. 406 async function test_emitLatchedEvents(eventPrefix, initialDelta, cmd) { 407 let cumulativeDelta = 0; 408 let isIncreasing = initialDelta > 0; 409 410 let expect = {}; 411 // Reset the call counters and initialize expected values 412 for (let dir in cmd) { 413 cmd[dir].callCount = expect[dir] = 0; 414 } 415 416 let check = (aDir, aMsg) => 417 Assert.equal(cmd[aDir].callCount, expect[aDir], aMsg); 418 let checkBoth = function (aNum, aInc, aDec) { 419 let prefix = "Step " + aNum + ": "; 420 check("inc", prefix + aInc); 421 check("dec", prefix + aDec); 422 }; 423 424 // Send the "Start" event. 425 await synthesizeSimpleGestureEvent( 426 test_normalTab.linkedBrowser, 427 eventPrefix + "Start", 428 10, 429 10, 430 0, 431 initialDelta, 432 0, 433 0 434 ); 435 cumulativeDelta += initialDelta; 436 if (isIncreasing) { 437 expect.inc++; 438 checkBoth( 439 1, 440 "Increasing command was not triggered", 441 "Decreasing command was triggered" 442 ); 443 } else { 444 expect.dec++; 445 checkBoth( 446 1, 447 "Increasing command was triggered", 448 "Decreasing command was not triggered" 449 ); 450 } 451 452 // Send random values in the same direction and ensure neither 453 // command triggers. 454 for (let i = 0; i < 5; i++) { 455 let delta = Math.random() * (isIncreasing ? 100 : -100); 456 457 await synthesizeSimpleGestureEvent( 458 test_normalTab.linkedBrowser, 459 eventPrefix + "Update", 460 10, 461 10, 462 0, 463 delta, 464 0, 465 0 466 ); 467 cumulativeDelta += delta; 468 checkBoth( 469 2, 470 "Increasing command was triggered", 471 "Decreasing command was triggered" 472 ); 473 } 474 475 // Now go back in the opposite direction. 476 await synthesizeSimpleGestureEvent( 477 test_normalTab.linkedBrowser, 478 eventPrefix + "Update", 479 10, 480 10, 481 0, 482 -initialDelta, 483 0, 484 0 485 ); 486 cumulativeDelta += -initialDelta; 487 if (isIncreasing) { 488 expect.dec++; 489 checkBoth( 490 3, 491 "Increasing command was triggered", 492 "Decreasing command was not triggered" 493 ); 494 } else { 495 expect.inc++; 496 checkBoth( 497 3, 498 "Increasing command was not triggered", 499 "Decreasing command was triggered" 500 ); 501 } 502 503 // Send random values in the opposite direction and ensure neither 504 // command triggers. 505 for (let i = 0; i < 5; i++) { 506 let delta = Math.random() * (isIncreasing ? -100 : 100); 507 await synthesizeSimpleGestureEvent( 508 test_normalTab.linkedBrowser, 509 eventPrefix + "Update", 510 10, 511 10, 512 0, 513 delta, 514 0, 515 0 516 ); 517 cumulativeDelta += delta; 518 checkBoth( 519 4, 520 "Increasing command was triggered", 521 "Decreasing command was triggered" 522 ); 523 } 524 525 // Go back to the original direction. The original command should trigger. 526 await synthesizeSimpleGestureEvent( 527 test_normalTab.linkedBrowser, 528 eventPrefix + "Update", 529 10, 530 10, 531 0, 532 initialDelta, 533 0, 534 0 535 ); 536 cumulativeDelta += initialDelta; 537 if (isIncreasing) { 538 expect.inc++; 539 checkBoth( 540 5, 541 "Increasing command was not triggered", 542 "Decreasing command was triggered" 543 ); 544 } else { 545 expect.dec++; 546 checkBoth( 547 5, 548 "Increasing command was triggered", 549 "Decreasing command was not triggered" 550 ); 551 } 552 553 // Send the wrap-up event. No commands should be triggered. 554 await synthesizeSimpleGestureEvent( 555 test_normalTab.linkedBrowser, 556 eventPrefix, 557 10, 558 10, 559 0, 560 cumulativeDelta, 561 0, 562 0 563 ); 564 checkBoth( 565 6, 566 "Increasing command was triggered", 567 "Decreasing command was triggered" 568 ); 569 } 570 571 function test_addCommand(prefName, id) { 572 let cmd = test_commandset.appendChild(document.createXULElement("command")); 573 cmd.setAttribute("id", id); 574 cmd.addEventListener("command", event => event.target.callCount++); 575 576 cmd.origPrefName = prefName; 577 cmd.origPrefValue = Services.prefs.getCharPref(prefName); 578 Services.prefs.setCharPref(prefName, id); 579 580 return cmd; 581 } 582 583 function test_removeCommand(cmd) { 584 Services.prefs.setCharPref(cmd.origPrefName, cmd.origPrefValue); 585 test_commandset.removeChild(cmd); 586 } 587 588 // Test whether latched events are only called once per direction of motion. 589 async function test_latchedGesture(gesture, inc, dec, eventPrefix) { 590 let branch = test_prefBranch + gesture + "."; 591 592 // Put the gesture into latched mode. 593 let oldLatchedValue = Services.prefs.getBoolPref(branch + "latched"); 594 Services.prefs.setBoolPref(branch + "latched", true); 595 596 // Install the test commands for increasing and decreasing motion. 597 let cmd = { 598 inc: test_addCommand(branch + inc, "test:incMotion"), 599 dec: test_addCommand(branch + dec, "test:decMotion"), 600 }; 601 602 // Test the gestures in each direction. 603 await test_emitLatchedEvents(eventPrefix, 500, cmd); 604 await test_emitLatchedEvents(eventPrefix, -500, cmd); 605 606 // Restore the gesture to its original configuration. 607 Services.prefs.setBoolPref(branch + "latched", oldLatchedValue); 608 for (let dir in cmd) { 609 test_removeCommand(cmd[dir]); 610 } 611 } 612 613 // Test whether non-latched events are triggered upon sufficient motion. 614 async function test_thresholdGesture(gesture, inc, dec, eventPrefix) { 615 let branch = test_prefBranch + gesture + "."; 616 617 // Disable latched mode for this gesture. 618 let oldLatchedValue = Services.prefs.getBoolPref(branch + "latched"); 619 Services.prefs.setBoolPref(branch + "latched", false); 620 621 // Set the triggering threshold value to 50. 622 let oldThresholdValue = Services.prefs.getIntPref(branch + "threshold"); 623 Services.prefs.setIntPref(branch + "threshold", 50); 624 625 // Install the test commands for increasing and decreasing motion. 626 let cmdInc = test_addCommand(branch + inc, "test:incMotion"); 627 let cmdDec = test_addCommand(branch + dec, "test:decMotion"); 628 629 // Send the start event but stop short of triggering threshold. 630 cmdInc.callCount = cmdDec.callCount = 0; 631 await synthesizeSimpleGestureEvent( 632 test_normalTab.linkedBrowser, 633 eventPrefix + "Start", 634 10, 635 10, 636 0, 637 49.5, 638 0, 639 0 640 ); 641 Assert.equal(cmdInc.callCount, 0, "Increasing command was triggered"); 642 Assert.equal(cmdDec.callCount, 0, "Decreasing command was triggered"); 643 644 // Now trigger the threshold. 645 cmdInc.callCount = cmdDec.callCount = 0; 646 await synthesizeSimpleGestureEvent( 647 test_normalTab.linkedBrowser, 648 eventPrefix + "Update", 649 10, 650 10, 651 0, 652 1, 653 0, 654 0 655 ); 656 Assert.equal(cmdInc.callCount, 1, "Increasing command was not triggered"); 657 Assert.equal(cmdDec.callCount, 0, "Decreasing command was triggered"); 658 659 // The tracking counter should go to zero. Go back the other way and 660 // stop short of triggering the threshold. 661 cmdInc.callCount = cmdDec.callCount = 0; 662 await synthesizeSimpleGestureEvent( 663 test_normalTab.linkedBrowser, 664 eventPrefix + "Update", 665 10, 666 10, 667 0, 668 -49.5, 669 0, 670 0 671 ); 672 Assert.equal(cmdInc.callCount, 0, "Increasing command was triggered"); 673 Assert.equal(cmdDec.callCount, 0, "Decreasing command was triggered"); 674 675 // Now cross the threshold and trigger the decreasing command. 676 cmdInc.callCount = cmdDec.callCount = 0; 677 await synthesizeSimpleGestureEvent( 678 test_normalTab.linkedBrowser, 679 eventPrefix + "Update", 680 10, 681 10, 682 0, 683 -1.5, 684 0, 685 0 686 ); 687 Assert.equal(cmdInc.callCount, 0, "Increasing command was triggered"); 688 Assert.equal(cmdDec.callCount, 1, "Decreasing command was not triggered"); 689 690 // Send the wrap-up event. No commands should trigger. 691 cmdInc.callCount = cmdDec.callCount = 0; 692 await synthesizeSimpleGestureEvent( 693 test_normalTab.linkedBrowser, 694 eventPrefix, 695 0, 696 0, 697 0, 698 -0.5, 699 0, 700 0 701 ); 702 Assert.equal(cmdInc.callCount, 0, "Increasing command was triggered"); 703 Assert.equal(cmdDec.callCount, 0, "Decreasing command was triggered"); 704 705 // Restore the gesture to its original configuration. 706 Services.prefs.setBoolPref(branch + "latched", oldLatchedValue); 707 Services.prefs.setIntPref(branch + "threshold", oldThresholdValue); 708 test_removeCommand(cmdInc); 709 test_removeCommand(cmdDec); 710 } 711 712 async function test_swipeGestures() { 713 // easier to type names for the direction constants 714 let up = SimpleGestureEvent.DIRECTION_UP; 715 let down = SimpleGestureEvent.DIRECTION_DOWN; 716 let left = SimpleGestureEvent.DIRECTION_LEFT; 717 let right = SimpleGestureEvent.DIRECTION_RIGHT; 718 719 let branch = test_prefBranch + "swipe."; 720 721 // Install the test commands for the swipe gestures. 722 let cmdUp = test_addCommand(branch + "up", "test:swipeUp"); 723 let cmdDown = test_addCommand(branch + "down", "test:swipeDown"); 724 let cmdLeft = test_addCommand(branch + "left", "test:swipeLeft"); 725 let cmdRight = test_addCommand(branch + "right", "test:swipeRight"); 726 727 function resetCounts() { 728 cmdUp.callCount = 0; 729 cmdDown.callCount = 0; 730 cmdLeft.callCount = 0; 731 cmdRight.callCount = 0; 732 } 733 734 // UP 735 resetCounts(); 736 await synthesizeSimpleGestureEvent( 737 test_normalTab.linkedBrowser, 738 "MozSwipeGesture", 739 10, 740 10, 741 up, 742 0, 743 0, 744 0 745 ); 746 Assert.equal(cmdUp.callCount, 1, "Step 1: Up command was not triggered"); 747 Assert.equal(cmdDown.callCount, 0, "Step 1: Down command was triggered"); 748 Assert.equal(cmdLeft.callCount, 0, "Step 1: Left command was triggered"); 749 Assert.equal(cmdRight.callCount, 0, "Step 1: Right command was triggered"); 750 751 // DOWN 752 resetCounts(); 753 await synthesizeSimpleGestureEvent( 754 test_normalTab.linkedBrowser, 755 "MozSwipeGesture", 756 10, 757 10, 758 down, 759 0, 760 0, 761 0 762 ); 763 Assert.equal(cmdUp.callCount, 0, "Step 2: Up command was triggered"); 764 Assert.equal(cmdDown.callCount, 1, "Step 2: Down command was not triggered"); 765 Assert.equal(cmdLeft.callCount, 0, "Step 2: Left command was triggered"); 766 Assert.equal(cmdRight.callCount, 0, "Step 2: Right command was triggered"); 767 768 // LEFT 769 resetCounts(); 770 await synthesizeSimpleGestureEvent( 771 test_normalTab.linkedBrowser, 772 "MozSwipeGesture", 773 10, 774 10, 775 left, 776 0, 777 0, 778 0 779 ); 780 Assert.equal(cmdUp.callCount, 0, "Step 3: Up command was triggered"); 781 Assert.equal(cmdDown.callCount, 0, "Step 3: Down command was triggered"); 782 Assert.equal(cmdLeft.callCount, 1, "Step 3: Left command was not triggered"); 783 Assert.equal(cmdRight.callCount, 0, "Step 3: Right command was triggered"); 784 785 // RIGHT 786 resetCounts(); 787 await synthesizeSimpleGestureEvent( 788 test_normalTab.linkedBrowser, 789 "MozSwipeGesture", 790 10, 791 10, 792 right, 793 0, 794 0, 795 0 796 ); 797 Assert.equal(cmdUp.callCount, 0, "Step 4: Up command was triggered"); 798 Assert.equal(cmdDown.callCount, 0, "Step 4: Down command was triggered"); 799 Assert.equal(cmdLeft.callCount, 0, "Step 4: Left command was triggered"); 800 Assert.equal( 801 cmdRight.callCount, 802 1, 803 "Step 4: Right command was not triggered" 804 ); 805 806 // Make sure combinations do not trigger events. 807 let combos = [up | left, up | right, down | left, down | right]; 808 for (let i = 0; i < combos.length; i++) { 809 resetCounts(); 810 await synthesizeSimpleGestureEvent( 811 test_normalTab.linkedBrowser, 812 "MozSwipeGesture", 813 10, 814 10, 815 combos[i], 816 0, 817 0, 818 0 819 ); 820 Assert.equal( 821 cmdUp.callCount, 822 0, 823 "Step 5-" + i + ": Up command was triggered" 824 ); 825 Assert.equal( 826 cmdDown.callCount, 827 0, 828 "Step 5-" + i + ": Down command was triggered" 829 ); 830 Assert.equal( 831 cmdLeft.callCount, 832 0, 833 "Step 5-" + i + ": Left command was triggered" 834 ); 835 Assert.equal( 836 cmdRight.callCount, 837 0, 838 "Step 5-" + i + ": Right command was triggered" 839 ); 840 } 841 842 // Remove the test commands. 843 test_removeCommand(cmdUp); 844 test_removeCommand(cmdDown); 845 test_removeCommand(cmdLeft); 846 test_removeCommand(cmdRight); 847 } 848 849 function test_rotateHelperGetImageRotation(aImageElement) { 850 // Get the true image rotation from the transform matrix, bounded 851 // to 0 <= result < 360 852 let transformValue = content.window.getComputedStyle(aImageElement).transform; 853 if (transformValue == "none") { 854 return 0; 855 } 856 857 transformValue = transformValue.split("(")[1].split(")")[0].split(","); 858 var rotation = Math.round( 859 Math.atan2(transformValue[1], transformValue[0]) * (180 / Math.PI) 860 ); 861 return rotation < 0 ? rotation + 360 : rotation; 862 } 863 864 async function test_rotateHelperOneGesture( 865 aImageElement, 866 aCurrentRotation, 867 aDirection, 868 aAmount, 869 aStop 870 ) { 871 if (aAmount <= 0 || aAmount > 90) { 872 // Bound to 0 < aAmount <= 90 873 return; 874 } 875 876 // easier to type names for the direction constants 877 let clockwise = SimpleGestureEvent.ROTATION_CLOCKWISE; 878 879 let delta = aAmount * (aDirection == clockwise ? 1 : -1); 880 881 // Kill transition time on image so test isn't wrong and doesn't take 10 seconds 882 aImageElement.style.transitionDuration = "0s"; 883 884 // Start the gesture, perform an update, and force flush 885 await synthesizeSimpleGestureEvent( 886 test_imageTab.linkedBrowser, 887 "MozRotateGestureStart", 888 10, 889 10, 890 aDirection, 891 0.001, 892 0, 893 0 894 ); 895 await synthesizeSimpleGestureEvent( 896 test_imageTab.linkedBrowser, 897 "MozRotateGestureUpdate", 898 10, 899 10, 900 aDirection, 901 delta, 902 0, 903 0 904 ); 905 aImageElement.clientTop; 906 907 // If stop, check intermediate 908 if (aStop) { 909 // Send near-zero-delta to stop, and force flush 910 await synthesizeSimpleGestureEvent( 911 test_imageTab.linkedBrowser, 912 "MozRotateGestureUpdate", 913 10, 914 10, 915 aDirection, 916 0.001, 917 0, 918 0 919 ); 920 aImageElement.clientTop; 921 922 let stopExpectedRotation = (aCurrentRotation + delta) % 360; 923 if (stopExpectedRotation < 0) { 924 stopExpectedRotation += 360; 925 } 926 927 is( 928 stopExpectedRotation, 929 test_rotateHelperGetImageRotation(aImageElement), 930 "Image rotation at gesture stop/hold: expected=" + 931 stopExpectedRotation + 932 ", observed=" + 933 test_rotateHelperGetImageRotation(aImageElement) + 934 ", init=" + 935 aCurrentRotation + 936 ", amt=" + 937 aAmount + 938 ", dir=" + 939 (aDirection == clockwise ? "cl" : "ccl") 940 ); 941 } 942 // End it and force flush 943 await synthesizeSimpleGestureEvent( 944 test_imageTab.linkedBrowser, 945 "MozRotateGesture", 946 10, 947 10, 948 aDirection, 949 0, 950 0, 951 0 952 ); 953 aImageElement.clientTop; 954 955 let finalExpectedRotation; 956 957 if (aAmount < 45 && aStop) { 958 // Rotate a bit, then stop. Expect no change at end of gesture. 959 finalExpectedRotation = aCurrentRotation; 960 } else { 961 // Either not stopping (expect 90 degree change in aDirection), OR 962 // stopping but after 45, (expect 90 degree change in aDirection) 963 finalExpectedRotation = 964 (aCurrentRotation + (aDirection == clockwise ? 1 : -1) * 90) % 360; 965 if (finalExpectedRotation < 0) { 966 finalExpectedRotation += 360; 967 } 968 } 969 970 is( 971 finalExpectedRotation, 972 test_rotateHelperGetImageRotation(aImageElement), 973 "Image rotation gesture end: expected=" + 974 finalExpectedRotation + 975 ", observed=" + 976 test_rotateHelperGetImageRotation(aImageElement) + 977 ", init=" + 978 aCurrentRotation + 979 ", amt=" + 980 aAmount + 981 ", dir=" + 982 (aDirection == clockwise ? "cl" : "ccl") 983 ); 984 } 985 986 async function test_rotateGesturesOnTab() { 987 gBrowser.selectedBrowser.removeEventListener( 988 "load", 989 test_rotateGesturesOnTab, 990 true 991 ); 992 993 if (!ImageDocument.isInstance(content.document)) { 994 ok(false, "Image document failed to open for rotation testing"); 995 gBrowser.removeTab(test_imageTab); 996 BrowserTestUtils.removeTab(test_normalTab); 997 test_imageTab = null; 998 test_normalTab = null; 999 finish(); 1000 return; 1001 } 1002 1003 // easier to type names for the direction constants 1004 let cl = SimpleGestureEvent.ROTATION_CLOCKWISE; 1005 let ccl = SimpleGestureEvent.ROTATION_COUNTERCLOCKWISE; 1006 1007 let imgElem = 1008 content.document.body && content.document.body.firstElementChild; 1009 1010 if (!imgElem) { 1011 ok(false, "Could not get image element on ImageDocument for rotation!"); 1012 gBrowser.removeTab(test_imageTab); 1013 BrowserTestUtils.removeTab(test_normalTab); 1014 test_imageTab = null; 1015 test_normalTab = null; 1016 finish(); 1017 return; 1018 } 1019 1020 // Quick function to normalize rotation to 0 <= r < 360 1021 var normRot = function (rotation) { 1022 rotation = rotation % 360; 1023 if (rotation < 0) { 1024 rotation += 360; 1025 } 1026 return rotation; 1027 }; 1028 1029 for (var initRot = 0; initRot < 360; initRot += 90) { 1030 // Test each case: at each 90 degree snap; cl/ccl; 1031 // amount more or less than 45; stop and hold or don't (32 total tests) 1032 // The amount added to the initRot is where it is expected to be 1033 await test_rotateHelperOneGesture( 1034 imgElem, 1035 normRot(initRot + 0), 1036 cl, 1037 35, 1038 true 1039 ); 1040 await test_rotateHelperOneGesture( 1041 imgElem, 1042 normRot(initRot + 0), 1043 cl, 1044 35, 1045 false 1046 ); 1047 await test_rotateHelperOneGesture( 1048 imgElem, 1049 normRot(initRot + 90), 1050 cl, 1051 55, 1052 true 1053 ); 1054 await test_rotateHelperOneGesture( 1055 imgElem, 1056 normRot(initRot + 180), 1057 cl, 1058 55, 1059 false 1060 ); 1061 await test_rotateHelperOneGesture( 1062 imgElem, 1063 normRot(initRot + 270), 1064 ccl, 1065 35, 1066 true 1067 ); 1068 await test_rotateHelperOneGesture( 1069 imgElem, 1070 normRot(initRot + 270), 1071 ccl, 1072 35, 1073 false 1074 ); 1075 await test_rotateHelperOneGesture( 1076 imgElem, 1077 normRot(initRot + 180), 1078 ccl, 1079 55, 1080 true 1081 ); 1082 await test_rotateHelperOneGesture( 1083 imgElem, 1084 normRot(initRot + 90), 1085 ccl, 1086 55, 1087 false 1088 ); 1089 1090 // Manually rotate it 90 degrees clockwise to prepare for next iteration, 1091 // and force flush 1092 await synthesizeSimpleGestureEvent( 1093 test_imageTab.linkedBrowser, 1094 "MozRotateGestureStart", 1095 10, 1096 10, 1097 cl, 1098 0.001, 1099 0, 1100 0 1101 ); 1102 await synthesizeSimpleGestureEvent( 1103 test_imageTab.linkedBrowser, 1104 "MozRotateGestureUpdate", 1105 10, 1106 10, 1107 cl, 1108 90, 1109 0, 1110 0 1111 ); 1112 await synthesizeSimpleGestureEvent( 1113 test_imageTab.linkedBrowser, 1114 "MozRotateGestureUpdate", 1115 10, 1116 10, 1117 cl, 1118 0.001, 1119 0, 1120 0 1121 ); 1122 await synthesizeSimpleGestureEvent( 1123 test_imageTab.linkedBrowser, 1124 "MozRotateGesture", 1125 10, 1126 10, 1127 cl, 1128 0, 1129 0, 1130 0 1131 ); 1132 imgElem.clientTop; 1133 } 1134 1135 gBrowser.removeTab(test_imageTab); 1136 BrowserTestUtils.removeTab(test_normalTab); 1137 test_imageTab = null; 1138 test_normalTab = null; 1139 finish(); 1140 } 1141 1142 function test_rotateGestures() { 1143 test_imageTab = BrowserTestUtils.addTab( 1144 gBrowser, 1145 "chrome://branding/content/about-logo.png" 1146 ); 1147 gBrowser.selectedTab = test_imageTab; 1148 1149 gBrowser.selectedBrowser.addEventListener( 1150 "load", 1151 test_rotateGesturesOnTab, 1152 true 1153 ); 1154 }