summaryrefslogtreecommitdiffstats
path: root/image/test/browser/browser_offscreen_image_in_out_of_process_iframe.js
diff options
context:
space:
mode:
Diffstat (limited to 'image/test/browser/browser_offscreen_image_in_out_of_process_iframe.js')
-rw-r--r--image/test/browser/browser_offscreen_image_in_out_of_process_iframe.js164
1 files changed, 164 insertions, 0 deletions
diff --git a/image/test/browser/browser_offscreen_image_in_out_of_process_iframe.js b/image/test/browser/browser_offscreen_image_in_out_of_process_iframe.js
new file mode 100644
index 0000000000..71b34a4715
--- /dev/null
+++ b/image/test/browser/browser_offscreen_image_in_out_of_process_iframe.js
@@ -0,0 +1,164 @@
+/* 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/. */
+
+"use strict";
+
+const DIRPATH = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content/",
+ ""
+);
+const parentPATH = DIRPATH + "empty.html";
+const iframePATH = DIRPATH + "empty.html";
+
+const parentURL = `http://example.com/${parentPATH}`;
+const iframeURL = `http://example.org/${iframePATH}`;
+
+add_task(async function setup_pref() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ // To avoid throttling requestAnimationFrame callbacks in invisible
+ // iframes
+ ["layout.throttled_frame_rate", 60],
+ ],
+ });
+});
+
+add_task(async function () {
+ const win = await BrowserTestUtils.openNewBrowserWindow({
+ fission: true,
+ });
+
+ try {
+ const browser = win.gBrowser.selectedTab.linkedBrowser;
+
+ BrowserTestUtils.loadURIString(browser, parentURL);
+ await BrowserTestUtils.browserLoaded(browser, false, parentURL);
+
+ async function setup(url) {
+ const scroller = content.document.createElement("div");
+ scroller.style = "width: 300px; height: 300px; overflow: scroll;";
+ scroller.setAttribute("id", "scroller");
+ content.document.body.appendChild(scroller);
+
+ // Make a space bigger than display port.
+ const spacer = content.document.createElement("div");
+ spacer.style = "width: 100%; height: 10000px;";
+ scroller.appendChild(spacer);
+
+ const iframe = content.document.createElement("iframe");
+ scroller.appendChild(iframe);
+
+ iframe.contentWindow.location = url;
+ await new Promise(resolve => {
+ iframe.addEventListener("load", resolve, { once: true });
+ });
+
+ return iframe.browsingContext;
+ }
+
+ async function setupImage() {
+ const img = content.document.createElement("img");
+ // This GIF is a 100ms interval animation.
+ img.setAttribute("src", "animated.gif");
+ img.setAttribute("id", "img");
+ content.document.body.appendChild(img);
+
+ const spacer = content.document.createElement("div");
+ spacer.style = "width: 100%; height: 10000px;";
+ content.document.body.appendChild(spacer);
+ await new Promise(resolve => {
+ img.addEventListener("load", resolve, { once: true });
+ });
+ }
+
+ // Returns the count of frameUpdate during |time| (in ms) period.
+ async function observeFrameUpdate(time) {
+ function ImageDecoderObserverStub() {
+ this.sizeAvailable = function sizeAvailable(aRequest) {};
+ this.frameComplete = function frameComplete(aRequest) {};
+ this.decodeComplete = function decodeComplete(aRequest) {};
+ this.loadComplete = function loadComplete(aRequest) {};
+ this.frameUpdate = function frameUpdate(aRequest) {};
+ this.discard = function discard(aRequest) {};
+ this.isAnimated = function isAnimated(aRequest) {};
+ this.hasTransparency = function hasTransparency(aRequest) {};
+ }
+
+ // Start from the callback of setTimeout.
+ await new Promise(resolve => content.window.setTimeout(resolve, 0));
+
+ let frameCount = 0;
+ const observer = new ImageDecoderObserverStub();
+ observer.frameUpdate = () => {
+ frameCount++;
+ };
+ observer.loadComplete = () => {
+ // Ignore the frameUpdate callback along with loadComplete. It seems
+ // a frameUpdate sometimes happens with a loadComplete when attatching
+ // observer in fission world.
+ frameCount--;
+ };
+
+ const gObserver = SpecialPowers.Cc["@mozilla.org/image/tools;1"]
+ .getService(SpecialPowers.Ci.imgITools)
+ .createScriptedObserver(observer);
+ const img = content.document.getElementById("img");
+
+ SpecialPowers.wrap(img).addObserver(gObserver);
+ await new Promise(resolve => content.window.setTimeout(resolve, time));
+ SpecialPowers.wrap(img).removeObserver(gObserver);
+
+ return frameCount;
+ }
+
+ // Setup an iframe which is initially scrolled out.
+ const iframe = await SpecialPowers.spawn(browser, [iframeURL], setup);
+
+ // Setup a 100ms interval animated GIF image in the iframe.
+ await SpecialPowers.spawn(iframe, [], setupImage);
+
+ let frameCount = await SpecialPowers.spawn(
+ iframe,
+ [1000],
+ observeFrameUpdate
+ );
+ // Bug 1577084.
+ if (frameCount == 0) {
+ is(frameCount, 0, "no frameupdates");
+ } else {
+ todo_is(frameCount, 0, "no frameupdates");
+ }
+
+ // Scroll the iframe into view.
+ await SpecialPowers.spawn(browser, [], async () => {
+ const scroller = content.document.getElementById("scroller");
+ scroller.scrollTo({ left: 0, top: 9800, behavior: "smooth" });
+ await new Promise(resolve => content.window.setTimeout(resolve, 1000));
+ });
+
+ await new Promise(resolve => requestAnimationFrame(resolve));
+
+ frameCount = await SpecialPowers.spawn(iframe, [1000], observeFrameUpdate);
+ ok(frameCount > 0, "There should be frameUpdate(s)");
+
+ await new Promise(resolve => requestAnimationFrame(resolve));
+
+ await SpecialPowers.spawn(iframe, [], async () => {
+ const img = content.document.getElementById("img");
+ // Move the image outside of the scroll port. 'position: absolute' causes
+ // a relow on the image element.
+ img.style = "position: absolute; top: 9000px;";
+ await new Promise(resolve =>
+ content.window.requestAnimationFrame(resolve)
+ );
+ });
+
+ await new Promise(resolve => requestAnimationFrame(resolve));
+
+ frameCount = await SpecialPowers.spawn(iframe, [1000], observeFrameUpdate);
+ is(frameCount, 0, "No frameUpdate should happen");
+ } finally {
+ await BrowserTestUtils.closeWindow(win);
+ }
+});