diff options
Diffstat (limited to 'toolkit/components/windowcreator')
30 files changed, 1038 insertions, 0 deletions
diff --git a/toolkit/components/windowcreator/moz.build b/toolkit/components/windowcreator/moz.build new file mode 100644 index 0000000000..66b328cc79 --- /dev/null +++ b/toolkit/components/windowcreator/moz.build @@ -0,0 +1,20 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +with Files("**"): + BUG_COMPONENT = ("Core", "Window Management") + +TEST_DIRS += ["test"] + +if CONFIG["ENABLE_TESTS"]: + XPCSHELL_TESTS_MANIFESTS += ["tests/unit/xpcshell.ini"] + +XPIDL_SOURCES += [ + "nsIWindowCreator.idl", + "nsIWindowProvider.idl", +] + +XPIDL_MODULE = "windowcreator" diff --git a/toolkit/components/windowcreator/nsIWindowCreator.idl b/toolkit/components/windowcreator/nsIWindowCreator.idl new file mode 100644 index 0000000000..b03ec11448 --- /dev/null +++ b/toolkit/components/windowcreator/nsIWindowCreator.idl @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * 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/. */ + +/** + * nsIWindowCreator is a callback interface used by Gecko to create + * new browser windows. The application, either Mozilla or an embedding app, + * must provide an implementation of the Window Watcher component and + * notify the WindowWatcher during application initialization. + * + * @see nsIWindowWatcher + */ + +#include "nsISupports.idl" + +interface nsIOpenWindowInfo; +interface nsIRemoteTab; +interface nsIURI; +interface nsIWebBrowserChrome; +interface mozIDOMWindowProxy; + +[scriptable, uuid(30465632-A777-44cc-90F9-8145475EF999)] +interface nsIWindowCreator : nsISupports { + + /** Create a new window. Gecko will/may call this method, if made + available to it, to create new windows. + @param parent Parent window, if any. Null if not. The newly created + window should be made a child/dependent window of + the parent, if any (and if the concept applies + to the underlying OS). + @param chromeFlags Chrome features from nsIWebBrowserChrome + @param aOpenWindowInfo Information used to open initial content in + the new chrome window. Can be nullptr. + @param cancel Return |true| to reject window creation. If true the + implementation has determined the window should not + be created at all. The caller should not default + to any possible backup scheme for creating the window. + @return the new window. Will be null if canceled or an error occurred. + */ + nsIWebBrowserChrome createChromeWindow(in nsIWebBrowserChrome parent, + in uint32_t chromeFlags, + in nsIOpenWindowInfo aOpenWindowInfo, + out boolean cancel); +}; + +%{C++ +// {30465632-A777-44cc-90F9-8145475EF999} +#define NS_WINDOWCREATOR_IID \ + {0x30465632, 0xa777, 0x44cc, {0x90, 0xf9, 0x81, 0x45, 0x47, 0x5e, 0xf9, 0x99}} +%} diff --git a/toolkit/components/windowcreator/nsIWindowProvider.idl b/toolkit/components/windowcreator/nsIWindowProvider.idl new file mode 100644 index 0000000000..a51b5689ee --- /dev/null +++ b/toolkit/components/windowcreator/nsIWindowProvider.idl @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +/** + * nsIWindowProvider is a callback interface used by Gecko when it needs to + * open a new window. This interface can be implemented by Gecko consumers who + * wish to provide a custom "new window" of their own (for example by returning + * a new tab, an existing window, etc) instead of just having a real new + * toplevel window open. + */ + +#include "nsISupports.idl" + +%{ C++ +class nsDocShellLoadState; +%} + +webidl BrowsingContext; +interface mozIDOMWindowProxy; +interface nsIURI; +interface nsIOpenWindowInfo; +native nsDocShellLoadStatePtr(nsDocShellLoadState*); + +/** + * The nsIWindowProvider interface exists so that the window watcher's default + * behavior of opening a new window can be easly modified. When the window + * watcher needs to open a new window, it will first check with the + * nsIWindowProvider it gets from the parent window. If there is no provider + * or the provider does not provide a window, the window watcher will proceed + * to actually open a new window. + */ +[scriptable, uuid(e97a3830-15ef-499b-8372-c22d128091c1)] +interface nsIWindowProvider : nsISupports +{ + /** + * A method to request that this provider provide a window. The window + * returned need not to have the right name or parent set on it; setting + * those is the caller's responsibility. The provider can always return null + * to have the caller create a brand-new window. + * + * @param aOpenWindowInfo Must not be null. This is the information the + * caller wants to be used to construct the new window. + * + * @param aChromeFlags The chrome flags the caller will use to create a new + * window if this provider returns null. See nsIWebBrowserChrome for + * the possible values of this field. + * + * @param aURI The URI to be loaded in the new window (may be NULL). The + * nsIWindowProvider implementation must not load this URI into the + * window it returns. This URI is provided solely to help the + * nsIWindowProvider implementation make decisions; the caller will + * handle loading the URI in the window returned if provideWindow + * returns a window. + * + * When making decisions based on aURI, note that even when it's not + * null, aURI may not represent all relevant information about the + * load. For example, the load may have extra load flags, POST data, + * etc. + * + * @param aName The name of the window being opened. Setting the name on the + * return value of provideWindow will be handled by the caller; aName + * is provided solely to help the nsIWindowProvider implementation + * make decisions. + * + * @param aFeatures The feature string for the window being opened. This may + * be empty. The nsIWindowProvider implementation is allowed to apply + * the feature string to the window it returns in any way it sees fit. + * See the nsIWindowWatcher interface for details on feature strings. + * + * @param aIsPopupRequested True if this window is opened by window.open + * with requesting a popup window. This doesn't necessarily mean + * whether the actual window is shown as minimal popup or not. + * + * @param aLoadState Specify setup information of the load in the new window + * + * @param aWindowIsNew [out] Whether the window being returned was just + * created by the window provider implementation. This can be used by + * callers to keep track of which windows were opened by the user as + * opposed to being opened programmatically. This should be set to + * false if the window being returned existed before the + * provideWindow() call. The value of this out parameter is + * meaningless if provideWindow() returns null. + * + * @return A window the caller should use or null if the caller should just + * create a new window. The returned window may be newly opened by + * the nsIWindowProvider implementation or may be a window that + * already existed. + * + * @throw NS_ERROR_ABORT if the caller should cease its attempt to open a new + * window. + * + * @see nsIWindowWatcher for more information on aFeatures. + * @see nsIWebBrowserChrome for more information on aChromeFlags. + */ + [noscript] + BrowsingContext provideWindow(in nsIOpenWindowInfo aOpenWindowInfo, + in unsigned long aChromeFlags, + in boolean aCalledFromJS, + in nsIURI aURI, + in AString aName, + in AUTF8String aFeatures, + in boolean aForceNoOpener, + in boolean aForceNoReferrer, + in boolean aIsPopupRequested, + in nsDocShellLoadStatePtr aLoadState, + out boolean aWindowIsNew); +}; diff --git a/toolkit/components/windowcreator/test/320x240.ogv b/toolkit/components/windowcreator/test/320x240.ogv Binary files differnew file mode 100644 index 0000000000..093158432a --- /dev/null +++ b/toolkit/components/windowcreator/test/320x240.ogv diff --git a/toolkit/components/windowcreator/test/browser.ini b/toolkit/components/windowcreator/test/browser.ini new file mode 100644 index 0000000000..53f53c0d61 --- /dev/null +++ b/toolkit/components/windowcreator/test/browser.ini @@ -0,0 +1,13 @@ +[browser_bug1204626.js] +support-files = + bug1204626_doc0.html + bug1204626_doc1.html +[browser_save_form_input_state.js] +support-files = + file_form_state.html +[browser_persist.js] +support-files = + file_persist_srcset.html + file_persist_svg.html + file_persist_picture_source.html + file_persist_image.png diff --git a/toolkit/components/windowcreator/test/browser_bug1204626.js b/toolkit/components/windowcreator/test/browser_bug1204626.js new file mode 100644 index 0000000000..84dbf5080a --- /dev/null +++ b/toolkit/components/windowcreator/test/browser_bug1204626.js @@ -0,0 +1,88 @@ +/* eslint-disable mozilla/no-arbitrary-setTimeout */ +"use strict"; // -*- js-indent-level: 2; indent-tabs-mode: nil -*- +const contentBase = + "https://example.com/browser/toolkit/components/windowcreator/test/"; +const chromeBase = + "chrome://mochitests/content/browser/toolkit/components/windowcreator/test/"; +const testPageURL = contentBase + "bug1204626_doc0.html"; + +function one_test(delay, continuation) { + let delayStr = delay === null ? "no delay" : "delay = " + delay + "ms"; + let browser; + + BrowserTestUtils.openNewForegroundTab(gBrowser, testPageURL).then(tab => { + browser = tab.linkedBrowser; + let persistable = browser.frameLoader; + persistable.startPersistence(null, { + onDocumentReady, + onError(status) { + ok(false, new Components.Exception("startPersistence failed", status)); + continuation(); + }, + }); + }); + + function onDocumentReady(doc) { + const nameStem = "test_bug1204626_" + Date.now(); + let wbp = Cc[ + "@mozilla.org/embedding/browser/nsWebBrowserPersist;1" + ].createInstance(Ci.nsIWebBrowserPersist); + let tmp = Services.dirsvc.get("TmpD", Ci.nsIFile); + let tmpFile = tmp.clone(); + tmpFile.append(nameStem + "_saved.html"); + let tmpDir = tmp.clone(); + tmpDir.append(nameStem + "_files"); + + registerCleanupFunction(function cleanUp() { + if (tmpFile.exists()) { + tmpFile.remove(/* recursive: */ false); + } + if (tmpDir.exists()) { + tmpDir.remove(/* recursive: */ true); + } + }); + + wbp.progressListener = { + onProgressChange() {}, + onLocationChange() {}, + onStatusChange() {}, + onSecurityChange() {}, + onContentBlockingEvent() {}, + onStateChange(_wbp, _req, state, _status) { + if ((state & Ci.nsIWebProgressListener.STATE_STOP) == 0) { + return; + } + ok(true, "Finished save (" + delayStr + ") but might have crashed."); + continuation(); + }, + }; + + function doSave() { + wbp.saveDocument(doc, tmpFile, tmpDir, null, 0, 0); + } + if (delay === null) { + doSave(); + } else { + setTimeout(doSave, delay); + } + SpecialPowers.spawn(browser, [], () => { + content.window.close(); + }); + } +} + +function test() { + waitForExplicitFinish(); + // 0ms breaks having the actor under PBrowser, but not 10ms. + // 10ms provokes the double-__delete__, but not 0ms. + // And a few others, just in case. + const testRuns = [null, 0, 10, 0, 10, 20, 50, 100]; + let i = 0; + (function next_test() { + if (i < testRuns.length) { + one_test(testRuns[i++], next_test); + } else { + finish(); + } + })(); +} diff --git a/toolkit/components/windowcreator/test/browser_persist.js b/toolkit/components/windowcreator/test/browser_persist.js new file mode 100644 index 0000000000..54ab889aac --- /dev/null +++ b/toolkit/components/windowcreator/test/browser_persist.js @@ -0,0 +1,105 @@ +"use strict"; // -*- js-indent-level: 2; indent-tabs-mode: nil -*- + +Services.scriptloader.loadSubScript( + "chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js", + this +); + +const contentBase = + "https://example.com/browser/toolkit/components/windowcreator/test/"; +const chromeBase = + "chrome://mochitests/content/browser/toolkit/components/windowcreator/test/"; + +// Checks that the source and target documents are the same. +const REFTESTS = [ + "file_persist_srcset.html", + "file_persist_picture_source.html", + "file_persist_svg.html", + // ... +]; + +async function persist(name, uri) { + return BrowserTestUtils.withNewTab(uri, async function (browser) { + // Snapshot the doc as loaded, this is our reference. + info("snapshotting reference"); + let reference = await snapshotWindow(browser); + + info("starting persistence"); + let doc = await new Promise(function (resolve) { + browser.frameLoader.startPersistence(null, { + onDocumentReady(d) { + resolve(d); + }, + onError(e) { + ok(false, "startPersistence failed: " + e); + }, + }); + }); + + let wbp = Cc[ + "@mozilla.org/embedding/browser/nsWebBrowserPersist;1" + ].createInstance(Ci.nsIWebBrowserPersist); + let tmp = Services.dirsvc.get("TmpD", Ci.nsIFile); + let tmpFile = tmp.clone(); + tmpFile.append(name + "_saved.html"); + let tmpDir = tmp.clone(); + tmpDir.append(name + "_files"); + + registerCleanupFunction(function cleanUp() { + if (tmpFile.exists()) { + tmpFile.remove(/* recursive = */ false); + } + if (tmpDir.exists()) { + tmpDir.remove(/* recursive = */ true); + } + }); + + info("persisting document"); + // Wait for the persisted document. + await new Promise(function (resolve) { + wbp.progressListener = { + onProgressChange() {}, + onLocationChange() {}, + onStatusChange() {}, + onSecurityChange() {}, + onContentBlockingEvent() {}, + onStateChange(_wbp, _req, state, _status) { + if (state & Ci.nsIWebProgressListener.STATE_STOP) { + resolve(); + } + }, + }; + + wbp.saveDocument(doc, tmpFile, tmpDir, null, 0, 0); + }); + + info("load done, loading persisted document"); + let fileUri = Services.io.newFileURI(tmpFile).spec; + let test = await BrowserTestUtils.withNewTab( + fileUri, + async function (persistedBrowser) { + info("snapshotting persisted document"); + return snapshotWindow(persistedBrowser); + } + ); + return { test, reference }; + }); +} + +add_task(async function () { + for (let filename of REFTESTS) { + let uri = contentBase + filename; + let { test, reference } = await persist(filename, uri); + let expectEqual = true; + let [same, testUri, refUri] = compareSnapshots( + test, + reference, + expectEqual + ); + ok(same, "test and references should match"); + if (!same) { + info(testUri); + info(refUri); + } + } +}); diff --git a/toolkit/components/windowcreator/test/browser_save_form_input_state.js b/toolkit/components/windowcreator/test/browser_save_form_input_state.js new file mode 100644 index 0000000000..6992c29c85 --- /dev/null +++ b/toolkit/components/windowcreator/test/browser_save_form_input_state.js @@ -0,0 +1,131 @@ +/* Any copyright is dedicated to the Public Domain. + * https://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const TEST_PATH = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://example.com" +); + +var textareas = ["a-textbox", "a-prefilled-textbox"]; +var textboxes = ["a-text", "a-prefilled-text"]; + +/** + * Ported from mochitest, this test verifies that form state is saved by our + * webbrowserpersist code. See bug 293834 for context. + */ +add_task(async function checkFormStateSaved() { + await BrowserTestUtils.withNewTab( + TEST_PATH + "file_form_state.html", + async browser => { + await SpecialPowers.spawn(browser, [{ textareas, textboxes }], fillform); + let fileURISpec = await new Promise((resolve, reject) => { + let stack = Components.stack.caller; + browser.frameLoader.startPersistence(null, { + onDocumentReady(document) { + // Note that 'document' here is going to be an nsIWebBrowserPersistDocument, + // not a regular DOM document. + resolve(persistDocument(document)); + }, + onError(status) { + reject( + Components.Exception( + "saveBrowser failed asynchronously in startPersistence", + status, + stack + ) + ); + }, + }); + }); + await BrowserTestUtils.withNewTab(fileURISpec, async otherBrowser => { + await SpecialPowers.spawn( + otherBrowser, + [{ textareas, textboxes }], + checkform + ); + }); + } + ); +}); + +// eslint-disable-next-line no-shadow +function fillform({ textareas, textboxes }) { + let doc = content.document; + for (let i in textareas) { + doc.getElementById(textareas[i]).textContent += "form state"; + } + for (let i in textboxes) { + doc.getElementById(textboxes[i]).value += "form state"; + } + doc.getElementById("a-checkbox").checked = true; + doc.getElementById("radioa").checked = true; + doc.getElementById("aselect").selectedIndex = 0; +} + +// eslint-disable-next-line no-shadow +function checkform({ textareas, textboxes }) { + let doc = content.document; + for (let i in textareas) { + var textContent = doc.getElementById(textareas[i]).textContent; + Assert.ok( + /form\s+state/m.test(textContent), + "Modified textarea " + textareas[i] + " form state should be preserved!" + ); + } + for (let i in textboxes) { + var value = doc.getElementById(textboxes[i]).value; + Assert.ok( + /form\s+state/m.test(value), + "Modified textbox " + textboxes[i] + " form state should be preserved!" + ); + } + Assert.ok( + doc.getElementById("a-checkbox").checked, + "Modified checkbox checked state should be preserved!" + ); + Assert.ok( + doc.getElementById("radioa").checked, + "Modified radio checked state should be preserved!" + ); + Assert.equal( + doc.getElementById("aselect").selectedIndex, + 0, + "Modified select selected index should be preserved" + ); +} + +function getTempDir() { + return Services.dirsvc.get("TmpD", Ci.nsIFile); +} + +function persistDocument(aDoc) { + const nsIWBP = Ci.nsIWebBrowserPersist; + const persistFlags = + nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES | + nsIWBP.PERSIST_FLAGS_FROM_CACHE | + nsIWBP.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION; + const encodingFlags = nsIWBP.ENCODE_FLAGS_ENCODE_BASIC_ENTITIES; + + var file = getTempDir(); + file.append("bug293834-serialized.html"); + + var persist = Cc[ + "@mozilla.org/embedding/browser/nsWebBrowserPersist;1" + ].createInstance(Ci.nsIWebBrowserPersist); + persist.progressListener = null; + persist.persistFlags = persistFlags; + const kWrapColumn = 80; + var folder = getTempDir(); + folder.append("bug293834-serialized"); + persist.saveDocument( + aDoc, + file, + folder, + "text/html", + encodingFlags, + kWrapColumn + ); + return Services.io.newFileURI(file).spec; +} diff --git a/toolkit/components/windowcreator/test/bug1170334_iframe.xml b/toolkit/components/windowcreator/test/bug1170334_iframe.xml new file mode 100644 index 0000000000..1821e07f96 --- /dev/null +++ b/toolkit/components/windowcreator/test/bug1170334_iframe.xml @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="utf-8"?> +<?xml-stylesheet href="bug1170334_style.css" type="text/css" title=""?>FAIL"?> +<thing/> diff --git a/toolkit/components/windowcreator/test/bug1170334_style.css b/toolkit/components/windowcreator/test/bug1170334_style.css new file mode 100644 index 0000000000..476c22b695 --- /dev/null +++ b/toolkit/components/windowcreator/test/bug1170334_style.css @@ -0,0 +1 @@ +/* This stylesheet intentionally left blank. */ diff --git a/toolkit/components/windowcreator/test/bug1204626_doc0.html b/toolkit/components/windowcreator/test/bug1204626_doc0.html new file mode 100644 index 0000000000..cbced762c3 --- /dev/null +++ b/toolkit/components/windowcreator/test/bug1204626_doc0.html @@ -0,0 +1,3 @@ +<!DOCTYPE html> +<p>This is a document, and it contains an iframe:</p> +<iframe src="bug1204626_doc1.html"></iframe> diff --git a/toolkit/components/windowcreator/test/bug1204626_doc1.html b/toolkit/components/windowcreator/test/bug1204626_doc1.html new file mode 100644 index 0000000000..cffc283d2c --- /dev/null +++ b/toolkit/components/windowcreator/test/bug1204626_doc1.html @@ -0,0 +1,5 @@ +<!DOCTYPE html> +<p>This is the document inside the iframe. <small>(Currently this +document doesn't even need to exist in order to reproduce the bug in +question, as long as the parent contains a frame, but it's probably +best not to depend on that.)</small></p> diff --git a/toolkit/components/windowcreator/test/bug449141_page.html b/toolkit/components/windowcreator/test/bug449141_page.html new file mode 100644 index 0000000000..3b8e3f550a --- /dev/null +++ b/toolkit/components/windowcreator/test/bug449141_page.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> + +<html> + <head> + <title>Nested iframe for bug 449141</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + </head> + <body> + <video src='320x240.ogv'></video> + </body> +</html> diff --git a/toolkit/components/windowcreator/test/chrome.ini b/toolkit/components/windowcreator/test/chrome.ini new file mode 100644 index 0000000000..9954dde591 --- /dev/null +++ b/toolkit/components/windowcreator/test/chrome.ini @@ -0,0 +1,11 @@ +[DEFAULT] +support-files = + 320x240.ogv + bug449141_page.html + bug1170334_iframe.xml + bug1170334_style.css + +[test_bug449141.html] +skip-if = toolkit == 'android' +[test_bug1170334_wbp_xmlstyle.html] +[test_bug1192654.html] diff --git a/toolkit/components/windowcreator/test/file_form_state.html b/toolkit/components/windowcreator/test/file_form_state.html new file mode 100644 index 0000000000..b5e4cd4ada --- /dev/null +++ b/toolkit/components/windowcreator/test/file_form_state.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> + +<html> + <head> + <title>Nested iframe for bug 293834</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + </head> + <body> + <form> + not prefilled: <input id="a-text" type="text"></input><br> + prefilled: <input id="a-prefilled-text" type="text" value="prefill "></input><br> + + <input name="a-radio" id="radioa" value="radio-a" type="radio">Should be saved checked</input><br> + <input name="a-radio" value="radio-c" type="radio" checked="true">Initially checked</input><br> + <select id="aselect"> + <option value="target">Should be saved selected</option> + <option value="default" selected="selected">Default Selected</option> + </select><br> + not prefilled: <textarea id="a-textbox"></textarea><br> + prefilled: <textarea id="a-prefilled-textbox">prefill </textarea><br> + <input id="a-checkbox" type="checkbox">Should be saved checked</input><br> + <input id="a-prefilled-checkbox" type="checkbox" checked="true">Initiallly checked</input><br> + </form> + </body> +</html> diff --git a/toolkit/components/windowcreator/test/file_persist_image.png b/toolkit/components/windowcreator/test/file_persist_image.png Binary files differnew file mode 100644 index 0000000000..820f8cace2 --- /dev/null +++ b/toolkit/components/windowcreator/test/file_persist_image.png diff --git a/toolkit/components/windowcreator/test/file_persist_picture_source.html b/toolkit/components/windowcreator/test/file_persist_picture_source.html new file mode 100644 index 0000000000..26988cbf78 --- /dev/null +++ b/toolkit/components/windowcreator/test/file_persist_picture_source.html @@ -0,0 +1,5 @@ +<!doctype html> +<picture> + <source srcset="file_persist_image.png"> + <img width=100 height=100> +</picture> diff --git a/toolkit/components/windowcreator/test/file_persist_srcset.html b/toolkit/components/windowcreator/test/file_persist_srcset.html new file mode 100644 index 0000000000..46f9318ad9 --- /dev/null +++ b/toolkit/components/windowcreator/test/file_persist_srcset.html @@ -0,0 +1,3 @@ +<!doctype html> +<img width=100 height=100 srcset="file_persist_image.png" onerror="this.alt = location.href;" alt="FAIL"> +<img width=100 height=100 srcset="file_persist_image.png 1x, file_persist_image.png 2x, file_persist_image.png 100w, file_persist_image_bad.png"> diff --git a/toolkit/components/windowcreator/test/file_persist_svg.html b/toolkit/components/windowcreator/test/file_persist_svg.html new file mode 100644 index 0000000000..55de728352 --- /dev/null +++ b/toolkit/components/windowcreator/test/file_persist_svg.html @@ -0,0 +1,5 @@ +<!doctype html> +<svg> + <image href="file_persist_image.png"/> + <image x="100" xlink:href="file_persist_image.png"/> +</svg> diff --git a/toolkit/components/windowcreator/test/mochitest.ini b/toolkit/components/windowcreator/test/mochitest.ini new file mode 100644 index 0000000000..f90d819f5d --- /dev/null +++ b/toolkit/components/windowcreator/test/mochitest.ini @@ -0,0 +1,5 @@ +[test_private_window_from_content.html] +[test_window_open_position_constraint.html] +skip-if = toolkit == 'android' +[test_window_open_units.html] +skip-if = toolkit == 'android' || (devedition && os == 'win' && bits == 32) # Windows: bug 1540566 diff --git a/toolkit/components/windowcreator/test/moz.build b/toolkit/components/windowcreator/test/moz.build new file mode 100644 index 0000000000..bef136aaef --- /dev/null +++ b/toolkit/components/windowcreator/test/moz.build @@ -0,0 +1,9 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +MOCHITEST_MANIFESTS += ["mochitest.ini"] +MOCHITEST_CHROME_MANIFESTS += ["chrome.ini"] +BROWSER_CHROME_MANIFESTS += ["browser.ini"] diff --git a/toolkit/components/windowcreator/test/test_bug1170334_wbp_xmlstyle.html b/toolkit/components/windowcreator/test/test_bug1170334_wbp_xmlstyle.html new file mode 100644 index 0000000000..89c160a50f --- /dev/null +++ b/toolkit/components/windowcreator/test/test_bug1170334_wbp_xmlstyle.html @@ -0,0 +1,77 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1170334 +--> +<head> + <title>Test for Bug 1170334 (nsWebBrowserPersist vs. XML stylesheets)</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1170334">Mozilla Bug 1170334</a> +<p id="display"></p> +<pre id="results"></pre> +<div id="content"> + <iframe src="bug1170334_iframe.xml" id="iframe"></iframe> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +const nameStem = "test_bug1170334_" + Date.now(); +const { Ci, Cc, Cu, Cr } = SpecialPowers; +let iframe = document.getElementById("iframe"); + +SimpleTest.waitForExplicitFinish(); + +iframe.onload = function iframe_onload1() { + let doc = iframe.contentDocument; + ok(doc, "iframe content document exists"); + + let wbp = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"] + .createInstance(Ci.nsIWebBrowserPersist); + let tmp = SpecialPowers.Services.dirsvc.get("TmpD", Ci.nsIFile); + let tmpFile = tmp.clone(); + tmpFile.append(nameStem + "_iframe.xml"); + let tmpDir = tmp.clone(); + tmpDir.append(nameStem + "_files"); + + // When the document in the iframe is saved, try to load the result. + wbp.progressListener = { + onProgressChange() {}, + onLocationChange() {}, + onStatusChange() {}, + onSecurityChange() {}, + onContentBlockingEvent() {}, + onStateChange: function wbp_stateChange(_wbp, _req, state, status) { + if ((state & Ci.nsIWebProgressListener.STATE_STOP) == 0) { + return; + } + is(status, Cr.NS_OK, "nsWebBrowserPersist status"); + iframe.onload = function iframe_onload2() { + let elem = iframe.contentDocument.documentElement; + is(elem && elem.tagName, "thing", "document element tag"); + if (elem && elem.tagName == "parsererror") { + ok(false, "Parser error: " + elem.textContent); + } + + cleanUp(); + SimpleTest.finish(); + }; + iframe.src = SpecialPowers.Services.io.newFileURI(tmpFile).spec; + }, + }; + wbp.saveDocument(doc, tmpFile, tmpDir, null, 0, 0); + + function cleanUp() { + if (tmpFile.exists()) { + tmpFile.remove(/* recursive: */ false); + } + if (tmpDir.exists()) { + tmpDir.remove(/* recursive: */ true); + } + } +}; +</script> +</pre> +</body> +</html> diff --git a/toolkit/components/windowcreator/test/test_bug1192654.html b/toolkit/components/windowcreator/test/test_bug1192654.html new file mode 100644 index 0000000000..8ec01630ff --- /dev/null +++ b/toolkit/components/windowcreator/test/test_bug1192654.html @@ -0,0 +1,77 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1192654 +--> +<head> + <title>Test for Bug 1192654 (nsWebBrowser vs. nonpersistable subdocuments)</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1192654">Mozilla Bug 1192654</a> +<p id="display"></p> +<pre id="results"></pre> +<div id="content"> + <!-- The outer iframe uses a data URI for simplicity; this would + also work if it were loaded from a support file by relative + URI. The inner iframe (the one nsWebBrowserPersist traverses) + uses a data URI because data: is a non-persistable scheme and + thus triggers the bug. + --> + <iframe src="data:text/html,<iframe%20src=%22data:text/plain,Example%22>" + id="iframe"></iframe> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +const nameStem = "test_bug1192654_" + Date.now(); +const { Ci, Cc, Cu, Cr } = SpecialPowers; +let iframe = document.getElementById("iframe"); + +SimpleTest.waitForExplicitFinish(); + +iframe.onload = function iframe_onload1() { + let doc = iframe.contentDocument; + ok(doc, "iframe content document exists"); + + let wbp = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"] + .createInstance(Ci.nsIWebBrowserPersist); + let tmp = SpecialPowers.Services.dirsvc.get("TmpD", Ci.nsIFile); + let tmpFile = tmp.clone(); + tmpFile.append(nameStem + "_iframe.xml"); + let tmpDir = tmp.clone(); + tmpDir.append(nameStem + "_files"); + + wbp.progressListener = { + onProgressChange() {}, + onLocationChange() {}, + onStatusChange() {}, + onSecurityChange() {}, + onContentBlockingEvent() {}, + onStateChange: wbp_stateChange, + }; + SimpleTest.registerCleanupFunction(cleanUp); + + wbp.saveDocument(doc, tmpFile, tmpDir, null, 0, 0); + + function wbp_stateChange(_wbp, _req, state, status) { + if ((state & Ci.nsIWebProgressListener.STATE_STOP) == 0) { + return; + } + is(status, Cr.NS_OK, "nsWebBrowserPersist status"); + SimpleTest.finish(); + } + + function cleanUp() { + if (tmpFile.exists()) { + tmpFile.remove(/* recursive: */ false); + } + if (tmpDir.exists()) { + tmpDir.remove(/* recursive: */ true); + } + } +}; +</script> +</pre> +</body> +</html> diff --git a/toolkit/components/windowcreator/test/test_bug449141.html b/toolkit/components/windowcreator/test/test_bug449141.html new file mode 100644 index 0000000000..f178689599 --- /dev/null +++ b/toolkit/components/windowcreator/test/test_bug449141.html @@ -0,0 +1,96 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=449141 +--> +<head> + <title>Test for Bug 449141</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=449141">Mozilla Bug 449141</a> +<p id="display"> + +</p> +<pre id="results"></pre> +<div id="content" style="display: none"> + <iframe src="bug449141_page.html" id="source"></iframe> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +/** Test for Bug 449141 */ + +const Cc = SpecialPowers.Cc; +const Ci = SpecialPowers.Ci; + +function getTempDir() { + return SpecialPowers.Services.dirsvc.get("TmpD", Ci.nsIFile); +} + +// STATE_STOP from nsIWebProgressListener.idl +const STATE_STOP = 0x00000010; + +var progressListener = { + onProgressChange() { + /* Ignore progress callback */ + }, + onStateChange(aProgress, aRequest, aStateFlag, aStatus) { + if (aStateFlag & STATE_STOP) { + var dirExists = false; + var videoExists = false; + + var videoFile = getTempDir(); + videoFile.append(this.dirName); + dirExists = videoFile.exists(); + videoFile.append("320x240.ogv"); + videoExists = videoFile.exists(); + this.folder.remove(true); + this.file.remove(false); + ok(dirExists, "Directory containing video file should be created"); + ok(videoExists, "Video should be persisted with document"); + SimpleTest.finish(); + } + }, +}; + +function persistDocument(aDoc) { + const nsIWBP = Ci.nsIWebBrowserPersist; + const persistFlags = + nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES + | nsIWBP.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION; + const encodingFlags = + nsIWBP.ENCODE_FLAGS_ENCODE_BASIC_ENTITIES; + + var id = Math.round(Math.random() * 10000); + var dirName = "bug449141_serialized" + id; + progressListener.dirName = dirName; + + var file = getTempDir(); + file.append("bug449141-serialized" + id + ".html"); + + var persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"] + .createInstance(Ci.nsIWebBrowserPersist); + persist.progressListener = progressListener; + persist.persistFlags = persistFlags; + const kWrapColumn = 80; + var folder = getTempDir(); + folder.append(dirName); + progressListener.folder = folder; + progressListener.file = file; + persist.saveDocument(aDoc, SpecialPowers.Services.io.newFileURI(file), + folder, + aDoc.contentType, + encodingFlags, kWrapColumn); +} + +SimpleTest.waitForExplicitFinish(); + +addLoadEvent(function() { + var srcDoc = document.getElementById("source").contentDocument; + persistDocument(srcDoc); +}); +</script> +</pre> +</body> +</html> diff --git a/toolkit/components/windowcreator/test/test_private_window_from_content.html b/toolkit/components/windowcreator/test/test_private_window_from_content.html new file mode 100644 index 0000000000..82ba0d9388 --- /dev/null +++ b/toolkit/components/windowcreator/test/test_private_window_from_content.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script> + // Make sure that we cannot open private browsing windows from unprivileged content + var win = window.open("about:blank", "_blank", "private"); + ok(!SpecialPowers.isContentWindowPrivate(win)); + win.close(); + // Also, make sure that passing non-private doesn't make any difference either + win = window.open("about:blank", "_blank", "non-private"); + ok(!SpecialPowers.isContentWindowPrivate(win)); + win.close(); +</script> diff --git a/toolkit/components/windowcreator/test/test_window_open_position_constraint.html b/toolkit/components/windowcreator/test/test_window_open_position_constraint.html new file mode 100644 index 0000000000..80e2371ed1 --- /dev/null +++ b/toolkit/components/windowcreator/test/test_window_open_position_constraint.html @@ -0,0 +1,56 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for Bug 978847</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=978847">Mozilla Bug 978847</a> +<p id="display"></p> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +SimpleTest.waitForExplicitFinish(); + +SimpleTest.waitForFocus(function() { + var x; + var y; + + // window should be constrained to the screen rect, + // which we assume is less than 10000px square + var w1 = window.open("about:blank", "", "left=16000,top=16000,width=100,height=100"); + SimpleTest.waitForFocus(function() { + ok(w1.screenX < 10000 && w1.screenY < 10000, + "window should not be opened off-screen: got location " + + w1.screenX + "," + w1.screenY); + x = w1.screenX; + y = w1.screenY; + w1.close(); + + // larger window dimensions should result in a shift of the constrained location + var w2 = window.open("about:blank", "", "left=16000,top=16000,width=150,height=150"); + SimpleTest.waitForFocus(function() { + ok(w2.screenX == x - 50 && w2.screenY == y - 50, + "constrained window position did not depend on size as expected: got " + + w2.screenX + "," + w2.screenY + ", expected " + (x - 50) + "," + (y - 50)); + w2.close(); + + // now try with coordinates that are close to MAXINT, + // so adding width/height risks 32-bit integer overflow + var w3 = window.open("about:blank", "", "left=2147483600,top=2147483600,width=100,height=100"); + SimpleTest.waitForFocus(function() { + ok(w3.screenX < 10000 && w3.screenY < 10000, + "window should not be opened off-screen: got location " + + w3.screenX + "," + w3.screenY); + w3.close(); + SimpleTest.finish(); + }, w3, true); + }, w2, true); + }, w1, true); +}, window, false); + +</script> +</pre> +</body> +</html> diff --git a/toolkit/components/windowcreator/test/test_window_open_units.html b/toolkit/components/windowcreator/test/test_window_open_units.html new file mode 100644 index 0000000000..b6f75b7fe9 --- /dev/null +++ b/toolkit/components/windowcreator/test/test_window_open_units.html @@ -0,0 +1,36 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for Bug 594140</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/WindowSnapshot.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=594140">Mozilla Bug 594140</a> +<p id="display"></p> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +SimpleTest.waitForExplicitFinish(); + +SimpleTest.waitForFocus(function() { + SpecialPowers.setFullZoom(window, 2); + + var w = window.open("about:blank", "", "width=200,height=100"); + SimpleTest.waitForFocus(function() { + ok(w.innerWidth <= 402 && w.innerWidth >= 398, + "width (" + w.innerWidth + ") should be around twice what was requested (200)"); + ok(w.innerHeight <= 202 && w.innerHeight >= 198, + "height (" + w.innerHeight + ") should be around twice what was requested (100)"); + + SpecialPowers.setFullZoom(window, 1); + w.close(); + SimpleTest.finish(); + }, w, true); +}, window, false); + +</script> +</pre> +</body> +</html> diff --git a/toolkit/components/windowcreator/tests/unit/test_wwauthpromptfactory.js b/toolkit/components/windowcreator/tests/unit/test_wwauthpromptfactory.js new file mode 100644 index 0000000000..ba4d4b8f9b --- /dev/null +++ b/toolkit/components/windowcreator/tests/unit/test_wwauthpromptfactory.js @@ -0,0 +1,55 @@ +var authPromptRequestReceived; + +const tPFCID = Components.ID("{749e62f4-60ae-4569-a8a2-de78b649660f}"); +const tPFContract = "@mozilla.org/passwordmanager/authpromptfactory;1"; + +/* + * TestPromptFactory + * + * Implements nsIPromptFactory + */ +var TestPromptFactory = { + QueryInterface: ChromeUtils.generateQI(["nsIFactory", "nsIPromptFactory"]), + + createInstance: function tPF_ci(iid) { + return this.QueryInterface(iid); + }, + + getPrompt: function tPF_getPrompt(aWindow, aIID) { + if (aIID.equals(Ci.nsIAuthPrompt) || aIID.equals(Ci.nsIAuthPrompt2)) { + authPromptRequestReceived = true; + return {}; + } + + throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE); + }, +}; // end of TestPromptFactory implementation + +/* + * The tests + */ +function run_test() { + Components.manager.nsIComponentRegistrar.registerFactory( + tPFCID, + "TestPromptFactory", + tPFContract, + TestPromptFactory + ); + + // Make sure that getting both nsIAuthPrompt and nsIAuthPrompt2 works + // (these should work independently of whether the application has + // nsIPromptService) + var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(); + + authPromptRequestReceived = false; + + Assert.notEqual(ww.nsIPromptFactory.getPrompt(null, Ci.nsIAuthPrompt), null); + + Assert.ok(authPromptRequestReceived); + + authPromptRequestReceived = false; + + Assert.notEqual(ww.nsIPromptFactory.getPrompt(null, Ci.nsIAuthPrompt2), null); + + Assert.ok(authPromptRequestReceived); +} diff --git a/toolkit/components/windowcreator/tests/unit/test_wwpromptfactory.js b/toolkit/components/windowcreator/tests/unit/test_wwpromptfactory.js new file mode 100644 index 0000000000..92c8d90c1f --- /dev/null +++ b/toolkit/components/windowcreator/tests/unit/test_wwpromptfactory.js @@ -0,0 +1,20 @@ +function run_test() { + // Make sure that getting both nsIAuthPrompt and nsIAuthPrompt2 works + // (these should work independently of whether the application has + // nsIPromptService) + var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(); + + var prompt; + + prompt = ww.nsIWindowWatcher.getNewPrompter(null); + Assert.notEqual(prompt, null); + prompt = ww.nsIWindowWatcher.getNewAuthPrompter(null); + Assert.notEqual(prompt, null); + + prompt = ww.nsIPromptFactory.getPrompt(null, Ci.nsIPrompt); + Assert.notEqual(prompt, null); + prompt = ww.nsIPromptFactory.getPrompt(null, Ci.nsIAuthPrompt); + Assert.notEqual(prompt, null); + prompt = ww.nsIPromptFactory.getPrompt(null, Ci.nsIAuthPrompt2); + Assert.notEqual(prompt, null); +} diff --git a/toolkit/components/windowcreator/tests/unit/xpcshell.ini b/toolkit/components/windowcreator/tests/unit/xpcshell.ini new file mode 100644 index 0000000000..bd6eb7a043 --- /dev/null +++ b/toolkit/components/windowcreator/tests/unit/xpcshell.ini @@ -0,0 +1,5 @@ +[DEFAULT] +head = + +[test_wwauthpromptfactory.js] +[test_wwpromptfactory.js] |