tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

browser_fullscreen-api-keys.js (9452B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 // List of key codes which should exit full-screen mode.
      7 const kKeyList = [
      8  { key: "Escape", keyCode: "VK_ESCAPE", suppressed: true },
      9  { key: "F11", keyCode: "VK_F11", suppressed: false },
     10 ];
     11 
     12 function receiveExpectedKeyEvents(aBrowser, aKeyCode, aTrusted) {
     13  return SpecialPowers.spawn(
     14    aBrowser,
     15    [aKeyCode, aTrusted],
     16    (keyCode, trusted) => {
     17      return new Promise(resolve => {
     18        let events = trusted
     19          ? ["keydown", "keyup"]
     20          : ["keydown", "keypress", "keyup"];
     21        if (trusted && keyCode == content.wrappedJSObject.KeyEvent.DOM_VK_F11) {
     22          // trusted `F11` key shouldn't be fired because of reserved when it's
     23          // a shortcut key for exiting from the full screen mode.
     24          events.shift();
     25        }
     26        function listener(event) {
     27          let expected = events.shift();
     28          Assert.equal(
     29            event.type,
     30            expected,
     31            `Should receive a ${expected} event`
     32          );
     33          Assert.equal(
     34            event.keyCode,
     35            keyCode,
     36            `Should receive the event with key code ${keyCode}`
     37          );
     38          if (!events.length) {
     39            content.document.removeEventListener("keydown", listener, true);
     40            content.document.removeEventListener("keyup", listener, true);
     41            content.document.removeEventListener("keypress", listener, true);
     42            resolve();
     43          }
     44        }
     45 
     46        content.document.addEventListener("keydown", listener, true);
     47        content.document.addEventListener("keyup", listener, true);
     48        content.document.addEventListener("keypress", listener, true);
     49      });
     50    }
     51  );
     52 }
     53 
     54 async function requestFullscreenAndWait(aBrowser) {
     55  await SimpleTest.promiseFocus(aBrowser);
     56  await SpecialPowers.spawn(aBrowser, [], async () => {
     57    // Wait for the document being activated, so that
     58    // fullscreen request won't be denied.
     59    await ContentTaskUtils.waitForCondition(
     60      () => content.browsingContext.isActive && content.document.hasFocus(),
     61      "document is active"
     62    );
     63 
     64    await new Promise(resolve => {
     65      content.document.addEventListener("fullscreenchange", resolve, {
     66        once: true,
     67      });
     68      content.document.body.requestFullscreen();
     69    });
     70  });
     71 }
     72 
     73 const kPage =
     74  "https://example.org/browser/" +
     75  "dom/base/test/fullscreen/file_fullscreen-api-keys.html";
     76 
     77 add_setup(async function init() {
     78  await pushPrefs(
     79    ["full-screen-api.transition-duration.enter", "0 0"],
     80    ["full-screen-api.transition-duration.leave", "0 0"]
     81  );
     82 });
     83 
     84 for (let { key, keyCode, suppressed } of kKeyList) {
     85  /** Test for Bug 545812 */
     86  add_task(async function testExitFullscreenByKeyboard() {
     87    let keyCodeValue = KeyEvent["DOM_" + keyCode];
     88    info(`Test keycode ${key} (${keyCodeValue})`);
     89 
     90    let tab = BrowserTestUtils.addTab(gBrowser, kPage);
     91    let browser = tab.linkedBrowser;
     92    gBrowser.selectedTab = tab;
     93    await waitForDocLoadComplete();
     94 
     95    // Wait for the document being activated, so that
     96    // fullscreen request won't be denied.
     97    await SimpleTest.promiseFocus(browser);
     98    await SpecialPowers.spawn(browser, [], () => {
     99      return ContentTaskUtils.waitForCondition(
    100        () => content.browsingContext.isActive && content.document.hasFocus(),
    101        "document is active"
    102      );
    103    });
    104 
    105    // Register listener to capture unexpected events
    106    let keyEventsCount = 0;
    107    let fullScreenEventsCount = 0;
    108    let removeFullScreenListener = BrowserTestUtils.addContentEventListener(
    109      browser,
    110      "fullscreenchange",
    111      () => fullScreenEventsCount++
    112    );
    113    let removeKeyDownListener = BrowserTestUtils.addContentEventListener(
    114      browser,
    115      "keydown",
    116      () => keyEventsCount++,
    117      { wantUntrusted: true }
    118    );
    119    let removeKeyPressListener = BrowserTestUtils.addContentEventListener(
    120      browser,
    121      "keypress",
    122      () => keyEventsCount++,
    123      { wantUntrusted: true }
    124    );
    125    let removeKeyUpListener = BrowserTestUtils.addContentEventListener(
    126      browser,
    127      "keyup",
    128      () => keyEventsCount++,
    129      { wantUntrusted: true }
    130    );
    131 
    132    let expectedFullScreenEventsCount = 0;
    133    let expectedKeyEventsCount = 0;
    134 
    135    info("Enter fullscreen");
    136    let state = new Promise(resolve => {
    137      let removeFun = BrowserTestUtils.addContentEventListener(
    138        browser,
    139        "fullscreenchange",
    140        async () => {
    141          removeFun();
    142          resolve(
    143            await SpecialPowers.spawn(browser, [], () => {
    144              return !!content.document.fullscreenElement;
    145            })
    146          );
    147        }
    148      );
    149    });
    150    // request fullscreen
    151    SpecialPowers.spawn(browser, [], () => {
    152      content.document.body.requestFullscreen();
    153    });
    154    ok(await state, "The content should have entered fullscreen");
    155    ok(document.fullscreenElement, "The chrome should also be in fullscreen");
    156 
    157    is(
    158      fullScreenEventsCount,
    159      ++expectedFullScreenEventsCount,
    160      "correct number of fullscreen events occurred"
    161    );
    162 
    163    info("Dispatch untrusted key events from content");
    164    let promiseExpectedKeyEvents = receiveExpectedKeyEvents(
    165      browser,
    166      keyCodeValue,
    167      false
    168    );
    169 
    170    SpecialPowers.spawn(browser, [keyCode], keyCodeChild => {
    171      var evt = new content.CustomEvent("Test:DispatchKeyEvents", {
    172        detail: Cu.cloneInto({ code: keyCodeChild }, content),
    173      });
    174      content.dispatchEvent(evt);
    175    });
    176    await promiseExpectedKeyEvents;
    177 
    178    expectedKeyEventsCount += 3;
    179    is(
    180      keyEventsCount,
    181      expectedKeyEventsCount,
    182      "correct number of key events occurred"
    183    );
    184 
    185    info("Send trusted key events");
    186 
    187    state = new Promise(resolve => {
    188      let removeFun = BrowserTestUtils.addContentEventListener(
    189        browser,
    190        "fullscreenchange",
    191        async () => {
    192          removeFun();
    193          resolve(
    194            await SpecialPowers.spawn(browser, [], () => {
    195              return !!content.document.fullscreenElement;
    196            })
    197          );
    198        }
    199      );
    200    });
    201 
    202    promiseExpectedKeyEvents = suppressed
    203      ? Promise.resolve()
    204      : receiveExpectedKeyEvents(browser, keyCodeValue, true);
    205    await SpecialPowers.spawn(browser, [], () => {});
    206 
    207    EventUtils.synthesizeKey("KEY_" + key);
    208    await promiseExpectedKeyEvents;
    209 
    210    ok(!(await state), "The content should have exited fullscreen");
    211    ok(
    212      !document.fullscreenElement,
    213      "The chrome should also have exited fullscreen"
    214    );
    215 
    216    is(
    217      fullScreenEventsCount,
    218      ++expectedFullScreenEventsCount,
    219      "correct number of fullscreen events occurred"
    220    );
    221    if (!suppressed) {
    222      expectedKeyEventsCount += keyCode == "VK_F11" ? 1 : 3;
    223    }
    224    is(
    225      keyEventsCount,
    226      expectedKeyEventsCount,
    227      "correct number of key events occurred"
    228    );
    229 
    230    info("Cleanup");
    231    removeFullScreenListener();
    232    removeKeyDownListener();
    233    removeKeyPressListener();
    234    removeKeyUpListener();
    235    gBrowser.removeTab(tab);
    236  });
    237 
    238  /** Test for Bug 1621736 */
    239  // macOS places fullscreen windows in their own virtual desktop, and it is not
    240  // possible to programmatically move focus to another chrome window in a different
    241  // virtual desktop, so this test doesn't work on macOS.
    242  if (AppConstants.platform != "macosx") {
    243    add_task(async function testMultipleFullscreenExitByKeyboard() {
    244      let keyCodeValue = KeyEvent["DOM_" + keyCode];
    245      info(`Test keycode ${key} (${keyCodeValue})`);
    246 
    247      await BrowserTestUtils.withNewTab(
    248        {
    249          gBrowser,
    250          url: kPage,
    251        },
    252        async function (browser) {
    253          info("Enter fullscreen");
    254          await requestFullscreenAndWait(browser);
    255 
    256          info("Open new browser window");
    257          const win = await BrowserTestUtils.openNewBrowserWindow();
    258          const tab = await BrowserTestUtils.openNewForegroundTab(
    259            win.gBrowser,
    260            kPage
    261          );
    262 
    263          info("Enter fullscreen on new browser window");
    264          const newBrowser = tab.linkedBrowser;
    265          await requestFullscreenAndWait(newBrowser);
    266 
    267          let removeFullScreenListener;
    268          let promiseFullscreenExit = new Promise(resolve => {
    269            removeFullScreenListener = BrowserTestUtils.addContentEventListener(
    270              newBrowser,
    271              "fullscreenchange",
    272              resolve,
    273              {},
    274              event => {
    275                return !event.target.fullscreenElement;
    276              }
    277            );
    278          });
    279 
    280          info("Send key event to new browser window");
    281          EventUtils.synthesizeKey("KEY_" + key, {}, win);
    282          await promiseFullscreenExit;
    283 
    284          ok(
    285            await SpecialPowers.spawn(browser, [], () => {
    286              return (
    287                content.document.fullscreenElement == content.document.body
    288              );
    289            }),
    290            "First browser window should still in fullscreen mode"
    291          );
    292 
    293          info("Cleanup");
    294          removeFullScreenListener();
    295 
    296          // Close opened tab
    297          let tabClosed = BrowserTestUtils.waitForTabClosing(tab);
    298          await BrowserTestUtils.removeTab(tab);
    299          await tabClosed;
    300 
    301          // Close opened window
    302          await BrowserTestUtils.closeWindow(win);
    303        }
    304      );
    305    });
    306  }
    307 }