Merge inbound to mozilla-central r=merge a=merge

This commit is contained in:
Andreea Pavel 2017-12-09 22:21:17 +02:00
commit 5ba2665757
229 changed files with 3734 additions and 1548 deletions

3
.arcconfig Normal file
View File

@ -0,0 +1,3 @@
{
"phabricator.uri" : "https://phabricator.services.mozilla.com/"
}

View File

@ -2,7 +2,7 @@
* 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/. */
/* globals windowTracker */
/* globals windowTracker */
"use strict";
@ -170,8 +170,9 @@ this.chrome_settings_overrides = class extends ExtensionAPI {
// Needs to be called every time to handle reenabling, but
// only sets default for install or enable.
await this.setDefault(engineName);
} else if (ExtensionSettingsStore.hasSetting(
extension.id, DEFAULT_SEARCH_STORE_TYPE, DEFAULT_SEARCH_SETTING_NAME)) {
} else if (ExtensionSettingsStore.hasSetting(extension.id,
DEFAULT_SEARCH_STORE_TYPE,
DEFAULT_SEARCH_SETTING_NAME)) {
// is_default has been removed, but we still have a setting. Remove it.
chrome_settings_overrides.processDefaultSearchSetting("removeSetting", extension.id);
}

View File

@ -193,8 +193,7 @@ var gMenuBuilder = {
}
if (item.id && item.extension && item.extension.id) {
element.setAttribute("id",
`${makeWidgetId(item.extension.id)}_${item.id}`);
element.setAttribute("id", `${makeWidgetId(item.extension.id)}_${item.id}`);
}
if (item.icons) {

View File

@ -6,10 +6,9 @@ XPCOMUtils.defineLazyModuleGetters(this, {
OS: "resource://gre/modules/osfile.jsm",
});
XPCOMUtils.defineLazyServiceGetter(this,
"pkcs11db",
"@mozilla.org/security/pkcs11moduledb;1",
"nsIPKCS11ModuleDB");
XPCOMUtils.defineLazyServiceGetter(this, "pkcs11db",
"@mozilla.org/security/pkcs11moduledb;1",
"nsIPKCS11ModuleDB");
var {DefaultMap} = ExtensionUtils;

View File

@ -190,8 +190,8 @@ this.windows = class extends ExtensionAPI {
if (allowScriptsToClose) {
for (let {linkedBrowser} of window.gBrowser.tabs) {
onXULFrameLoaderCreated({target: linkedBrowser});
linkedBrowser.addEventListener( // eslint-disable-line mozilla/balanced-listeners
"XULFrameLoaderCreated", onXULFrameLoaderCreated);
// eslint-disable-next-line mozilla/balanced-listeners
linkedBrowser.addEventListener("XULFrameLoaderCreated", onXULFrameLoaderCreated);
}
}
if (createData.titlePreface !== null) {

View File

@ -32,13 +32,13 @@ add_task(async function testBrowserActionPopupResize() {
Assert.lessOrEqual(Math.abs(dims.window.innerHeight - expected), 1,
`Panel window should be ${expected}px tall (was ${dims.window.innerHeight})`);
is(dims.body.clientHeight, dims.body.scrollHeight,
"Panel body should be tall enough to fit its contents");
"Panel body should be tall enough to fit its contents");
// Tolerate if it is 1px too wide, as that may happen with the current resizing method.
Assert.lessOrEqual(Math.abs(dims.window.innerWidth - expected), 1,
`Panel window should be ${expected}px wide`);
is(dims.body.clientWidth, dims.body.scrollWidth,
"Panel body should be wide enough to fit its contents");
"Panel body should be wide enough to fit its contents");
}
/* eslint-disable mozilla/no-cpows-in-tests */
@ -162,7 +162,7 @@ async function testPopupSize(standardsMode, browserWin = window, arrowSide = "to
// The 'ViewShown' event is the only way to correctly determine when the extensions'
// panelview has finished transitioning and is fully in view.
let shownPromise = BrowserTestUtils.waitForEvent(panelMultiView, "ViewShown",
e => (e.originalTarget.id || "").includes(widgetId));
e => (e.originalTarget.id || "").includes(widgetId));
let browser = await openPanel(extension, browserWin);
let origPanelRect = panel.getBoundingClientRect();

View File

@ -56,13 +56,13 @@ add_task(async function testBrowserActionTelemetryTiming() {
histogram.clear();
is(histogram.snapshot().sum, 0,
`No data recorded for histogram: ${TIMING_HISTOGRAM}.`);
`No data recorded for histogram: ${TIMING_HISTOGRAM}.`);
await extension1.startup();
await extension2.startup();
is(histogram.snapshot().sum, 0,
`No data recorded for histogram after startup: ${TIMING_HISTOGRAM}.`);
`No data recorded for histogram after startup: ${TIMING_HISTOGRAM}.`);
clickBrowserAction(extension1);
await awaitExtensionPanel(extension1);
@ -117,7 +117,7 @@ add_task(async function testBrowserActionTelemetryResults() {
histogram.clear();
is(histogram.snapshot().sum, 0,
`No data recorded for histogram: ${TIMING_HISTOGRAM}.`);
`No data recorded for histogram: ${TIMING_HISTOGRAM}.`);
await extension.startup();

View File

@ -6,8 +6,8 @@
add_task(async function setup() {
await SpecialPowers.pushPrefEnv({
set: [["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true]],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true]],
});
});

View File

@ -486,7 +486,8 @@ add_task(async function test_bookmark_contextmenu() {
});
await extension.startup();
await extension.awaitMessage("bookmark-created");
let menu = await openChromeContextMenu("placesContext",
let menu = await openChromeContextMenu(
"placesContext",
"#PersonalToolbar .bookmark-item:last-child");
let menuItem = menu.getElementsByAttribute("label", "Get bookmark")[0];
@ -515,11 +516,12 @@ add_task(async function test_bookmark_context_requires_permission() {
});
await extension.startup();
await extension.awaitMessage("bookmark-created");
let menu = await openChromeContextMenu("placesContext",
let menu = await openChromeContextMenu(
"placesContext",
"#PersonalToolbar .bookmark-item:last-child");
Assert.equal(menu.getElementsByAttribute("label", "Get bookmark").length, 0,
"bookmark context menu not created with `bookmarks` permission.");
"bookmark context menu not created with `bookmarks` permission.");
closeChromeContextMenu("placesContext");

View File

@ -3,7 +3,8 @@
"use strict";
add_task(async function() {
let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser,
let tab1 = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
"http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html");
gBrowser.selectedTab = tab1;

View File

@ -69,10 +69,10 @@ function testScript() {
// Sanity check - the pages must be in the same process.
let pages = browser.extension.getViews();
browser.test.assertTrue(pages.includes(window),
"Expected this tab to be an extension view");
"Expected this tab to be an extension view");
pages = pages.filter(w => w !== window);
browser.test.assertEq(pages[0], browser.extension.getBackgroundPage(),
"Expected the other page to be a background page");
"Expected the other page to be a background page");
browser.test.sendMessage("tab.html ready");
}
}

View File

@ -3,7 +3,8 @@
"use strict";
add_task(async function() {
let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser,
let tab1 = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
"http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html");
gBrowser.selectedTab = tab1;

View File

@ -3,7 +3,8 @@
"use strict";
add_task(async function() {
let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser,
let tab1 = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
"http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html");
// Install an extension.

View File

@ -3,7 +3,8 @@
"use strict";
add_task(async function() {
let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser,
let tab1 = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
"http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html");
let extension = ExtensionTestUtils.loadExtension({

View File

@ -49,9 +49,9 @@ add_task(async function test_devtools_inspectedWindow_tabId() {
}
function devtools_page() {
browser.test.assertEq(undefined, browser.runtime.getBackgroundPage,
"The `runtime.getBackgroundPage` API method should be missing in a devtools_page context"
);
browser.test.assertEq(
undefined, browser.runtime.getBackgroundPage,
"The `runtime.getBackgroundPage` API method should be missing in a devtools_page context");
try {
let tabId = browser.devtools.inspectedWindow.tabId;

View File

@ -173,7 +173,7 @@ add_task(async function test_devtools_inspectedWindow_eval_bindings() {
const objectPreviewProperties = options.objectActor.preview.ownProperties;
is(objectType, "object", "The inspected object has the expected type");
Assert.deepEqual(Object.keys(objectPreviewProperties), ["testkey"],
"The inspected object has the expected preview properties");
"The inspected object has the expected preview properties");
}
})();

View File

@ -181,7 +181,7 @@ add_task(async function test_devtools_inspectedWindow_reload_custom_user_agent()
try {
const [text] = await browser.tabs.executeScript(activeTabId, {code});
browser.test.assertEq(expectedContent, text,
`Got the expected userAgent with userAgent=${enabled}`);
`Got the expected userAgent with userAgent=${enabled}`);
} catch (err) {
browser.test.fail(`Error: ${err.message} - ${err.stack}`);
}

View File

@ -31,11 +31,11 @@ async function testThemeSwitching(extension, locations = ["page"]) {
await switchTheme(newTheme);
for (let location of locations) {
is(await extension.awaitMessage(`devtools_theme_changed_${location}`),
newTheme,
`The onThemeChanged event listener fired for the ${location}.`);
newTheme,
`The onThemeChanged event listener fired for the ${location}.`);
is(await extension.awaitMessage(`current_theme_${location}`),
newTheme,
`The current theme is reported as expected for the ${location}.`);
newTheme,
`The current theme is reported as expected for the ${location}.`);
}
}
}
@ -80,8 +80,8 @@ add_task(async function test_theme_name_no_panel() {
info("developer toolbox opened");
is(await extension.awaitMessage("initial_theme"),
"light",
"The initial theme is reported as expected.");
"light",
"The initial theme is reported as expected.");
await testThemeSwitching(extension);
@ -201,8 +201,8 @@ add_task(async function test_devtools_page_panels_create() {
await extension.awaitMessage("devtools_panel_created");
is(await extension.awaitMessage("initial_theme_page"),
"light",
"The initial theme is reported as expected from a devtools page.");
"light",
"The initial theme is reported as expected from a devtools page.");
const toolboxAdditionalTools = toolbox.getAdditionalTools();
@ -220,8 +220,8 @@ add_task(async function test_devtools_page_panels_create() {
is(devtoolsPanelTabId, devtoolsPageTabId,
"Got the same devtools.inspectedWindow.tabId from devtools page and panel");
is(await extension.awaitMessage("initial_theme_panel"),
"light",
"The initial theme is reported as expected from a devtools panel.");
"light",
"The initial theme is reported as expected from a devtools panel.");
info("Addon Devtools Panel shown");
await testThemeSwitching(extension, ["page", "panel"]);
@ -282,8 +282,8 @@ add_task(async function test_devtools_page_panels_create() {
await gDevTools.showToolbox(target, panelId);
await extension.awaitMessage("devtools_panel_shown");
is(await extension.awaitMessage("initial_theme_panel"),
"light",
"The initial theme is reported as expected from a devtools panel.");
"light",
"The initial theme is reported as expected from a devtools panel.");
info("Addon Devtools Panel shown - after visibilityswitch toggled");
info("Wait until the Addon Devtools Panel has been loaded - after visibilityswitch toggled");

View File

@ -49,7 +49,7 @@ add_task(async function test_legacy_extension_context_contentscript_connection()
function contentScript() {
browser.runtime.sendMessage("webextension -> legacy_extension message", (reply) => {
browser.test.assertEq("legacy_extension -> webextension reply", reply,
"Got the expected reply from the LegacyExtensionContext");
"Got the expected reply from the LegacyExtensionContext");
browser.test.sendMessage("got-reply-message");
});

View File

@ -76,11 +76,11 @@ add_task(async function() {
let actual = await extension.awaitMessage(event);
if (expected.text) {
is(actual.text, expected.text,
`Expected "${event}" to have fired with text: "${expected.text}".`);
`Expected "${event}" to have fired with text: "${expected.text}".`);
}
if (expected.disposition) {
is(actual.disposition, expected.disposition,
`Expected "${event}" to have fired with disposition: "${expected.disposition}".`);
`Expected "${event}" to have fired with disposition: "${expected.disposition}".`);
}
}
@ -205,10 +205,10 @@ add_task(async function() {
let item = gURLBar.popup.richlistbox.children[0];
is(item.getAttribute("title"), expectedText,
`Expected heuristic result to have title: "${expectedText}".`);
`Expected heuristic result to have title: "${expectedText}".`);
is(item.getAttribute("displayurl"), `${keyword} ${text}`,
`Expected heuristic result to have displayurl: "${keyword} ${text}".`);
`Expected heuristic result to have displayurl: "${keyword} ${text}".`);
let promiseEvent = expectEvent("on-input-entered-fired", {
text,
@ -250,10 +250,10 @@ add_task(async function() {
ok(!!item, "Expected item to exist");
is(item.getAttribute("title"), description,
`Expected suggestion to have title: "${description}".`);
`Expected suggestion to have title: "${description}".`);
is(item.getAttribute("displayurl"), `${keyword} ${content}`,
`Expected suggestion to have displayurl: "${keyword} ${content}".`);
`Expected suggestion to have displayurl: "${keyword} ${content}".`);
}
let text = await startInputSession(info.suggestions.length - 1);

View File

@ -41,9 +41,9 @@ add_task(async function testPageActionPopupResize() {
is(dims.window.innerHeight, expected, `Panel window should be ${expected}px tall`);
is(body.clientHeight, body.scrollHeight,
"Panel body should be tall enough to fit its contents");
"Panel body should be tall enough to fit its contents");
is(root.clientHeight, root.scrollHeight,
"Panel root should be tall enough to fit its contents");
"Panel root should be tall enough to fit its contents");
// Tolerate if it is 1px too wide, as that may happen with the current resizing method.
ok(Math.abs(dims.window.innerWidth - expected) <= 1, `Panel window should be ${expected}px wide`);
@ -141,9 +141,9 @@ add_task(async function testPageActionPopupReflow() {
`Panel window height (${dims.window.innerHeight}px) should be taller than two lines of text.`);
is(dims.body.clientHeight, dims.body.scrollHeight,
"Panel body should be tall enough to fit its contents");
"Panel body should be tall enough to fit its contents");
is(dims.root.clientHeight, dims.root.scrollHeight,
"Panel root should be tall enough to fit its contents");
"Panel root should be tall enough to fit its contents");
await extension.unload();
});

View File

@ -16,7 +16,7 @@ add_task(async function test_sessions_forget_closed_tab() {
},
error => {
browser.test.assertEq(error.message,
`Could not find closed tab using sessionId ${sessionId}.`);
`Could not find closed tab using sessionId ${sessionId}.`);
browser.test.sendMessage("forget-reject");
}
);
@ -45,8 +45,9 @@ add_task(async function test_sessions_forget_closed_tab() {
let recentlyClosedTab = recentlyClosed[0].tab;
// Check that forgetting a tab works properly
extension.sendMessage("forget-tab", recentlyClosedTab.windowId,
recentlyClosedTab.sessionId);
extension.sendMessage("forget-tab",
recentlyClosedTab.windowId,
recentlyClosedTab.sessionId);
await extension.awaitMessage("forgot-tab");
extension.sendMessage("check-sessions");
let remainingClosed = await extension.awaitMessage("recentlyClosed");
@ -56,8 +57,9 @@ add_task(async function test_sessions_forget_closed_tab() {
"The correct tab was forgotten.");
// Check that re-forgetting the same tab fails properly
extension.sendMessage("forget-tab", recentlyClosedTab.windowId,
recentlyClosedTab.sessionId);
extension.sendMessage("forget-tab",
recentlyClosedTab.windowId,
recentlyClosedTab.sessionId);
await extension.awaitMessage("forget-reject");
extension.sendMessage("check-sessions");
remainingClosed = await extension.awaitMessage("recentlyClosed");

View File

@ -22,8 +22,9 @@ add_task(async function test_sessions_forget_closed_window() {
browser.test.sendMessage("forgot-window");
},
error => {
browser.test.assertEq(error.message,
`Could not find closed window using sessionId ${sessionId}.`);
browser.test.assertEq(
error.message,
`Could not find closed window using sessionId ${sessionId}.`);
browser.test.sendMessage("forget-reject");
}
);

View File

@ -98,9 +98,11 @@ add_task(async function test_sessions_get_recently_closed_navigated() {
function background() {
browser.sessions.getRecentlyClosed({maxResults: 1}).then(recentlyClosed => {
let tab = recentlyClosed[0].window.tabs[0];
browser.test.assertEq("http://example.com/", tab.url,
browser.test.assertEq(
"http://example.com/", tab.url,
"Tab in closed window has the expected url.");
browser.test.assertTrue(tab.title.includes("mochitest index"),
browser.test.assertTrue(
tab.title.includes("mochitest index"),
"Tab in closed window has the expected title.");
browser.test.notifyPass("getRecentlyClosed with navigation");
});

View File

@ -15,10 +15,10 @@ add_task(async function test_extension_adding_engine() {
manifest: {
"chrome_settings_overrides": {
"search_provider": {
"name": "MozSearch",
"keyword": "MozSearch",
"search_url": kSearchEngineURL,
"suggest_url": kSearchSuggestURL,
"name": "MozSearch",
"keyword": "MozSearch",
"search_url": kSearchEngineURL,
"suggest_url": kSearchSuggestURL,
},
},
},
@ -49,9 +49,9 @@ add_task(async function test_extension_adding_engine_with_spaces() {
manifest: {
"chrome_settings_overrides": {
"search_provider": {
"name": "MozSearch ",
"keyword": "MozSearch",
"search_url": "https://example.com/?q={searchTerms}",
"name": "MozSearch ",
"keyword": "MozSearch",
"search_url": "https://example.com/?q={searchTerms}",
},
},
},
@ -75,14 +75,14 @@ add_task(async function test_upgrade_default_position_engine() {
manifest: {
"chrome_settings_overrides": {
"search_provider": {
"name": "MozSearch",
"keyword": "MozSearch",
"search_url": "https://example.com/?q={searchTerms}",
"name": "MozSearch",
"keyword": "MozSearch",
"search_url": "https://example.com/?q={searchTerms}",
},
},
"applications": {
"gecko": {
"id": "testengine@mozilla.com",
"id": "testengine@mozilla.com",
},
},
"version": "0.1",
@ -94,14 +94,14 @@ add_task(async function test_upgrade_default_position_engine() {
manifest: {
"chrome_settings_overrides": {
"search_provider": {
"name": "MozSearch",
"keyword": "MozSearch",
"search_url": "https://example.com/?q={searchTerms}",
"name": "MozSearch",
"keyword": "MozSearch",
"search_url": "https://example.com/?q={searchTerms}",
},
},
"applications": {
"gecko": {
"id": "testengine@mozilla.com",
"id": "testengine@mozilla.com",
},
},
"version": "0.2",

View File

@ -142,7 +142,7 @@ add_task(async function testCaptureVisibleTabPermissions() {
background() {
browser.test.assertEq(undefined, browser.tabs.captureVisibleTab,
'Extension without "<all_urls>" permission should not have access to captureVisibleTab');
'Extension without "<all_urls>" permission should not have access to captureVisibleTab');
browser.test.notifyPass("captureVisibleTabPermissions");
},
});

View File

@ -28,9 +28,8 @@ add_task(async function moveMultiple() {
async function reset() {
let tabs = await browser.tabs.query({url: "http://example.com/*"});
await browser.tabs.move(
tabs.sort((a, b) => (num(a.url) - num(b.url))).map(tab => tab.id),
{index: 0}
);
tabs.sort((a, b) => (num(a.url) - num(b.url))).map(tab => tab.id),
{index: 0});
}
async function move(moveIndexes, moveTo) {

View File

@ -74,7 +74,7 @@ add_task(async function testTabEvents() {
*/
async function openTab(windowId) {
browser.test.assertEq(0, Object.keys(events).length,
"No events remaining before testing openTab.");
"No events remaining before testing openTab.");
let tab = await browser.tabs.create({windowId});
@ -95,7 +95,7 @@ add_task(async function testTabEvents() {
*/
async function openWindow(urls) {
browser.test.assertEq(0, Object.keys(events).length,
"No events remaining before testing openWindow.");
"No events remaining before testing openWindow.");
let window = await browser.windows.create({url: urls});
browser.test.log(`Opened new window ${window.id}`);
@ -105,9 +105,9 @@ add_task(async function testTabEvents() {
tabIds.push(tab.id);
let expectedEvents = [
"onCreated",
"onActivated",
"onHighlighted",
"onCreated",
"onActivated",
"onHighlighted",
];
if (i !== 0) {
expectedEvents.splice(1);
@ -123,7 +123,7 @@ add_task(async function testTabEvents() {
*/
async function highlightTab(tabId) {
browser.test.assertEq(0, Object.keys(events).length,
"No events remaining before testing highlightTab.");
"No events remaining before testing highlightTab.");
browser.test.log(`Highlighting tab ${tabId}`);
let tab = await browser.tabs.update(tabId, {active: true});

View File

@ -154,7 +154,7 @@ add_task(async function test_update_reload() {
is(history.entries.length, 1,
"Tab history contains the expected number of entries.");
is(history.entries[0].url, URL,
`Tab history contains the expected entry: URL.`);
`Tab history contains the expected entry: URL.`);
extension.sendMessage("update", tabId, {url: `${URL}1/`});
await Promise.all([
@ -166,7 +166,7 @@ add_task(async function test_update_reload() {
is(history.entries.length, 2,
"Tab history contains the expected number of entries.");
is(history.entries[1].url, `${URL}1/`,
`Tab history contains the expected entry: ${URL}1/.`);
`Tab history contains the expected entry: ${URL}1/.`);
extension.sendMessage("update", tabId, {url: `${URL}2/`, loadReplace: true});
await Promise.all([
@ -178,7 +178,7 @@ add_task(async function test_update_reload() {
is(history.entries.length, 2,
"Tab history contains the expected number of entries.");
is(history.entries[1].url, `${URL}2/`,
`Tab history contains the expected entry: ${URL}2/.`);
`Tab history contains the expected entry: ${URL}2/.`);
await extension.unload();
await BrowserTestUtils.closeWindow(win);

View File

@ -2,16 +2,16 @@
const ENCODED_IMAGE_DATA = "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NCA2NCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgNjQgNjQiPjxwYXRoIGQ9Im01NS45IDMyLjFsLTIyLjctMTQuOWMwIDAgMTIuOS0xNy40IDE5LjQtMTQuOSAzLjEgMS4xIDUuNCAyNS4xIDMuMyAyOS44IiBmaWxsPSIjM2U0MzQ3Ii8+PHBhdGggZD0ibTU0LjkgMzMuOWwtOS00LjFjMCAwLTUuMy0xNCA2LjEtMjQuMSAyLjQgMiA1LjEgMjUgMi45IDI4LjIiIGZpbGw9IiNmZmYiLz48cGF0aCBkPSJtOC4xIDMyLjFsMjIuNi0xNC45YzAgMC0xMi45LTE3LjQtMTkuNC0xNC45LTMgMS4xLTUuMyAyNS4xLTMuMiAyOS44IiBmaWxsPSIjM2U0MzQ3Ii8+PHBhdGggZD0ibTkuMSAzMy45bDktNC4xYzAgMCA1LjMtMTQtNi4xLTI0LjEtMi40IDItNS4xIDI1LTIuOSAyOC4yIiBmaWxsPSIjZmZmIi8+PHBhdGggZD0iTTMyLDEzQzE4LjksMTMsMiwzMy42LDIsNDUuNEMyMC41LDQ1LjQsMTkuNyw2MiwzMiw2MnMxMS41LTE2LjYsMzAtMTYuNkM2MiwzMy42LDQ1LjEsMTMsMzIsMTN6IiBmaWxsPSIjZmY4NzM2Ii8+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTMyLDU2LjJjMCw1LjEsOS42LDQuMiw5LjUtMi45YzYuNy05LjQsMTkuOS04LjcsMTkuOS04LjdDMzkuNiwzMi40LDMyLDU2LjIsMzIsNTYuMnoiLz48cGF0aCBkPSJNMzIsNTYuMmMwLDUuMS05LjYsNC4yLTkuNS0yLjlDMTUuOCw0NCwyLjYsNDQuNywyLjYsNDQuN0MyNC40LDMyLjQsMzIsNTYuMiwzMiw1Ni4yeiIvPjwvZz48ZyBmaWxsPSIjZmY4NzM2Ij48cGF0aCBkPSJtNTMuNCAxOC41Yy00IC43LTQuOSA2LjMtNC45IDYuM2w2IDUuM2MtMi4zLTUuOS0xLjEtMTEuNi0xLjEtMTEuNiIvPjxwYXRoIGQ9Im01MS4xIDEzLjVjLTQuNCAzLjktNS4xIDguNy01LjEgOC43bDYgNS4zYy0yLjQtNS44LS45LTE0LS45LTE0Ii8+PHBhdGggZD0ibTEwLjYgMTguNWM0IC43IDQuOSA2LjMgNC45IDYuM2wtNiA1LjNjMi4zLTUuOSAxLjEtMTEuNiAxLjEtMTEuNiIvPjxwYXRoIGQ9Im0xMi45IDEzLjVjNC40IDMuOSA1LjEgOC43IDUuMSA4LjdsLTYgNS4zYzIuNC01LjguOS0xNCAuOS0xNCIvPjwvZz48cGF0aCBkPSJtNTIuOCAzMS4xYy01LjctMS44LTEwLjktMy40LTEzLjguOS0yLjQgMy43LjcgOS40LjcgOS40IDExLjIgMS4yIDEzLjEtMTAuMyAxMy4xLTEwLjMiIGZpbGw9IiMzZTQzNDciLz48ZWxsaXBzZSBjeD0iNDMiIGN5PSIzNi4zIiByeD0iNC4yIiByeT0iNC4xIiBmaWxsPSIjZDVmZjgzIi8+PGcgZmlsbD0iIzNlNDM0NyI+PGVsbGlwc2UgY3g9IjQzIiBjeT0iMzYuMyIgcng9IjIuNyIgcnk9IjIuNyIvPjxwYXRoIGQ9Im0xMS4yIDMxLjFjNS43LTEuOCAxMC45LTMuNCAxMy43LjkgMi40IDMuNy0uNyA5LjQtLjcgOS40LTExLjEgMS4yLTEzLTEwLjMtMTMtMTAuMyIvPjwvZz48ZWxsaXBzZSBjeD0iMjEiIGN5PSIzNi4zIiByeD0iNC4yIiByeT0iNC4xIiBmaWxsPSIjZDVmZjgzIi8+PGcgZmlsbD0iIzNlNDM0NyI+PGVsbGlwc2UgY3g9IjIxIiBjeT0iMzYuMyIgcng9IjIuNyIgcnk9IjIuNyIvPjxwYXRoIGQ9Im00MS4yIDQ3LjljLS43LTIuMy0xLjgtNC40LTMtNi41IDEuMSAyLjEgMiA0LjMgMi41IDYuNi41IDIuMy43IDQuNyAwIDYuOC0uNCAxLTEgMi0xLjggMi42LS44LjYtMS44IDEtMi43IDEtLjkgMC0xLjktLjMtMi41LTEtLjYtLjctLjktMS42LS44LTIuNmwtLjkuMmgtLjljMCAxLS4yIDEuOS0uOCAyLjYtLjYuNy0xLjUgMS0yLjUgMS0uOSAwLTEuOS0uNC0yLjctMS0uOC0uNi0xLjQtMS42LTEuOC0yLjYtLjgtMi4xLS42LTQuNiAwLTYuOC41LTIuMyAxLjUtNC41IDIuNS02LjYtMS4yIDItMi4zIDQuMS0zIDYuNS0uNyAyLjMtMS4xIDQuOC0uNCA3LjMuMyAxLjIgMSAyLjQgMS45IDMuMy45LjkgMi4xIDEuNCAzLjQgMS41IDEuMi4xIDIuNi0uMiAzLjctMS4yLjMtLjIuNS0uNS43LS44LjIuMy40LjYuNy44IDEgMSAyLjQgMS4zIDMuNyAxLjIgMS4zLS4xIDIuNC0uNyAzLjQtMS41LjktLjkgMS42LTIgMS45LTMuMy41LTIuNi4xLTUuMi0uNi03LjUiLz48cGF0aCBkPSJtMzcuNiA1MC4zYy0xLjEtMS4xLTQuNS0xLjItNS42LTEuMi0xIDAtNC41LjEtNS42IDEuMi0uOC44LS4yIDIuOCAxLjkgNC41IDEuMyAxLjEgMi42IDEuNCAzLjYgMS40IDEgMCAyLjMtLjMgMy42LTEuNCAyLjMtMS43IDIuOS0zLjcgMi4xLTQuNSIvPjwvZz48L3N2Zz4=";
/**
* Verifies that the button uses the expected icon.
*
* @param {string} selector The CSS selector used to find the button
* within the DOM.
* @param {boolean} shouldHaveCustomStyling True if the button should
* have custom styling, False otherwise.
* @param {string} message The message that is printed to the console
* by the verifyFn.
*/
/**
* Verifies that the button uses the expected icon.
*
* @param {string} selector The CSS selector used to find the button
* within the DOM.
* @param {boolean} shouldHaveCustomStyling True if the button should
* have custom styling, False otherwise.
* @param {string} message The message that is printed to the console
* by the verifyFn.
*/
function verifyButtonProperties(selector, shouldHaveCustomStyling, message) {
try {
let element = document.querySelector(selector);
@ -23,48 +23,50 @@ function verifyButtonProperties(selector, shouldHaveCustomStyling, message) {
}
}
/**
* Verifies that the button uses default styling.
*
* @param {string} selector The CSS selector used to find the button
* within the DOM.
* @param {string} message The message that is printed to the console
* by the verifyFn.
*/
/**
* Verifies that the button uses default styling.
*
* @param {string} selector The CSS selector used to find the button
* within the DOM.
* @param {string} message The message that is printed to the console
* by the verifyFn.
*/
function verifyButtonWithoutCustomStyling(selector, message) {
verifyButtonProperties(selector, false, message);
}
/**
* Verifies that the button uses non-default styling.
*
* @param {string} selector The CSS selector used to find the button
* within the DOM.
* @param {string} message The message that is printed to the console
* by the verifyFn.
*/
/**
* Verifies that the button uses non-default styling.
*
* @param {string} selector The CSS selector used to find the button
* within the DOM.
* @param {string} message The message that is printed to the console
* by the verifyFn.
*/
function verifyButtonWithCustomStyling(selector, message) {
verifyButtonProperties(selector, true, message);
}
/**
* Loops through all of the buttons to confirm that they are styled
* as expected (either with or without custom styling).
*
* @param {object} icons Array of an array that specifies which buttons should
* have custom icons.
* @param {object} iconInfo An array of arrays that maps API names to
* CSS selectors.
* @param {string} area The name of the area that the button resides in.
*/
/**
* Loops through all of the buttons to confirm that they are styled
* as expected (either with or without custom styling).
*
* @param {object} icons Array of an array that specifies which buttons should
* have custom icons.
* @param {object} iconInfo An array of arrays that maps API names to
* CSS selectors.
* @param {string} area The name of the area that the button resides in.
*/
function checkButtons(icons, iconInfo, area) {
for (let button of iconInfo) {
let iconInfo = icons.find(arr => arr[0] == button[0]);
if (iconInfo[1]) {
verifyButtonWithCustomStyling(button[1],
verifyButtonWithCustomStyling(
button[1],
`The ${button[1]} should have its icon customized in the ${area}`);
} else {
verifyButtonWithoutCustomStyling(button[1],
verifyButtonWithoutCustomStyling(
button[1],
`The ${button[1]} should not have its icon customized in the ${area}`);
}
}
@ -135,7 +137,8 @@ async function runTestWithIcons(icons) {
CustomizableUI.addWidgetToArea(button[2], CustomizableUI.AREA_NAVBAR);
}
verifyButtonWithoutCustomStyling(button[1],
verifyButtonWithoutCustomStyling(
button[1],
`The ${button[1]} should not have its icon customized when the test starts`);
let iconInfo = icons.find(arr => arr[0] == button[0]);
@ -151,7 +154,8 @@ async function runTestWithIcons(icons) {
await extension.unload();
for (let button of ICON_INFO) {
verifyButtonWithoutCustomStyling(button[1],
verifyButtonWithoutCustomStyling(
button[1],
`The ${button[1]} should not have its icon customized when the theme is unloaded`);
}
}

View File

@ -70,14 +70,14 @@ add_task(async function testWindowTitle() {
if (msg === "update") {
let win = await browser.windows.get(windowId);
browser.test.assertTrue(win.title.startsWith(expected.before.preface),
"Window has the expected title preface before update.");
"Window has the expected title preface before update.");
browser.test.assertTrue(win.title.includes(expected.before.text),
"Window has the expected title text before update.");
"Window has the expected title text before update.");
win = await browser.windows.update(windowId, options);
browser.test.assertTrue(win.title.startsWith(expected.after.preface),
"Window has the expected title preface after update.");
"Window has the expected title preface after update.");
browser.test.assertTrue(win.title.includes(expected.after.text),
"Window has the expected title text after update.");
"Window has the expected title text after update.");
browser.test.sendMessage("updated", win);
}
});

View File

@ -144,12 +144,15 @@ function promisePossiblyInaccurateContentDimensions(browser) {
}
return {
window: copyProps(content,
window: copyProps(
content,
["innerWidth", "innerHeight", "outerWidth", "outerHeight",
"scrollX", "scrollY", "scrollMaxX", "scrollMaxY"]),
body: copyProps(content.document.body,
body: copyProps(
content.document.body,
["clientWidth", "clientHeight", "scrollWidth", "scrollHeight"]),
root: copyProps(content.document.documentElement,
root: copyProps(
content.document.documentElement,
["clientWidth", "clientHeight", "scrollWidth", "scrollHeight"]),
isStandards: content.document.compatMode !== "BackCompat",
};

View File

@ -194,10 +194,9 @@ add_task(async function test_bookmarks() {
browser.test.assertEq(1, results.length, "getTree returns one result");
let bookmark = results[0].children.find(bookmarkItem => bookmarkItem.id == unsortedId);
browser.test.assertEq(
"Other Bookmarks",
bookmark.title,
"Folder returned from getTree has the expected title"
);
"Other Bookmarks",
bookmark.title,
"Folder returned from getTree has the expected title");
browser.test.assertEq("folder", bookmark.type,
"Folder returned from getTree has the expected type");
@ -207,9 +206,8 @@ add_task(async function test_bookmarks() {
"Expected error thrown when trying to create a bookmark with an invalid parentId"
);
browser.test.assertTrue(
error.message.includes(`"parentGuid":"invalid"`),
"Expected error thrown when trying to create a bookmark with an invalid parentId"
);
error.message.includes(`"parentGuid":"invalid"`),
"Expected error thrown when trying to create a bookmark with an invalid parentId");
});
}).then(() => {
return browser.bookmarks.remove(ourId);
@ -695,19 +693,19 @@ add_task(async function test_tree_with_empty_folder() {
await browser.bookmarks.create({title: "A bookmark", url: "http://example.com", parentId: nonEmptyFolder.id});
let tree = await browser.bookmarks.getSubTree(nonEmptyFolder.parentId);
browser.test.assertEq(0,
tree[0].children[0].children.length,
browser.test.assertEq(
0, tree[0].children[0].children.length,
"The empty folder returns an empty array for children.");
browser.test.assertEq(1,
tree[0].children[1].children.length,
browser.test.assertEq(
1, tree[0].children[1].children.length,
"The non-empty folder returns a single item array for children.");
let children = await browser.bookmarks.getChildren(nonEmptyFolder.parentId);
// getChildren should only return immediate children. This is not tested in the
// monster test above.
for (let child of children) {
browser.test.assertEq(undefined,
child.children,
browser.test.assertEq(
undefined, child.children,
"Child from getChildren does not contain any children.");
}

View File

@ -32,15 +32,18 @@ add_task(async function testSettingsProperties() {
let settings = await extension.awaitMessage("settings");
// Verify that we get the keys back we expect.
deepEqual(Object.keys(settings.dataToRemove).sort(), SETTINGS_LIST,
"dataToRemove contains expected properties.");
deepEqual(Object.keys(settings.dataRemovalPermitted).sort(), SETTINGS_LIST,
"dataToRemove contains expected properties.");
deepEqual(Object.keys(settings.dataToRemove).sort(),
SETTINGS_LIST,
"dataToRemove contains expected properties.");
deepEqual(Object.keys(settings.dataRemovalPermitted).sort(),
SETTINGS_LIST,
"dataToRemove contains expected properties.");
let dataTypeSet = settings.dataToRemove;
for (let key of Object.keys(dataTypeSet)) {
equal(Preferences.get(`${PREF_DOMAIN}${key.toLowerCase()}`), dataTypeSet[key],
`${key} property of dataToRemove matches the expected pref.`);
equal(Preferences.get(`${PREF_DOMAIN}${key.toLowerCase()}`),
dataTypeSet[key],
`${key} property of dataToRemove matches the expected pref.`);
}
dataTypeSet = settings.dataRemovalPermitted;

View File

@ -73,9 +73,10 @@ add_task(async function test_overrides_update_removal() {
equal(extension.version, "1.0", "The installed addon has the expected version.");
ok(getHomePageURL().endsWith(HOMEPAGE_URI),
"Home page url is overriden by the extension.");
equal(Services.search.currentEngine.name, "DuckDuckGo",
"Default engine is overriden by the extension");
"Home page url is overriden by the extension.");
equal(Services.search.currentEngine.name,
"DuckDuckGo",
"Default engine is overriden by the extension");
extensionInfo.manifest = {
"version": "2.0",
@ -91,10 +92,12 @@ add_task(async function test_overrides_update_removal() {
await prefPromise;
equal(extension.version, "2.0", "The updated addon has the expected version.");
equal(getHomePageURL(), defaultHomepageURL,
"Home page url reverted to the default after update.");
equal(Services.search.currentEngine.name, defaultEngineName,
"Default engine reverted to the default after update.");
equal(getHomePageURL(),
defaultHomepageURL,
"Home page url reverted to the default after update.");
equal(Services.search.currentEngine.name,
defaultEngineName,
"Default engine reverted to the default after update.");
await extension.unload();

View File

@ -6,7 +6,8 @@ add_task(async function() {
let extension = ExtensionTestUtils.loadExtension({
background: () => {
browser.test.sendMessage("features",
browser.test.sendMessage(
"features",
Object.values(browser.geckoProfiler.ProfilerFeature));
},
manifest: {
@ -27,16 +28,16 @@ add_task(async function() {
const allFeaturesAcceptedByProfiler = Services.profiler.GetAllFeatures([]);
ok(allFeaturesAcceptedByProfiler.length >= 2,
"Either we've massively reduced the profiler's feature set, or something is wrong.");
"Either we've massively reduced the profiler's feature set, or something is wrong.");
// Check that the list of available values in the ProfilerFeature enum
// matches the list of features supported by the profiler.
for (const feature of allFeaturesAcceptedByProfiler) {
ok(acceptedFeatures.includes(feature),
`The schema of the geckoProfiler.start() method should accept the "${feature}" feature.`);
`The schema of the geckoProfiler.start() method should accept the "${feature}" feature.`);
}
for (const feature of acceptedFeatures) {
ok(allFeaturesAcceptedByProfiler.includes(feature),
`The schema of the geckoProfiler.start() method mentions a "${feature}" feature which is not supported by the profiler.`);
`The schema of the geckoProfiler.start() method mentions a "${feature}" feature which is not supported by the profiler.`);
}
});

View File

@ -309,8 +309,8 @@ add_task(async function test_add_url() {
equal(results.result.title, results.details.title, "URL was added with the correct title");
if (results.details.visitTime) {
equal(results.result.lastVisitTime,
Number(ExtensionUtils.normalizeTime(results.details.visitTime)),
"URL was added with the correct date");
Number(ExtensionUtils.normalizeTime(results.details.visitTime)),
"URL was added with the correct date");
}
}

View File

@ -99,13 +99,13 @@ add_task(async function test_multiple_extensions_overriding_newtab_page() {
let ext3 = ExtensionTestUtils.loadExtension(extObj);
equal(aboutNewTabService.newTabURL, DEFAULT_NEW_TAB_URL,
"newTabURL is set to the default.");
"newTabURL is set to the default.");
await promiseStartupManager();
await ext1.startup();
equal(aboutNewTabService.newTabURL, DEFAULT_NEW_TAB_URL,
"newTabURL is still set to the default.");
"newTabURL is still set to the default.");
await checkNewTabPageOverride(ext1, aboutNewTabService.newTabURL, NOT_CONTROLLABLE);
@ -147,7 +147,7 @@ add_task(async function test_multiple_extensions_overriding_newtab_page() {
await ext3.startup();
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_3),
"newTabURL is overriden by the third extension.");
"newTabURL is overriden by the third extension.");
await checkNewTabPageOverride(ext2, NEWTAB_URI_3, CONTROLLED_BY_OTHER);
// Disable the second extension.
@ -155,7 +155,7 @@ add_task(async function test_multiple_extensions_overriding_newtab_page() {
addon.userDisabled = true;
await disabledPromise;
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_3),
"newTabURL is still overriden by the third extension.");
"newTabURL is still overriden by the third extension.");
await checkNewTabPageOverride(ext3, NEWTAB_URI_3, CONTROLLED_BY_THIS);
// Re-enable the second extension.
@ -163,7 +163,7 @@ add_task(async function test_multiple_extensions_overriding_newtab_page() {
addon.userDisabled = false;
await enabledPromise;
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_3),
"newTabURL is still overriden by the third extension.");
"newTabURL is still overriden by the third extension.");
await checkNewTabPageOverride(ext3, NEWTAB_URI_3, CONTROLLED_BY_THIS);
await ext3.unload();
@ -173,7 +173,7 @@ add_task(async function test_multiple_extensions_overriding_newtab_page() {
await ext2.unload();
equal(aboutNewTabService.newTabURL, DEFAULT_NEW_TAB_URL,
"newTabURL url is reset to the default.");
"newTabURL url is reset to the default.");
await promiseShutdownManager();
});

View File

@ -29,6 +29,7 @@ const NOTIFY_INITIATING_MANUAL_RESTORE = "sessionstore-initiating-manual-restore
const NOTIFY_CLOSED_OBJECTS_CHANGED = "sessionstore-closed-objects-changed";
const NOTIFY_TAB_RESTORED = "sessionstore-debug-tab-restored"; // WARNING: debug-only
const NOTIFY_DOMWINDOWCLOSED_HANDLED = "sessionstore-debug-domwindowclosed-handled"; // WARNING: debug-only
// Maximum number of tabs to restore simultaneously. Previously controlled by
// the browser.sessionstore.max_concurrent_tabs pref.
@ -772,6 +773,9 @@ var SessionStoreInternal = {
this.onClose(aSubject).then(() => {
this._notifyOfClosedObjectsChange();
});
if (gDebuggingEnabled) {
Services.obs.notifyObservers(null, NOTIFY_DOMWINDOWCLOSED_HANDLED);
}
break;
case "quit-application-granted":
let syncShutdown = aData == "syncShutdown";

View File

@ -42,28 +42,30 @@ add_task(async function test_add_interesting_window() {
// it's really not worth restoring.
browser.userTypedValue = null;
// Once the domWindowClosed Promise resolves, the window should
// have closed, and SessionStore's onClose handler should have just
// run.
let domWindowClosed = BrowserTestUtils.domWindowClosed(newWin);
// Once this windowClosed Promise resolves, we should have finished
// the flush and revisited our decision to put this window into
// the closed windows array.
let windowClosed = BrowserTestUtils.windowClosed(newWin);
let handled = false;
whenDomWindowClosedHandled(() => {
// SessionStore's onClose handler should have just run.
let currentClosedWindows = ss.getClosedWindowCount();
is(currentClosedWindows, initialClosedWindows,
"We should not have added the window to the closed windows array");
handled = true;
});
// Ok, let's close the window.
newWin.close();
await domWindowClosed;
// OnClose has just finished running.
let currentClosedWindows = ss.getClosedWindowCount();
is(currentClosedWindows, initialClosedWindows,
"We should not have added the window to the closed windows array");
await windowClosed;
ok(handled, "domwindowclosed should already be handled here");
// The window flush has finished
currentClosedWindows = ss.getClosedWindowCount();
let currentClosedWindows = ss.getClosedWindowCount();
is(currentClosedWindows,
initialClosedWindows + 1,
"We should have added the window to the closed windows array");
@ -110,28 +112,30 @@ add_task(async function test_remove_uninteresting_window() {
sessionHistory.PurgeHistory(sessionHistory.count);
});
// Once the domWindowClosed Promise resolves, the window should
// have closed, and SessionStore's onClose handler should have just
// run.
let domWindowClosed = BrowserTestUtils.domWindowClosed(newWin);
// Once this windowClosed Promise resolves, we should have finished
// the flush and revisited our decision to put this window into
// the closed windows array.
let windowClosed = BrowserTestUtils.windowClosed(newWin);
let handled = false;
whenDomWindowClosedHandled(() => {
// SessionStore's onClose handler should have just run.
let currentClosedWindows = ss.getClosedWindowCount();
is(currentClosedWindows, initialClosedWindows + 1,
"We should have added the window to the closed windows array");
handled = true;
});
// Ok, let's close the window.
newWin.close();
await domWindowClosed;
// OnClose has just finished running.
let currentClosedWindows = ss.getClosedWindowCount();
is(currentClosedWindows, initialClosedWindows + 1,
"We should have added the window to the closed windows array");
await windowClosed;
ok(handled, "domwindowclosed should already be handled here");
// The window flush has finished
currentClosedWindows = ss.getClosedWindowCount();
let currentClosedWindows = ss.getClosedWindowCount();
is(currentClosedWindows,
initialClosedWindows,
"We should have removed the window from the closed windows array");

View File

@ -84,21 +84,26 @@ let forgetWinHelper = async function(forgetFn) {
// Now close the window and immediately choose to forget it.
let windowClosed = BrowserTestUtils.windowClosed(newWin);
let domWindowClosed = BrowserTestUtils.domWindowClosed(newWin);
let handled = false;
whenDomWindowClosedHandled(() => {
// At this point, the window will have closed and the onClose handler
// has run, but the final update to SessionStore hasn't come up yet.
// Now do the oepration that should cause us to forget the window.
forgetFn();
is(ss.getClosedWindowCount(), 0, "Should have forgotten the closed window");
handled = true;
});
newWin.close();
await domWindowClosed;
// At this point, the window will have closed and the onClose handler
// has run, but the final update to SessionStore hasn't come up yet.
// Now do the oepration that should cause us to forget the window.
forgetFn();
is(ss.getClosedWindowCount(), 0, "Should have forgotten the closed window");
// Now wait for the final update to come up.
await windowClosed;
ok(handled, "domwindowclosed should already be handled here");
is(ss.getClosedWindowCount(), 0, "Should not have stored the closed window");
};

View File

@ -564,3 +564,10 @@ async function checkScroll(tab, expected, msg) {
let scroll = JSON.parse(ss.getTabState(tab)).scroll || null;
is(JSON.stringify(scroll), JSON.stringify(expected), msg);
}
function whenDomWindowClosedHandled(aCallback) {
Services.obs.addObserver(function observer(aSubject, aTopic) {
Services.obs.removeObserver(observer, aTopic);
aCallback();
}, "sessionstore-debug-domwindowclosed-handled");
}

View File

@ -1,5 +1,5 @@
This is the PDF.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 2.0.185
Current extension version is: 2.0.197
Taken from upstream commit: f2994736
Taken from upstream commit: 371ca514

View File

@ -79,6 +79,7 @@ function isDefaultHandler() {
}
function initializeDefaultPreferences() {
/* eslint-disable semi */
var DEFAULT_PREFERENCES =
{
"showPreviousViewOnLoad": true,
@ -101,8 +102,9 @@ function initializeDefaultPreferences() {
"enablePrintAutoRotate": false,
"disablePageMode": false,
"disablePageLabels": false
};
}
/* eslint-enable semi */
var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + ".");
var defaultValue;

View File

@ -33,6 +33,7 @@ XPCOMUtils.defineLazyServiceGetter(Svc, "mime",
"@mozilla.org/mime;1",
"nsIMIMEService");
/* eslint-disable semi */
var DEFAULT_PREFERENCES =
{
"showPreviousViewOnLoad": true,
@ -55,8 +56,9 @@ var DEFAULT_PREFERENCES =
"enablePrintAutoRotate": false,
"disablePageMode": false,
"disablePageLabels": false
};
}
/* eslint-enable semi */
var PdfjsChromeUtils = {
// For security purposes when running remote, we restrict preferences

View File

@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.loadJpegStream = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isNodeJS = exports.isSpace = exports.isString = exports.isNum = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.info = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.createBlob = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.StatTimer = exports.PasswordResponses = exports.PasswordException = exports.PageViewport = exports.NotImplementedException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.MessageHandler = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VERBOSITY_LEVELS = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined;
exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.loadJpegStream = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isNodeJS = exports.isSpace = exports.isString = exports.isNum = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.info = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.createBlob = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PasswordResponses = exports.PasswordException = exports.PageViewport = exports.NotImplementedException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.MessageHandler = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VERBOSITY_LEVELS = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined;
__w_pdfjs_require__(9);
@ -904,63 +904,6 @@ function createPromiseCapability() {
});
return capability;
}
var StatTimer = function StatTimerClosure() {
function rpad(str, pad, length) {
while (str.length < length) {
str += pad;
}
return str;
}
function StatTimer() {
this.started = Object.create(null);
this.times = [];
this.enabled = true;
}
StatTimer.prototype = {
time: function StatTimer_time(name) {
if (!this.enabled) {
return;
}
if (name in this.started) {
warn('Timer is already running for ' + name);
}
this.started[name] = Date.now();
},
timeEnd: function StatTimer_timeEnd(name) {
if (!this.enabled) {
return;
}
if (!(name in this.started)) {
warn('Timer has not been started for ' + name);
}
this.times.push({
'name': name,
'start': this.started[name],
'end': Date.now()
});
delete this.started[name];
},
toString: function StatTimer_toString() {
var i, ii;
var times = this.times;
var out = '';
var longest = 0;
for (i = 0, ii = times.length; i < ii; ++i) {
var name = times[i]['name'];
if (name.length > longest) {
longest = name.length;
}
}
for (i = 0, ii = times.length; i < ii; ++i) {
var span = times[i];
var duration = span.end - span.start;
out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n';
}
return out;
}
};
return StatTimer;
}();
var createBlob = function createBlob(data, contentType) {
if (typeof Blob !== 'undefined') {
return new Blob([data], { type: contentType });
@ -1399,7 +1342,6 @@ exports.NotImplementedException = NotImplementedException;
exports.PageViewport = PageViewport;
exports.PasswordException = PasswordException;
exports.PasswordResponses = PasswordResponses;
exports.StatTimer = StatTimer;
exports.StreamType = StreamType;
exports.TextRenderingMode = TextRenderingMode;
exports.UnexpectedResponseException = UnexpectedResponseException;
@ -1456,7 +1398,7 @@ exports.unreachable = unreachable;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SimpleXMLParser = exports.DOMSVGFactory = exports.DOMCMapReaderFactory = exports.DOMCanvasFactory = exports.DEFAULT_LINK_REL = exports.getDefaultSetting = exports.LinkTarget = exports.getFilenameFromUrl = exports.isExternalLinkTargetSet = exports.addLinkAttributes = exports.RenderingCancelledException = exports.CustomStyle = undefined;
exports.DummyStatTimer = exports.StatTimer = exports.SimpleXMLParser = exports.DOMSVGFactory = exports.DOMCMapReaderFactory = exports.DOMCanvasFactory = exports.DEFAULT_LINK_REL = exports.getDefaultSetting = exports.LinkTarget = exports.getFilenameFromUrl = exports.isExternalLinkTargetSet = exports.addLinkAttributes = exports.RenderingCancelledException = exports.CustomStyle = undefined;
var _util = __w_pdfjs_require__(0);
@ -1805,6 +1747,67 @@ function isExternalLinkTargetSet() {
return true;
}
}
class StatTimer {
constructor(enable = true) {
this.enabled = !!enable;
this.reset();
}
reset() {
this.started = Object.create(null);
this.times = [];
}
time(name) {
if (!this.enabled) {
return;
}
if (name in this.started) {
(0, _util.warn)('Timer is already running for ' + name);
}
this.started[name] = Date.now();
}
timeEnd(name) {
if (!this.enabled) {
return;
}
if (!(name in this.started)) {
(0, _util.warn)('Timer has not been started for ' + name);
}
this.times.push({
'name': name,
'start': this.started[name],
'end': Date.now()
});
delete this.started[name];
}
toString() {
let times = this.times;
let out = '',
longest = 0;
for (let i = 0, ii = times.length; i < ii; ++i) {
let name = times[i]['name'];
if (name.length > longest) {
longest = name.length;
}
}
for (let i = 0, ii = times.length; i < ii; ++i) {
let span = times[i];
let duration = span.end - span.start;
out += `${span['name'].padEnd(longest)} ${duration}ms\n`;
}
return out;
}
}
class DummyStatTimer {
constructor() {
throw new Error('Cannot initialize DummyStatTimer.');
}
static reset() {}
static time(name) {}
static timeEnd(name) {}
static toString() {
return '';
}
}
exports.CustomStyle = CustomStyle;
exports.RenderingCancelledException = RenderingCancelledException;
exports.addLinkAttributes = addLinkAttributes;
@ -1817,6 +1820,8 @@ exports.DOMCanvasFactory = DOMCanvasFactory;
exports.DOMCMapReaderFactory = DOMCMapReaderFactory;
exports.DOMSVGFactory = DOMSVGFactory;
exports.SimpleXMLParser = SimpleXMLParser;
exports.StatTimer = StatTimer;
exports.DummyStatTimer = DummyStatTimer;
/***/ }),
/* 2 */
@ -1960,7 +1965,7 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
if (worker.destroyed) {
return Promise.reject(new Error('Worker was destroyed'));
}
let apiVersion = '2.0.185';
let apiVersion = '2.0.197';
source.disableRange = (0, _dom_utils.getDefaultSetting)('disableRange');
source.disableAutoFetch = (0, _dom_utils.getDefaultSetting)('disableAutoFetch');
source.disableStream = (0, _dom_utils.getDefaultSetting)('disableStream');
@ -2144,8 +2149,7 @@ var PDFPageProxy = function PDFPageProxyClosure() {
this.pageIndex = pageIndex;
this.pageInfo = pageInfo;
this.transport = transport;
this.stats = new _util.StatTimer();
this.stats.enabled = (0, _dom_utils.getDefaultSetting)('enableStats');
this._stats = (0, _dom_utils.getDefaultSetting)('enableStats') ? new _dom_utils.StatTimer() : _dom_utils.DummyStatTimer;
this.commonObjs = transport.commonObjs;
this.objs = new PDFObjects();
this.cleanupAfterRender = false;
@ -2184,7 +2188,7 @@ var PDFPageProxy = function PDFPageProxyClosure() {
return this.annotationsPromise;
},
render: function PDFPageProxy_render(params) {
var stats = this.stats;
let stats = this._stats;
stats.time('Overall');
this.pendingCleanup = false;
var renderingIntent = params.intent === 'print' ? 'print' : 'display';
@ -2202,7 +2206,7 @@ var PDFPageProxy = function PDFPageProxyClosure() {
argsArray: [],
lastChunk: false
};
this.stats.time('Page Request');
stats.time('Page Request');
this.transport.messageHandler.send('RenderPageRequest', {
pageIndex: this.pageNumber - 1,
intent: renderingIntent,
@ -2335,11 +2339,11 @@ var PDFPageProxy = function PDFPageProxyClosure() {
this.pendingCleanup = false;
return Promise.all(waitOn);
},
cleanup: function PDFPageProxy_cleanup() {
cleanup(resetStats = false) {
this.pendingCleanup = true;
this._tryCleanup();
this._tryCleanup(resetStats);
},
_tryCleanup: function PDFPageProxy_tryCleanup() {
_tryCleanup(resetStats = false) {
if (!this.pendingCleanup || Object.keys(this.intentStates).some(function (intent) {
var intentState = this.intentStates[intent];
return intentState.renderTasks.length !== 0 || intentState.receivingOperatorList;
@ -2351,6 +2355,9 @@ var PDFPageProxy = function PDFPageProxyClosure() {
}, this);
this.objs.clear();
this.annotationsPromise = null;
if (resetStats) {
this._stats.reset();
}
this.pendingCleanup = false;
},
_startRenderPage: function PDFPageProxy_startRenderPage(transparency, intent) {
@ -2374,6 +2381,9 @@ var PDFPageProxy = function PDFPageProxyClosure() {
intentState.receivingOperatorList = false;
this._tryCleanup();
}
},
get stats() {
return this._stats instanceof _dom_utils.StatTimer ? this._stats : null;
}
};
return PDFPageProxy;
@ -2804,7 +2814,7 @@ var WorkerTransport = function WorkerTransportClosure() {
return;
}
var page = this.pageCache[data.pageIndex];
page.stats.timeEnd('Page Request');
page._stats.timeEnd('Page Request');
page._startRenderPage(data.transparency, data.intent);
}, this);
messageHandler.on('RenderPageChunk', function transportRender(data) {
@ -3253,8 +3263,8 @@ var InternalRenderTask = function InternalRenderTaskClosure() {
}();
var version, build;
{
exports.version = version = '2.0.185';
exports.build = build = 'f2994736';
exports.version = version = '2.0.197';
exports.build = build = '371ca514';
}
exports.getDocument = getDocument;
exports.LoopbackPort = LoopbackPort;
@ -4627,8 +4637,8 @@ exports.SVGGraphics = SVGGraphics;
"use strict";
var pdfjsVersion = '2.0.185';
var pdfjsBuild = 'f2994736';
var pdfjsVersion = '2.0.197';
var pdfjsBuild = '371ca514';
var pdfjsSharedUtil = __w_pdfjs_require__(0);
var pdfjsDisplayGlobal = __w_pdfjs_require__(12);
var pdfjsDisplayAPI = __w_pdfjs_require__(3);
@ -4664,7 +4674,6 @@ exports.createBlob = pdfjsSharedUtil.createBlob;
exports.RenderingCancelledException = pdfjsDisplayDOMUtils.RenderingCancelledException;
exports.getFilenameFromUrl = pdfjsDisplayDOMUtils.getFilenameFromUrl;
exports.addLinkAttributes = pdfjsDisplayDOMUtils.addLinkAttributes;
exports.StatTimer = pdfjsSharedUtil.StatTimer;
/***/ }),
/* 9 */
@ -7752,8 +7761,8 @@ if (!_global_scope2.default.PDFJS) {
}
var PDFJS = _global_scope2.default.PDFJS;
{
PDFJS.version = '2.0.185';
PDFJS.build = 'f2994736';
PDFJS.version = '2.0.197';
PDFJS.build = '371ca514';
}
PDFJS.pdfBug = false;
if (PDFJS.verbosity !== undefined) {

View File

@ -98,7 +98,7 @@ return /******/ (function(modules) { // webpackBootstrap
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.loadJpegStream = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isNodeJS = exports.isSpace = exports.isString = exports.isNum = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.info = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.createBlob = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.StatTimer = exports.PasswordResponses = exports.PasswordException = exports.PageViewport = exports.NotImplementedException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.MessageHandler = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VERBOSITY_LEVELS = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined;
exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.loadJpegStream = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isNodeJS = exports.isSpace = exports.isString = exports.isNum = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.info = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.createBlob = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PasswordResponses = exports.PasswordException = exports.PageViewport = exports.NotImplementedException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.MessageHandler = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VERBOSITY_LEVELS = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined;
__w_pdfjs_require__(20);
@ -904,63 +904,6 @@ function createPromiseCapability() {
});
return capability;
}
var StatTimer = function StatTimerClosure() {
function rpad(str, pad, length) {
while (str.length < length) {
str += pad;
}
return str;
}
function StatTimer() {
this.started = Object.create(null);
this.times = [];
this.enabled = true;
}
StatTimer.prototype = {
time: function StatTimer_time(name) {
if (!this.enabled) {
return;
}
if (name in this.started) {
warn('Timer is already running for ' + name);
}
this.started[name] = Date.now();
},
timeEnd: function StatTimer_timeEnd(name) {
if (!this.enabled) {
return;
}
if (!(name in this.started)) {
warn('Timer has not been started for ' + name);
}
this.times.push({
'name': name,
'start': this.started[name],
'end': Date.now()
});
delete this.started[name];
},
toString: function StatTimer_toString() {
var i, ii;
var times = this.times;
var out = '';
var longest = 0;
for (i = 0, ii = times.length; i < ii; ++i) {
var name = times[i]['name'];
if (name.length > longest) {
longest = name.length;
}
}
for (i = 0, ii = times.length; i < ii; ++i) {
var span = times[i];
var duration = span.end - span.start;
out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n';
}
return out;
}
};
return StatTimer;
}();
var createBlob = function createBlob(data, contentType) {
if (typeof Blob !== 'undefined') {
return new Blob([data], { type: contentType });
@ -1399,7 +1342,6 @@ exports.NotImplementedException = NotImplementedException;
exports.PageViewport = PageViewport;
exports.PasswordException = PasswordException;
exports.PasswordResponses = PasswordResponses;
exports.StatTimer = StatTimer;
exports.StreamType = StreamType;
exports.TextRenderingMode = TextRenderingMode;
exports.UnexpectedResponseException = UnexpectedResponseException;
@ -17047,7 +16989,7 @@ exports.CFFCompiler = CFFCompiler;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getSupplementalGlyphMapForArialBlack = exports.getGlyphMapForStandardFonts = exports.getSymbolsFonts = exports.getSerifFonts = exports.getNonStdFontMap = exports.getStdFontMap = undefined;
exports.getSupplementalGlyphMapForCalibri = exports.getSupplementalGlyphMapForArialBlack = exports.getGlyphMapForStandardFonts = exports.getSymbolsFonts = exports.getSerifFonts = exports.getNonStdFontMap = exports.getStdFontMap = undefined;
var _util = __w_pdfjs_require__(0);
@ -17110,6 +17052,10 @@ var getStdFontMap = (0, _util.getLookupTableFactory)(function (t) {
t['TimesNewRomanPSMT-Italic'] = 'Times-Italic';
});
var getNonStdFontMap = (0, _util.getLookupTableFactory)(function (t) {
t['Calibri'] = 'Helvetica';
t['Calibri-Bold'] = 'Helvetica-Bold';
t['Calibri-BoldItalic'] = 'Helvetica-BoldOblique';
t['Calibri-Italic'] = 'Helvetica-Oblique';
t['CenturyGothic'] = 'Helvetica';
t['CenturyGothic-Bold'] = 'Helvetica-Bold';
t['CenturyGothic-BoldItalic'] = 'Helvetica-BoldOblique';
@ -17681,12 +17627,99 @@ var getSupplementalGlyphMapForArialBlack = (0, _util.getLookupTableFactory)(func
t[264] = 261;
t[291] = 346;
});
let getSupplementalGlyphMapForCalibri = (0, _util.getLookupTableFactory)(function (t) {
t[1] = 32;
t[4] = 65;
t[17] = 66;
t[18] = 67;
t[24] = 68;
t[28] = 69;
t[38] = 70;
t[39] = 71;
t[44] = 72;
t[47] = 73;
t[58] = 74;
t[60] = 75;
t[62] = 76;
t[68] = 77;
t[69] = 78;
t[75] = 79;
t[87] = 80;
t[89] = 81;
t[90] = 82;
t[94] = 83;
t[100] = 84;
t[104] = 85;
t[115] = 86;
t[116] = 87;
t[121] = 88;
t[122] = 89;
t[127] = 90;
t[258] = 97;
t[268] = 261;
t[271] = 98;
t[272] = 99;
t[273] = 263;
t[282] = 100;
t[286] = 101;
t[295] = 281;
t[296] = 102;
t[336] = 103;
t[346] = 104;
t[349] = 105;
t[361] = 106;
t[364] = 107;
t[367] = 108;
t[371] = 322;
t[373] = 109;
t[374] = 110;
t[381] = 111;
t[383] = 243;
t[393] = 112;
t[395] = 113;
t[396] = 114;
t[400] = 115;
t[401] = 347;
t[410] = 116;
t[437] = 117;
t[448] = 118;
t[449] = 119;
t[454] = 120;
t[455] = 121;
t[460] = 122;
t[463] = 380;
t[853] = 44;
t[855] = 58;
t[856] = 46;
t[876] = 47;
t[878] = 45;
t[882] = 45;
t[894] = 40;
t[895] = 41;
t[896] = 91;
t[897] = 93;
t[923] = 64;
t[1004] = 48;
t[1005] = 49;
t[1006] = 50;
t[1007] = 51;
t[1008] = 52;
t[1009] = 53;
t[1010] = 54;
t[1011] = 55;
t[1012] = 56;
t[1013] = 57;
t[1081] = 37;
t[1085] = 43;
t[1086] = 45;
});
exports.getStdFontMap = getStdFontMap;
exports.getNonStdFontMap = getNonStdFontMap;
exports.getSerifFonts = getSerifFonts;
exports.getSymbolsFonts = getSymbolsFonts;
exports.getGlyphMapForStandardFonts = getGlyphMapForStandardFonts;
exports.getSupplementalGlyphMapForArialBlack = getSupplementalGlyphMapForArialBlack;
exports.getSupplementalGlyphMapForCalibri = getSupplementalGlyphMapForCalibri;
/***/ }),
/* 16 */
@ -20728,8 +20761,8 @@ exports.PostScriptCompiler = PostScriptCompiler;
"use strict";
var pdfjsVersion = '2.0.185';
var pdfjsBuild = 'f2994736';
var pdfjsVersion = '2.0.197';
var pdfjsBuild = '371ca514';
var pdfjsCoreWorker = __w_pdfjs_require__(19);
exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
@ -20924,7 +20957,7 @@ var WorkerMessageHandler = {
var cancelXHRs = null;
var WorkerTasks = [];
let apiVersion = docParams.apiVersion;
let workerVersion = '2.0.185';
let workerVersion = '2.0.197';
if (apiVersion !== null && apiVersion !== workerVersion) {
throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`);
}
@ -32329,7 +32362,7 @@ var OpenTypeFileBuilder = function OpenTypeFileBuilderClosure() {
};
return OpenTypeFileBuilder;
}();
var ProblematicCharRanges = new Int32Array([0x0000, 0x0020, 0x007F, 0x00A1, 0x00AD, 0x00AE, 0x0600, 0x0780, 0x08A0, 0x10A0, 0x1780, 0x1800, 0x1C00, 0x1C50, 0x2000, 0x2010, 0x2011, 0x2012, 0x2028, 0x2030, 0x205F, 0x2070, 0x25CC, 0x25CD, 0x3000, 0x3001, 0x3164, 0x3165, 0xAA60, 0xAA80, 0xFFF0, 0x10000]);
var ProblematicCharRanges = new Int32Array([0x0000, 0x0020, 0x007F, 0x00A1, 0x00AD, 0x00AE, 0x0600, 0x0780, 0x08A0, 0x10A0, 0x1780, 0x1800, 0x1C00, 0x1C50, 0x2000, 0x2010, 0x2011, 0x2012, 0x2028, 0x2030, 0x205F, 0x2070, 0x25CC, 0x25CD, 0x3000, 0x3001, 0x3164, 0x3165, 0xAA60, 0xAA80, 0xD800, 0xE000, 0xFFF0, 0x10000]);
var Font = function FontClosure() {
function Font(name, file, properties) {
var charCode;
@ -32848,6 +32881,11 @@ var Font = function FontClosure() {
for (charCode in SupplementalGlyphMapForArialBlack) {
map[+charCode] = SupplementalGlyphMapForArialBlack[charCode];
}
} else if (/Calibri/i.test(name)) {
let SupplementalGlyphMapForCalibri = (0, _standard_fonts.getSupplementalGlyphMapForCalibri)();
for (charCode in SupplementalGlyphMapForCalibri) {
map[+charCode] = SupplementalGlyphMapForCalibri[charCode];
}
}
var isIdentityUnicode = this.toUnicode instanceof IdentityToUnicodeMap;
if (!isIdentityUnicode) {

View File

@ -1911,7 +1911,7 @@ function webViewerPageRendered(evt) {
let thumbnailView = PDFViewerApplication.pdfThumbnailViewer.getThumbnail(pageIndex);
thumbnailView.setImage(pageView);
}
if (_pdfjsLib.PDFJS.pdfBug && Stats.enabled && pageView.stats) {
if (_pdfjsLib.PDFJS.pdfBug && typeof Stats !== 'undefined' && Stats.enabled && pageView.stats) {
Stats.add(pageNumber, pageView.stats);
}
if (pageView.error) {
@ -2111,9 +2111,9 @@ function webViewerPageChanging(evt) {
if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) {
PDFViewerApplication.pdfThumbnailViewer.scrollThumbnailIntoView(page);
}
if (_pdfjsLib.PDFJS.pdfBug && Stats.enabled) {
if (_pdfjsLib.PDFJS.pdfBug && typeof Stats !== 'undefined' && Stats.enabled) {
let pageView = PDFViewerApplication.pdfViewer.getPageView(page - 1);
if (pageView.stats) {
if (pageView && pageView.stats) {
Stats.add(page, pageView.stats);
}
}

View File

@ -192,6 +192,9 @@
@RESPATH@/components/dom.xpt
@RESPATH@/components/dom_base.xpt
@RESPATH@/components/dom_bindings.xpt
#ifdef MOZ_DEBUG
@RESPATH@/components/dom_bindings_test.xpt
#endif
@RESPATH@/components/dom_file.xpt
@RESPATH@/components/dom_system.xpt
@RESPATH@/components/dom_canvas.xpt

View File

@ -12,6 +12,7 @@
#include "nsIAnonymousContentCreator.h"
#include "nsIFrame.h"
#include "nsCSSAnonBoxes.h"
#include "nsDocument.h"
namespace mozilla {
namespace dom {
@ -66,7 +67,8 @@ ExplicitChildIterator::ExplicitChildIterator(const nsIContent* aParent,
mIsFirst(aStartAtBeginning),
mIndexInInserted(0)
{
mParentAsSlot = HTMLSlotElement::FromContent(mParent);
mParentAsSlot = nsDocument::IsWebComponentsEnabled(mParent) ?
HTMLSlotElement::FromContent(mParent) : nullptr;
}
nsIContent*

View File

@ -26,6 +26,7 @@
#include "nsString.h"
#include "mozilla/Attributes.h"
#include "nsAtom.h"
#include "plhash.h"
class nsIDocument;
class nsNodeInfoManager;

View File

@ -0,0 +1,6 @@
<!DOCTYPE html>
<html>
<body>
<!-- Testing slot element with "dom.webcomponents.enabled" set to false -->
<slot><div></div></slot>
</html>

View File

@ -236,4 +236,5 @@ load 1406109-1.html
pref(dom.webcomponents.enabled,true) load 1324463.html
pref(dom.webcomponents.customelements.enabled,true) load 1413815.html
load 1411473.html
pref(dom.webcomponents.enabled,false) load 1422931.html
pref(dom.webcomponents.enabled,true) load 1419799.html

View File

@ -7534,7 +7534,7 @@ nsContentUtils::IsContentInsertionPoint(nsIContent* aContent)
bool
nsContentUtils::HasDistributedChildren(nsIContent* aContent)
{
if (!aContent) {
if (!aContent || !nsDocument::IsWebComponentsEnabled(aContent)) {
return false;
}

View File

@ -1208,7 +1208,8 @@ nsExternalResourceMap::PendingLoad::OnDataAvailable(nsIRequest* aRequest,
uint64_t aOffset,
uint32_t aCount)
{
NS_PRECONDITION(mTargetListener, "Shouldn't be getting called!");
// mTargetListener might be null if SetupViewer or AddExternalResource failed.
NS_ENSURE_TRUE(mTargetListener, NS_ERROR_FAILURE);
if (mDisplayDocument->ExternalResourceMap().HaveShutDown()) {
return NS_BINDING_ABORTED;
}
@ -1581,6 +1582,10 @@ nsIDocument::nsIDocument()
for (auto& cnt : mIncCounters) {
cnt = 0;
}
// Set this when document is created and value stays the same for the lifetime
// of the document.
mIsWebComponentsEnabled = nsContentUtils::IsWebComponentsEnabled();
}
nsDocument::nsDocument(const char* aContentType)
@ -2720,6 +2725,30 @@ nsDocument::IsSynthesized() {
return synthesized;
}
bool
nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
{
JS::Rooted<JSObject*> obj(aCx, aObject);
JSAutoCompartment ac(aCx, obj);
JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, obj));
nsCOMPtr<nsPIDOMWindowInner> window =
do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(global));
nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
if (!doc) {
return false;
}
return doc->IsWebComponentsEnabled();
}
bool
nsDocument::IsWebComponentsEnabled(const nsINode* aNode)
{
return aNode->OwnerDoc()->IsWebComponentsEnabled();
}
nsresult
nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
nsILoadGroup* aLoadGroup,

View File

@ -665,6 +665,11 @@ public:
virtual void ResolveScheduledSVGPresAttrs() override;
bool IsSynthesized();
// Check whether web components are enabled for the global of aObject.
static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
// Check whether web components are enabled for the document this node belongs
// to.
static bool IsWebComponentsEnabled(const nsINode* aNode);
private:
void AddOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet);
void SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages);

View File

@ -259,6 +259,7 @@
#include "mozilla/dom/ClientManager.h"
#include "mozilla/dom/ClientSource.h"
#include "mozilla/dom/ClientState.h"
// Apple system headers seem to have a check() macro. <sigh>
#ifdef check
@ -2317,6 +2318,12 @@ nsPIDOMWindowInner::GetClientInfo() const
return Move(nsGlobalWindowInner::Cast(this)->GetClientInfo());
}
Maybe<ClientState>
nsPIDOMWindowInner::GetClientState() const
{
return Move(nsGlobalWindowInner::Cast(this)->GetClientState());
}
Maybe<ServiceWorkerDescriptor>
nsPIDOMWindowInner::GetController() const
{
@ -6157,6 +6164,21 @@ nsGlobalWindowInner::GetClientInfo() const
return Move(clientInfo);
}
Maybe<ClientState>
nsGlobalWindowInner::GetClientState() const
{
MOZ_ASSERT(NS_IsMainThread());
Maybe<ClientState> clientState;
if (mClientSource) {
ClientState state;
nsresult rv = mClientSource->SnapshotState(&state);
if (NS_SUCCEEDED(rv)) {
clientState.emplace(state);
}
}
return Move(clientState);
}
Maybe<ServiceWorkerDescriptor>
nsGlobalWindowInner::GetController() const
{

View File

@ -348,6 +348,7 @@ public:
void SyncStateFromParentWindow();
mozilla::Maybe<mozilla::dom::ClientInfo> GetClientInfo() const;
mozilla::Maybe<mozilla::dom::ClientState> GetClientState() const;
mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor> GetController() const;
virtual nsresult FireDelayedDOMEvents() override;

View File

@ -5966,24 +5966,26 @@ nsGlobalWindowOuter::CloseOuter(bool aTrustedCaller)
// Don't allow scripts from content to close non-neterror windows that
// were not opened by script.
nsAutoString url;
nsresult rv = mDoc->GetURL(url);
NS_ENSURE_SUCCESS_VOID(rv);
if (mDoc) {
nsAutoString url;
nsresult rv = mDoc->GetURL(url);
NS_ENSURE_SUCCESS_VOID(rv);
if (!StringBeginsWith(url, NS_LITERAL_STRING("about:neterror")) &&
!mHadOriginalOpener && !aTrustedCaller) {
bool allowClose = mAllowScriptsToClose ||
Preferences::GetBool("dom.allow_scripts_to_close_windows", true);
if (!allowClose) {
// We're blocking the close operation
// report localized error msg in JS console
nsContentUtils::ReportToConsole(
nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("DOM Window"), mDoc, // Better name for the category?
nsContentUtils::eDOM_PROPERTIES,
"WindowCloseBlockedWarning");
if (!StringBeginsWith(url, NS_LITERAL_STRING("about:neterror")) &&
!mHadOriginalOpener && !aTrustedCaller) {
bool allowClose = mAllowScriptsToClose ||
Preferences::GetBool("dom.allow_scripts_to_close_windows", true);
if (!allowClose) {
// We're blocking the close operation
// report localized error msg in JS console
nsContentUtils::ReportToConsole(
nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("DOM Window"), mDoc, // Better name for the category?
nsContentUtils::eDOM_PROPERTIES,
"WindowCloseBlockedWarning");
return;
return;
}
}
}

View File

@ -3256,6 +3256,11 @@ public:
virtual bool AllowPaymentRequest() const = 0;
virtual void SetAllowPaymentRequest(bool aAllowPaymentRequest) = 0;
bool IsWebComponentsEnabled() const
{
return mIsWebComponentsEnabled;
}
protected:
bool GetUseCounter(mozilla::UseCounter aUseCounter)
{
@ -3612,6 +3617,9 @@ protected:
// True if the encoding menu should be disabled.
bool mEncodingMenuDisabled : 1;
// True if dom.webcomponents.enabled pref is set when document is created.
bool mIsWebComponentsEnabled : 1;
// Whether <style scoped> support is enabled in this document.
enum { eScopedStyle_Unknown, eScopedStyle_Disabled, eScopedStyle_Enabled };
unsigned int mIsScopedStyleEnabled : 2;

View File

@ -47,6 +47,7 @@ class ThrottledEventQueue;
namespace dom {
class AudioContext;
class ClientInfo;
class ClientState;
class DocGroup;
class TabGroup;
class Element;
@ -327,6 +328,7 @@ public:
bool HasOpenWebSockets() const;
mozilla::Maybe<mozilla::dom::ClientInfo> GetClientInfo() const;
mozilla::Maybe<mozilla::dom::ClientState> GetClientState() const;
mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor> GetController() const;
mozilla::dom::TabGroup* TabGroup();

View File

@ -21,6 +21,7 @@
#ifdef DEBUG
#include "nsRange.h"
#endif
#include "nsDocument.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -157,6 +158,12 @@ void nsTextNode::UnbindFromTree(bool aDeep, bool aNullParent)
nsGenericDOMDataNode::UnbindFromTree(aDeep, aNullParent);
}
bool
nsTextNode::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
{
return nsDocument::IsWebComponentsEnabled(aCx, aObject);
}
#ifdef DEBUG
void
nsTextNode::List(FILE* out, int32_t aIndent) const

View File

@ -75,6 +75,10 @@ public:
virtual nsIDOMNode* AsDOMNode() override { return this; }
// Need to have a copy here because including nsDocument.h in this file will
// fail to build on Windows.
static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
#ifdef DEBUG
virtual void List(FILE* out, int32_t aIndent) const override;
virtual void DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const override;

View File

@ -7,6 +7,8 @@
#include "mozilla/dom/TestFunctions.h"
#include "mozilla/dom/TestFunctionsBinding.h"
#include "nsStringBuffer.h"
#include "mozITestInterfaceJS.h"
#include "nsComponentManagerUtils.h"
namespace mozilla {
namespace dom {
@ -83,6 +85,22 @@ TestFunctions::GetStringDataAsDOMString(const Optional<uint32_t>& aLength,
// No need to do anything here; aString is already empty.
}
void
TestFunctions::TestThrowNsresult(ErrorResult& aError)
{
nsCOMPtr<mozITestInterfaceJS> impl =
do_CreateInstance("@mozilla.org/dom/test-interface-js;1");
aError = impl->TestThrowNsresult();
}
void
TestFunctions::TestThrowNsresultFromNative(ErrorResult& aError)
{
nsCOMPtr<mozITestInterfaceJS> impl =
do_CreateInstance("@mozilla.org/dom/test-interface-js;1");
aError = impl->TestThrowNsresultFromNative();
}
bool
TestFunctions::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
JS::MutableHandle<JSObject*> aWrapper)

View File

@ -40,6 +40,9 @@ public:
void GetStringDataAsDOMString(const Optional<uint32_t>& aLength,
DOMString& aString);
void TestThrowNsresult(ErrorResult& aError);
void TestThrowNsresultFromNative(ErrorResult& aError);
bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
JS::MutableHandle<JSObject*> aWrapper);
private:

View File

@ -16,7 +16,8 @@ TestInterfaceJS.prototype = {
classID: Components.ID("{2ac4e026-cf25-47d5-b067-78d553c3cad8}"),
contractID: "@mozilla.org/dom/test-interface-js;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
Ci.nsIDOMGlobalPropertyInitializer]),
Ci.nsIDOMGlobalPropertyInitializer,
Ci.mozITestInterfaceJS]),
init: function(win) { this._win = win; },
@ -77,6 +78,21 @@ TestInterfaceJS.prototype = {
throw new this._win.TypeError("We are a TypeError");
},
testThrowNsresult: function() {
throw Components.results.NS_BINDING_ABORTED;
},
testThrowNsresultFromNative: function(x) {
// We want to throw an exception that we generate from an nsresult thrown
// by a C++ component. Ideally we'd have one explicitly for testing, but
// for now just piggyback on nsStandardURL.
var url = Components.classes["@mozilla.org/network/standard-url;1"]
.createInstance(Ci.nsIURI);
url.QueryInterface(Ci.nsIMutable);
url.mutable = false;
url.spec = "http://example.com";
},
testThrowCallbackError: function(callback) {
callback();
},

View File

@ -78,7 +78,7 @@ skip-if = debug == false
[test_oom_reporting.html]
[test_domProxyArrayLengthGetter.html]
[test_exceptionSanitization.html]
skip-if = os == "android"
skip-if = debug == false
[test_stringBindings.html]
skip-if = debug == false
[test_jsimplemented_subclassing.html]

View File

@ -56,3 +56,10 @@ LOCAL_INCLUDES += [
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']
if CONFIG['MOZ_DEBUG']:
XPIDL_SOURCES += [
'mozITestInterfaceJS.idl',
]
XPIDL_MODULE = 'dom_bindings_test'

View File

@ -0,0 +1,21 @@
/* -*- Mode: IDL; tab-width: 4; 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/. */
#include "nsISupports.idl"
/**
* An interface to allow testing of binding interactions with JS-implemented
* XPCOM components. The actual implementation is TestInterfaceJS, just like
* for TestInteraceJS.webidl.
*/
[scriptable, uuid(9eeb2c12-ddd9-4734-8cfb-c0cdfb136e07)]
interface mozITestInterfaceJS : nsISupports {
// Test throwing Components.results.NS_BINDING_ABORTED.
void testThrowNsresult();
// Test calling a C++ component which throws an nsresult exception.
void testThrowNsresultFromNative();
};

View File

@ -19,27 +19,42 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1295322
</pre>
<script type="application/javascript">
/** Test for Bug 1295322 **/
iframe = document.createElement('iframe');
iframe.name = "eWin";
document.body.appendChild(iframe);
SimpleTest.waitForExplicitFinish();
async function runTests() {
await SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]});
try{
// NOTE: The idea here is to call something that will end up throwing an
// exception in a JS component and then propagate back to C++ code before
// returning to us. If opening a feed: URI stops doing that, we will need a
// new guinea pig here.
open('feed://java:script:codeshouldgohere','eWin');
ok(false, "Should have thrown!");
} catch(e){
try {
is(e.name, "SyntaxError", "Should have the right exception");
is(e.filename, location.href,
"Should not be seeing where the exception really came from");
} catch (e2) {
ok(false, "Should be able to work with the exception");
var t = new TestFunctions();
try {
t.testThrowNsresult();
} catch (e) {
try {
is(e.name, "NS_BINDING_ABORTED",
"Should have the right exception");
is(e.filename, location.href,
"Should not be seeing where the exception really came from");
} catch (e2) {
ok(false, "Should be able to work with the exception");
}
}
try {
t.testThrowNsresultFromNative();
} catch (e) {
try {
is(e.name, "NS_ERROR_UNEXPECTED",
"Should have the right exception");
is(e.filename, location.href,
"Should not be seeing where the exception really came from");
} catch (e2) {
ok(false, "Should be able to work with the exception");
}
}
SimpleTest.finish();
}
}
runTests();
</script>
</body>
</html>

View File

@ -9,12 +9,16 @@
#include "ClientHandleChild.h"
#include "ClientHandleOpChild.h"
#include "ClientManager.h"
#include "ClientState.h"
#include "mozilla/dom/PClientManagerChild.h"
#include "mozilla/dom/ServiceWorkerDescriptor.h"
#include "mozilla/dom/ipc/StructuredCloneData.h"
namespace mozilla {
namespace dom {
using mozilla::dom::ipc::StructuredCloneData;
ClientHandle::~ClientHandle()
{
Shutdown();
@ -122,5 +126,59 @@ ClientHandle::Control(const ServiceWorkerDescriptor& aServiceWorker)
return outerPromise.forget();
}
RefPtr<ClientStatePromise>
ClientHandle::Focus()
{
RefPtr<ClientStatePromise::Private> outerPromise =
new ClientStatePromise::Private(__func__);
RefPtr<ClientOpPromise> innerPromise = StartOp(ClientFocusArgs());
innerPromise->Then(mSerialEventTarget, __func__,
[outerPromise](const ClientOpResult& aResult) {
outerPromise->Resolve(ClientState::FromIPC(aResult.get_IPCClientState()), __func__);
}, [outerPromise](const ClientOpResult& aResult) {
outerPromise->Reject(aResult.get_nsresult(), __func__);
});
RefPtr<ClientStatePromise> ref = outerPromise.get();
return ref.forget();
}
RefPtr<GenericPromise>
ClientHandle::PostMessage(StructuredCloneData& aData,
const ServiceWorkerDescriptor& aSource)
{
RefPtr<GenericPromise> ref;
if (IsShutdown()) {
ref = GenericPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
return ref.forget();
}
ClientPostMessageArgs args;
args.serviceWorker() = aSource.ToIPC();
if (!aData.BuildClonedMessageDataForBackgroundChild(GetActor()->Manager()->Manager(),
args.clonedData())) {
ref = GenericPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
return ref.forget();
}
RefPtr<GenericPromise::Private> outerPromise =
new GenericPromise::Private(__func__);
RefPtr<ClientOpPromise> innerPromise = StartOp(args);
innerPromise->Then(mSerialEventTarget, __func__,
[outerPromise](const ClientOpResult& aResult) {
outerPromise->Resolve(true, __func__);
}, [outerPromise](const ClientOpResult& aResult) {
outerPromise->Reject(aResult.get_nsresult(), __func__);
});
ref = outerPromise.get();
return ref.forget();
}
} // namespace dom
} // namespace mozilla

View File

@ -25,6 +25,10 @@ class ClientOpConstructorArgs;
class PClientManagerChild;
class ServiceWorkerDescriptor;
namespace ipc {
class StructuredCloneData;
}
// The ClientHandle allows code to take a simple ClientInfo struct and
// convert it into a live actor-backed object attached to a particular
// ClientSource somewhere in the browser. If the ClientSource is
@ -70,6 +74,22 @@ public:
RefPtr<GenericPromise>
Control(const ServiceWorkerDescriptor& aServiceWorker);
// Focus the Client if possible. If successful the promise will resolve with
// a new ClientState snapshot after focus has completed. If focusing fails
// for any reason then the promise will reject.
RefPtr<ClientStatePromise>
Focus();
// Send a postMessage() call to the target Client. Currently this only
// supports sending from a ServiceWorker source and the MessageEvent is
// dispatched to the Client's navigator.serviceWorker event target. The
// returned promise will resolve if the MessageEvent is dispatched or if
// it triggers an error handled in the Client's context. Other errors
// will result in the promise rejecting.
RefPtr<GenericPromise>
PostMessage(ipc::StructuredCloneData& aData,
const ServiceWorkerDescriptor& aSource);
NS_INLINE_DECL_REFCOUNTING(ClientHandle);
};

View File

@ -8,6 +8,7 @@
#include "ClientHandleParent.h"
#include "ClientSourceParent.h"
#include "mozilla/dom/PClientManagerParent.h"
namespace mozilla {
namespace dom {
@ -34,7 +35,33 @@ ClientHandleOpParent::Init(const ClientOpConstructorArgs& aArgs)
return;
}
RefPtr<ClientOpPromise> p = source->StartOp(aArgs);
RefPtr<ClientOpPromise> p;
// ClientPostMessageArgs can contain PBlob actors. This means we
// can't just forward the args from one PBackground manager to
// another. Instead, unpack the structured clone data and repack
// it into a new set of arguments.
if (aArgs.type() == ClientOpConstructorArgs::TClientPostMessageArgs) {
const ClientPostMessageArgs& orig = aArgs.get_ClientPostMessageArgs();
ClientPostMessageArgs rebuild;
rebuild.serviceWorker() = orig.serviceWorker();
StructuredCloneData data;
data.BorrowFromClonedMessageDataForBackgroundParent(orig.clonedData());
if (!data.BuildClonedMessageDataForBackgroundParent(source->Manager()->Manager(),
rebuild.clonedData())) {
Unused << PClientHandleOpParent::Send__delete__(this, NS_ERROR_DOM_ABORT_ERR);
return;
}
p = source->StartOp(rebuild);
}
// Other argument types can just be forwarded straight through.
else {
p = source->StartOp(aArgs);
}
// Capturing 'this' is safe here because we disconnect the promise in
// ActorDestroy() which ensures neither lambda is called if the actor

View File

@ -67,6 +67,35 @@ struct ClientControlledArgs
IPCServiceWorkerDescriptor serviceWorker;
};
struct ClientFocusArgs
{
};
struct ClientNavigateArgs
{
IPCClientInfo target;
nsCString url;
nsCString baseURL;
};
struct ClientPostMessageArgs
{
ClonedMessageData clonedData;
IPCServiceWorkerDescriptor serviceWorker;
};
struct ClientMatchAllArgs
{
IPCServiceWorkerDescriptor serviceWorker;
ClientType type;
bool includeUncontrolled;
};
struct ClientClaimArgs
{
IPCServiceWorkerDescriptor serviceWorker;
};
struct ClientGetInfoAndStateArgs
{
nsID id;
@ -75,22 +104,41 @@ struct ClientGetInfoAndStateArgs
struct ClientOpenWindowArgs
{
PrincipalInfo principalInfo;
nsCString url;
nsCString baseURL;
};
union ClientOpConstructorArgs
{
ClientControlledArgs;
ClientFocusArgs;
ClientNavigateArgs;
ClientPostMessageArgs;
ClientMatchAllArgs;
ClientClaimArgs;
ClientGetInfoAndStateArgs;
ClientOpenWindowArgs;
};
struct ClientList
{
ClientInfoAndState[] values;
};
struct ClientNavigateOpConstructorArgs
{
PClientSource target;
nsCString url;
nsCString baseURL;
};
union ClientOpResult
{
nsresult;
IPCClientState;
ClientInfoAndState;
ClientList;
};
} // namespace dom

View File

@ -257,6 +257,24 @@ ClientManager::CreateHandle(const ClientInfo& aClientInfo,
return mgr->CreateHandleInternal(aClientInfo, aSerialEventTarget);
}
// static
RefPtr<ClientOpPromise>
ClientManager::MatchAll(const ClientMatchAllArgs& aArgs,
nsISerialEventTarget* aSerialEventTarget)
{
RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
return mgr->StartOp(aArgs, aSerialEventTarget);
}
// static
RefPtr<ClientOpPromise>
ClientManager::Claim(const ClientClaimArgs& aArgs,
nsISerialEventTarget* aSerialEventTarget)
{
RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
return mgr->StartOp(aArgs, aSerialEventTarget);
}
// static
RefPtr<ClientOpPromise>
ClientManager::GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs,
@ -266,5 +284,23 @@ ClientManager::GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs,
return mgr->StartOp(aArgs, aSerialEventTarget);
}
// static
RefPtr<ClientOpPromise>
ClientManager::Navigate(const ClientNavigateArgs& aArgs,
nsISerialEventTarget* aSerialEventTarget)
{
RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
return mgr->StartOp(aArgs, aSerialEventTarget);
}
// static
RefPtr<ClientOpPromise>
ClientManager::OpenWindow(const ClientOpenWindowArgs& aArgs,
nsISerialEventTarget* aSerialEventTarget)
{
RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
return mgr->StartOp(aArgs, aSerialEventTarget);
}
} // namespace dom
} // namespace mozilla

View File

@ -18,11 +18,15 @@ class PrincipalInfo;
} // namespace ipc
namespace dom {
class ClientClaimArgs;
class ClientGetInfoAndStateArgs;
class ClientHandle;
class ClientInfo;
class ClientManagerChild;
class ClientMatchAllArgs;
class ClientNavigateArgs;
class ClientOpConstructorArgs;
class ClientOpenWindowArgs;
class ClientSource;
enum class ClientType : uint8_t;
@ -94,10 +98,24 @@ public:
CreateHandle(const ClientInfo& aClientInfo,
nsISerialEventTarget* aSerialEventTarget);
static RefPtr<ClientOpPromise>
MatchAll(const ClientMatchAllArgs& aArgs, nsISerialEventTarget* aTarget);
static RefPtr<ClientOpPromise>
Claim(const ClientClaimArgs& aArgs, nsISerialEventTarget* aSerialEventTarget);
static RefPtr<ClientOpPromise>
GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs,
nsISerialEventTarget* aSerialEventTarget);
static RefPtr<ClientOpPromise>
Navigate(const ClientNavigateArgs& aArgs,
nsISerialEventTarget* aSerialEventTarget);
static RefPtr<ClientOpPromise>
OpenWindow(const ClientOpenWindowArgs& aArgs,
nsISerialEventTarget* aSerialEventTarget);
NS_INLINE_DECL_REFCOUNTING(mozilla::dom::ClientManager)
};

View File

@ -7,10 +7,13 @@
#include "ClientManagerOpParent.h"
#include "ClientManagerService.h"
#include "mozilla/ipc/BackgroundParent.h"
namespace mozilla {
namespace dom {
using mozilla::ipc::BackgroundParent;
template <typename Method, typename... Args>
void
ClientManagerOpParent::DoServiceOp(Method aMethod, Args&&... aArgs)
@ -48,12 +51,37 @@ void
ClientManagerOpParent::Init(const ClientOpConstructorArgs& aArgs)
{
switch (aArgs.type()) {
case ClientOpConstructorArgs::TClientNavigateArgs:
{
DoServiceOp(&ClientManagerService::Navigate,
aArgs.get_ClientNavigateArgs());
break;
}
case ClientOpConstructorArgs::TClientMatchAllArgs:
{
DoServiceOp(&ClientManagerService::MatchAll,
aArgs.get_ClientMatchAllArgs());
break;
}
case ClientOpConstructorArgs::TClientClaimArgs:
{
DoServiceOp(&ClientManagerService::Claim, aArgs.get_ClientClaimArgs());
break;
}
case ClientOpConstructorArgs::TClientGetInfoAndStateArgs:
{
DoServiceOp(&ClientManagerService::GetInfoAndState,
aArgs.get_ClientGetInfoAndStateArgs());
break;
}
case ClientOpConstructorArgs::TClientOpenWindowArgs:
{
RefPtr<ContentParent> contentParent =
BackgroundParent::GetContentParent(Manager()->Manager());
DoServiceOp(&ClientManagerService::OpenWindow,
aArgs.get_ClientOpenWindowArgs(), contentParent.forget());
break;
}
default:
{
MOZ_ASSERT_UNREACHABLE("Unknown Client operation!");

View File

@ -7,12 +7,18 @@
#include "ClientManagerService.h"
#include "ClientManagerParent.h"
#include "ClientNavigateOpParent.h"
#include "ClientOpenWindowOpParent.h"
#include "ClientOpenWindowUtils.h"
#include "ClientSourceParent.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/ipc/PBackgroundSharedTypes.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/SystemGroup.h"
#include "nsIAsyncShutdown.h"
#include "nsIXULRuntime.h"
#include "nsProxyRelease.h"
namespace mozilla {
namespace dom {
@ -302,6 +308,229 @@ ClientManagerService::RemoveManager(ClientManagerParent* aManager)
MOZ_ASSERT(removed);
}
RefPtr<ClientOpPromise>
ClientManagerService::Navigate(const ClientNavigateArgs& aArgs)
{
RefPtr<ClientOpPromise> ref;
ClientSourceParent* source = FindSource(aArgs.target().id(),
aArgs.target().principalInfo());
if (!source) {
ref = ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
return ref.forget();
}
PClientManagerParent* manager = source->Manager();
MOZ_DIAGNOSTIC_ASSERT(manager);
ClientNavigateOpConstructorArgs args;
args.url() = aArgs.url();
args.baseURL() = aArgs.baseURL();
// This is safe to do because the ClientSourceChild cannot directly delete
// itself. Instead it sends a Teardown message to the parent which then
// calls delete. That means we can be sure that we are not racing with
// source destruction here.
args.targetParent() = source;
RefPtr<ClientOpPromise::Private> promise =
new ClientOpPromise::Private(__func__);
ClientNavigateOpParent* op = new ClientNavigateOpParent(args, promise);
PClientNavigateOpParent* result =
manager->SendPClientNavigateOpConstructor(op, args);
if (!result) {
promise->Reject(NS_ERROR_FAILURE, __func__);
ref = promise;
return ref.forget();
}
ref = promise;
return ref.forget();
}
namespace
{
class PromiseListHolder final
{
RefPtr<ClientOpPromise::Private> mResultPromise;
nsTArray<RefPtr<ClientOpPromise>> mPromiseList;
nsTArray<ClientInfoAndState> mResultList;
uint32_t mOutstandingPromiseCount;
void
ProcessSuccess(const ClientInfoAndState& aResult)
{
mResultList.AppendElement(aResult);
ProcessCompletion();
}
void
ProcessCompletion()
{
MOZ_DIAGNOSTIC_ASSERT(mOutstandingPromiseCount > 0);
mOutstandingPromiseCount -= 1;
MaybeFinish();
}
~PromiseListHolder() = default;
public:
PromiseListHolder()
: mResultPromise(new ClientOpPromise::Private(__func__))
, mOutstandingPromiseCount(0)
{
}
already_AddRefed<ClientOpPromise>
GetResultPromise()
{
RefPtr<PromiseListHolder> kungFuDeathGrip = this;
mResultPromise->Then(
GetCurrentThreadSerialEventTarget(), __func__,
[kungFuDeathGrip] (const ClientOpResult& aResult) { },
[kungFuDeathGrip] (nsresult aResult) { });
RefPtr<ClientOpPromise> ref = mResultPromise;
return ref.forget();
}
void
AddPromise(RefPtr<ClientOpPromise>&& aPromise)
{
mPromiseList.AppendElement(Move(aPromise));
MOZ_DIAGNOSTIC_ASSERT(mPromiseList.LastElement());
mOutstandingPromiseCount += 1;
RefPtr<PromiseListHolder> self(this);
mPromiseList.LastElement()->Then(
GetCurrentThreadSerialEventTarget(), __func__,
[self] (const ClientOpResult& aResult) {
// TODO: This is pretty clunky. Try to figure out a better
// wait for MatchAll() and Claim() to share this code
// even though they expect different return values.
if (aResult.type() == ClientOpResult::TClientInfoAndState) {
self->ProcessSuccess(aResult.get_ClientInfoAndState());
} else {
self->ProcessCompletion();
}
}, [self] (nsresult aResult) {
self->ProcessCompletion();
});
}
void
MaybeFinish()
{
if (!mOutstandingPromiseCount) {
mResultPromise->Resolve(mResultList, __func__);
}
}
NS_INLINE_DECL_REFCOUNTING(PromiseListHolder)
};
} // anonymous namespace
RefPtr<ClientOpPromise>
ClientManagerService::MatchAll(const ClientMatchAllArgs& aArgs)
{
AssertIsOnBackgroundThread();
ServiceWorkerDescriptor swd(aArgs.serviceWorker());
const PrincipalInfo& principalInfo = swd.PrincipalInfo();
RefPtr<PromiseListHolder> promiseList = new PromiseListHolder();
for (auto iter = mSourceTable.Iter(); !iter.Done(); iter.Next()) {
ClientSourceParent* source = iter.UserData();
MOZ_DIAGNOSTIC_ASSERT(source);
if (source->IsFrozen() || !source->ExecutionReady()) {
continue;
}
if (aArgs.type() != ClientType::All &&
source->Info().Type() != aArgs.type()) {
continue;
}
if (!MatchPrincipalInfo(source->Info().PrincipalInfo(), principalInfo)) {
continue;
}
if (!aArgs.includeUncontrolled()) {
const Maybe<ServiceWorkerDescriptor>& controller =
source->GetController();
if (controller.isNothing()) {
continue;
}
if(controller.ref().Id() != swd.Id() ||
controller.ref().Scope() != swd.Scope()) {
continue;
}
}
promiseList->AddPromise(
source->StartOp(Move(ClientGetInfoAndStateArgs(source->Info().Id(),
source->Info().PrincipalInfo()))));
}
// Maybe finish the promise now in case we didn't find any matching clients.
promiseList->MaybeFinish();
return promiseList->GetResultPromise();
}
RefPtr<ClientOpPromise>
ClientManagerService::Claim(const ClientClaimArgs& aArgs)
{
AssertIsOnBackgroundThread();
const IPCServiceWorkerDescriptor& serviceWorker = aArgs.serviceWorker();
const PrincipalInfo& principalInfo = serviceWorker.principalInfo();
RefPtr<PromiseListHolder> promiseList = new PromiseListHolder();
for (auto iter = mSourceTable.Iter(); !iter.Done(); iter.Next()) {
ClientSourceParent* source = iter.UserData();
MOZ_DIAGNOSTIC_ASSERT(source);
if (source->IsFrozen()) {
continue;
}
if (!MatchPrincipalInfo(source->Info().PrincipalInfo(), principalInfo)) {
continue;
}
const Maybe<ServiceWorkerDescriptor>& controller = source->GetController();
if (controller.isSome() &&
controller.ref().Scope() == serviceWorker.scope() &&
controller.ref().Id() == serviceWorker.id()) {
continue;
}
// TODO: This logic to determine if a service worker should control
// a particular client should be moved to the ServiceWorkerManager.
// This can't happen until the SWM is moved to the parent process,
// though.
if (!source->ExecutionReady() ||
source->Info().Type() == ClientType::Serviceworker ||
source->Info().URL().Find(serviceWorker.scope()) != 0) {
continue;
}
promiseList->AddPromise(source->StartOp(aArgs));
}
// Maybe finish the promise now in case we didn't find any matching clients.
promiseList->MaybeFinish();
return promiseList->GetResultPromise();
}
RefPtr<ClientOpPromise>
ClientManagerService::GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs)
{
@ -316,5 +545,90 @@ ClientManagerService::GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs)
return source->StartOp(aArgs);
}
namespace {
class OpenWindowRunnable final : public Runnable
{
RefPtr<ClientOpPromise::Private> mPromise;
const ClientOpenWindowArgs mArgs;
RefPtr<ContentParent> mSourceProcess;
~OpenWindowRunnable()
{
NS_ReleaseOnMainThreadSystemGroup(mSourceProcess.forget());
}
public:
OpenWindowRunnable(ClientOpPromise::Private* aPromise,
const ClientOpenWindowArgs& aArgs,
already_AddRefed<ContentParent> aSourceProcess)
: Runnable("ClientManagerService::OpenWindowRunnable")
, mPromise(aPromise)
, mArgs(aArgs)
, mSourceProcess(aSourceProcess)
{
MOZ_DIAGNOSTIC_ASSERT(mPromise);
}
NS_IMETHOD
Run() override
{
MOZ_ASSERT(NS_IsMainThread());
if (!BrowserTabsRemoteAutostart()) {
RefPtr<ClientOpPromise> p = ClientOpenWindowInCurrentProcess(mArgs);
p->ChainTo(mPromise.forget(), __func__);
return NS_OK;
}
RefPtr<ContentParent> targetProcess;
// Possibly try to open the window in the same process that called
// openWindow(). This is a temporary compat setting until the
// multi-e10s service worker refactor is complete.
if (Preferences::GetBool("dom.clients.openwindow_favors_same_process",
false)) {
targetProcess = mSourceProcess;
}
// Otherwise, use our normal remote process selection mechanism for
// opening the window. This will start a process if one is not
// present.
if (!targetProcess) {
targetProcess =
ContentParent::GetNewOrUsedBrowserProcess(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE),
ContentParent::GetInitialProcessPriority(nullptr),
nullptr);
}
ClientOpenWindowOpParent* actor =
new ClientOpenWindowOpParent(mArgs, mPromise);
// If this fails the actor will be automatically destroyed which will
// reject the promise.
Unused << targetProcess->SendPClientOpenWindowOpConstructor(actor, mArgs);
return NS_OK;
}
};
} // anonymous namespace
RefPtr<ClientOpPromise>
ClientManagerService::OpenWindow(const ClientOpenWindowArgs& aArgs,
already_AddRefed<ContentParent> aSourceProcess)
{
RefPtr<ClientOpPromise::Private> promise =
new ClientOpPromise::Private(__func__);
nsCOMPtr<nsIRunnable> r = new OpenWindowRunnable(promise, aArgs,
Move(aSourceProcess));
MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other,
r.forget()));
RefPtr<ClientOpPromise> ref = promise;
return ref.forget();
}
} // namespace dom
} // namespace mozilla

View File

@ -59,9 +59,22 @@ public:
void
RemoveManager(ClientManagerParent* aManager);
RefPtr<ClientOpPromise>
Navigate(const ClientNavigateArgs& aArgs);
RefPtr<ClientOpPromise>
MatchAll(const ClientMatchAllArgs& aArgs);
RefPtr<ClientOpPromise>
Claim(const ClientClaimArgs& aArgs);
RefPtr<ClientOpPromise>
GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs);
RefPtr<ClientOpPromise>
OpenWindow(const ClientOpenWindowArgs& aArgs,
already_AddRefed<ContentParent> aSourceProcess);
NS_INLINE_DECL_REFCOUNTING(mozilla::dom::ClientManagerService)
};

View File

@ -6,17 +6,284 @@
#include "ClientNavigateOpChild.h"
#include "ClientState.h"
#include "mozilla/Unused.h"
#include "nsIDocShell.h"
#include "nsIDocShellLoadInfo.h"
#include "nsIWebNavigation.h"
#include "nsIWebProgress.h"
#include "nsIWebProgressListener.h"
#include "nsNetUtil.h"
#include "nsPIDOMWindow.h"
namespace mozilla {
namespace dom {
namespace {
class NavigateLoadListener final : public nsIWebProgressListener
, public nsSupportsWeakReference
{
RefPtr<ClientOpPromise::Private> mPromise;
RefPtr<nsPIDOMWindowOuter> mOuterWindow;
nsCOMPtr<nsIURI> mBaseURL;
~NavigateLoadListener() = default;
public:
NavigateLoadListener(ClientOpPromise::Private* aPromise,
nsPIDOMWindowOuter* aOuterWindow,
nsIURI* aBaseURL)
: mPromise(aPromise)
, mOuterWindow(aOuterWindow)
, mBaseURL(aBaseURL)
{
MOZ_DIAGNOSTIC_ASSERT(mPromise);
MOZ_DIAGNOSTIC_ASSERT(mOuterWindow);
MOZ_DIAGNOSTIC_ASSERT(mBaseURL);
}
NS_IMETHOD
OnStateChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
uint32_t aStateFlags, nsresult aResult) override
{
if (!(aStateFlags & STATE_IS_DOCUMENT) ||
!(aStateFlags & (STATE_STOP | STATE_TRANSFERRING))) {
return NS_OK;
}
aWebProgress->RemoveProgressListener(this);
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
if (!channel) {
mPromise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
return NS_OK;
}
nsCOMPtr<nsIURI> channelURL;
nsresult rv = NS_GetFinalChannelURI(channel, getter_AddRefs(channelURL));
if (NS_FAILED(rv)) {
mPromise->Reject(rv, __func__);
return NS_OK;
}
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
MOZ_DIAGNOSTIC_ASSERT(ssm);
// If the resulting window is not same origin, then resolve immediately
// without returning any information about the new Client. This is
// step 6.10 in the Client.navigate(url) spec.
rv = ssm->CheckSameOriginURI(mBaseURL, channelURL, false);
if (NS_FAILED(rv)) {
mPromise->Resolve(NS_OK, __func__);
return NS_OK;
}
nsPIDOMWindowInner* innerWindow = mOuterWindow->GetCurrentInnerWindow();
MOZ_DIAGNOSTIC_ASSERT(innerWindow);
Maybe<ClientInfo> clientInfo = innerWindow->GetClientInfo();
MOZ_DIAGNOSTIC_ASSERT(clientInfo.isSome());
Maybe<ClientState> clientState = innerWindow->GetClientState();
MOZ_DIAGNOSTIC_ASSERT(clientState.isSome());
// Otherwise, if the new window is same-origin we want to return a
// ClientInfoAndState object so we can provide a Client snapshot
// to the caller. This is step 6.11 and 6.12 in the Client.navigate(url)
// spec.
mPromise->Resolve(ClientInfoAndState(clientInfo.ref().ToIPC(),
clientState.ref().ToIPC()), __func__);
return NS_OK;
}
NS_IMETHOD
OnProgressChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
int32_t aCurSelfProgress, int32_t aMaxSelfProgress,
int32_t aCurTotalProgress, int32_t aMaxTotalProgress) override
{
MOZ_CRASH("Unexpected notification.");
return NS_OK;
}
NS_IMETHOD
OnLocationChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
nsIURI* aLocation, uint32_t aFlags) override
{
MOZ_CRASH("Unexpected notification.");
return NS_OK;
}
NS_IMETHOD
OnStatusChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
nsresult aStatus, const char16_t* aMessage) override
{
MOZ_CRASH("Unexpected notification.");
return NS_OK;
}
NS_IMETHOD
OnSecurityChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
uint32_t aState) override
{
MOZ_CRASH("Unexpected notification.");
return NS_OK;
}
NS_DECL_ISUPPORTS
};
NS_IMPL_ISUPPORTS(NavigateLoadListener, nsIWebProgressListener,
nsISupportsWeakReference);
} // anonymous namespace
already_AddRefed<ClientOpPromise>
ClientNavigateOpChild::DoNavigate(const ClientNavigateOpConstructorArgs& aArgs)
{
RefPtr<ClientOpPromise> ref;
nsCOMPtr<nsPIDOMWindowInner> window;
// Navigating the target client window will result in the original
// ClientSource being destroyed. To avoid potential UAF mistakes
// we use a small scope to access the ClientSource object. Once
// we have a strong reference to the window object we should not
// access the ClientSource again.
{
ClientSourceChild* targetActor =
static_cast<ClientSourceChild*>(aArgs.targetChild());
MOZ_DIAGNOSTIC_ASSERT(targetActor);
ClientSource* target = targetActor->GetSource();
if (!target) {
ref = ClientOpPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR,
__func__);
return ref.forget();
}
window = target->GetInnerWindow();
if (!window) {
ref = ClientOpPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR,
__func__);
return ref.forget();
}
}
MOZ_ASSERT(NS_IsMainThread());
mSerialEventTarget = window->EventTargetFor(TaskCategory::Other);
// In theory we could do the URL work before paying the IPC overhead
// cost, but in practice its easier to do it here. The ClientHandle
// may be off-main-thread while this method is guaranteed to always
// be main thread.
nsCOMPtr<nsIURI> baseURL;
nsresult rv = NS_NewURI(getter_AddRefs(baseURL), aArgs.baseURL());
if (NS_FAILED(rv)) {
ref = ClientOpPromise::CreateAndReject(rv, __func__);
return ref.forget();
}
nsCOMPtr<nsIURI> url;
rv = NS_NewURI(getter_AddRefs(url), aArgs.url(), nullptr, baseURL);
if (NS_FAILED(rv)) {
ref = ClientOpPromise::CreateAndReject(rv, __func__);
return ref.forget();
}
if (url->GetSpecOrDefault().EqualsLiteral("about:blank")) {
ref = ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
return ref.forget();
}
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
if (!doc || !doc->IsActive()) {
ref = ClientOpPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
return ref.forget();
}
nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
if (!principal) {
ref = ClientOpPromise::CreateAndReject(rv, __func__);
return ref.forget();
}
nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
if (!docShell || !webProgress) {
ref = ClientOpPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
return ref.forget();
}
nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
rv = docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
if (NS_FAILED(rv)) {
ref = ClientOpPromise::CreateAndReject(rv, __func__);
return ref.forget();
}
loadInfo->SetTriggeringPrincipal(principal);
loadInfo->SetReferrerPolicy(doc->GetReferrerPolicy());
loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContent);
loadInfo->SetSourceDocShell(docShell);
rv = docShell->LoadURI(url, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, true);
if (NS_FAILED(rv)) {
ref = ClientOpPromise::CreateAndReject(rv, __func__);
return ref.forget();
}
RefPtr<ClientOpPromise::Private> promise =
new ClientOpPromise::Private(__func__);
nsCOMPtr<nsIWebProgressListener> listener =
new NavigateLoadListener(promise, window->GetOuterWindow(), baseURL);
rv = webProgress->AddProgressListener(listener,
nsIWebProgress::NOTIFY_STATE_DOCUMENT);
if (NS_FAILED(rv)) {
promise->Reject(rv, __func__);
ref = promise;
return ref.forget();
}
ref = promise.get();
ref->Then(mSerialEventTarget, __func__,
[listener] (const ClientOpResult& aResult) { },
[listener] (nsresult aResult) { });
return ref.forget();
}
void
ClientNavigateOpChild::ActorDestroy(ActorDestroyReason aReason)
{
mPromiseRequestHolder.DisconnectIfExists();
}
void
ClientNavigateOpChild::Init(const ClientNavigateOpConstructorArgs& aArgs)
{
RefPtr<ClientOpPromise> promise = DoNavigate(aArgs);
// Normally we get the event target from the window in DoNavigate(). If a
// failure occurred, though, we may need to fall back to the current thread
// target.
if (!mSerialEventTarget) {
mSerialEventTarget = GetCurrentThreadSerialEventTarget();
}
// Capturing `this` is safe here since we clear the mPromiseRequestHolder in
// ActorDestroy.
promise->Then(mSerialEventTarget, __func__,
[this] (const ClientOpResult& aResult) {
mPromiseRequestHolder.Complete();
PClientNavigateOpChild::Send__delete__(this, aResult);
}, [this] (nsresult aResult) {
mPromiseRequestHolder.Complete();
PClientNavigateOpChild::Send__delete__(this, aResult);
})->Track(mPromiseRequestHolder);
}
} // namespace dom

View File

@ -7,12 +7,19 @@
#define _mozilla_dom_ClientNavigateOpChild_h
#include "mozilla/dom/PClientNavigateOpChild.h"
#include "ClientOpPromise.h"
namespace mozilla {
namespace dom {
class ClientNavigateOpChild final : public PClientNavigateOpChild
{
MozPromiseRequestHolder<ClientOpPromise> mPromiseRequestHolder;
nsCOMPtr<nsISerialEventTarget> mSerialEventTarget;
already_AddRefed<ClientOpPromise>
DoNavigate(const ClientNavigateOpConstructorArgs& aArgs);
// PClientNavigateOpChild interface
void
ActorDestroy(ActorDestroyReason aReason) override;

View File

@ -14,6 +14,10 @@ using mozilla::ipc::IPCResult;
void
ClientNavigateOpParent::ActorDestroy(ActorDestroyReason aReason)
{
if (mPromise) {
mPromise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__);
mPromise = nullptr;
}
}
IPCResult

View File

@ -5,18 +5,38 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ClientOpenWindowOpChild.h"
#include "ClientOpenWindowUtils.h"
#include "mozilla/SystemGroup.h"
namespace mozilla {
namespace dom {
already_AddRefed<ClientOpPromise>
ClientOpenWindowOpChild::DoOpenWindow(const ClientOpenWindowArgs& aArgs)
{
RefPtr<ClientOpPromise> ref =
ClientOpenWindowInCurrentProcess(aArgs);
return ref.forget();
}
void
ClientOpenWindowOpChild::ActorDestroy(ActorDestroyReason aReason)
{
mPromiseRequestHolder.DisconnectIfExists();
}
void
ClientOpenWindowOpChild::Init(const ClientOpenWindowArgs& aArgs)
{
RefPtr<ClientOpPromise> promise = DoOpenWindow(aArgs);
promise->Then(SystemGroup::EventTargetFor(TaskCategory::Other), __func__,
[this] (const ClientOpResult& aResult) {
mPromiseRequestHolder.Complete();
PClientOpenWindowOpChild::Send__delete__(this, aResult);
}, [this] (nsresult aResult) {
mPromiseRequestHolder.Complete();
PClientOpenWindowOpChild::Send__delete__(this, aResult);
})->Track(mPromiseRequestHolder);
}
} // namespace dom

View File

@ -7,12 +7,18 @@
#define _mozilla_dom_ClientOpenWindowOpChild_h
#include "mozilla/dom/PClientOpenWindowOpChild.h"
#include "ClientOpPromise.h"
namespace mozilla {
namespace dom {
class ClientOpenWindowOpChild final : public PClientOpenWindowOpChild
{
MozPromiseRequestHolder<ClientOpPromise> mPromiseRequestHolder;
already_AddRefed<ClientOpPromise>
DoOpenWindow(const ClientOpenWindowArgs& aArgs);
// PClientOpenWindowOpChild interface
void
ActorDestroy(ActorDestroyReason aReason) override;

View File

@ -0,0 +1,463 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "ClientOpenWindowUtils.h"
#include "ClientInfo.h"
#include "ClientState.h"
#include "nsContentUtils.h"
#include "nsIBrowserDOMWindow.h"
#include "nsIDocShell.h"
#include "nsIDOMChromeWindow.h"
#include "nsIURI.h"
#include "nsIWebProgress.h"
#include "nsIWebProgressListener.h"
#include "nsIWindowWatcher.h"
#include "nsNetUtil.h"
#include "nsPIDOMWindow.h"
#include "nsPIWindowWatcher.h"
#ifdef MOZ_WIDGET_ANDROID
#include "FennecJNIWrappers.h"
#endif
namespace mozilla {
namespace dom {
namespace {
class WebProgressListener final : public nsIWebProgressListener
, public nsSupportsWeakReference
{
public:
NS_DECL_ISUPPORTS
WebProgressListener(nsPIDOMWindowOuter* aWindow,
nsIURI* aBaseURI,
already_AddRefed<ClientOpPromise::Private> aPromise)
: mPromise(aPromise)
, mWindow(aWindow)
, mBaseURI(aBaseURI)
{
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aBaseURI);
MOZ_ASSERT(NS_IsMainThread());
}
NS_IMETHOD
OnStateChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
uint32_t aStateFlags, nsresult aStatus) override
{
if (!(aStateFlags & STATE_IS_DOCUMENT) ||
!(aStateFlags & (STATE_STOP | STATE_TRANSFERRING))) {
return NS_OK;
}
// Our caller keeps a strong reference, so it is safe to remove the listener
// from ServiceWorkerPrivate.
aWebProgress->RemoveProgressListener(this);
nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc();
if (NS_WARN_IF(!doc)) {
mPromise->Reject(NS_ERROR_FAILURE, __func__);
mPromise = nullptr;
return NS_OK;
}
// Check same origin.
nsCOMPtr<nsIScriptSecurityManager> securityManager =
nsContentUtils::GetSecurityManager();
nsresult rv = securityManager->CheckSameOriginURI(doc->GetOriginalURI(),
mBaseURI, false);
if (NS_FAILED(rv)) {
mPromise->Resolve(NS_OK, __func__);
mPromise = nullptr;
return NS_OK;
}
nsPIDOMWindowInner* innerWindow = doc->GetInnerWindow();
if (NS_WARN_IF(!innerWindow)) {
mPromise->Reject(NS_ERROR_FAILURE, __func__);
mPromise = nullptr;
return NS_OK;
}
Maybe<ClientInfo> info = innerWindow->GetClientInfo();
Maybe<ClientState> state = innerWindow->GetClientState();
if (NS_WARN_IF(info.isNothing() || state.isNothing())) {
mPromise->Reject(NS_ERROR_FAILURE, __func__);
mPromise = nullptr;
return NS_OK;
}
mPromise->Resolve(ClientInfoAndState(info.ref().ToIPC(), state.ref().ToIPC()),
__func__);
mPromise = nullptr;
return NS_OK;
}
NS_IMETHOD
OnProgressChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
int32_t aCurSelfProgress,
int32_t aMaxSelfProgress,
int32_t aCurTotalProgress,
int32_t aMaxTotalProgress) override
{
MOZ_ASSERT(false, "Unexpected notification.");
return NS_OK;
}
NS_IMETHOD
OnLocationChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
nsIURI* aLocation,
uint32_t aFlags) override
{
MOZ_ASSERT(false, "Unexpected notification.");
return NS_OK;
}
NS_IMETHOD
OnStatusChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
nsresult aStatus, const char16_t* aMessage) override
{
MOZ_ASSERT(false, "Unexpected notification.");
return NS_OK;
}
NS_IMETHOD
OnSecurityChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
uint32_t aState) override
{
MOZ_ASSERT(false, "Unexpected notification.");
return NS_OK;
}
private:
~WebProgressListener()
{
if (mPromise) {
mPromise->Reject(NS_ERROR_ABORT, __func__);
mPromise = nullptr;
}
}
RefPtr<ClientOpPromise::Private> mPromise;
// TODO: make window a weak ref and stop cycle collecting
nsCOMPtr<nsPIDOMWindowOuter> mWindow;
nsCOMPtr<nsIURI> mBaseURI;
};
NS_IMPL_ISUPPORTS(WebProgressListener, nsIWebProgressListener,
nsISupportsWeakReference);
nsresult
OpenWindow(const ClientOpenWindowArgs& aArgs,
nsPIDOMWindowOuter** aWindow)
{
MOZ_DIAGNOSTIC_ASSERT(aWindow);
// [[1. Let url be the result of parsing url with entry settings object's API
// base URL.]]
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIURI> baseURI;
nsresult rv = NS_NewURI(getter_AddRefs(baseURI), aArgs.baseURL());
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_TYPE_ERR;
}
rv = NS_NewURI(getter_AddRefs(uri), aArgs.url(), nullptr, baseURI);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_TYPE_ERR;
}
nsCOMPtr<nsIPrincipal> principal =
PrincipalInfoToPrincipal(aArgs.principalInfo());
MOZ_DIAGNOSTIC_ASSERT(principal);
// [[6.1 Open Window]]
if (XRE_IsContentProcess()) {
// Let's create a sandbox in order to have a valid JSContext and correctly
// propagate the SubjectPrincipal.
AutoJSAPI jsapi;
jsapi.Init();
JSContext* cx = jsapi.cx();
nsIXPConnect* xpc = nsContentUtils::XPConnect();
MOZ_DIAGNOSTIC_ASSERT(xpc);
JS::Rooted<JSObject*> sandbox(cx);
rv = xpc->CreateSandbox(cx, principal, sandbox.address());
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_TYPE_ERR;
}
JSAutoCompartment ac(cx, sandbox);
// ContentProcess
nsCOMPtr<nsIWindowWatcher> wwatch =
do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
NS_ENSURE_STATE(pwwatch);
nsCString spec;
rv = uri->GetSpec(spec);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<mozIDOMWindowProxy> newWindow;
rv = pwwatch->OpenWindow2(nullptr,
spec.get(),
nullptr,
nullptr,
false, false, true, nullptr,
// Not a spammy popup; we got permission, we swear!
/* aIsPopupSpam = */ false,
// Don't force noopener. We're not passing in an
// opener anyway, and we _do_ want the returned
// window.
/* aForceNoOpener = */ false,
/* aLoadInfp = */ nullptr,
getter_AddRefs(newWindow));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsPIDOMWindowOuter> pwindow = nsPIDOMWindowOuter::From(newWindow);
pwindow.forget(aWindow);
MOZ_DIAGNOSTIC_ASSERT(*aWindow);
return NS_OK;
}
// Find the most recent browser window and open a new tab in it.
nsCOMPtr<nsPIDOMWindowOuter> browserWindow =
nsContentUtils::GetMostRecentNonPBWindow();
if (!browserWindow) {
// It is possible to be running without a browser window on Mac OS, so
// we need to open a new chrome window.
// TODO(catalinb): open new chrome window. Bug 1218080
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIDOMChromeWindow> chromeWin = do_QueryInterface(browserWindow);
if (NS_WARN_IF(!chromeWin)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIBrowserDOMWindow> bwin;
chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
if (NS_WARN_IF(!bwin)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<mozIDOMWindowProxy> win;
rv = bwin->OpenURI(uri, nullptr,
nsIBrowserDOMWindow::OPEN_DEFAULTWINDOW,
nsIBrowserDOMWindow::OPEN_NEW,
principal,
getter_AddRefs(win));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
NS_ENSURE_STATE(win);
nsCOMPtr<nsPIDOMWindowOuter> pWin = nsPIDOMWindowOuter::From(win);
pWin.forget(aWindow);
MOZ_DIAGNOSTIC_ASSERT(*aWindow);
return NS_OK;
}
void
WaitForLoad(const ClientOpenWindowArgs& aArgs,
nsPIDOMWindowOuter* aOuterWindow,
ClientOpPromise::Private* aPromise)
{
MOZ_DIAGNOSTIC_ASSERT(aOuterWindow);
RefPtr<ClientOpPromise::Private> promise = aPromise;
nsresult rv = nsContentUtils::DispatchFocusChromeEvent(aOuterWindow);
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->Reject(rv, __func__);
return;
}
nsCOMPtr<nsIURI> baseURI;
rv = NS_NewURI(getter_AddRefs(baseURI), aArgs.baseURL());
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->Reject(rv, __func__);
return;
}
nsCOMPtr<nsIDocShell> docShell = aOuterWindow->GetDocShell();
nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
if (NS_WARN_IF(!webProgress)) {
promise->Reject(NS_ERROR_FAILURE, __func__);
return;
}
RefPtr<ClientOpPromise> ref = promise;
RefPtr<WebProgressListener> listener =
new WebProgressListener(aOuterWindow, baseURI, promise.forget());
rv = webProgress->AddProgressListener(listener,
nsIWebProgress::NOTIFY_STATE_DOCUMENT);
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->Reject(rv, __func__);
return;
}
// Hold the listener alive until the promise settles
ref->Then(aOuterWindow->EventTargetFor(TaskCategory::Other), __func__,
[listener] (const ClientOpResult& aResult) { },
[listener] (nsresult aResult) { });
}
#ifdef MOZ_WIDGET_ANDROID
class LaunchObserver final : public nsIObserver
{
RefPtr<GenericPromise::Private> mPromise;
LaunchObserver()
: mPromise(new GenericPromise::Private(__func__))
{
}
~LaunchObserver() = default;
NS_IMETHOD
Observe(nsISupports* aSubject, const char* aTopic, const char16_t * aData) override
{
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
os->RemoveObserver(this, "BrowserChrome:Ready");
}
mPromise->Resolve(true, __func__);
return NS_OK;
}
public:
static already_AddRefed<LaunchObserver>
Create()
{
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (NS_WARN_IF(!os)) {
return nullptr;
}
RefPtr<LaunchObserver> ref = new LaunchObserver();
nsresult rv = os->AddObserver(ref, "BrowserChrome:Ready", /* weakRef */ false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
return ref.forget();
}
void
Cancel()
{
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
os->RemoveObserver(this, "BrowserChrome:Ready");
}
mPromise->Reject(NS_ERROR_ABORT, __func__);
}
GenericPromise*
Promise()
{
return mPromise;
}
NS_DECL_ISUPPORTS
};
NS_IMPL_ISUPPORTS(LaunchObserver, nsIObserver);
#endif // MOZ_WIDGET_ANDROID
} // anonymous namespace
already_AddRefed<ClientOpPromise>
ClientOpenWindowInCurrentProcess(const ClientOpenWindowArgs& aArgs)
{
RefPtr<ClientOpPromise::Private> promise =
new ClientOpPromise::Private(__func__);
RefPtr<ClientOpPromise> ref = promise;
#ifdef MOZ_WIDGET_ANDROID
// This fires an intent that will start launching Fennec and foreground it,
// if necessary. We create an observer so that we can determine when
// the launch has completed.
RefPtr<LaunchObserver> launchObserver = LaunchObserver::Create();
java::GeckoApp::LaunchOrBringToFront();
#endif // MOZ_WIDGET_ANDROID
nsCOMPtr<nsPIDOMWindowOuter> outerWindow;
nsresult rv = OpenWindow(aArgs, getter_AddRefs(outerWindow));
#ifdef MOZ_WIDGET_ANDROID
// If we get the NOT_AVAILABLE error that means the browser is still
// launching on android. Use the observer we created above to wait
// until the launch completes and then try to open the window again.
if (rv == NS_ERROR_NOT_AVAILABLE && launchObserver) {
RefPtr<GenericPromise> p = launchObserver->Promise();
p->Then(outerWindow->EventTargetFor(TaskCategory::Other), __func__,
[aArgs, promise] (bool aResult) {
nsCOMPtr<nsPIDOMWindowOuter> outerWindow;
nsresult rv = OpenWindow(aArgs, getter_AddRefs(outerWindow));
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->Reject(rv, __func__);
}
WaitForLoad(aArgs, outerWindow, promise);
}, [promise] (nsresult aResult) {
promise->Reject(aResult, __func__);
});
return ref.forget();
}
// If we didn't get the NOT_AVAILABLE error then there is no need
// wait for the browser to launch. Cancel the observer so that it
// will release.
if (launchObserver) {
launchObserver->Cancel();
}
#endif // MOZ_WIDGET_ANDROID
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->Reject(rv, __func__);
return ref.forget();
}
MOZ_DIAGNOSTIC_ASSERT(outerWindow);
WaitForLoad(aArgs, outerWindow, promise);
return ref.forget();
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,21 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef _mozilla_dom_ClientOpenWindowUtils_h
#define _mozilla_dom_ClientOpenWindowUtils_h
#include "ClientOpPromise.h"
#include "mozilla/dom/ClientIPCTypes.h"
namespace mozilla {
namespace dom {
already_AddRefed<ClientOpPromise>
ClientOpenWindowInCurrentProcess(const ClientOpenWindowArgs &aArgs);
} // namespace dom
} // namespace mozilla
#endif // _mozilla_dom_ClientOpenWindowUtils_h

View File

@ -12,15 +12,29 @@
#include "ClientState.h"
#include "ClientValidation.h"
#include "mozilla/dom/ClientIPCTypes.h"
#include "mozilla/dom/ipc/StructuredCloneData.h"
#include "mozilla/dom/MessageEvent.h"
#include "mozilla/dom/MessageEventBinding.h"
#include "mozilla/dom/Navigator.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerScope.h"
#include "mozilla/dom/ServiceWorkerContainer.h"
#include "mozilla/dom/workers/ServiceWorkerManager.h"
#include "mozilla/dom/workers/bindings/ServiceWorker.h"
#include "nsContentUtils.h"
#include "nsIDocShell.h"
#include "nsPIDOMWindow.h"
namespace mozilla {
namespace dom {
using mozilla::dom::ipc::StructuredCloneData;
using mozilla::dom::workers::ServiceWorkerInfo;
using mozilla::dom::workers::ServiceWorkerManager;
using mozilla::dom::workers::ServiceWorkerRegistrationInfo;
using mozilla::dom::workers::WorkerPrivate;
using mozilla::ipc::PrincipalInfo;
using mozilla::ipc::PrincipalInfoToPrincipal;
void
ClientSource::Shutdown()
@ -361,6 +375,188 @@ ClientSource::GetController() const
return mController;
}
RefPtr<ClientOpPromise>
ClientSource::Focus(const ClientFocusArgs& aArgs)
{
NS_ASSERT_OWNINGTHREAD(ClientSource);
RefPtr<ClientOpPromise> ref;
if (mClientInfo.Type() != ClientType::Window) {
ref = ClientOpPromise::CreateAndReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
__func__);
return ref.forget();
}
nsPIDOMWindowOuter* outer = nullptr;
nsPIDOMWindowInner* inner = GetInnerWindow();
if (inner) {
outer = inner->GetOuterWindow();
} else {
nsIDocShell* docshell = GetDocShell();
if (docshell) {
outer = docshell->GetWindow();
}
}
if (!outer) {
ref = ClientOpPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR,
__func__);
return ref.forget();
}
MOZ_ASSERT(NS_IsMainThread());
nsresult rv = nsContentUtils::DispatchFocusChromeEvent(outer);
if (NS_FAILED(rv)) {
ref = ClientOpPromise::CreateAndReject(rv, __func__);
return ref.forget();
}
ClientState state;
rv = SnapshotState(&state);
if (NS_FAILED(rv)) {
ref = ClientOpPromise::CreateAndReject(rv, __func__);
return ref.forget();
}
ref = ClientOpPromise::CreateAndResolve(state.ToIPC(), __func__);
return ref.forget();
}
RefPtr<ClientOpPromise>
ClientSource::PostMessage(const ClientPostMessageArgs& aArgs)
{
NS_ASSERT_OWNINGTHREAD(ClientSource);
RefPtr<ClientOpPromise> ref;
ServiceWorkerDescriptor source(aArgs.serviceWorker());
const PrincipalInfo& principalInfo = source.PrincipalInfo();
StructuredCloneData clonedData;
clonedData.BorrowFromClonedMessageDataForBackgroundChild(aArgs.clonedData());
// Currently we only support firing these messages on window Clients.
// Once we expose ServiceWorkerContainer and the ServiceWorker on Worker
// threads then this will need to change. See bug 1113522.
if (mClientInfo.Type() != ClientType::Window) {
ref = ClientOpPromise::CreateAndReject(NS_ERROR_NOT_IMPLEMENTED, __func__);
return ref.forget();
}
MOZ_ASSERT(NS_IsMainThread());
RefPtr<ServiceWorkerContainer> target;
nsCOMPtr<nsIGlobalObject> globalObject;
// We don't need to force the creation of the about:blank document
// here because there is no postMessage listener. If a listener
// was registered then the document will already be created.
nsPIDOMWindowInner* window = GetInnerWindow();
if (window) {
globalObject = do_QueryInterface(window);
RefPtr<Navigator> navigator =
static_cast<Navigator*>(window->GetNavigator());
if (navigator) {
target = navigator->ServiceWorker();
}
}
if (NS_WARN_IF(!target)) {
ref = ClientOpPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR,
__func__);
return ref.forget();
}
// If AutoJSAPI::Init() fails then either global is nullptr or not
// in a usable state.
AutoJSAPI jsapi;
if (!jsapi.Init(globalObject)) {
ref = ClientOpPromise::CreateAndResolve(NS_OK, __func__);
return ref.forget();
}
JSContext* cx = jsapi.cx();
ErrorResult result;
JS::Rooted<JS::Value> messageData(cx);
clonedData.Read(cx, &messageData, result);
if (result.MaybeSetPendingException(cx)) {
// We reported the error in the current window context. Resolve
// promise instead of rejecting.
ref = ClientOpPromise::CreateAndResolve(NS_OK, __func__);
return ref.forget();
}
RootedDictionary<MessageEventInit> init(cx);
init.mData = messageData;
if (!clonedData.TakeTransferredPortsAsSequence(init.mPorts)) {
// Report the error in the current window context and resolve the
// promise instead of rejecting.
xpc::Throw(cx, NS_ERROR_OUT_OF_MEMORY);
ref = ClientOpPromise::CreateAndResolve(NS_OK, __func__);
return ref.forget();
}
nsresult rv = NS_OK;
nsCOMPtr<nsIPrincipal> principal =
PrincipalInfoToPrincipal(principalInfo, &rv);
if (NS_FAILED(rv) || !principal) {
ref = ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
return ref.forget();
}
nsAutoCString origin;
rv = principal->GetOriginNoSuffix(origin);
if (NS_SUCCEEDED(rv)) {
CopyUTF8toUTF16(origin, init.mOrigin);
}
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) {
// Shutting down. Just don't deliver this message.
ref = ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
return ref.forget();
}
RefPtr<ServiceWorkerRegistrationInfo> reg =
swm->GetRegistration(principal, source.Scope());
if (reg) {
RefPtr<ServiceWorkerInfo> serviceWorker = reg->GetByID(source.Id());
if (serviceWorker) {
init.mSource.SetValue().SetAsServiceWorker() =
serviceWorker->GetOrCreateInstance(GetInnerWindow());
}
}
RefPtr<MessageEvent> event =
MessageEvent::Constructor(target, NS_LITERAL_STRING("message"), init);
event->SetTrusted(true);
bool preventDefaultCalled = false;
rv = target->DispatchEvent(static_cast<dom::Event*>(event.get()),
&preventDefaultCalled);
if (NS_FAILED(rv)) {
ref = ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
return ref.forget();
}
ref = ClientOpPromise::CreateAndResolve(NS_OK, __func__);
return ref.forget();
}
RefPtr<ClientOpPromise>
ClientSource::Claim(const ClientClaimArgs& aArgs)
{
SetController(ServiceWorkerDescriptor(aArgs.serviceWorker()));
RefPtr<ClientOpPromise> ref =
ClientOpPromise::CreateAndResolve(NS_OK, __func__);
return ref.forget();
}
RefPtr<ClientOpPromise>
ClientSource::GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs)
{

View File

@ -12,6 +12,10 @@
#include "mozilla/dom/ServiceWorkerDescriptor.h"
#include "mozilla/Variant.h"
#ifdef XP_WIN
#undef PostMessage
#endif
class nsIDocShell;
class nsISerialEventTarget;
class nsPIDOMWindowInner;
@ -19,11 +23,17 @@ class nsPIDOMWindowInner;
namespace mozilla {
namespace dom {
class ClientClaimArgs;
class ClientControlledArgs;
class ClientFocusArgs;
class ClientGetInfoAndStateArgs;
class ClientManager;
class ClientPostMessageArgs;
class ClientSourceChild;
class ClientSourceConstructorArgs;
class ClientSourceExecutionReadyArgs;
class ClientState;
class ClientWindowState;
class PClientManagerChild;
namespace workers {
@ -131,6 +141,15 @@ public:
const Maybe<ServiceWorkerDescriptor>&
GetController() const;
RefPtr<ClientOpPromise>
Focus(const ClientFocusArgs& aArgs);
RefPtr<ClientOpPromise>
PostMessage(const ClientPostMessageArgs& aArgs);
RefPtr<ClientOpPromise>
Claim(const ClientClaimArgs& aArgs);
RefPtr<ClientOpPromise>
GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs);

View File

@ -79,6 +79,21 @@ ClientSourceOpChild::Init(const ClientOpConstructorArgs& aArgs)
DoSourceOp(&ClientSource::Control, aArgs.get_ClientControlledArgs());
break;
}
case ClientOpConstructorArgs::TClientFocusArgs:
{
DoSourceOp(&ClientSource::Focus, aArgs.get_ClientFocusArgs());
break;
}
case ClientOpConstructorArgs::TClientPostMessageArgs:
{
DoSourceOp(&ClientSource::PostMessage, aArgs.get_ClientPostMessageArgs());
break;
}
case ClientOpConstructorArgs::TClientClaimArgs:
{
DoSourceOp(&ClientSource::Claim, aArgs.get_ClientClaimArgs());
break;
}
case ClientOpConstructorArgs::TClientGetInfoAndStateArgs:
{
DoSourceOp(&ClientSource::GetInfoAndState,

View File

@ -225,6 +225,12 @@ ClientSourceParent::ExecutionReady() const
return mExecutionReady;
}
const Maybe<ServiceWorkerDescriptor>&
ClientSourceParent::GetController() const
{
return mController;
}
void
ClientSourceParent::AttachHandle(ClientHandleParent* aClientHandle)
{

View File

@ -70,6 +70,9 @@ public:
bool
ExecutionReady() const;
const Maybe<ServiceWorkerDescriptor>&
GetController() const;
void
AttachHandle(ClientHandleParent* aClientSource);

View File

@ -38,6 +38,7 @@ UNIFIED_SOURCES += [
'ClientOpenWindowOpActors.cpp',
'ClientOpenWindowOpChild.cpp',
'ClientOpenWindowOpParent.cpp',
'ClientOpenWindowUtils.cpp',
'ClientPrefs.cpp',
'ClientSource.cpp',
'ClientSourceChild.cpp',

View File

@ -16,7 +16,7 @@ NS_NewHTMLSlotElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
mozilla::dom::FromParser aFromParser)
{
RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);
if (nsContentUtils::IsWebComponentsEnabled()) {
if (nsDocument::IsWebComponentsEnabled(nodeInfo->GetDocument())) {
already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
return new mozilla::dom::HTMLSlotElement(nodeInfoArg);
}

View File

@ -647,6 +647,8 @@ public:
virtual bool
DeallocPClientOpenWindowOpParent(PClientOpenWindowOpParent* aActor) override;
static hal::ProcessPriority GetInitialProcessPriority(Element* aFrameElement);
// Control the priority of the IPC messages for input events.
void SetInputPriorityEventEnabled(bool aEnabled);
bool IsInputPriorityEventEnabled()
@ -680,8 +682,6 @@ private:
static nsDataHashtable<nsUint32HashKey, ContentParent*> *sJSPluginContentParents;
static StaticAutoPtr<LinkedList<ContentParent> > sContentParents;
static hal::ProcessPriority GetInitialProcessPriority(Element* aFrameElement);
static ContentBridgeParent* CreateContentBridgeParent(const TabContext& aContext,
const hal::ProcessPriority& aPriority,
const TabId& aOpenerTabId,

View File

@ -11,6 +11,7 @@
#include "mozilla/dom/DOMStringList.h"
#include "nsIPrefetchService.h"
#include "nsCPrefetchService.h"
#include "nsMemory.h"
#include "nsNetUtil.h"
#include "nsNetCID.h"
#include "nsServiceManagerUtils.h"

View File

@ -254,19 +254,19 @@ dictionary ShadowRootInit {
// https://dom.spec.whatwg.org/#element
partial interface Element {
// Shadow DOM v1
[Throws, Pref="dom.webcomponents.enabled"]
[Throws, Func="nsDocument::IsWebComponentsEnabled"]
ShadowRoot attachShadow(ShadowRootInit shadowRootInitDict);
[BinaryName="shadowRootByMode", Pref="dom.webcomponents.enabled"]
[BinaryName="shadowRootByMode", Func="nsDocument::IsWebComponentsEnabled"]
readonly attribute ShadowRoot? shadowRoot;
[BinaryName="assignedSlotByMode", Pref="dom.webcomponents.enabled"]
[BinaryName="assignedSlotByMode", Func="nsDocument::IsWebComponentsEnabled"]
readonly attribute HTMLSlotElement? assignedSlot;
[CEReactions, Unscopable, SetterThrows, Pref="dom.webcomponents.enabled"]
[CEReactions, Unscopable, SetterThrows, Func="nsDocument::IsWebComponentsEnabled"]
attribute DOMString slot;
// [deprecated] Shadow DOM v0
[Throws, Pref="dom.webcomponents.enabled"]
[Throws, Func="nsDocument::IsWebComponentsEnabled"]
ShadowRoot createShadowRoot();
[Pref="dom.webcomponents.enabled"]
[Func="nsDocument::IsWebComponentsEnabled"]
NodeList getDestinationInsertionPoints();
};

View File

@ -11,7 +11,7 @@
* and create derivative works of this document.
*/
[Pref="dom.webcomponents.enabled", Exposed=Window, HTMLConstructor]
[Func="nsDocument::IsWebComponentsEnabled", Exposed=Window, HTMLConstructor]
interface HTMLSlotElement : HTMLElement {
[CEReactions, SetterThrows] attribute DOMString name;
sequence<Node> assignedNodes(optional AssignedNodesOptions options);

View File

@ -17,7 +17,7 @@ enum ShadowRootMode {
};
// https://dom.spec.whatwg.org/#shadowroot
[Pref="dom.webcomponents.enabled"]
[Func="nsDocument::IsWebComponentsEnabled"]
interface ShadowRoot : DocumentFragment
{
// Shadow DOM v1

View File

@ -38,4 +38,10 @@ interface TestFunctions {
// DOMString argument on the C++ side and trying to hand it
// stringbuffers. If length not passed, use our full length.
DOMString getStringDataAsDOMString(optional unsigned long length);
// Functions that just punch through to mozITestInterfaceJS.idl
[Throws]
void testThrowNsresult();
[Throws]
void testThrowNsresultFromNative();
};

View File

@ -19,7 +19,7 @@ interface Text : CharacterData {
};
partial interface Text {
[BinaryName="assignedSlotByMode", Pref="dom.webcomponents.enabled"]
[BinaryName="assignedSlotByMode", Func="nsTextNode::IsWebComponentsEnabled"]
readonly attribute HTMLSlotElement? assignedSlot;
};

Some files were not shown because too many files have changed in this diff Show More