forked from mirrors/gecko-dev
		
	Now, `nsIFrame::HandleEvent` moves selection at middle mouse button down. This occurs before dispatching the event into the system event group. Therefore, `AutoScrollChild` cannot prevent it. On the other hand, Chrome does not start autoscroll when a modifier is pressed. This means that our users may not be able to use middle click with modifiers if web apps do not call `preventDefault()` as expected. So, this difference is a potential risk of web-compat. Therefore, this patch makes `AutoScrollChild` stop starting autoscroll if `Shift` key is pressed. Differential Revision: https://phabricator.services.mozilla.com/D119253
		
			
				
	
	
		
			576 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			576 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* Any copyright is dedicated to the Public Domain.
 | 
						|
   http://creativecommons.org/publicdomain/zero/1.0/ */
 | 
						|
 | 
						|
"use strict";
 | 
						|
 | 
						|
add_task(async function() {
 | 
						|
  await SpecialPowers.pushPrefEnv({
 | 
						|
    set: [
 | 
						|
      ["general.autoScroll", true],
 | 
						|
      ["middlemouse.contentLoadURL", false],
 | 
						|
      ["test.events.async.enabled", false],
 | 
						|
    ],
 | 
						|
  });
 | 
						|
 | 
						|
  await BrowserTestUtils.withNewTab(
 | 
						|
    "https://example.com/browser/toolkit/content/tests/browser/file_empty.html",
 | 
						|
    async function(browser) {
 | 
						|
      ok(browser.isRemoteBrowser, "This test passes only in e10s mode");
 | 
						|
      await SpecialPowers.spawn(browser, [], () => {
 | 
						|
        content.document.body.innerHTML =
 | 
						|
          '<div style="height: 10000px;"></div>';
 | 
						|
        content.document.documentElement.scrollTop = 500;
 | 
						|
        content.document.documentElement.scrollTop; // Flush layout.
 | 
						|
        // Prevent to open context menu when testing the secondary button click.
 | 
						|
        content.window.addEventListener(
 | 
						|
          "contextmenu",
 | 
						|
          event => event.preventDefault(),
 | 
						|
          { capture: true }
 | 
						|
        );
 | 
						|
      });
 | 
						|
 | 
						|
      function promiseFlushLayoutInContent() {
 | 
						|
        return SpecialPowers.spawn(browser, [], () => {
 | 
						|
          content.document.documentElement.scrollTop; // Flush layout in the remote content.
 | 
						|
        });
 | 
						|
      }
 | 
						|
 | 
						|
      function promiseContentTick() {
 | 
						|
        return SpecialPowers.spawn(browser, [], async () => {
 | 
						|
          await new Promise(r => {
 | 
						|
            content.requestAnimationFrame(() => {
 | 
						|
              content.requestAnimationFrame(r);
 | 
						|
            });
 | 
						|
          });
 | 
						|
        });
 | 
						|
      }
 | 
						|
 | 
						|
      let autoScroller;
 | 
						|
      function promiseWaitForAutoScrollerOpen() {
 | 
						|
        if (autoScroller?.state == "open") {
 | 
						|
          info("The autoscroller has already been open");
 | 
						|
          return Promise.resolve();
 | 
						|
        }
 | 
						|
        return BrowserTestUtils.waitForEvent(
 | 
						|
          window,
 | 
						|
          "popupshown",
 | 
						|
          { capture: true },
 | 
						|
          event => {
 | 
						|
            if (event.originalTarget.id != "autoscroller") {
 | 
						|
              return false;
 | 
						|
            }
 | 
						|
            autoScroller = event.originalTarget;
 | 
						|
            info('"popupshown" event is fired');
 | 
						|
            autoScroller.getBoundingClientRect(); // Flush layout of the autoscroller
 | 
						|
            return true;
 | 
						|
          }
 | 
						|
        );
 | 
						|
      }
 | 
						|
 | 
						|
      function promiseWaitForAutoScrollerClosed() {
 | 
						|
        if (!autoScroller || autoScroller.state == "closed") {
 | 
						|
          info("The autoscroller has already been closed");
 | 
						|
          return Promise.resolve();
 | 
						|
        }
 | 
						|
        return BrowserTestUtils.waitForEvent(
 | 
						|
          autoScroller,
 | 
						|
          "popuphidden",
 | 
						|
          { capture: true },
 | 
						|
          () => {
 | 
						|
            info('"popuphidden" event is fired');
 | 
						|
            return true;
 | 
						|
          }
 | 
						|
        );
 | 
						|
      }
 | 
						|
 | 
						|
      // Unfortunately, we cannot use synthesized mouse events for starting and
 | 
						|
      // stopping autoscrolling because they may run different path from user
 | 
						|
      // operation especially when there is a popup.
 | 
						|
 | 
						|
      /**
 | 
						|
       * Instead of using `waitForContentEvent`, we use `addContentEventListener`
 | 
						|
       * for checking which events are fired because `waitForContentEvent` cannot
 | 
						|
       * detect redundant event since it's removed automatically at first event
 | 
						|
       * or timeout if the expected count is 0.
 | 
						|
       */
 | 
						|
      class ContentEventCounter {
 | 
						|
        constructor(aBrowser, aEventTypes) {
 | 
						|
          this.eventData = new Map();
 | 
						|
          for (let eventType of aEventTypes) {
 | 
						|
            const removeEventListener = BrowserTestUtils.addContentEventListener(
 | 
						|
              aBrowser,
 | 
						|
              eventType,
 | 
						|
              () => {
 | 
						|
                let eventData = this.eventData.get(eventType);
 | 
						|
                eventData.count++;
 | 
						|
              },
 | 
						|
              { capture: true }
 | 
						|
            );
 | 
						|
            this.eventData.set(eventType, {
 | 
						|
              count: 0, // how many times the event fired.
 | 
						|
              removeEventListener, // function to remove the event listener.
 | 
						|
            });
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        getCountAndRemoveEventListener(aEventType) {
 | 
						|
          let eventData = this.eventData.get(aEventType);
 | 
						|
          if (eventData.removeEventListener) {
 | 
						|
            eventData.removeEventListener();
 | 
						|
            eventData.removeEventListener = null;
 | 
						|
          }
 | 
						|
          return eventData.count;
 | 
						|
        }
 | 
						|
 | 
						|
        promiseMouseEvents(aEventTypes, aMessage) {
 | 
						|
          let needsToWait = [];
 | 
						|
          for (const eventType of aEventTypes) {
 | 
						|
            let eventData = this.eventData.get(eventType);
 | 
						|
            if (eventData.count > 0) {
 | 
						|
              info(`${aMessage}: Waiting "${eventType}" event in content...`);
 | 
						|
              needsToWait.push(
 | 
						|
                // Let's use `waitForCondition` here.  "timeout" is not worthwhile
 | 
						|
                // to debug this test.  We want clearer failure log.
 | 
						|
                TestUtils.waitForCondition(
 | 
						|
                  () => eventData.count > 0,
 | 
						|
                  `${aMessage}: "${eventType}" should be fired, but timed-out`
 | 
						|
                )
 | 
						|
              );
 | 
						|
              break;
 | 
						|
            }
 | 
						|
          }
 | 
						|
          return Promise.all(needsToWait);
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      await SpecialPowers.pushPrefEnv({ set: [["middlemouse.paste", true]] });
 | 
						|
      await (async function testMouseEventsAtStartingAutoScrolling() {
 | 
						|
        info(
 | 
						|
          "Waiting autoscroller popup for testing mouse events at starting autoscrolling"
 | 
						|
        );
 | 
						|
        await promiseFlushLayoutInContent();
 | 
						|
        let eventsInContent = new ContentEventCounter(browser, [
 | 
						|
          "click",
 | 
						|
          "auxclick",
 | 
						|
          "mousedown",
 | 
						|
          "mouseup",
 | 
						|
          "paste",
 | 
						|
        ]);
 | 
						|
        // Ensure that the event listeners added in the content with accessing
 | 
						|
        // the remote content.
 | 
						|
        await promiseFlushLayoutInContent();
 | 
						|
        await EventUtils.promiseNativeMouseEvent({
 | 
						|
          type: "mousemove",
 | 
						|
          target: browser,
 | 
						|
          atCenter: true,
 | 
						|
        });
 | 
						|
        const waitForOpenAutoScroll = promiseWaitForAutoScrollerOpen();
 | 
						|
        await EventUtils.promiseNativeMouseEvent({
 | 
						|
          type: "mousedown",
 | 
						|
          target: browser,
 | 
						|
          atCenter: true,
 | 
						|
          button: 1, // middle button
 | 
						|
        });
 | 
						|
        await waitForOpenAutoScroll;
 | 
						|
        // In the wild, native "mouseup" event occurs after the popup is open.
 | 
						|
        await EventUtils.promiseNativeMouseEvent({
 | 
						|
          type: "mouseup",
 | 
						|
          target: browser,
 | 
						|
          atCenter: true,
 | 
						|
          button: 1, // middle button
 | 
						|
        });
 | 
						|
        await promiseFlushLayoutInContent();
 | 
						|
        await promiseContentTick();
 | 
						|
        await eventsInContent.promiseMouseEvents(
 | 
						|
          ["mouseup"],
 | 
						|
          "At starting autoscrolling"
 | 
						|
        );
 | 
						|
        for (let eventType of ["click", "auxclick", "paste"]) {
 | 
						|
          is(
 | 
						|
            eventsInContent.getCountAndRemoveEventListener(eventType),
 | 
						|
            0,
 | 
						|
            `"${eventType}" event shouldn't be fired in the content when a middle click starts autoscrolling`
 | 
						|
          );
 | 
						|
        }
 | 
						|
        for (let eventType of ["mousedown", "mouseup"]) {
 | 
						|
          is(
 | 
						|
            eventsInContent.getCountAndRemoveEventListener(eventType),
 | 
						|
            1,
 | 
						|
            `"${eventType}" event should be fired in the content when a middle click starts autoscrolling`
 | 
						|
          );
 | 
						|
        }
 | 
						|
        info("Waiting autoscroller close for preparing the following tests");
 | 
						|
        let waitForAutoScrollEnd = promiseWaitForAutoScrollerClosed();
 | 
						|
        EventUtils.synthesizeKey("KEY_Escape");
 | 
						|
        await waitForAutoScrollEnd;
 | 
						|
      })();
 | 
						|
 | 
						|
      if (
 | 
						|
        // Bug 1693240: We don't support setting modifiers while posting a mouse event on Windows.
 | 
						|
        !navigator.platform.includes("Win") &&
 | 
						|
        // Bug 1693237: We don't support setting modifiers on Android.
 | 
						|
        !navigator.appVersion.includes("Android") &&
 | 
						|
        // In Headless mode, modifiers are not supported by this kind of APIs.
 | 
						|
        !Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo).isHeadless
 | 
						|
      ) {
 | 
						|
        await SpecialPowers.pushPrefEnv({
 | 
						|
          set: [
 | 
						|
            ["general.autoscroll.prevent_to_start.shiftKey", true],
 | 
						|
            ["general.autoscroll.prevent_to_start.altKey", true],
 | 
						|
            ["general.autoscroll.prevent_to_start.ctrlKey", true],
 | 
						|
            ["general.autoscroll.prevent_to_start.metaKey", true],
 | 
						|
          ],
 | 
						|
        });
 | 
						|
        for (const modifier of ["Shift", "Control", "Alt", "Meta"]) {
 | 
						|
          if (modifier == "Meta" && !navigator.platform.includes("Mac")) {
 | 
						|
            continue; // Delete this after fixing bug 1232918.
 | 
						|
          }
 | 
						|
          await (async function modifiersPreventToStartAutoScrolling() {
 | 
						|
            info(
 | 
						|
              `Waiting to check not to open autoscroller popup with middle button click with ${modifier}`
 | 
						|
            );
 | 
						|
            await promiseFlushLayoutInContent();
 | 
						|
            let eventsInContent = new ContentEventCounter(browser, [
 | 
						|
              "click",
 | 
						|
              "auxclick",
 | 
						|
              "mousedown",
 | 
						|
              "mouseup",
 | 
						|
              "paste",
 | 
						|
            ]);
 | 
						|
            // Ensure that the event listeners added in the content with accessing
 | 
						|
            // the remote content.
 | 
						|
            await promiseFlushLayoutInContent();
 | 
						|
            await EventUtils.promiseNativeMouseEvent({
 | 
						|
              type: "mousemove",
 | 
						|
              target: browser,
 | 
						|
              atCenter: true,
 | 
						|
            });
 | 
						|
            info(
 | 
						|
              `Waiting to MozAutoScrollNoStart event for the middle button click with ${modifier}`
 | 
						|
            );
 | 
						|
            await EventUtils.promiseNativeMouseEvent({
 | 
						|
              type: "mousedown",
 | 
						|
              target: browser,
 | 
						|
              atCenter: true,
 | 
						|
              button: 1, // middle button
 | 
						|
              modifiers: {
 | 
						|
                altKey: modifier == "Alt",
 | 
						|
                ctrlKey: modifier == "Control",
 | 
						|
                metaKey: modifier == "Meta",
 | 
						|
                shiftKey: modifier == "Shift",
 | 
						|
              },
 | 
						|
            });
 | 
						|
            try {
 | 
						|
              await TestUtils.waitForCondition(
 | 
						|
                () => autoScroller?.state == "open",
 | 
						|
                `Waiting to check not to open autoscroller popup with ${modifier}`,
 | 
						|
                100,
 | 
						|
                10
 | 
						|
              );
 | 
						|
              ok(
 | 
						|
                false,
 | 
						|
                `The autoscroller popup shouldn't be opened by middle click with ${modifier}`
 | 
						|
              );
 | 
						|
            } catch (ex) {
 | 
						|
              ok(
 | 
						|
                true,
 | 
						|
                `The autoscroller popup was not open as expected after middle click with ${modifier}`
 | 
						|
              );
 | 
						|
            }
 | 
						|
            // In the wild, native "mouseup" event occurs after the popup is open.
 | 
						|
            await EventUtils.promiseNativeMouseEvent({
 | 
						|
              type: "mouseup",
 | 
						|
              target: browser,
 | 
						|
              atCenter: true,
 | 
						|
              button: 1, // middle button
 | 
						|
            });
 | 
						|
            await promiseFlushLayoutInContent();
 | 
						|
            await promiseContentTick();
 | 
						|
            await eventsInContent.promiseMouseEvents(
 | 
						|
              ["paste"],
 | 
						|
              `At middle clicking with ${modifier}`
 | 
						|
            );
 | 
						|
            for (let eventType of [
 | 
						|
              "mousedown",
 | 
						|
              "mouseup",
 | 
						|
              "click",
 | 
						|
              "auxclick",
 | 
						|
              "paste",
 | 
						|
            ]) {
 | 
						|
              is(
 | 
						|
                eventsInContent.getCountAndRemoveEventListener(eventType),
 | 
						|
                1,
 | 
						|
                `"${eventType}" event should be fired in the content when a middle click with ${modifier}`
 | 
						|
              );
 | 
						|
            }
 | 
						|
            info(
 | 
						|
              "Waiting autoscroller close for preparing the following tests"
 | 
						|
            );
 | 
						|
          })();
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      async function doTestMouseEventsAtStoppingAutoScrolling({
 | 
						|
        aButton = 0,
 | 
						|
        aClickOutsideAutoScroller = false,
 | 
						|
        aDescription = "Unspecified",
 | 
						|
      }) {
 | 
						|
        info(
 | 
						|
          `Starting autoscrolling for testing to stop autoscrolling with ${aDescription}`
 | 
						|
        );
 | 
						|
        await promiseFlushLayoutInContent();
 | 
						|
        await EventUtils.promiseNativeMouseEvent({
 | 
						|
          type: "mousemove",
 | 
						|
          target: browser,
 | 
						|
          atCenter: true,
 | 
						|
        });
 | 
						|
        const waitForOpenAutoScroll = promiseWaitForAutoScrollerOpen();
 | 
						|
        await EventUtils.promiseNativeMouseEvent({
 | 
						|
          type: "mousedown",
 | 
						|
          target: browser,
 | 
						|
          atCenter: true,
 | 
						|
          button: 1, // middle button
 | 
						|
        });
 | 
						|
        // In the wild, native "mouseup" event occurs after the popup is open.
 | 
						|
        await waitForOpenAutoScroll;
 | 
						|
        await EventUtils.promiseNativeMouseEvent({
 | 
						|
          type: "mouseup",
 | 
						|
          target: browser,
 | 
						|
          atCenter: true,
 | 
						|
          button: 1, // middle button
 | 
						|
        });
 | 
						|
        await promiseFlushLayoutInContent();
 | 
						|
        // Just to be sure, wait for a tick for wait APZ stable.
 | 
						|
        await TestUtils.waitForTick();
 | 
						|
 | 
						|
        let eventsInContent = new ContentEventCounter(browser, [
 | 
						|
          "click",
 | 
						|
          "auxclick",
 | 
						|
          "mousedown",
 | 
						|
          "mouseup",
 | 
						|
          "paste",
 | 
						|
          "contextmenu",
 | 
						|
        ]);
 | 
						|
        // Ensure that the event listeners added in the content with accessing
 | 
						|
        // the remote content.
 | 
						|
        await promiseFlushLayoutInContent();
 | 
						|
 | 
						|
        aDescription = `Stop autoscrolling with ${aDescription}`;
 | 
						|
        info(
 | 
						|
          `${aDescription}: Synthesizing primary mouse button event on the autoscroller`
 | 
						|
        );
 | 
						|
        const autoScrollerRect = autoScroller.getOuterScreenRect();
 | 
						|
        info(
 | 
						|
          `${aDescription}: autoScroller: { left: ${autoScrollerRect.left}, top: ${autoScrollerRect.top}, width: ${autoScrollerRect.width}, height: ${autoScrollerRect.height} }`
 | 
						|
        );
 | 
						|
        const waitForCloseAutoScroller = promiseWaitForAutoScrollerClosed();
 | 
						|
        if (aClickOutsideAutoScroller) {
 | 
						|
          info(
 | 
						|
            `${aDescription}: Synthesizing mousemove move cursor outside the autoscroller...`
 | 
						|
          );
 | 
						|
          await EventUtils.promiseNativeMouseEvent({
 | 
						|
            type: "mousemove",
 | 
						|
            target: autoScroller,
 | 
						|
            offsetX: -10,
 | 
						|
            offsetY: -10,
 | 
						|
            elementOnWidget: browser, // use widget for the parent window of the autoscroller
 | 
						|
          });
 | 
						|
          info(
 | 
						|
            `${aDescription}: Synthesizing mousedown to stop autoscrolling...`
 | 
						|
          );
 | 
						|
          await EventUtils.promiseNativeMouseEvent({
 | 
						|
            type: "mousedown",
 | 
						|
            target: autoScroller,
 | 
						|
            offsetX: -10,
 | 
						|
            offsetY: -10,
 | 
						|
            button: aButton,
 | 
						|
            elementOnWidget: browser, // use widget for the parent window of the autoscroller
 | 
						|
          });
 | 
						|
        } else {
 | 
						|
          info(
 | 
						|
            `${aDescription}: Synthesizing mousemove move cursor onto the autoscroller...`
 | 
						|
          );
 | 
						|
          await EventUtils.promiseNativeMouseEvent({
 | 
						|
            type: "mousemove",
 | 
						|
            target: autoScroller,
 | 
						|
            atCenter: true,
 | 
						|
            elementOnWidget: browser, // use widget for the parent window of the autoscroller
 | 
						|
          });
 | 
						|
          info(
 | 
						|
            `${aDescription}: Synthesizing mousedown to stop autoscrolling...`
 | 
						|
          );
 | 
						|
          await EventUtils.promiseNativeMouseEvent({
 | 
						|
            type: "mousedown",
 | 
						|
            target: autoScroller,
 | 
						|
            atCenter: true,
 | 
						|
            button: aButton,
 | 
						|
            elementOnWidget: browser, // use widget for the parent window of the autoscroller
 | 
						|
          });
 | 
						|
        }
 | 
						|
        // In the wild, native "mouseup" event occurs after the popup is closed.
 | 
						|
        await waitForCloseAutoScroller;
 | 
						|
        info(
 | 
						|
          `${aDescription}: Synthesizing mouseup event for preceding mousedown which is for stopping autoscrolling`
 | 
						|
        );
 | 
						|
        await EventUtils.promiseNativeMouseEvent({
 | 
						|
          type: "mouseup",
 | 
						|
          target: browser,
 | 
						|
          atCenter: true,
 | 
						|
          button: aButton,
 | 
						|
        });
 | 
						|
        await promiseFlushLayoutInContent();
 | 
						|
        await promiseContentTick();
 | 
						|
        await eventsInContent.promiseMouseEvents(
 | 
						|
          aButton != 2 ? ["mouseup"] : ["mouseup", "contextmenu"],
 | 
						|
          aDescription
 | 
						|
        );
 | 
						|
        is(
 | 
						|
          autoScroller.state,
 | 
						|
          "closed",
 | 
						|
          `${aDescription}: The autoscroller should've been closed`
 | 
						|
        );
 | 
						|
        // - On macOS, when clicking outside autoscroller, nsChildView
 | 
						|
        // intentionally blocks both "mousedown" and "mouseup" events in the
 | 
						|
        // case of the primary button click, and only "mousedown" for the
 | 
						|
        // middle button when the "mousedown".  I'm not sure how it should work
 | 
						|
        // on macOS for conforming to the platform manner.  Note that autoscroll
 | 
						|
        // isn't available on the other browsers on macOS.  So, there is no
 | 
						|
        // reference, but for consistency between platforms, it may be better
 | 
						|
        // to ignore the platform manner.
 | 
						|
        // - On Windows, when clicking outside autoscroller, nsWindow
 | 
						|
        // intentionally blocks only "mousedown" events for the primary button
 | 
						|
        // and the middle button.  But this behavior is different from Chrome
 | 
						|
        // so that we need to fix this in the future.
 | 
						|
        // - On Linux, when clicking outside autoscroller, nsWindow
 | 
						|
        // intentionally blocks only "mousedown" events for any buttons.  But
 | 
						|
        // on Linux, autoscroll isn't available by the default settings.  So,
 | 
						|
        // not so urgent, but should be fixed in the future for consistency
 | 
						|
        // between platforms and compatibility with Chrome on Windows.
 | 
						|
        const rollingUpPopupConsumeMouseDown =
 | 
						|
          aClickOutsideAutoScroller &&
 | 
						|
          (aButton != 2 || navigator.platform.includes("Linux"));
 | 
						|
        const rollingUpPopupConsumeMouseUp =
 | 
						|
          aClickOutsideAutoScroller &&
 | 
						|
          aButton == 0 &&
 | 
						|
          navigator.platform.includes("Mac");
 | 
						|
        const checkFuncForClick =
 | 
						|
          aClickOutsideAutoScroller &&
 | 
						|
          aButton == 2 &&
 | 
						|
          !navigator.platform.includes("Linux")
 | 
						|
            ? todo_is
 | 
						|
            : is;
 | 
						|
        for (let eventType of ["click", "auxclick"]) {
 | 
						|
          checkFuncForClick(
 | 
						|
            eventsInContent.getCountAndRemoveEventListener(eventType),
 | 
						|
            0,
 | 
						|
            `${aDescription}: "${eventType}" event shouldn't be fired in the remote content`
 | 
						|
          );
 | 
						|
        }
 | 
						|
        is(
 | 
						|
          eventsInContent.getCountAndRemoveEventListener("paste"),
 | 
						|
          0,
 | 
						|
          `${aDescription}: "paste" event shouldn't be fired in the remote content`
 | 
						|
        );
 | 
						|
        const checkFuncForMouseDown = rollingUpPopupConsumeMouseDown
 | 
						|
          ? todo_is
 | 
						|
          : is;
 | 
						|
        checkFuncForMouseDown(
 | 
						|
          eventsInContent.getCountAndRemoveEventListener("mousedown"),
 | 
						|
          1,
 | 
						|
          `${aDescription}: "mousedown" event should be fired in the remote content`
 | 
						|
        );
 | 
						|
        const checkFuncForMouseUp = rollingUpPopupConsumeMouseUp ? todo_is : is;
 | 
						|
        checkFuncForMouseUp(
 | 
						|
          eventsInContent.getCountAndRemoveEventListener("mouseup"),
 | 
						|
          1,
 | 
						|
          `${aDescription}: "mouseup" event should be fired in the remote content`
 | 
						|
        );
 | 
						|
        const checkFuncForContextMenu =
 | 
						|
          aButton == 2 &&
 | 
						|
          aClickOutsideAutoScroller &&
 | 
						|
          navigator.platform.includes("Linux")
 | 
						|
            ? todo_is
 | 
						|
            : is;
 | 
						|
        checkFuncForContextMenu(
 | 
						|
          eventsInContent.getCountAndRemoveEventListener("contextmenu"),
 | 
						|
          aButton == 2 ? 1 : 0,
 | 
						|
          `${aDescription}: "contextmenu" event should${
 | 
						|
            aButton != 2 ? " not" : ""
 | 
						|
          } be fired in the remote content`
 | 
						|
        );
 | 
						|
 | 
						|
        const promiseClickEvent = BrowserTestUtils.waitForContentEvent(
 | 
						|
          browser,
 | 
						|
          "click",
 | 
						|
          {
 | 
						|
            capture: true,
 | 
						|
          }
 | 
						|
        );
 | 
						|
        await promiseFlushLayoutInContent();
 | 
						|
        info(`${aDescription}: Waiting for click event in the remote content`);
 | 
						|
        EventUtils.synthesizeNativeMouseEvent({
 | 
						|
          type: "click",
 | 
						|
          target: browser,
 | 
						|
          atCenter: true,
 | 
						|
        });
 | 
						|
        await promiseClickEvent;
 | 
						|
        ok(
 | 
						|
          true,
 | 
						|
          `${aDescription}: click event is fired in the remote content after stopping autoscrolling`
 | 
						|
        );
 | 
						|
      }
 | 
						|
 | 
						|
      // Clicking the primary button to stop autoscrolling.
 | 
						|
      await doTestMouseEventsAtStoppingAutoScrolling({
 | 
						|
        aButton: 0,
 | 
						|
        aClickOutsideAutoScroller: false,
 | 
						|
        aDescription: "a primary button click on autoscroller",
 | 
						|
      });
 | 
						|
      await doTestMouseEventsAtStoppingAutoScrolling({
 | 
						|
        aButton: 0,
 | 
						|
        aClickOutsideAutoScroller: true,
 | 
						|
        aDescription: "a primary button click outside autoscroller",
 | 
						|
      });
 | 
						|
 | 
						|
      // Clicking the secondary button to stop autoscrolling.
 | 
						|
      await doTestMouseEventsAtStoppingAutoScrolling({
 | 
						|
        aButton: 2,
 | 
						|
        aClickOutsideAutoScroller: false,
 | 
						|
        aDescription: "a secondary button click on autoscroller",
 | 
						|
      });
 | 
						|
      await doTestMouseEventsAtStoppingAutoScrolling({
 | 
						|
        aButton: 2,
 | 
						|
        aClickOutsideAutoScroller: true,
 | 
						|
        aDescription: "a secondary button click outside autoscroller",
 | 
						|
      });
 | 
						|
 | 
						|
      // Clicking the middle button to stop autoscrolling.
 | 
						|
      await SpecialPowers.pushPrefEnv({ set: [["middlemouse.paste", true]] });
 | 
						|
      await doTestMouseEventsAtStoppingAutoScrolling({
 | 
						|
        aButton: 1,
 | 
						|
        aClickOutsideAutoScroller: false,
 | 
						|
        aDescription:
 | 
						|
          "a middle button click on autoscroller (middle click paste enabled)",
 | 
						|
      });
 | 
						|
      await doTestMouseEventsAtStoppingAutoScrolling({
 | 
						|
        aButton: 1,
 | 
						|
        aClickOutsideAutoScroller: true,
 | 
						|
        aDescription:
 | 
						|
          "a middle button click outside autoscroller (middle click paste enabled)",
 | 
						|
      });
 | 
						|
      await SpecialPowers.pushPrefEnv({ set: [["middlemouse.paste", false]] });
 | 
						|
      await doTestMouseEventsAtStoppingAutoScrolling({
 | 
						|
        aButton: 1,
 | 
						|
        aClickOutsideAutoScroller: false,
 | 
						|
        aDescription:
 | 
						|
          "a middle button click on autoscroller (middle click paste disabled)",
 | 
						|
      });
 | 
						|
      await doTestMouseEventsAtStoppingAutoScrolling({
 | 
						|
        aButton: 1,
 | 
						|
        aClickOutsideAutoScroller: true,
 | 
						|
        aDescription:
 | 
						|
          "a middle button click outside autoscroller (middle click paste disabled)",
 | 
						|
      });
 | 
						|
    }
 | 
						|
  );
 | 
						|
});
 |