diff options
Diffstat (limited to 'toolkit/components/windowcreator')
32 files changed, 1428 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..835db0359a --- /dev/null +++ b/toolkit/components/windowcreator/nsIWindowCreator.idl @@ -0,0 +1,53 @@ +/* -*- 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..135b0b0bd9 --- /dev/null +++ b/toolkit/components/windowcreator/nsIWindowProvider.idl @@ -0,0 +1,108 @@ +/* -*- 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 aWidthSpecified Whether the attempt to create a window is trying + * to specify the width for the new window. + * + * @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 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 boolean aWidthSpecified, + in nsIURI aURI, + in AString aName, + in AUTF8String aFeatures, + in boolean aForceNoOpener, + in boolean aForceNoReferrer, + in nsDocShellLoadStatePtr aLoadState, + out boolean aWindowIsNew); +}; diff --git a/toolkit/components/windowcreator/test/.eslintrc.js b/toolkit/components/windowcreator/test/.eslintrc.js new file mode 100644 index 0000000000..317abe7b48 --- /dev/null +++ b/toolkit/components/windowcreator/test/.eslintrc.js @@ -0,0 +1,9 @@ +"use strict"; + +module.exports = { + extends: [ + "plugin:mozilla/browser-test", + "plugin:mozilla/chrome-test", + "plugin:mozilla/mochitest-test", + ], +}; 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..5e24f9cba3 --- /dev/null +++ b/toolkit/components/windowcreator/test/browser.ini @@ -0,0 +1,12 @@ +[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_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..d958ce2794 --- /dev/null +++ b/toolkit/components/windowcreator/test/browser_persist.js @@ -0,0 +1,103 @@ +"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", + // ... +]; + +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 new file mode 100644 index 0000000000..e69de29bb2 --- /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..5b84c7ef37 --- /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"> +<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/mochitest.ini b/toolkit/components/windowcreator/test/mochitest.ini new file mode 100644 index 0000000000..05ad11fa38 --- /dev/null +++ b/toolkit/components/windowcreator/test/mochitest.ini @@ -0,0 +1,7 @@ +[test_bug499115.html] +[test_nsFind.html] +[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..0a1ba31428 --- /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_bug499115.html b/toolkit/components/windowcreator/test/test_bug499115.html new file mode 100644 index 0000000000..f77663956f --- /dev/null +++ b/toolkit/components/windowcreator/test/test_bug499115.html @@ -0,0 +1,66 @@ +<!DOCTYPE HTML> +<!-- 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/. --> + +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=499115 +--> +<head> + <title>Test for Bug 499115</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body onload="onLoad();"> + <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=499115">Mozilla Bug 499115</a> + <p id="display"></p> + <div id="content" style="display: none"> + </div> + <pre id="test"> + <script type="application/javascript"> + + /** Test for Bug 499115 **/ + SimpleTest.waitForExplicitFinish(); + + const SEARCH_TEXT = "minefield"; + + function getMatches() { + var numMatches = 0; + + var searchRange = document.createRange(); + searchRange.selectNodeContents(document.body); + + var startPoint = searchRange.cloneRange(); + startPoint.collapse(true); + + var endPoint = searchRange.cloneRange(); + endPoint.collapse(false); + + var retRange = null; + var finder = SpecialPowers.Cc["@mozilla.org/embedcomp/rangefind;1"] + .createInstance(SpecialPowers.Ci.nsIFind); + + finder.caseSensitive = false; + + while ((retRange = finder.Find(SEARCH_TEXT, searchRange, + startPoint, endPoint))) { + numMatches++; + + // Start next search from end of current match + startPoint = retRange.cloneRange(); + startPoint.collapse(false); + } + + return numMatches; + } + + function onLoad() { + var matches = getMatches(); + is(matches, 2, "found second match in anonymous content"); + SimpleTest.finish(); + } + </script> + </pre> +<input type="text" value="minefield minefield"></body> +</html> diff --git a/toolkit/components/windowcreator/test/test_nsFind.html b/toolkit/components/windowcreator/test/test_nsFind.html new file mode 100644 index 0000000000..2095e5610a --- /dev/null +++ b/toolkit/components/windowcreator/test/test_nsFind.html @@ -0,0 +1,314 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=202251 +https://bugzilla.mozilla.org/show_bug.cgi?id=450048 +https://bugzilla.mozilla.org/show_bug.cgi?id=812837 +https://bugzilla.mozilla.org/show_bug.cgi?id=969980 +https://bugzilla.mozilla.org/show_bug.cgi?id=1589786 +https://bugzilla.mozilla.org/show_bug.cgi?id=1611568 +--> +<head> + <meta charset="UTF-8"> + <title>Test for nsFind::Find()</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + +<script type="application/javascript"> + +SimpleTest.waitForExplicitFinish(); + +async function runTests() { + // Check nsFind class and its nsIFind interface. + + // Inject some text that we'll search for later. + const NULL_CHARACTER = "\0"; + const INJECTED_NULL_TEXT = "injected null\0"; + const nullcharsinjected = document.getElementById("nullcharsinjected"); + const nulltextnode = document.createTextNode(INJECTED_NULL_TEXT); + nullcharsinjected.appendChild(nulltextnode); + + // Take steps to ensure that the frame is created for the newly added + // nulltextnode. Our find code is dependent upon finding visible frames. + // One way to ensure the frame exists is to ask for its bounds. + const injectionBounds = nullcharsinjected.getBoundingClientRect(); + ok(injectionBounds, "Got a bounding rect for the injected text container."); + + var rf = SpecialPowers.Cc["@mozilla.org/embedcomp/rangefind;1"] + .getService(SpecialPowers.Ci.nsIFind); + + var display = window.document.getElementById("display"); + var searchRange = window.document.createRange(); + searchRange.setStart(display, 0); + searchRange.setEnd(display, display.childNodes.length); + var startPt = searchRange; + var endPt = searchRange; + + var searchValue, retRange; + + rf.findBackwards = false; + + rf.caseSensitive = false; + rf.matchDiacritics = false; + + searchValue = "TexT"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(retRange, "\"" + searchValue + "\" not found (not caseSensitive)"); + + searchValue = "λογος"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(retRange, "\"" + searchValue + "\" not found (not caseSensitive)"); + + searchValue = "유"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(!retRange, "\"" + searchValue + "\" found (not caseSensitive)"); + + searchValue = "istanbul"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(retRange, "\"" + searchValue + "\" not found (not caseSensitive)"); + + searchValue = "degrees k"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(retRange, "\"" + searchValue + "\" not found (not caseSensitive)"); + + searchValue = "guahe"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(retRange, "\"" + searchValue + "\" not found (not caseSensitive)"); + + searchValue = "g̃uah̰e"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(retRange, "\"" + searchValue + "\" not found (not caseSensitive)"); + + searchValue = "𐐸𐐯𐑊𐐬"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(retRange, "\"" + searchValue + "\" not found (not caseSensitive)"); + + rf.matchDiacritics = true; + + searchValue = "λογος"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(!retRange, "\"" + searchValue + "\" found (matchDiacritics on)"); + + searchValue = "g̃uahe"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(retRange, "\"" + searchValue + "\" not found (matchDiacritics on)"); + + searchValue = "guahe"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(!retRange, "\"" + searchValue + "\" found (matchDiacritics on)"); + + rf.caseSensitive = true; + + searchValue = "TexT"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(!retRange, "\"" + searchValue + "\" found (caseSensitive)"); + + searchValue = "text"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(retRange, "\"" + searchValue + "\" not found"); + + // Matches |i<b>n­t</b>o|. + searchValue = "into"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(retRange, "\"" + searchValue + "\" not found"); + + // Matches inside |search|. + searchValue = "ear"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(retRange, "\"" + searchValue + "\" not found"); + + // Set new start point (to end of last search). + startPt = retRange.endContainer.ownerDocument.createRange(); + startPt.setStart(retRange.endContainer, retRange.endOffset); + startPt.setEnd(retRange.endContainer, retRange.endOffset); + + searchValue = "t"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(retRange, "\"" + searchValue + "\" not found (forward)"); + + searchValue = "the"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(!retRange, "\"" + searchValue + "\" found (forward)"); + + rf.findBackwards = true; + + // searchValue = "the"; + retRange = rf.Find(searchValue, searchRange, startPt, endPt); + ok(retRange, "\"" + searchValue + "\" not found (backward)"); + + // Curly quotes and straight quotes should match. + + rf.caseSensitive = false; + rf.findBackwards = false; + + function find(node, value) { + var range = document.createRange(); + range.setStart(node, 0); + range.setEnd(node, node.childNodes.length); + return rf.Find(value, range, range, range); + } + + function assertFound(node, value) { + ok(find(node, value), "\"" + value + "\" should be found"); + } + + function assertNotFound(node, value) { + ok(!find(node, value), "\"" + value + "\" should not be found"); + } + + var quotes = document.getElementById("quotes"); + + assertFound(quotes, "\"straight\""); + assertFound(quotes, "\u201Cstraight\u201D"); + + assertNotFound(quotes, "'straight'"); + assertNotFound(quotes, "\u2018straight\u2019"); + assertNotFound(quotes, "\u2019straight\u2018"); + assertNotFound(quotes, ".straight."); + + assertFound(quotes, "\"curly\""); + assertFound(quotes, "\u201Ccurly\u201D"); + + assertNotFound(quotes, "'curly'"); + assertNotFound(quotes, "\u2018curly\u2019"); + assertNotFound(quotes, ".curly."); + + assertFound(quotes, "didn't"); + assertFound(quotes, "didn\u2018t"); + assertFound(quotes, "didn\u2019t"); + + assertNotFound(quotes, "didnt"); + assertNotFound(quotes, "didn t"); + assertNotFound(quotes, "didn.t"); + + assertFound(quotes, "'didn't'"); + assertFound(quotes, "'didn\u2018t'"); + assertFound(quotes, "'didn\u2019t'"); + assertFound(quotes, "\u2018didn't\u2019"); + assertFound(quotes, "\u2019didn't\u2018"); + assertFound(quotes, "\u2018didn't\u2018"); + assertFound(quotes, "\u2019didn't\u2019"); + assertFound(quotes, "\u2018didn\u2019t\u2019"); + assertFound(quotes, "\u2019didn\u2018t\u2019"); + assertFound(quotes, "\u2018didn\u2019t\u2018"); + + assertNotFound(quotes, "\"didn't\""); + assertNotFound(quotes, "\u201Cdidn't\u201D"); + + assertFound(quotes, "doesn't"); + assertFound(quotes, "doesn\u2018t"); + assertFound(quotes, "doesn\u2019t"); + + assertNotFound(quotes, "doesnt"); + assertNotFound(quotes, "doesn t"); + assertNotFound(quotes, "doesn.t"); + + assertFound(quotes, "'doesn't'"); + assertFound(quotes, "'doesn\u2018t'"); + assertFound(quotes, "'doesn\u2019t'"); + assertFound(quotes, "\u2018doesn't\u2019"); + assertFound(quotes, "\u2019doesn't\u2018"); + assertFound(quotes, "\u2018doesn't\u2018"); + assertFound(quotes, "\u2019doesn't\u2019"); + assertFound(quotes, "\u2018doesn\u2019t\u2019"); + assertFound(quotes, "\u2019doesn\u2018t\u2019"); + assertFound(quotes, "\u2018doesn\u2019t\u2018"); + + assertNotFound(quotes, "\"doesn't\""); + assertNotFound(quotes, "\u201Cdoesn't\u201D"); + + // Curly quotes and straight quotes should not match. + rf.caseSensitive = true; + + assertFound(quotes, "\"straight\""); + assertNotFound(quotes, "\u201Cstraight\u201D"); + + assertNotFound(quotes, "\"curly\""); + assertFound(quotes, "\u201Ccurly\u201D"); + + assertFound(quotes, "\u2018didn't\u2019"); + assertNotFound(quotes, "'didn't'"); + + assertFound(quotes, "'doesn\u2019t'"); + assertNotFound(quotes, "'doesn\u2018t'"); + assertNotFound(quotes, "'doesn't'"); + + // Embedded strings containing null characters can't be found, because + // the HTML parser converts them to \ufffd, which is the replacement + // character. + const nullcharsnative = document.getElementById("nullcharsnative"); + assertFound(nullcharsnative, "native null\ufffd"); + + // Injected strings containing null characters can be found. + assertFound(nullcharsinjected, NULL_CHARACTER); + assertFound(nullcharsinjected, INJECTED_NULL_TEXT); + + // Do these test at the end since they trigger failure screenshots in + // the test harness, and we want as much information as possible about + // any OTHER tests that may have already failed. + + // Check |null| detection on |aSearchRange| parameter. + try { + rf.Find("", null, startPt, endPt); + + ok(false, "Missing NS_ERROR_ILLEGAL_VALUE exception"); + } catch (e) { + let wrappedError = SpecialPowers.wrap(e); + if (wrappedError.result == SpecialPowers.Cr.NS_ERROR_ILLEGAL_VALUE) { + ok(true, null); + } else { + throw wrappedError; + } + } + + // Check |null| detection on |aStartPoint| parameter. + try { + rf.Find("", searchRange, null, endPt); + + ok(false, "Missing NS_ERROR_ILLEGAL_VALUE exception"); + } catch (e) { + let wrappedError = SpecialPowers.wrap(e); + if (wrappedError.result == SpecialPowers.Cr.NS_ERROR_ILLEGAL_VALUE) { + ok(true, null); + } else { + throw wrappedError; + } + } + + // Check |null| detection on |aEndPoint| parameter. + try { + rf.Find("", searchRange, startPt, null); + + ok(false, "Missing NS_ERROR_ILLEGAL_VALUE exception"); + } catch (e) { + let wrappedError = SpecialPowers.wrap(e); + if (wrappedError.result == SpecialPowers.Cr.NS_ERROR_ILLEGAL_VALUE) { + ok(true, null); + } else { + throw wrappedError; + } + } + + SimpleTest.finish(); +} +</script> +</head> +<body onload="runTests()"> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=450048">Mozilla Bug 450048</a> +<p id="display">This is the text to search i<b>n­t</b>o</p> +<p id="quotes">"straight" and “curly” and ‘didn't’ and 'doesn’t'</p> +<p id="nullcharsnative">native null�</p> +<p id="nullcharsinjected"></p> +<p id="greek">ΛΌΓΟΣ</p> +<p id="korean">위</p> +<p id="turkish">İstanbul</p> +<p id="kelvin">degrees K</p> +<p id="guarani">G̃uahe</p> +<p id="deseret">𐐐𐐯𐑊𐐬 𐐶𐐯𐑉𐑊𐐼!</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</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..e094ced45c --- /dev/null +++ b/toolkit/components/windowcreator/tests/unit/test_wwauthpromptfactory.js @@ -0,0 +1,62 @@ +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(outer, iid) { + if (outer) { + throw Components.Exception("", Cr.NS_ERROR_NO_AGGREGATION); + } + return this.QueryInterface(iid); + }, + + lockFactory: function tPF_lockf(lock) { + throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED); + }, + + 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] |