summaryrefslogtreecommitdiffstats
path: root/browser/components/resistfingerprinting/test/browser/browser_dynamical_window_rounding.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/resistfingerprinting/test/browser/browser_dynamical_window_rounding.js')
-rw-r--r--browser/components/resistfingerprinting/test/browser/browser_dynamical_window_rounding.js397
1 files changed, 397 insertions, 0 deletions
diff --git a/browser/components/resistfingerprinting/test/browser/browser_dynamical_window_rounding.js b/browser/components/resistfingerprinting/test/browser/browser_dynamical_window_rounding.js
new file mode 100644
index 0000000000..13dcec8ea1
--- /dev/null
+++ b/browser/components/resistfingerprinting/test/browser/browser_dynamical_window_rounding.js
@@ -0,0 +1,397 @@
+/* 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/.
+ *
+ * Bug 1407366 - A test case for reassuring the size of the content viewport is
+ * rounded if the window is resized when letterboxing is enabled.
+ *
+ * A helpful note: if this test starts randomly failing; it may be because the
+ * zoom level was not reset by an earlier-run test. See Bug 1407366 for an
+ * example.
+ */
+
+const { RFPHelper } = ChromeUtils.importESModule(
+ "resource://gre/modules/RFPHelper.sys.mjs"
+);
+
+// A set of test cases which defines the width and the height of the outer window.
+const TEST_CASES = [
+ { width: 1250, height: 1000 },
+ { width: 1500, height: 1050 },
+ { width: 1120, height: 760 },
+ { width: 800, height: 600 },
+ { width: 640, height: 400 },
+ { width: 500, height: 350 },
+];
+
+function getPlatform() {
+ const { OS } = Services.appinfo;
+ if (OS == "WINNT") {
+ return "win";
+ } else if (OS == "Darwin") {
+ return "mac";
+ }
+ return "linux";
+}
+
+function handleOSFuzziness(aContent, aTarget) {
+ /*
+ * On Windows, we observed off-by-one pixel differences that
+ * couldn't be expained. When manually setting the window size
+ * to try to reproduce it; it did not occur.
+ */
+ if (getPlatform() == "win") {
+ return Math.abs(aContent - aTarget) <= 1;
+ }
+ return aContent == aTarget;
+}
+
+function checkForDefaultSetting(
+ aContentWidth,
+ aContentHeight,
+ aRealWidth,
+ aRealHeight
+) {
+ // We can get the rounded size by subtracting twice the margin.
+ let targetWidth = aRealWidth - 2 * RFPHelper.steppedRange(aRealWidth);
+ let targetHeight = aRealHeight - 2 * RFPHelper.steppedRange(aRealHeight);
+
+ // This platform-specific code is explained in the large comment below.
+ if (getPlatform() != "linux") {
+ ok(
+ handleOSFuzziness(aContentWidth, targetWidth),
+ `Default Dimensions: The content window width is correctly rounded into. ${aRealWidth}px -> ${aContentWidth}px should equal ${targetWidth}px`
+ );
+
+ ok(
+ handleOSFuzziness(aContentHeight, targetHeight),
+ `Default Dimensions: The content window height is correctly rounded into. ${aRealHeight}px -> ${aContentHeight}px should equal ${targetHeight}px`
+ );
+
+ // Using ok() above will cause Win/Mac to fail on even the first test, we don't need to repeat it, return true so waitForCondition ends
+ return true;
+ }
+ // Returning true or false depending on if the test succeeded will cause Linux to repeat until it succeeds.
+ return (
+ handleOSFuzziness(aContentWidth, targetWidth) &&
+ handleOSFuzziness(aContentHeight, targetHeight)
+ );
+}
+
+async function test_dynamical_window_rounding(aWindow, aCheckFunc) {
+ // We need to wait for the updating the margins for the newly opened tab, or
+ // it will affect the following tests.
+ let promiseForTheFirstRounding = TestUtils.topicObserved(
+ "test:letterboxing:update-margin-finish"
+ );
+
+ info("Open a content tab for testing.");
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ aWindow.gBrowser,
+ TEST_PATH + "file_dummy.html"
+ );
+
+ info("Wait until the margins are applied for the opened tab.");
+ await promiseForTheFirstRounding;
+
+ let getContainerSize = aTab => {
+ let browserContainer = aWindow.gBrowser.getBrowserContainer(
+ aTab.linkedBrowser
+ );
+ return {
+ containerWidth: browserContainer.clientWidth,
+ containerHeight: browserContainer.clientHeight,
+ };
+ };
+
+ for (let { width, height } of TEST_CASES) {
+ let caseString = "Case " + width + "x" + height + ": ";
+ // Create a promise for waiting for the margin update.
+ let promiseRounding = TestUtils.topicObserved(
+ "test:letterboxing:update-margin-finish"
+ );
+
+ let { containerWidth, containerHeight } = getContainerSize(tab);
+
+ info(
+ caseString +
+ "Resize the window and wait until resize event happened (currently " +
+ containerWidth +
+ "x" +
+ containerHeight +
+ ")"
+ );
+ await new Promise(resolve => {
+ ({ containerWidth, containerHeight } = getContainerSize(tab));
+ info(
+ caseString +
+ "Resizing (currently " +
+ containerWidth +
+ "x" +
+ containerHeight +
+ ")"
+ );
+
+ aWindow.onresize = () => {
+ ({ containerWidth, containerHeight } = getContainerSize(tab));
+ info(
+ caseString +
+ "Resized (currently " +
+ containerWidth +
+ "x" +
+ containerHeight +
+ ")"
+ );
+ if (getPlatform() == "linux" && containerWidth != width) {
+ /*
+ * We observed frequent test failures that resulted from receiving an onresize
+ * event where the browser was resized to an earlier requested dimension. This
+ * resize event happens on Linux only, and is an artifact of the asynchronous
+ * resizing. (See more discussion on 1407366#53)
+ *
+ * We cope with this problem in two ways.
+ *
+ * 1: If we detect that the browser was resized to the wrong value; we
+ * redo the resize. (This is the lines of code immediately following this
+ * comment)
+ * 2: We repeat the test until it works using waitForCondition(). But we still
+ * test Win/Mac more thoroughly: they do not loop in waitForCondition more
+ * than once, and can fail the test on the first attempt (because their
+ * check() functions use ok() while on Linux, we do not all ok() and instead
+ * rely on waitForCondition to fail).
+ *
+ * The logging statements in this test, and RFPHelper.jsm, help narrow down and
+ * illustrate the issue.
+ */
+ info(caseString + "We hit the weird resize bug. Resize it again.");
+ aWindow.resizeTo(width, height);
+ } else {
+ resolve();
+ }
+ };
+ aWindow.resizeTo(width, height);
+ });
+
+ ({ containerWidth, containerHeight } = getContainerSize(tab));
+ info(
+ caseString +
+ "Waiting until margin has been updated on browser element. (currently " +
+ containerWidth +
+ "x" +
+ containerHeight +
+ ")"
+ );
+ await promiseRounding;
+
+ info(caseString + "Get innerWidth/Height from the content.");
+ await BrowserTestUtils.waitForCondition(async () => {
+ let { contentWidth, contentHeight } = await SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [],
+ () => {
+ return {
+ contentWidth: content.innerWidth,
+ contentHeight: content.innerHeight,
+ };
+ }
+ );
+
+ info(caseString + "Check the result.");
+ return aCheckFunc(
+ contentWidth,
+ contentHeight,
+ containerWidth,
+ containerHeight
+ );
+ }, "Default Dimensions: The content window width is correctly rounded into.");
+ }
+
+ BrowserTestUtils.removeTab(tab);
+}
+
+async function test_customize_width_and_height(aWindow) {
+ const test_dimensions = `120x80, 200x143, 335x255, 600x312, 742x447, 813x558,
+ 990x672, 1200x733, 1470x858`;
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["privacy.resistFingerprinting.letterboxing.dimensions", test_dimensions],
+ ],
+ });
+
+ let dimensions_set = test_dimensions.split(",").map(item => {
+ let sizes = item.split("x").map(size => parseInt(size, 10));
+
+ return {
+ width: sizes[0],
+ height: sizes[1],
+ };
+ });
+
+ let checkDimension = (
+ aContentWidth,
+ aContentHeight,
+ aRealWidth,
+ aRealHeight
+ ) => {
+ let matchingArea = aRealWidth * aRealHeight;
+ let minWaste = Number.MAX_SAFE_INTEGER;
+ let targetDimensions = undefined;
+
+ // Find the dimensions which waste the least content area.
+ for (let dim of dimensions_set) {
+ if (dim.width > aRealWidth || dim.height > aRealHeight) {
+ continue;
+ }
+
+ let waste = matchingArea - dim.width * dim.height;
+
+ if (waste >= 0 && waste < minWaste) {
+ targetDimensions = dim;
+ minWaste = waste;
+ }
+ }
+
+ // This platform-specific code is explained in the large comment above.
+ if (getPlatform() != "linux") {
+ ok(
+ handleOSFuzziness(aContentWidth, targetDimensions.width),
+ `Custom Dimension: The content window width is correctly rounded into. ${aRealWidth}px -> ${aContentWidth}px should equal ${targetDimensions.width}`
+ );
+
+ ok(
+ handleOSFuzziness(aContentHeight, targetDimensions.height),
+ `Custom Dimension: The content window height is correctly rounded into. ${aRealHeight}px -> ${aContentHeight}px should equal ${targetDimensions.height}`
+ );
+
+ // Using ok() above will cause Win/Mac to fail on even the first test, we don't need to repeat it, return true so waitForCondition ends
+ return true;
+ }
+ // Returning true or false depending on if the test succeeded will cause Linux to repeat until it succeeds.
+ return (
+ handleOSFuzziness(aContentWidth, targetDimensions.width) &&
+ handleOSFuzziness(aContentHeight, targetDimensions.height)
+ );
+ };
+
+ await test_dynamical_window_rounding(aWindow, checkDimension);
+
+ await SpecialPowers.popPrefEnv();
+}
+
+async function test_no_rounding_for_chrome(aWindow) {
+ // First, resize the window to a size which is not rounded.
+ await new Promise(resolve => {
+ aWindow.onresize = () => resolve();
+ aWindow.resizeTo(700, 450);
+ });
+
+ // open a chrome privilege tab, like about:config.
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ aWindow.gBrowser,
+ "about:config"
+ );
+
+ // Check that the browser element should not have a margin.
+ is(
+ tab.linkedBrowser.style.margin,
+ "",
+ "There is no margin around chrome tab."
+ );
+
+ BrowserTestUtils.removeTab(tab);
+}
+
+// Tests that the findbar opening and closing causes a margin update.
+async function test_findbar(aWindow) {
+ // First, resize the window to a size which is not rounded.
+ await new Promise(resolve => {
+ aWindow.onresize = () => resolve();
+ aWindow.resizeTo(701, 451);
+ });
+
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ aWindow.gBrowser,
+ TEST_PATH + "file_dummy.html"
+ );
+
+ let promiseRounding = TestUtils.topicObserved(
+ "test:letterboxing:update-margin-finish"
+ );
+
+ let findBarOpenPromise = BrowserTestUtils.waitForEvent(
+ aWindow,
+ "findbaropen"
+ );
+ EventUtils.synthesizeKey("F", { accelKey: true }, aWindow);
+ await findBarOpenPromise;
+ await promiseRounding;
+
+ ok(true, "Margin updated when findbar opened");
+
+ promiseRounding = TestUtils.topicObserved(
+ "test:letterboxing:update-margin-finish"
+ );
+
+ let findBarClosePromise = BrowserTestUtils.waitForEvent(
+ aWindow,
+ "findbarclose"
+ );
+ EventUtils.synthesizeKey("KEY_Escape", {}, aWindow);
+ await findBarClosePromise;
+ await promiseRounding;
+
+ ok(true, "Margin updated when findbar closed");
+
+ BrowserTestUtils.removeTab(tab);
+}
+
+add_setup(async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["privacy.resistFingerprinting.letterboxing", true],
+ ["privacy.resistFingerprinting.letterboxing.testing", true],
+ ],
+ });
+});
+
+add_task(async function do_tests() {
+ // Store the original window size before testing.
+ let originalOuterWidth = window.outerWidth;
+ let originalOuterHeight = window.outerHeight;
+
+ info("Run test for the default window rounding.");
+ await test_dynamical_window_rounding(window, checkForDefaultSetting);
+
+ info("Run test for the window rounding with customized dimensions.");
+ await test_customize_width_and_height(window);
+
+ info("Run test for no margin around tab with the chrome privilege.");
+ await test_no_rounding_for_chrome(window);
+
+ await test_findbar(window);
+
+ // Restore the original window size.
+ window.outerWidth = originalOuterWidth;
+ window.outerHeight = originalOuterHeight;
+
+ // Testing that whether the dynamical rounding works for new windows.
+ let win = await BrowserTestUtils.openNewBrowserWindow();
+
+ info("Run test for the default window rounding in new window.");
+ await test_dynamical_window_rounding(win, checkForDefaultSetting);
+
+ info(
+ "Run test for the window rounding with customized dimensions in new window."
+ );
+ await test_customize_width_and_height(win);
+
+ info(
+ "Run test for no margin around tab with the chrome privilege in new window."
+ );
+ await test_no_rounding_for_chrome(win);
+
+ await test_findbar(win);
+
+ await BrowserTestUtils.closeWindow(win);
+});