This commit is contained in:
Ryan Hunt 2017-02-07 09:05:18 +00:00
Родитель 21e27083d4 092e5dc5f1
Коммит 5e2990dc18
387 изменённых файлов: 10663 добавлений и 4420 удалений

Просмотреть файл

@ -25,3 +25,13 @@ jobs:
- date
when: [] # never (temporary)
- name: nightly-mochitest-valgrind
job:
type: decision-task
treeherder-symbol: Vg
target-tasks-method: mochitest_valgrind
run-on-projects:
- mozilla-central
when:
- {hour: 16, minute: 0}
- {hour: 4, minute: 0}

Просмотреть файл

@ -115,7 +115,6 @@ devtools/server/tests/browser/**
devtools/server/tests/mochitest/**
devtools/server/tests/unit/**
devtools/shared/heapsnapshot/**
devtools/shared/transport/tests/unit/**
devtools/shared/webconsole/test/**
# Ignore devtools pre-processed files

Просмотреть файл

@ -461,11 +461,15 @@ DocAccessibleParent::Destroy()
return;
}
NS_ASSERTION(mChildDocs.IsEmpty(),
"why weren't the child docs destroyed already?");
mShutdown = true;
uint32_t childDocCount = mChildDocs.Length();
for (uint32_t i = 0; i < childDocCount; i++) {
for (uint32_t j = i + 1; j < childDocCount; j++) {
MOZ_DIAGNOSTIC_ASSERT(mChildDocs[i] != mChildDocs[j]);
}
}
for (uint32_t i = childDocCount - 1; i < childDocCount; i--)
mChildDocs[i]->Destroy();

Просмотреть файл

@ -7,6 +7,6 @@ module.exports = {
"rules": {
"no-shadow": "error",
"no-undef": "off"
"no-undef": "error"
}
};

Просмотреть файл

@ -1,4 +1,7 @@
"use strict";
module.exports = {
rules: {
"no-undef": "off"
}
};

Просмотреть файл

@ -4121,6 +4121,13 @@ function OpenBrowserWindow(options) {
extraFeatures += ",non-remote";
}
// If the window is maximized, we want to skip the animation, since we're
// going to be taking up most of the screen anyways, and we want to optimize
// for showing the user a useful window as soon as possible.
if (window.windowState == window.STATE_MAXIMIZED) {
extraFeatures += ",suppressanimation";
}
// if and only if the current window is a browser window and it has a document with a character
// set, then extract the current charset menu setting from the current document and use it to
// initialize the new browser window...

Просмотреть файл

@ -703,6 +703,7 @@
consumeanchor="identity-box"
onclick="PageProxyClickHandler(event);"/>
<image id="sharing-icon" mousethrough="always"/>
<image id="tracking-protection-icon"/>
<box id="blocked-permissions-container" align="center">
<image data-permission-id="geo" class="blocked-permission-icon geo-icon" role="button"
tooltiptext="&urlbar.geolocationBlocked.tooltip;"/>
@ -751,7 +752,6 @@
<image id="eme-notification-icon" class="notification-anchor-icon drm-icon" role="button"
tooltiptext="&urlbar.emeNotificationAnchor.tooltip;"/>
</box>
<image id="tracking-protection-icon"/>
<image id="connection-icon"/>
<hbox id="identity-icon-labels">
<label id="identity-icon-label" class="plain" flex="1"/>

Просмотреть файл

@ -79,6 +79,8 @@ support-files =
browser_webext_nopermissions.xpi
browser_webext_update1.xpi
browser_webext_update2.xpi
browser_webext_update_icon1.xpi
browser_webext_update_icon2.xpi
browser_webext_update.json
!/image/test/mochitest/blue.png
!/toolkit/content/tests/browser/common/mockTransfer.js

Просмотреть файл

@ -2,6 +2,7 @@ const {AddonManagerPrivate} = Cu.import("resource://gre/modules/AddonManager.jsm
const URL_BASE = "https://example.com/browser/browser/base/content/test/general";
const ID = "update@tests.mozilla.org";
const ID_ICON = "update_icon@tests.mozilla.org";
function promiseInstallAddon(url) {
return AddonManager.getInstallForURL(url, null, "application/x-xpinstall")
@ -84,7 +85,8 @@ add_task(function setup() {
]});
});
add_task(function* test_background_update() {
// Helper function to test background updates.
function* backgroundUpdateTest(url, id, checkIconFn) {
yield SpecialPowers.pushPrefEnv({set: [
// Turn on background updates
["extensions.update.enabled", true],
@ -94,7 +96,7 @@ add_task(function* test_background_update() {
]});
// Install version 1.0 of the test extension
let addon = yield promiseInstallAddon(`${URL_BASE}/browser_webext_update1.xpi`);
let addon = yield promiseInstallAddon(url);
ok(addon, "Addon was installed");
is(getBadgeStatus(), "", "Should not start out with an addon alert badge");
@ -129,11 +131,12 @@ add_task(function* test_background_update() {
ok(!win.gViewController.isLoading, "about:addons view is fully loaded");
is(win.gViewController.currentViewId, VIEW, "about:addons is at extensions list");
// Wait for the permission prompt and cancel it
// Wait for the permission prompt, check the contents, then cancel the update
let panel = yield popupPromise;
checkIconFn(panel.getAttribute("icon"));
panel.secondaryButton.click();
addon = yield AddonManager.getAddonByID(ID);
addon = yield AddonManager.getAddonByID(id);
is(addon.version, "1.0", "Should still be running the old version");
yield BrowserTestUtils.removeTab(tab);
@ -187,7 +190,26 @@ add_task(function* test_background_update() {
addon.uninstall();
yield SpecialPowers.popPrefEnv();
});
}
function checkDefaultIcon(icon) {
is(icon, "chrome://mozapps/skin/extensions/extensionGeneric.svg",
"Popup has the default extension icon");
}
add_task(() => backgroundUpdateTest(`${URL_BASE}/browser_webext_update1.xpi`,
ID, checkDefaultIcon));
function checkNonDefaultIcon(icon) {
// The icon should come from the extension, don't bother with the precise
// path, just make sure we've got a jar url pointing to the right path
// inside the jar.
ok(icon.startsWith("jar:file://"), "Icon is a jar url");
ok(icon.endsWith("/icon.png"), "Icon is icon.png inside a jar");
}
add_task(() => backgroundUpdateTest(`${URL_BASE}/browser_webext_update_icon1.xpi`,
ID_ICON, checkNonDefaultIcon));
// Helper function to test a specific scenario for interactive updates.
// `checkFn` is a callable that triggers a check for updates.

Просмотреть файл

@ -13,6 +13,20 @@
}
}
]
},
"update_icon@tests.mozilla.org": {
"updates": [
{
"version": "2.0",
"update_link": "https://example.com/browser/browser/base/content/test/general/browser_webext_update_icon2.xpi",
"applications": {
"gecko": {
"strict_min_version": "1",
"advisory_max_version": "55.0"
}
}
}
]
}
}
}

Двоичные данные
browser/base/content/test/general/browser_webext_update_icon1.xpi Normal file

Двоичный файл не отображается.

Двоичные данные
browser/base/content/test/general/browser_webext_update_icon2.xpi Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -321,7 +321,7 @@ var gTests = [
{
desc: "getUserMedia screen: clicking through without selecting a screen denies",
run: function* checkReloading() {
run: function* checkClickThroughDenies() {
let promise = promisePopupNotificationShown("webRTC-shareDevices");
yield promiseRequestDevice(false, true, null, "screen");
yield promise;

Просмотреть файл

@ -407,12 +407,14 @@ function* closeStream(aAlreadyClosed, aFrameId, aStreamCount = 1) {
function* reloadAndAssertClosedStreams() {
info("reloading the web page");
let promise = promiseObserverCalled("recording-device-events");
let promises = [
promiseObserverCalled("recording-device-events"),
promiseObserverCalled("recording-window-ended")
];
yield ContentTask.spawn(gBrowser.selectedBrowser, null,
"() => content.location.reload()");
yield promise;
yield Promise.all(promises);
yield expectObserverCalled("recording-window-ended");
yield expectNoObserverCalled();
yield checkNotSharing();
}

Просмотреть файл

@ -0,0 +1,7 @@
"use strict";
module.exports = {
rules: {
"no-undef": "off"
}
};

Просмотреть файл

@ -221,7 +221,7 @@ BrowserAction.prototype = {
// If we have a pending pre-loaded popup, cancel it after we've waited
// long enough that we can be relatively certain it won't be opening.
if (this.pendingPopup) {
let {node} = this.widget.forWindow(window);
let node = window.gBrowser && this.widget.forWindow(window).node;
if (isAncestorOrSelf(node, event.originalTarget)) {
this.pendingPopupTimeout = setTimeout(() => this.clearPopup(),
POPUP_PRELOAD_TIMEOUT_MS);

Просмотреть файл

@ -58,9 +58,9 @@ extensions.on("page-shutdown", (type, context) => {
}
let {gBrowser} = context.xulBrowser.ownerGlobal;
if (gBrowser) {
let tab = gBrowser.getTabForBrowser(context.xulBrowser);
if (tab) {
gBrowser.removeTab(tab);
let nativeTab = gBrowser.getTabForBrowser(context.xulBrowser);
if (nativeTab) {
gBrowser.removeTab(nativeTab);
}
}
}
@ -83,16 +83,16 @@ let tabListener = {
onLocationChange(browser, webProgress, request, locationURI, flags) {
if (webProgress.isTopLevel) {
let {gBrowser} = browser.ownerGlobal;
let tab = gBrowser.getTabForBrowser(browser);
let nativeTab = gBrowser.getTabForBrowser(browser);
// Now we are certain that the first page in the tab was loaded.
this.initializingTabs.delete(tab);
this.initializingTabs.delete(nativeTab);
// browser.innerWindowID is now set, resolve the promises if any.
let deferred = this.tabReadyPromises.get(tab);
let deferred = this.tabReadyPromises.get(nativeTab);
if (deferred) {
deferred.resolve(tab);
this.tabReadyPromises.delete(tab);
deferred.resolve(nativeTab);
this.tabReadyPromises.delete(nativeTab);
}
}
},
@ -103,19 +103,20 @@ let tabListener = {
* changes to the requested URL. Other tabs are assumed to be ready once their
* inner window ID is known.
*
* @param {XULElement} tab The <tab> element.
* @param {XULElement} nativeTab The <tab> element.
* @returns {Promise} Resolves with the given tab once ready.
*/
awaitTabReady(tab) {
let deferred = this.tabReadyPromises.get(tab);
awaitTabReady(nativeTab) {
let deferred = this.tabReadyPromises.get(nativeTab);
if (!deferred) {
deferred = PromiseUtils.defer();
if (!this.initializingTabs.has(tab) && (tab.linkedBrowser.innerWindowID ||
tab.linkedBrowser.currentURI.spec === "about:blank")) {
deferred.resolve(tab);
if (!this.initializingTabs.has(nativeTab) &&
(nativeTab.linkedBrowser.innerWindowID ||
nativeTab.linkedBrowser.currentURI.spec === "about:blank")) {
deferred.resolve(nativeTab);
} else {
this.initTabReady();
this.tabReadyPromises.set(tab, deferred);
this.tabReadyPromises.set(nativeTab, deferred);
}
}
return deferred.promise;
@ -142,7 +143,7 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
tab = tabManager.getWrapper(tabTracker.activeTab);
}
await tabListener.awaitTabReady(tab.tab);
await tabListener.awaitTabReady(tab.nativeTab);
return tab;
}
@ -150,15 +151,15 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
let self = {
tabs: {
onActivated: new WindowEventManager(context, "tabs.onActivated", "TabSelect", (fire, event) => {
let tab = event.originalTarget;
let tabId = tabTracker.getId(tab);
let windowId = windowTracker.getId(tab.ownerGlobal);
let nativeTab = event.originalTarget;
let tabId = tabTracker.getId(nativeTab);
let windowId = windowTracker.getId(nativeTab.ownerGlobal);
fire.async({tabId, windowId});
}).api(),
onCreated: new SingletonEventManager(context, "tabs.onCreated", fire => {
let listener = (eventName, event) => {
fire.async(tabManager.convert(event.tab));
fire.async(tabManager.convert(event.nativeTab));
};
tabTracker.on("tab-created", listener);
@ -174,9 +175,9 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
* @see https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/Tabs/onHighlighted
*/
onHighlighted: new WindowEventManager(context, "tabs.onHighlighted", "TabSelect", (fire, event) => {
let tab = event.originalTarget;
let tabIds = [tabTracker.getId(tab)];
let windowId = windowTracker.getId(tab.ownerGlobal);
let nativeTab = event.originalTarget;
let tabIds = [tabTracker.getId(nativeTab)];
let windowId = windowTracker.getId(nativeTab.ownerGlobal);
fire.async({tabIds, windowId});
}).api(),
@ -236,17 +237,17 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
};
let moveListener = event => {
let tab = event.originalTarget;
let nativeTab = event.originalTarget;
if (ignoreNextMove.has(tab)) {
ignoreNextMove.delete(tab);
if (ignoreNextMove.has(nativeTab)) {
ignoreNextMove.delete(nativeTab);
return;
}
fire.async(tabTracker.getId(tab), {
windowId: windowTracker.getId(tab.ownerGlobal),
fire.async(tabTracker.getId(nativeTab), {
windowId: windowTracker.getId(nativeTab.ownerGlobal),
fromIndex: event.detail,
toIndex: tab._tPos,
toIndex: nativeTab._tPos,
});
};
@ -400,22 +401,26 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
options.disallowInheritPrincipal = true;
tabListener.initTabReady();
let tab = window.gBrowser.addTab(url || window.BROWSER_NEW_TAB_URL, options);
let nativeTab = window.gBrowser.addTab(url || window.BROWSER_NEW_TAB_URL, options);
let active = true;
if (createProperties.active !== null) {
active = createProperties.active;
}
if (active) {
window.gBrowser.selectedTab = tab;
window.gBrowser.selectedTab = nativeTab;
}
if (createProperties.index !== null) {
window.gBrowser.moveTabTo(tab, createProperties.index);
window.gBrowser.moveTabTo(nativeTab, createProperties.index);
}
if (createProperties.pinned) {
window.gBrowser.pinTab(tab);
window.gBrowser.pinTab(nativeTab);
}
if (active && !url) {
window.focusAndSelectUrlBar();
}
if (createProperties.url && createProperties.url !== window.BROWSER_NEW_TAB_URL) {
@ -427,10 +432,10 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
// `executeScript` wait until the requested URL is loaded in
// the tab before dispatching messages to the inner window
// that contains the URL we're attempting to load.
tabListener.initializingTabs.add(tab);
tabListener.initializingTabs.add(nativeTab);
}
return tabManager.convert(tab);
return tabManager.convert(nativeTab);
});
},
@ -440,15 +445,15 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
}
for (let tabId of tabs) {
let tab = tabTracker.getTab(tabId);
tab.ownerGlobal.gBrowser.removeTab(tab);
let nativeTab = tabTracker.getTab(tabId);
nativeTab.ownerGlobal.gBrowser.removeTab(nativeTab);
}
},
async update(tabId, updateProperties) {
let tab = getTabOrActive(tabId);
let nativeTab = getTabOrActive(tabId);
let tabbrowser = tab.ownerGlobal.gBrowser;
let tabbrowser = nativeTab.ownerGlobal.gBrowser;
if (updateProperties.url !== null) {
let url = context.uri.resolve(updateProperties.url);
@ -457,55 +462,53 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
return Promise.reject({message: `Illegal URL: ${url}`});
}
tab.linkedBrowser.loadURI(url);
nativeTab.linkedBrowser.loadURI(url);
}
if (updateProperties.active !== null) {
if (updateProperties.active) {
tabbrowser.selectedTab = tab;
tabbrowser.selectedTab = nativeTab;
} else {
// Not sure what to do here? Which tab should we select?
}
}
if (updateProperties.muted !== null) {
if (tab.muted != updateProperties.muted) {
tab.toggleMuteAudio(extension.uuid);
if (nativeTab.muted != updateProperties.muted) {
nativeTab.toggleMuteAudio(extension.uuid);
}
}
if (updateProperties.pinned !== null) {
if (updateProperties.pinned) {
tabbrowser.pinTab(tab);
tabbrowser.pinTab(nativeTab);
} else {
tabbrowser.unpinTab(tab);
tabbrowser.unpinTab(nativeTab);
}
}
// FIXME: highlighted/selected, openerTabId
return tabManager.convert(tab);
return tabManager.convert(nativeTab);
},
async reload(tabId, reloadProperties) {
let tab = getTabOrActive(tabId);
let nativeTab = getTabOrActive(tabId);
let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
if (reloadProperties && reloadProperties.bypassCache) {
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
}
tab.linkedBrowser.reloadWithFlags(flags);
nativeTab.linkedBrowser.reloadWithFlags(flags);
},
async get(tabId) {
let tab = tabTracker.getTab(tabId);
return tabManager.convert(tab);
return tabManager.get(tabId).convert();
},
getCurrent() {
let tab;
let tabData;
if (context.tabId) {
tab = tabManager.get(context.tabId).convert();
tabData = tabManager.get(context.tabId).convert();
}
return Promise.resolve(tab);
return Promise.resolve(tabData);
},
async query(queryInfo) {
@ -522,53 +525,21 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
tab => tab.convert());
},
captureVisibleTab(windowId, options) {
if (!extension.hasPermission("<all_urls>")) {
return Promise.reject({message: "The <all_urls> permission is required to use the captureVisibleTab API"});
}
async captureVisibleTab(windowId, options) {
let window = windowId == null ?
windowTracker.topWindow :
windowTracker.getWindow(windowId, context);
let tab = window.gBrowser.selectedTab;
return tabListener.awaitTabReady(tab).then(() => {
let browser = tab.linkedBrowser;
let recipient = {
innerWindowID: browser.innerWindowID,
};
let tab = tabManager.wrapTab(window.gBrowser.selectedTab);
await tabListener.awaitTabReady(tab.nativeTab);
if (!options) {
options = {};
}
if (options.format == null) {
options.format = "png";
}
if (options.quality == null) {
options.quality = 92;
}
let message = {
options,
width: browser.clientWidth,
height: browser.clientHeight,
};
return context.sendMessage(browser.messageManager, "Extension:Capture",
message, {recipient});
});
return tab.capture(context, options);
},
async detectLanguage(tabId) {
let tab = getTabOrActive(tabId);
let tab = await promiseTabWhenReady(tabId);
return tabListener.awaitTabReady(tab).then(() => {
let browser = tab.linkedBrowser;
let recipient = {innerWindowID: browser.innerWindowID};
return context.sendMessage(browser.messageManager, "Extension:DetectLanguage",
{}, {recipient});
});
return tab.sendMessage(context, "Extension:DetectLanguage");
},
async executeScript(tabId, details) {
@ -615,9 +586,9 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
let indexMap = new Map();
let tabs = tabIds.map(tabId => tabTracker.getTab(tabId));
for (let tab of tabs) {
for (let nativeTab of tabs) {
// If the window is not specified, use the window from the tab.
let window = destinationWindow || tab.ownerGlobal;
let window = destinationWindow || nativeTab.ownerGlobal;
let gBrowser = window.gBrowser;
let insertionPoint = indexMap.get(window) || index;
@ -631,32 +602,32 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
// be moved to a position after the current set of pinned tabs.
// Attempts to move a tab to an illegal position are ignored.
let numPinned = gBrowser._numPinnedTabs;
let ok = tab.pinned ? insertionPoint <= numPinned : insertionPoint >= numPinned;
let ok = nativeTab.pinned ? insertionPoint <= numPinned : insertionPoint >= numPinned;
if (!ok) {
continue;
}
indexMap.set(window, insertionPoint + 1);
if (tab.ownerGlobal != window) {
if (nativeTab.ownerGlobal != window) {
// If the window we are moving the tab in is different, then move the tab
// to the new window.
tab = gBrowser.adoptTab(tab, insertionPoint, false);
nativeTab = gBrowser.adoptTab(nativeTab, insertionPoint, false);
} else {
// If the window we are moving is the same, just move the tab.
gBrowser.moveTabTo(tab, insertionPoint);
gBrowser.moveTabTo(nativeTab, insertionPoint);
}
tabsMoved.push(tab);
tabsMoved.push(nativeTab);
}
return tabsMoved.map(tab => tabManager.convert(tab));
return tabsMoved.map(nativeTab => tabManager.convert(nativeTab));
},
duplicate(tabId) {
let tab = tabTracker.getTab(tabId);
let nativeTab = tabTracker.getTab(tabId);
let gBrowser = tab.ownerGlobal.gBrowser;
let newTab = gBrowser.duplicateTab(tab);
let gBrowser = nativeTab.ownerGlobal.gBrowser;
let newTab = gBrowser.duplicateTab(nativeTab);
return new Promise(resolve => {
// We need to use SSTabRestoring because any attributes set before
@ -667,10 +638,10 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
// Pinned tabs that are duplicated are inserted
// after the existing pinned tab and pinned.
if (tab.pinned) {
if (nativeTab.pinned) {
gBrowser.pinTab(newTab);
}
gBrowser.moveTabTo(newTab, tab._tPos + 1);
gBrowser.moveTabTo(newTab, nativeTab._tPos + 1);
}, {once: true});
newTab.addEventListener("SSTabRestored", function() {
@ -683,24 +654,24 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
},
getZoom(tabId) {
let tab = getTabOrActive(tabId);
let nativeTab = getTabOrActive(tabId);
let {ZoomManager} = tab.ownerGlobal;
let zoom = ZoomManager.getZoomForBrowser(tab.linkedBrowser);
let {ZoomManager} = nativeTab.ownerGlobal;
let zoom = ZoomManager.getZoomForBrowser(nativeTab.linkedBrowser);
return Promise.resolve(zoom);
},
setZoom(tabId, zoom) {
let tab = getTabOrActive(tabId);
let nativeTab = getTabOrActive(tabId);
let {FullZoom, ZoomManager} = tab.ownerGlobal;
let {FullZoom, ZoomManager} = nativeTab.ownerGlobal;
if (zoom === 0) {
// A value of zero means use the default zoom factor.
return FullZoom.reset(tab.linkedBrowser);
return FullZoom.reset(nativeTab.linkedBrowser);
} else if (zoom >= ZoomManager.MIN && zoom <= ZoomManager.MAX) {
FullZoom.setZoom(zoom, tab.linkedBrowser);
FullZoom.setZoom(zoom, nativeTab.linkedBrowser);
} else {
return Promise.reject({
message: `Zoom value ${zoom} out of range (must be between ${ZoomManager.MIN} and ${ZoomManager.MAX})`,
@ -711,9 +682,9 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
},
_getZoomSettings(tabId) {
let tab = getTabOrActive(tabId);
let nativeTab = getTabOrActive(tabId);
let {FullZoom} = tab.ownerGlobal;
let {FullZoom} = nativeTab.ownerGlobal;
return {
mode: "automatic",
@ -727,9 +698,9 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
},
setZoomSettings(tabId, settings) {
let tab = getTabOrActive(tabId);
let nativeTab = getTabOrActive(tabId);
let currentSettings = this._getZoomSettings(tab.id);
let currentSettings = this._getZoomSettings(tabTracker.getId(nativeTab));
if (!Object.keys(settings).every(key => settings[key] === currentSettings[key])) {
return Promise.reject(`Unsupported zoom settings: ${JSON.stringify(settings)}`);
@ -750,14 +721,14 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
// Store the zoom level for all existing tabs.
for (let window of windowTracker.browserWindows()) {
for (let tab of window.gBrowser.tabs) {
let browser = tab.linkedBrowser;
for (let nativeTab of window.gBrowser.tabs) {
let browser = nativeTab.linkedBrowser;
zoomLevels.set(browser, getZoomLevel(browser));
}
}
let tabCreated = (eventName, event) => {
let browser = event.tab.linkedBrowser;
let browser = event.nativeTab.linkedBrowser;
zoomLevels.set(browser, getZoomLevel(browser));
};
@ -774,8 +745,8 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
}
let {gBrowser} = browser.ownerGlobal;
let tab = gBrowser.getTabForBrowser(browser);
if (!tab) {
let nativeTab = gBrowser.getTabForBrowser(browser);
if (!nativeTab) {
// We only care about zoom events in the top-level browser of a tab.
return;
}
@ -786,7 +757,7 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
if (oldZoomFactor != newZoomFactor) {
zoomLevels.set(browser, newZoomFactor);
let tabId = tabTracker.getId(tab);
let tabId = tabTracker.getId(nativeTab);
fire.async({
tabId,
oldZoomFactor,

Просмотреть файл

@ -49,23 +49,23 @@ global.TabContext = function TabContext(getDefaults, extension) {
};
TabContext.prototype = {
get(tab) {
if (!this.tabData.has(tab)) {
this.tabData.set(tab, this.getDefaults(tab));
get(nativeTab) {
if (!this.tabData.has(nativeTab)) {
this.tabData.set(nativeTab, this.getDefaults(nativeTab));
}
return this.tabData.get(tab);
return this.tabData.get(nativeTab);
},
clear(tab) {
this.tabData.delete(tab);
clear(nativeTab) {
this.tabData.delete(nativeTab);
},
handleEvent(event) {
if (event.type == "TabSelect") {
let tab = event.target;
this.emit("tab-select", tab);
this.emit("location-change", tab);
let nativeTab = event.target;
this.emit("tab-select", nativeTab);
this.emit("location-change", nativeTab);
}
},
@ -83,8 +83,8 @@ TabContext.prototype = {
let lastLocation = this.lastLocation.get(browser);
if (browser === gBrowser.selectedBrowser &&
!(lastLocation && lastLocation.equalsExceptRef(browser.currentURI))) {
let tab = gBrowser.getTabForBrowser(browser);
this.emit("location-change", tab, true);
let nativeTab = gBrowser.getTabForBrowser(browser);
this.emit("location-change", nativeTab, true);
}
this.lastLocation.set(browser, browser.currentURI);
},
@ -106,6 +106,21 @@ class WindowTracker extends WindowTrackerBase {
}
}
/**
* An event manager API provider which listens for a DOM event in any browser
* window, and calls the given listener function whenever an event is received.
* That listener function receives a `fire` object, which it can use to dispatch
* events to the extension, and a DOM event object.
*
* @param {BaseContext} context
* The extension context which the event manager belongs to.
* @param {string} name
* The API name of the event manager, e.g.,"runtime.onMessage".
* @param {string} event
* The name of the DOM event to listen for.
* @param {function} listener
* The listener function to call when a DOM event is received.
*/
global.WindowEventManager = class extends SingletonEventManager {
constructor(context, name, event, listener) {
super(context, name, fire => {
@ -152,28 +167,28 @@ class TabTracker extends TabTrackerBase {
/* eslint-enable mozilla/balanced-listeners */
}
getId(tab) {
if (this._tabs.has(tab)) {
return this._tabs.get(tab);
getId(nativeTab) {
if (this._tabs.has(nativeTab)) {
return this._tabs.get(nativeTab);
}
this.init();
let id = this._nextId++;
this.setId(tab, id);
this.setId(nativeTab, id);
return id;
}
setId(tab, id) {
this._tabs.set(tab, id);
this._tabIds.set(id, tab);
setId(nativeTab, id) {
this._tabs.set(nativeTab, id);
this._tabIds.set(id, nativeTab);
}
_handleTabDestroyed(event, {tab}) {
let id = this._tabs.get(tab);
_handleTabDestroyed(event, {nativeTab}) {
let id = this._tabs.get(nativeTab);
if (id) {
this._tabs.delete(tab);
if (this._tabIds.get(id) === tab) {
this._tabs.delete(nativeTab);
if (this._tabIds.get(id) === nativeTab) {
this._tabIds.delete(id);
}
}
@ -192,9 +207,9 @@ class TabTracker extends TabTrackerBase {
* A XUL <tab> element.
*/
getTab(tabId, default_ = undefined) {
let tab = this._tabIds.get(tabId);
if (tab) {
return tab;
let nativeTab = this._tabIds.get(tabId);
if (nativeTab) {
return nativeTab;
}
if (default_ !== undefined) {
return default_;
@ -202,8 +217,13 @@ class TabTracker extends TabTrackerBase {
throw new ExtensionError(`Invalid tab ID: ${tabId}`);
}
/**
* @param {Event} event
* The DOM Event to handle.
* @private
*/
handleEvent(event) {
let tab = event.target;
let nativeTab = event.target;
switch (event.type) {
case "TabOpen":
@ -213,10 +233,10 @@ class TabTracker extends TabTrackerBase {
// This tab is being created to adopt a tab from a different window.
// Copy the ID from the old tab to the new.
this.setId(tab, this.getId(adoptedTab));
this.setId(nativeTab, this.getId(adoptedTab));
adoptedTab.linkedBrowser.messageManager.sendAsyncMessage("Extension:SetTabAndWindowId", {
windowId: windowTracker.getId(tab.ownerGlobal),
windowId: windowTracker.getId(nativeTab.ownerGlobal),
});
}
@ -238,16 +258,24 @@ class TabTracker extends TabTrackerBase {
// Copy its ID to the new tab, in case it was created as the first tab
// of a new window, and did not have an `adoptedTab` detail when it was
// opened.
this.setId(adoptedBy, this.getId(tab));
this.setId(adoptedBy, this.getId(nativeTab));
this.emitDetached(tab, adoptedBy);
this.emitDetached(nativeTab, adoptedBy);
} else {
this.emitRemoved(tab, false);
this.emitRemoved(nativeTab, false);
}
break;
}
}
/**
* A private method which is called whenever a new browser window is opened,
* and dispatches the necessary events for it.
*
* @param {DOMWindow} window
* The window being opened.
* @private
*/
_handleWindowOpen(window) {
if (window.arguments && window.arguments[0] instanceof window.XULElement) {
// If the first window argument is a XUL element, it means the
@ -259,16 +287,16 @@ class TabTracker extends TabTrackerBase {
// by the first MozAfterPaint event. That code handles finally
// adopting the tab, and clears it from the arguments list in the
// process, so if we run later than it, we're too late.
let tab = window.arguments[0];
let nativeTab = window.arguments[0];
let adoptedBy = window.gBrowser.tabs[0];
this.adoptedTabs.set(tab, adoptedBy);
this.setId(adoptedBy, this.getId(tab));
this.adoptedTabs.set(nativeTab, adoptedBy);
this.setId(adoptedBy, this.getId(nativeTab));
// We need to be sure to fire this event after the onDetached event
// for the original tab.
let listener = (event, details) => {
if (details.tab === tab) {
if (details.nativeTab === nativeTab) {
this.off("tab-detached", listener);
Promise.resolve().then(() => {
@ -279,43 +307,85 @@ class TabTracker extends TabTrackerBase {
this.on("tab-detached", listener);
} else {
for (let tab of window.gBrowser.tabs) {
this.emitCreated(tab);
for (let nativeTab of window.gBrowser.tabs) {
this.emitCreated(nativeTab);
}
}
}
/**
* A private method which is called whenever a browser window is closed,
* and dispatches the necessary events for it.
*
* @param {DOMWindow} window
* The window being closed.
* @private
*/
_handleWindowClose(window) {
for (let tab of window.gBrowser.tabs) {
if (this.adoptedTabs.has(tab)) {
this.emitDetached(tab, this.adoptedTabs.get(tab));
for (let nativeTab of window.gBrowser.tabs) {
if (this.adoptedTabs.has(nativeTab)) {
this.emitDetached(nativeTab, this.adoptedTabs.get(nativeTab));
} else {
this.emitRemoved(tab, true);
this.emitRemoved(nativeTab, true);
}
}
}
emitAttached(tab) {
let newWindowId = windowTracker.getId(tab.ownerGlobal);
let tabId = this.getId(tab);
/**
* Emits a "tab-attached" event for the given tab element.
*
* @param {NativeTab} nativeTab
* The tab element in the window to which the tab is being attached.
* @private
*/
emitAttached(nativeTab) {
let newWindowId = windowTracker.getId(nativeTab.ownerGlobal);
let tabId = this.getId(nativeTab);
this.emit("tab-attached", {tab, tabId, newWindowId, newPosition: tab._tPos});
this.emit("tab-attached", {nativeTab, tabId, newWindowId, newPosition: nativeTab._tPos});
}
emitDetached(tab, adoptedBy) {
let oldWindowId = windowTracker.getId(tab.ownerGlobal);
let tabId = this.getId(tab);
/**
* Emits a "tab-detached" event for the given tab element.
*
* @param {NativeTab} nativeTab
* The tab element in the window from which the tab is being detached.
* @param {NativeTab} adoptedBy
* The tab element in the window to which detached tab is being moved,
* and will adopt this tab's contents.
* @private
*/
emitDetached(nativeTab, adoptedBy) {
let oldWindowId = windowTracker.getId(nativeTab.ownerGlobal);
let tabId = this.getId(nativeTab);
this.emit("tab-detached", {tab, adoptedBy, tabId, oldWindowId, oldPosition: tab._tPos});
this.emit("tab-detached", {nativeTab, adoptedBy, tabId, oldWindowId, oldPosition: nativeTab._tPos});
}
emitCreated(tab) {
this.emit("tab-created", {tab});
/**
* Emits a "tab-created" event for the given tab element.
*
* @param {NativeTab} nativeTab
* The tab element which is being created.
* @private
*/
emitCreated(nativeTab) {
this.emit("tab-created", {nativeTab});
}
emitRemoved(tab, isWindowClosing) {
let windowId = windowTracker.getId(tab.ownerGlobal);
let tabId = this.getId(tab);
/**
* Emits a "tab-removed" event for the given tab element.
*
* @param {NativeTab} nativeTab
* The tab element which is being removed.
* @param {boolean} isWindowClosing
* True if the tab is being removed because the browser window is
* closing.
* @private
*/
emitRemoved(nativeTab, isWindowClosing) {
let windowId = windowTracker.getId(nativeTab.ownerGlobal);
let tabId = this.getId(nativeTab);
// When addons run in-process, `window.close()` is synchronous. Most other
// addon-invoked calls are asynchronous since they go through a proxy
@ -327,7 +397,7 @@ class TabTracker extends TabTrackerBase {
// event listener is registered. To make sure that the event listener is
// notified, we dispatch `tabs.onRemoved` asynchronously.
Services.tm.mainThread.dispatch(() => {
this.emit("tab-removed", {tab, tabId, windowId, isWindowClosing});
this.emit("tab-removed", {nativeTab, tabId, windowId, isWindowClosing});
}, Ci.nsIThread.DISPATCH_NORMAL);
}
@ -351,9 +421,9 @@ class TabTracker extends TabTrackerBase {
if (gBrowser && gBrowser.getTabForBrowser) {
result.windowId = windowTracker.getId(browser.ownerGlobal);
let tab = gBrowser.getTabForBrowser(browser);
if (tab) {
result.tabId = this.getId(tab);
let nativeTab = gBrowser.getTabForBrowser(browser);
if (nativeTab) {
result.tabId = this.getId(nativeTab);
}
}
@ -376,19 +446,19 @@ Object.assign(global, {tabTracker, windowTracker});
class Tab extends TabBase {
get _favIconUrl() {
return this.window.gBrowser.getIcon(this.tab);
return this.window.gBrowser.getIcon(this.nativeTab);
}
get audible() {
return this.tab.soundPlaying;
return this.nativeTab.soundPlaying;
}
get browser() {
return this.tab.linkedBrowser;
return this.nativeTab.linkedBrowser;
}
get cookieStoreId() {
return getCookieStoreIdForTab(this, this.tab);
return getCookieStoreIdForTab(this, this.nativeTab);
}
get height() {
@ -396,41 +466,37 @@ class Tab extends TabBase {
}
get index() {
return this.tab._tPos;
}
get innerWindowID() {
return this.browser.innerWindowID;
return this.nativeTab._tPos;
}
get mutedInfo() {
let tab = this.tab;
let {nativeTab} = this;
let mutedInfo = {muted: tab.muted};
if (tab.muteReason === null) {
let mutedInfo = {muted: nativeTab.muted};
if (nativeTab.muteReason === null) {
mutedInfo.reason = "user";
} else if (tab.muteReason) {
} else if (nativeTab.muteReason) {
mutedInfo.reason = "extension";
mutedInfo.extensionId = tab.muteReason;
mutedInfo.extensionId = nativeTab.muteReason;
}
return mutedInfo;
}
get pinned() {
return this.tab.pinned;
return this.nativeTab.pinned;
}
get active() {
return this.tab.selected;
return this.nativeTab.selected;
}
get selected() {
return this.tab.selected;
return this.nativeTab.selected;
}
get status() {
if (this.tab.getAttribute("busy") === "true") {
if (this.nativeTab.getAttribute("busy") === "true") {
return "loading";
}
return "complete";
@ -441,31 +507,47 @@ class Tab extends TabBase {
}
get window() {
return this.tab.ownerGlobal;
return this.nativeTab.ownerGlobal;
}
get windowId() {
return windowTracker.getId(this.window);
}
static convertFromSessionStoreClosedData(extension, tab, window = null) {
/**
* Converts session store data to an object compatible with the return value
* of the convert() method, representing that data.
*
* @param {Extension} extension
* The extension for which to convert the data.
* @param {Object} tabData
* Session store data for a closed tab, as returned by
* `SessionStore.getClosedTabData()`.
* @param {DOMWindow} [window = null]
* The browser window which the tab belonged to before it was closed.
* May be null if the window the tab belonged to no longer exists.
*
* @returns {Object}
* @static
*/
static convertFromSessionStoreClosedData(extension, tabData, window = null) {
let result = {
sessionId: String(tab.closedId),
index: tab.pos ? tab.pos : 0,
sessionId: String(tabData.closedId),
index: tabData.pos ? tabData.pos : 0,
windowId: window && windowTracker.getId(window),
selected: false,
highlighted: false,
active: false,
pinned: false,
incognito: Boolean(tab.state && tab.state.isPrivate),
incognito: Boolean(tabData.state && tabData.state.isPrivate),
};
if (extension.tabManager.hasTabPermission(tab)) {
let entries = tab.state ? tab.state.entries : tab.entries;
if (extension.tabManager.hasTabPermission(tabData)) {
let entries = tabData.state ? tabData.state.entries : tabData.entries;
result.url = entries[0].url;
result.title = entries[0].title;
if (tab.image) {
result.favIconUrl = tab.image;
if (tabData.image) {
result.favIconUrl = tabData.image;
}
}
@ -474,6 +556,22 @@ class Tab extends TabBase {
}
class Window extends WindowBase {
/**
* Update the geometry of the browser window.
*
* @param {Object} options
* An object containing new values for the window's geometry.
* @param {integer} [options.left]
* The new pixel distance of the left side of the browser window from
* the left of the screen.
* @param {integer} [options.top]
* The new pixel distance of the top side of the browser window from
* the top of the screen.
* @param {integer} [options.width]
* The new pixel width of the window.
* @param {integer} [options.height]
* The new pixel height of the window.
*/
updateGeometry(options) {
let {window} = this;
@ -582,25 +680,38 @@ class Window extends WindowBase {
* getTabs() {
let {tabManager} = this.extension;
for (let tab of this.window.gBrowser.tabs) {
yield tabManager.getWrapper(tab);
for (let nativeTab of this.window.gBrowser.tabs) {
yield tabManager.getWrapper(nativeTab);
}
}
static convertFromSessionStoreClosedData(extension, window) {
/**
* Converts session store data to an object compatible with the return value
* of the convert() method, representing that data.
*
* @param {Extension} extension
* The extension for which to convert the data.
* @param {Object} windowData
* Session store data for a closed window, as returned by
* `SessionStore.getClosedWindowData()`.
*
* @returns {Object}
* @static
*/
static convertFromSessionStoreClosedData(extension, windowData) {
let result = {
sessionId: String(window.closedId),
sessionId: String(windowData.closedId),
focused: false,
incognito: false,
type: "normal", // this is always "normal" for a closed window
// Surely this does not actually work?
state: this.getState(window),
state: this.getState(windowData),
alwaysOnTop: false,
};
if (window.tabs.length) {
result.tabs = window.tabs.map(tab => {
return Tab.convertFromSessionStoreClosedData(extension, tab);
if (windowData.tabs.length) {
result.tabs = windowData.tabs.map(tabData => {
return Tab.convertFromSessionStoreClosedData(extension, tabData);
});
}
@ -612,24 +723,24 @@ Object.assign(global, {Tab, Window});
class TabManager extends TabManagerBase {
get(tabId, default_ = undefined) {
let tab = tabTracker.getTab(tabId, default_);
let nativeTab = tabTracker.getTab(tabId, default_);
if (tab) {
return this.getWrapper(tab);
if (nativeTab) {
return this.getWrapper(nativeTab);
}
return default_;
}
addActiveTabPermission(tab = tabTracker.activeTab) {
return super.addActiveTabPermission(tab);
addActiveTabPermission(nativeTab = tabTracker.activeTab) {
return super.addActiveTabPermission(nativeTab);
}
revokeActiveTabPermission(tab = tabTracker.activeTab) {
return super.revokeActiveTabPermission(tab);
revokeActiveTabPermission(nativeTab = tabTracker.activeTab) {
return super.revokeActiveTabPermission(nativeTab);
}
wrapTab(tab) {
return new Tab(this.extension, tab, tabTracker.getId(tab));
wrapTab(nativeTab) {
return new Tab(this.extension, nativeTab, tabTracker.getId(nativeTab));
}
}

Просмотреть файл

@ -5,6 +5,8 @@
let scriptPage = url => `<html><head><meta charset="utf-8"><script src="${url}"></script></head><body>${url}</body></html>`;
add_task(function* testBrowserActionClickCanceled() {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"browser_action": {
@ -27,7 +29,6 @@ add_task(function* testBrowserActionClickCanceled() {
let browserAction = browserActionFor(ext);
let widget = getBrowserActionWidget(extension).forWindow(window);
let tab = window.gBrowser.selectedTab;
// Test canceled click.
EventUtils.synthesizeMouseAtCenter(widget.node, {type: "mousedown", button: 0}, window);
@ -76,6 +77,8 @@ add_task(function* testBrowserActionClickCanceled() {
yield closeBrowserAction(extension);
yield extension.unload();
yield BrowserTestUtils.removeTab(tab);
});
add_task(function* testBrowserActionDisabled() {

Просмотреть файл

@ -2,7 +2,7 @@
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* () {
add_task(function* test_create_options() {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:robots");
gBrowser.selectedTab = tab;
@ -164,3 +164,44 @@ add_task(function* () {
yield BrowserTestUtils.removeTab(tab);
});
add_task(function* test_urlbar_focus() {
const extension = ExtensionTestUtils.loadExtension({
background() {
browser.test.onMessage.addListener(async (cmd, ...args) => {
const result = await browser.tabs[cmd](...args);
browser.test.sendMessage("result", result);
});
},
});
yield extension.startup();
// Test content is focused after opening a regular url
extension.sendMessage("create", {url: "https://example.com"});
const tab1 = yield extension.awaitMessage("result");
is(document.activeElement.tagName, "browser", "Content focused after opening a web page");
extension.sendMessage("remove", tab1.id);
yield extension.awaitMessage("result");
// Test urlbar is focused after opening an empty tab
extension.sendMessage("create", {});
const tab2 = yield extension.awaitMessage("result");
const active = document.activeElement;
info(`Active element: ${active.tagName}, id: ${active.id}, class: ${active.className}`);
const parent = active.parentNode;
info(`Parent element: ${parent.tagName}, id: ${parent.id}, class: ${parent.className}`);
info(`After opening an empty tab, gURLBar.focused: ${gURLBar.focused}`);
is(active.tagName, "html:input", "Input element focused");
ok(active.classList.contains("urlbar-input"), "Urlbar focused");
extension.sendMessage("remove", tab2.id);
yield extension.awaitMessage("result");
yield extension.unload();
});

Просмотреть файл

@ -2318,7 +2318,9 @@ BrowserGlue.prototype = {
"chrome://browser/locale/accounts.properties"
);
let title = accountsBundle.GetStringFromName("deviceConnectedTitle");
let body = accountsBundle.formatStringFromName("deviceConnectedBody", [deviceName], 1);
let body = accountsBundle.formatStringFromName("deviceConnectedBody" +
(deviceName ? "" : ".noDeviceName"),
[deviceName], 1);
let url = Services.urlFormatter.formatURLPref("identity.fxaccounts.settings.devices.uri");
function clickCallback(subject, topic, data) {

Просмотреть файл

@ -9,6 +9,7 @@ support-files =
testEngine.xml
testEngine_diacritics.xml
testEngine_dupe.xml
testEngine_missing_namespace.xml
testEngine_mozsearch.xml
tooManyEnginesOffered.html
webapi.html

Просмотреть файл

@ -67,11 +67,12 @@ add_task(function* test_relative() {
});
add_task(function* test_invalid() {
gBrowser.selectedTab = AddSearchProvider("z://foobar");
let url = "z://foobar";
gBrowser.selectedTab = AddSearchProvider(url);
let dialog = yield promiseDialogOpened();
is(dialog.args.promptType, "alert", "Should see the alert dialog.");
is(dialog.args.text, getString("error_invalid_engine_msg", brandName),
is(dialog.args.text, getString("error_invalid_engine_msg2", brandName, url),
"Should have seen the right error message")
dialog.document.documentElement.acceptDialog();
@ -90,3 +91,16 @@ add_task(function* test_missing() {
gBrowser.removeCurrentTab();
});
add_task(function* test_missing_namespace() {
let url = ROOT + "testEngine_missing_namespace.xml";
gBrowser.selectedTab = AddSearchProvider(url);
let dialog = yield promiseDialogOpened();
is(dialog.args.promptType, "alert", "Should see the alert dialog.");
is(dialog.args.text, getString("error_invalid_engine_msg2", brandName, url),
"Should have seen the right error message")
dialog.document.documentElement.acceptDialog();
gBrowser.removeCurrentTab();
});

Просмотреть файл

@ -0,0 +1,11 @@
<OpenSearchDescription>
<ShortName>Foo</ShortName>
<Description>Foo Search</Description>
<InputEncoding>utf-8</InputEncoding>
<Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC</Image>
<Url type="text/html" method="GET" template="http://mochi.test:8888/browser/browser/components/search/test/?search">
<Param name="test" value="{searchTerms}"/>
</Url>
<moz:SearchForm>http://mochi.test:8888/browser/browser/components/search/test/</moz:SearchForm>
<moz:Alias>fooalias</moz:Alias>
</OpenSearchDescription>

Просмотреть файл

@ -4032,7 +4032,7 @@ var SessionStoreInternal = {
argString.data = "";
// Build feature string
let features = "chrome,dialog=no,macsuppressanimation,all";
let features = "chrome,dialog=no,suppressanimation,all";
let winState = aState.windows[0];
WINDOW_ATTRIBUTES.forEach(function(aFeature) {
// Use !isNaN as an easy way to ignore sizemode and check for numbers

2
browser/extensions/pocket/bootstrap.js поставляемый
Просмотреть файл

@ -3,6 +3,8 @@
* 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/. */
/* global ADDON_ENABLE:false, ADDON_DISABLE:false, APP_SHUTDOWN: false */
const {classes: Cc, interfaces: Ci, utils: Cu, manager: Cm} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");

Просмотреть файл

@ -42,6 +42,7 @@
// TODO : [nice to have] - Immediately save, buffer the actions in a local queue and send (so it works offline, works like our native extensions)
/* eslint-disable no-shadow */
/* eslint "mozilla/import-browserjs-globals": "error" */
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",

Просмотреть файл

@ -1,3 +1,6 @@
/* global $:false, Handlebars:false */
/* import-globals-from messages.js */
/*
PKT_SAVED_OVERLAY is the view itself and contains all of the methods to manipute the overlay and messaging.
It does not contain any logic for saving or communication with the extension or server.
@ -171,7 +174,7 @@ var PKT_SAVED_OVERLAY = function(options) {
if ($.trim(text).length > 25 || !$.trim(text).length) {
if (text.length > 25) {
myself.showTagsError(myself.dictJSON.maxtaglength);
changestamp = Date.now();
this.changestamp = Date.now();
setTimeout(function() {
$(".token-input-input-token input").val(text).focus();
}, 10);
@ -203,7 +206,7 @@ var PKT_SAVED_OVERLAY = function(options) {
}
}).on("keypress", "input", function(e) {
if (e.which == 13) {
if (typeof changestamp == "undefined" || (Date.now() - changestamp > 250)) {
if (typeof this.changestamp == "undefined" || (Date.now() - this.changestamp > 250)) {
e.preventDefault();
myself.wrapper.find(".pkt_ext_btn").trigger("click");
}
@ -215,13 +218,13 @@ var PKT_SAVED_OVERLAY = function(options) {
},
onAdd() {
myself.checkValidTagSubmit();
changestamp = Date.now();
this.changestamp = Date.now();
myself.hideInactiveTags();
myself.checkPlaceholderStatus();
},
onDelete() {
myself.checkValidTagSubmit();
changestamp = Date.now();
this.changestamp = Date.now();
myself.showActiveTags();
myself.checkPlaceholderStatus();
},
@ -533,6 +536,7 @@ PKT_SAVED.prototype = {
$(function() {
if (!window.thePKT_SAVED) {
var thePKT_SAVED = new PKT_SAVED();
/* global thePKT_SAVED */
window.thePKT_SAVED = thePKT_SAVED;
thePKT_SAVED.init();
}

Просмотреть файл

@ -1,3 +1,6 @@
/* global $:false, Handlebars:false */
/* import-globals-from messages.js */
/*
PKT_SIGNUP_OVERLAY is the view itself and contains all of the methods to manipute the overlay and messaging.
It does not contain any logic for saving or communication with the extension or server.
@ -157,6 +160,7 @@ PKT_SIGNUP.prototype = {
$(function() {
if (!window.thePKT_SIGNUP) {
var thePKT_SIGNUP = new PKT_SIGNUP();
/* global thePKT_SIGNUP */
window.thePKT_SIGNUP = thePKT_SIGNUP;
thePKT_SIGNUP.init();
}

Просмотреть файл

@ -58,7 +58,8 @@ var Presentation = {
init() {
log("init");
// Register PresentationDevicePrompt into a XPCOM component.
Cu.import(PRESENTATION_DEVICE_PROMPT_PATH);
let {PresentationDevicePrompt} = Cu.import(PRESENTATION_DEVICE_PROMPT_PATH, {});
this.PresentationDevicePrompt = PresentationDevicePrompt;
this._register();
},
@ -66,6 +67,7 @@ var Presentation = {
log("uninit");
// Unregister PresentationDevicePrompt XPCOM component.
this._unregister();
delete this.PresentationDevicePrompt;
Cu.unload(PRESENTATION_DEVICE_PROMPT_PATH);
},
@ -73,7 +75,7 @@ var Presentation = {
_register() {
log("_register");
this._devicePromptFactory = new Factory();
this._devicePromptFactory.register(PresentationDevicePrompt);
this._devicePromptFactory.register(this.PresentationDevicePrompt);
},
_unregister() {

Просмотреть файл

@ -4,6 +4,8 @@
"use strict";
const {utils: Cu} = Components;
this.EXPORTED_SYMBOLS = ["CleanupManager"];
const cleanupHandlers = new Set();

Просмотреть файл

@ -2,6 +2,8 @@
* 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/. */
/* global APP_SHUTDOWN:false */
let { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/Services.jsm");

Просмотреть файл

@ -31,6 +31,7 @@ let WebCompatReporter = {
},
init() {
/* global TabListener */
Cu.import(TABLISTENER_JSM);
let styleSheetService = Cc["@mozilla.org/content/style-sheet-service;1"]

Просмотреть файл

@ -2,6 +2,8 @@
* 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/. */
/* global content:false, sendAsyncMessage:false */
let { utils: Cu } = Components;
const TABDATA_MESSAGE = "WebCompat:SendTabData";

Просмотреть файл

@ -2,6 +2,8 @@
* 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/. */
/* global content:false, addMessageListener:false, removeMessageListener: false */
let { utils: Cu } = Components;
const SCREENSHOT_MESSAGE = "WebCompat:SendScreenshot";

Просмотреть файл

@ -0,0 +1,7 @@
"use strict";
module.exports = {
"extends": [
"../../../../testing/mochitest/browser.eslintrc.js"
]
};

Просмотреть файл

@ -16,10 +16,13 @@ verificationSentBody = A verification link has been sent to %S.
verificationNotSentTitle = Unable to Send Verification
verificationNotSentBody = We are unable to send a verification mail at this time, please try again later.
# LOCALIZATION NOTE (deviceConnectedTitle, deviceConnectedBody)
# LOCALIZATION NOTE (deviceConnectedTitle, deviceConnectedBody, deviceConnectedBody.noDeviceName)
# These strings are used in a notification shown when a new device joins the Sync account.
# deviceConnectedBody.noDeviceName is shown instead of deviceConnectedBody when we
# could not get the device name that joined
deviceConnectedTitle = Firefox Sync
deviceConnectedBody = This computer is now syncing with %S.
deviceConnectedBody.noDeviceName = This computer is now syncing with a new device.
# LOCALIZATION NOTE (syncStartNotification.title, syncStartNotification.body)
# These strings are used in a notification shown after Sync is connected.

Просмотреть файл

@ -83,6 +83,7 @@ webextPerms.updateAccept.accessKey=U
webextPerms.description.bookmarks=Read and modify bookmarks
webextPerms.description.downloads=Download files and read and modify the browsers download history
webextPerms.description.geolocation=Access your location
webextPerms.description.history=Access browsing history
# LOCALIZATION NOTE (webextPerms.description.nativeMessaging)
# %S will be replaced with the name of the application

Просмотреть файл

@ -13,8 +13,12 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyPreferenceGetter(this, "useRemoteWebExtensions",
"extensions.webextensions.remote", false);
XPCOMUtils.defineLazyPreferenceGetter(this, "useSeparateFileUriProcess",
"browser.tabs.remote.separateFileUriProcess", false);
XPCOMUtils.defineLazyModuleGetter(this, "Utils",
"resource://gre/modules/sessionstore/Utils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "console",
"resource://gre/modules/Console.jsm");
function getAboutModule(aURL) {
// Needs to match NS_GetAboutModuleName
@ -56,7 +60,7 @@ this.E10SUtils = {
},
getRemoteTypeForURI(aURL, aMultiProcess,
aPreferredRemoteType = DEFAULT_REMOTE_TYPE) {
aPreferredRemoteType = DEFAULT_REMOTE_TYPE) {
if (!aMultiProcess) {
return NOT_REMOTE;
}
@ -66,92 +70,105 @@ this.E10SUtils = {
aURL = "about:blank";
}
// Javascript urls can load in any process, they apply to the current document
if (aURL.startsWith("javascript:")) {
return aPreferredRemoteType;
let uri;
try {
uri = Services.io.newURI(aURL);
} catch (e) {
// If we have an invalid URI, it's still possible that it might get
// fixed-up into a valid URI later on. However, we don't want to return
// aPreferredRemoteType here, in case the URI gets fixed-up into
// something that wouldn't normally run in that process.
return DEFAULT_REMOTE_TYPE;
}
// We need data: URI's to load in a remote process, because some of our
// tests rely on this. For blob: URI's, load them in their originating
// process unless it is non-remote. In that case, favor a remote (sandboxed)
// process with fewer privileges to limit exposure.
if (aURL.startsWith("data:") || aURL.startsWith("blob:")) {
return aPreferredRemoteType == NOT_REMOTE ? DEFAULT_REMOTE_TYPE
: aPreferredRemoteType;
}
if (aURL.startsWith("file:")) {
return Services.prefs.getBoolPref("browser.tabs.remote.separateFileUriProcess")
? FILE_REMOTE_TYPE : DEFAULT_REMOTE_TYPE;
}
if (aURL.startsWith("about:")) {
// We need to special case about:blank because it needs to load in any.
if (aURL == "about:blank") {
return aPreferredRemoteType;
}
let url = Services.io.newURI(aURL);
let module = getAboutModule(url);
// If the module doesn't exist then an error page will be loading, that
// should be ok to load in any process
if (!module) {
return aPreferredRemoteType;
}
let flags = module.getURIFlags(url);
if (flags & Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD) {
return DEFAULT_REMOTE_TYPE;
}
// If the about page can load in parent or child, it should be safe to
// load in any remote type.
if (flags & Ci.nsIAboutModule.URI_CAN_LOAD_IN_CHILD) {
return aPreferredRemoteType;
}
return this.getRemoteTypeForURIObject(uri, aMultiProcess,
aPreferredRemoteType);
},
getRemoteTypeForURIObject(aURI, aMultiProcess,
aPreferredRemoteType = DEFAULT_REMOTE_TYPE) {
if (!aMultiProcess) {
return NOT_REMOTE;
}
if (aURL.startsWith("chrome:")) {
let url;
try {
// This can fail for invalid Chrome URIs, in which case we will end up
// not loading anything anyway.
url = Services.io.newURI(aURL);
} catch (ex) {
switch (aURI.scheme) {
case "javascript":
// javascript URIs can load in any, they apply to the current document.
return aPreferredRemoteType;
}
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
getService(Ci.nsIXULChromeRegistry);
if (chromeReg.mustLoadURLRemotely(url)) {
return DEFAULT_REMOTE_TYPE;
}
case "data":
case "blob":
// We need data: and blob: URIs to load in any remote process, because
// they need to be able to load in whatever is the current process
// unless it is non-remote. In that case we don't want to load them in
// the parent process, so we load them in the default remote process,
// which is sandboxed and limits any risk.
return aPreferredRemoteType == NOT_REMOTE ? DEFAULT_REMOTE_TYPE
: aPreferredRemoteType;
if (chromeReg.canLoadURLRemotely(url) &&
aPreferredRemoteType != NOT_REMOTE) {
return DEFAULT_REMOTE_TYPE;
}
case "file":
return useSeparateFileUriProcess ? FILE_REMOTE_TYPE
: DEFAULT_REMOTE_TYPE;
return NOT_REMOTE;
case "about":
let module = getAboutModule(aURI);
// If the module doesn't exist then an error page will be loading, that
// should be ok to load in any process
if (!module) {
return aPreferredRemoteType;
}
let flags = module.getURIFlags(aURI);
if (flags & Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD) {
return DEFAULT_REMOTE_TYPE;
}
// If the about page can load in parent or child, it should be safe to
// load in any remote type.
if (flags & Ci.nsIAboutModule.URI_CAN_LOAD_IN_CHILD) {
return aPreferredRemoteType;
}
return NOT_REMOTE;
case "chrome":
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
getService(Ci.nsIXULChromeRegistry);
if (chromeReg.mustLoadURLRemotely(aURI)) {
return DEFAULT_REMOTE_TYPE;
}
if (chromeReg.canLoadURLRemotely(aURI) &&
aPreferredRemoteType != NOT_REMOTE) {
return DEFAULT_REMOTE_TYPE;
}
return NOT_REMOTE;
case "moz-extension":
return useRemoteWebExtensions ? EXTENSION_REMOTE_TYPE : NOT_REMOTE;
default:
// For any other nested URIs, we use the innerURI to determine the
// remote type. In theory we should use the innermost URI, but some URIs
// have fake inner URIs (e.g. about URIs with inner moz-safe-about) and
// if such URIs are wrapped in other nested schemes like view-source:,
// we don't want to "skip" past "about:" by going straight to the
// innermost URI. Any URIs like this will need to be handled in the
// cases above, so we don't still end up using the fake inner URI here.
if (aURI instanceof Ci.nsINestedURI) {
let innerURI = aURI.QueryInterface(Ci.nsINestedURI).innerURI;
return this.getRemoteTypeForURIObject(innerURI, aMultiProcess,
aPreferredRemoteType);
}
return validatedWebRemoteType(aPreferredRemoteType);
}
if (aURL.startsWith("moz-extension:")) {
return useRemoteWebExtensions ? EXTENSION_REMOTE_TYPE : NOT_REMOTE;
}
if (aURL.startsWith("view-source:")) {
return this.getRemoteTypeForURI(aURL.substr("view-source:".length),
aMultiProcess, aPreferredRemoteType);
}
return validatedWebRemoteType(aPreferredRemoteType);
},
shouldLoadURIInThisProcess(aURI) {
let remoteType = Services.appinfo.remoteType;
return remoteType == this.getRemoteTypeForURI(aURI.spec, true, remoteType);
return remoteType == this.getRemoteTypeForURIObject(aURI, true, remoteType);
},
shouldLoadURI(aDocShell, aURI, aReferrer) {

Просмотреть файл

@ -92,7 +92,7 @@ this.ExtensionsUI = {
let info = {
addon,
permissions: addon.userPermissions,
icon: addon.iconURL || DEFAULT_EXTENSION_ICON,
icon: addon.iconURL,
type: "sideload",
};
this.showAddonsManager(browser, info).then(answer => {
@ -101,6 +101,7 @@ this.ExtensionsUI = {
},
showUpdate(browser, info) {
info.icon = info.addon.iconURL;
info.type = "update";
this.showAddonsManager(browser, info).then(answer => {
if (answer) {
@ -268,7 +269,7 @@ this.ExtensionsUI = {
let popupOptions = {
hideClose: true,
popupIconURL: info.icon,
popupIconURL: info.icon || DEFAULT_EXTENSION_ICON,
persistent: true,
eventCallback(topic) {

Просмотреть файл

@ -246,16 +246,11 @@ this.PermissionPromptPrototype = {
* allow or cancel itself based on the user's current
* permission settings without displaying the prompt.
*
* If the <xul:browser> that the request is associated with
* does not belong to a browser window with the PopupNotifications
* global set, the prompt request is ignored.
* If the permission is not already set and the <xul:browser> that the request
* is associated with does not belong to a browser window with the
* PopupNotifications global set, the prompt request is ignored.
*/
prompt() {
let chromeWin = this.browser.ownerGlobal;
if (!chromeWin.PopupNotifications) {
return;
}
// We ignore requests from non-nsIStandardURLs
let requestingURI = this.principal.URI;
if (!(requestingURI instanceof Ci.nsIStandardURL)) {
@ -286,6 +281,12 @@ this.PermissionPromptPrototype = {
.CustomEvent("PermissionStateChange"));
}
let chromeWin = this.browser.ownerGlobal;
if (!chromeWin.PopupNotifications) {
this.cancel();
return;
}
// Transform the PermissionPrompt actions into PopupNotification actions.
let popupNotificationActions = [];
for (let promptAction of this.promptActions) {

Просмотреть файл

@ -252,7 +252,7 @@ this.SitePermissions = {
* @return {boolean} if the URI is supported.
*/
isSupportedURI(uri) {
return uri && (uri.schemeIs("http") || uri.schemeIs("https"));
return uri && ["http", "https", "moz-extension"].includes(uri.scheme);
},
/**

Просмотреть файл

@ -19,11 +19,12 @@ function* getPriority(aBrowser) {
aBrowser = aBrowser.linkedBrowser;
return yield ContentTask.spawn(aBrowser, null, function* () {
return docShell.QueryInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocumentLoader)
.loadGroup
.QueryInterface(Components.interfaces.nsISupportsPriority)
.priority;
return content.document.docShell
.QueryInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocumentLoader)
.loadGroup
.QueryInterface(Components.interfaces.nsISupportsPriority)
.priority;
});
}
@ -32,11 +33,12 @@ function* setPriority(aBrowser, aPriority) {
aBrowser = aBrowser.linkedBrowser;
yield ContentTask.spawn(aBrowser, aPriority, function* (contentPriority) {
docShell.QueryInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocumentLoader)
.loadGroup
.QueryInterface(Ci.nsISupportsPriority)
.priority = contentPriority;
content.document.docShell
.QueryInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocumentLoader)
.loadGroup
.QueryInterface(Ci.nsISupportsPriority)
.priority = contentPriority;
});
}

Просмотреть файл

@ -2,6 +2,8 @@
* 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/. */
/* global addMessageListener:false, sendAsyncMessage:false, XPCOMUtils */
const TEST_MSG = "ContentSearchTest";
const SERVICE_EVENT_TYPE = "ContentSearchService";
const CLIENT_EVENT_TYPE = "ContentSearchClient";
@ -38,8 +40,8 @@ addMessageListener(TEST_MSG, msg => {
function waitForLoadAndStopIt(expectedURL, callback) {
let Ci = Components.interfaces;
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
let webProgress = content.document.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
let listener = {
onStateChange(webProg, req, flags, status) {
if (req instanceof Ci.nsIChannel) {

Просмотреть файл

@ -0,0 +1,94 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
const {utils: Cu, interfaces: Ci} = Components;
Cu.import("resource:///modules/E10SUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
var TEST_PREFERRED_REMOTE_TYPES = [
E10SUtils.WEB_REMOTE_TYPE,
E10SUtils.NOT_REMOTE,
"fakeRemoteType",
]
// These test cases give a nestedURL and a plainURL that should always load in
// the same remote type. By making these tests comparisons, they should work
// with any pref combination.
var TEST_CASES = [
{
nestedURL: "jar:file:///some.file!/",
plainURL: "file:///some.file",
},
{
nestedURL: "jar:jar:file:///some.file!/!/",
plainURL: "file:///some.file",
},
{
nestedURL: "jar:http://some.site/file!/",
plainURL: "http://some.site/file",
},
{
nestedURL: "feed:http://some.site",
plainURL: "http://some.site",
},
{
nestedURL: "pcast:http://some.site",
plainURL: "http://some.site",
},
{
nestedURL: "view-source:http://some.site",
plainURL: "http://some.site",
},
{
nestedURL: "view-source:file:///some.file",
plainURL: "file:///some.file",
},
{
nestedURL: "view-source:about:home",
plainURL: "about:home",
},
{
nestedURL: "view-source:about:robots",
plainURL: "about:robots",
},
{
nestedURL: "view-source:feed:http://some.site",
plainURL: "http://some.site",
},
{
nestedURL: "view-source:pcast:http://some.site",
plainURL: "http://some.site",
},
]
function run_test() {
for (let testCase of TEST_CASES) {
for (let preferredRemoteType of TEST_PREFERRED_REMOTE_TYPES) {
let plainUri = Services.io.newURI(testCase.plainURL);
let plainRemoteType =
E10SUtils.getRemoteTypeForURIObject(plainUri, true, preferredRemoteType);
let nestedUri = Services.io.newURI(testCase.nestedURL);
let nestedRemoteType =
E10SUtils.getRemoteTypeForURIObject(nestedUri, true, preferredRemoteType);
let nestedStr = nestedUri.scheme + ":";
do {
nestedUri = nestedUri.QueryInterface(Ci.nsINestedURI).innerURI;
if (nestedUri.scheme == "about") {
nestedStr += nestedUri.spec;
break;
}
nestedStr += nestedUri.scheme + ":";
} while (nestedUri instanceof Ci.nsINestedURI);
let plainStr = plainUri.scheme == "about" ? plainUri.spec
: plainUri.scheme + ":";
equal(nestedRemoteType, plainRemoteType,
`Check that ${nestedStr} loads in same remote type as ${plainStr}`
+ ` with preferred remote type: ${preferredRemoteType}`);
}
}
}

Просмотреть файл

@ -6,5 +6,6 @@ skip-if = toolkit == 'android'
[test_AttributionCode.js]
skip-if = os != 'win'
[test_DirectoryLinksProvider.js]
[test_E10SUtils_nested_URIs.js]
[test_SitePermissions.js]
[test_LaterRun.js]

Просмотреть файл

@ -109,6 +109,7 @@ def rust_triple_alias(host_or_target):
# NetBSD
('x86_64', 'NetBSD'): 'x86_64-unknown-netbsd',
# OpenBSD
('x86', 'OpenBSD'): 'i686-unknown-openbsd',
('x86_64', 'OpenBSD'): 'x86_64-unknown-openbsd',
# Linux
('x86', 'Linux'): 'i686-unknown-linux-gnu',

Просмотреть файл

@ -139,7 +139,7 @@ CopyURIs(const InfallibleTArray<URIParams>& aDomains, nsIDomainSet* aSet)
}
void
DomainPolicy::ApplyClone(DomainPolicyClone* aClone)
DomainPolicy::ApplyClone(const DomainPolicyClone* aClone)
{
CopyURIs(aClone->blacklist(), mBlacklist);
CopyURIs(aClone->whitelist(), mWhitelist);

Просмотреть файл

@ -17,6 +17,7 @@ class DomainPolicyClone;
%}
[ptr] native DomainPolicyClonePtr(mozilla::dom::DomainPolicyClone);
[ptr] native DomainPolicyCloneConstPtr(const mozilla::dom::DomainPolicyClone);
/*
* When a domain policy is instantiated by invoking activateDomainPolicy() on
@ -41,7 +42,7 @@ interface nsIDomainPolicy : nsISupports
void deactivate();
[noscript, notxpcom] void cloneDomainPolicy(in DomainPolicyClonePtr aClone);
[noscript, notxpcom] void applyClone(in DomainPolicyClonePtr aClone);
[noscript, notxpcom] void applyClone(in DomainPolicyCloneConstPtr aClone);
};
[scriptable, builtinclass, uuid(665c981b-0a0f-4229-ac06-a826e02d4f69)]

Просмотреть файл

@ -489,6 +489,7 @@ gdk/gdkkeysyms.h
gdk/gdkprivate.h
gdk/gdkx.h
gdk/gdkdirectfb.h
gdk/gdkwayland.h
gdk-pixbuf/gdk-pixbuf.h
Gestalt.h
getopt.h

Просмотреть файл

@ -111,6 +111,7 @@ registerCleanupFunction(function* cleanup() {
* @param {Object} options Object with various optional fields:
* - {Boolean} background If true, open the tab in background
* - {ChromeWindow} window Firefox top level window we should use to open the tab
* - {Number} userContextId The userContextId of the tab.
* @return a promise that resolves to the tab object when the url is loaded
*/
var addTab = Task.async(function* (url, options = { background: false, window: window }) {
@ -118,8 +119,9 @@ var addTab = Task.async(function* (url, options = { background: false, window: w
let { background } = options;
let { gBrowser } = options.window ? options.window : window;
let { userContextId } = options;
let tab = gBrowser.addTab(url);
let tab = gBrowser.addTab(url, {userContextId});
if (!background) {
gBrowser.selectedTab = tab;
}

Просмотреть файл

@ -59,9 +59,9 @@ exports.viewSourceInDebugger = Task.async(function* (toolbox, sourceURL, sourceL
// New debugger frontend
if (Services.prefs.getBoolPref("devtools.debugger.new-debugger-frontend")) {
yield toolbox.selectTool("jsdebugger");
const source = dbg._selectors().getSourceByURL(dbg._getState(), sourceURL);
if (source) {
yield toolbox.selectTool("jsdebugger");
dbg._actions().selectSourceURL(sourceURL, { line: sourceLine });
return true;
}

Просмотреть файл

@ -9,18 +9,23 @@ support-files =
storage-idb-delete-blocked.html
storage-indexeddb-duplicate-names.html
storage-listings.html
storage-listings-usercontextid.html
storage-listings-with-fragment.html
storage-localstorage.html
storage-overflow.html
storage-search.html
storage-secured-iframe.html
storage-secured-iframe-usercontextid.html
storage-sessionstorage.html
storage-unsecured-iframe.html
storage-unsecured-iframe-usercontextid.html
storage-updates.html
head.js
!/devtools/client/framework/test/shared-head.js
[browser_storage_basic.js]
[browser_storage_basic_usercontextid.js]
tags = usercontextid
[browser_storage_basic_with_fragment.js]
[browser_storage_cache_delete.js]
[browser_storage_cache_error.js]
@ -32,6 +37,8 @@ support-files =
[browser_storage_delete.js]
[browser_storage_delete_all.js]
[browser_storage_delete_tree.js]
[browser_storage_delete_usercontextid.js]
tags = usercontextid
[browser_storage_dom_cache_disabled.js]
[browser_storage_dynamic_updates_cookies.js]
[browser_storage_dynamic_updates_localStorage.js]

Просмотреть файл

@ -0,0 +1,184 @@
/* 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/. */
// A test to check that the storage inspector is working correctly with
// userContextId.
"use strict";
const testCases = [
[
["cookies", "http://test1.example.org"],
[
getCookieId("c1", "test1.example.org", "/browser"),
getCookieId("cs2", ".example.org", "/"),
getCookieId("c3", "test1.example.org", "/"),
getCookieId("uc1", ".example.org", "/")
]
],
[
["cookies", "https://sectest1.example.org"],
[
getCookieId("uc1", ".example.org", "/"),
getCookieId("cs2", ".example.org", "/"),
getCookieId("sc1", "sectest1.example.org", "/browser/devtools/client/storage/test/")
]
],
[["localStorage", "http://test1.example.org"],
["ls1", "ls2"]],
[["localStorage", "http://sectest1.example.org"],
["iframe-u-ls1"]],
[["localStorage", "https://sectest1.example.org"],
["iframe-s-ls1"]],
[["sessionStorage", "http://test1.example.org"],
["ss1"]],
[["sessionStorage", "http://sectest1.example.org"],
["iframe-u-ss1", "iframe-u-ss2"]],
[["sessionStorage", "https://sectest1.example.org"],
["iframe-s-ss1"]],
[["indexedDB", "http://test1.example.org"],
["idb1 (default)", "idb2 (default)"]],
[["indexedDB", "http://test1.example.org", "idb1 (default)"],
["obj1", "obj2"]],
[["indexedDB", "http://test1.example.org", "idb2 (default)"],
["obj3"]],
[["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
[1, 2, 3]],
[["indexedDB", "http://test1.example.org", "idb1 (default)", "obj2"],
[1]],
[["indexedDB", "http://test1.example.org", "idb2 (default)", "obj3"],
[]],
[["indexedDB", "http://sectest1.example.org"],
[]],
[["indexedDB", "https://sectest1.example.org"],
["idb-s1 (default)", "idb-s2 (default)"]],
[["indexedDB", "https://sectest1.example.org", "idb-s1 (default)"],
["obj-s1"]],
[["indexedDB", "https://sectest1.example.org", "idb-s2 (default)"],
["obj-s2"]],
[["indexedDB", "https://sectest1.example.org", "idb-s1 (default)", "obj-s1"],
[6, 7]],
[["indexedDB", "https://sectest1.example.org", "idb-s2 (default)", "obj-s2"],
[16]],
[["Cache", "http://test1.example.org", "plop"],
[MAIN_DOMAIN + "404_cached_file.js",
MAIN_DOMAIN + "browser_storage_basic.js"]],
];
const testCasesUserContextId = [
[
["cookies", "http://test1.example.org"],
[
getCookieId("c1uc1", "test1.example.org", "/browser"),
getCookieId("cs2uc1", ".example.org", "/"),
getCookieId("c3uc1", "test1.example.org", "/"),
getCookieId("uc1uc1", ".example.org", "/")
]
],
[
["cookies", "https://sectest1.example.org"],
[
getCookieId("uc1uc1", ".example.org", "/"),
getCookieId("cs2uc1", ".example.org", "/"),
getCookieId("sc1uc1", "sectest1.example.org",
"/browser/devtools/client/storage/test/")
]
],
[["localStorage", "http://test1.example.org"],
["ls1uc1", "ls2uc1"]],
[["localStorage", "http://sectest1.example.org"],
["iframe-u-ls1uc1"]],
[["localStorage", "https://sectest1.example.org"],
["iframe-s-ls1uc1"]],
[["sessionStorage", "http://test1.example.org"],
["ss1uc1"]],
[["sessionStorage", "http://sectest1.example.org"],
["iframe-u-ss1uc1", "iframe-u-ss2uc1"]],
[["sessionStorage", "https://sectest1.example.org"],
["iframe-s-ss1uc1"]],
[["indexedDB", "http://test1.example.org"],
["idb1uc1 (default)", "idb2uc1 (default)"]],
[["indexedDB", "http://test1.example.org", "idb1uc1 (default)"],
["obj1uc1", "obj2uc1"]],
[["indexedDB", "http://test1.example.org", "idb2uc1 (default)"],
["obj3uc1"]],
[["indexedDB", "http://test1.example.org", "idb1uc1 (default)", "obj1uc1"],
[1, 2, 3]],
[["indexedDB", "http://test1.example.org", "idb1uc1 (default)", "obj2uc1"],
[1]],
[["indexedDB", "http://test1.example.org", "idb2uc1 (default)", "obj3uc1"],
[]],
[["indexedDB", "http://sectest1.example.org"],
[]],
[["indexedDB", "https://sectest1.example.org"],
["idb-s1uc1 (default)", "idb-s2uc1 (default)"]],
[["indexedDB", "https://sectest1.example.org", "idb-s1uc1 (default)"],
["obj-s1uc1"]],
[["indexedDB", "https://sectest1.example.org", "idb-s2uc1 (default)"],
["obj-s2uc1"]],
[["indexedDB", "https://sectest1.example.org", "idb-s1uc1 (default)", "obj-s1uc1"],
[6, 7]],
[["indexedDB", "https://sectest1.example.org", "idb-s2uc1 (default)", "obj-s2uc1"],
[16]],
[["Cache", "http://test1.example.org", "plopuc1"],
[MAIN_DOMAIN + "404_cached_file.js",
MAIN_DOMAIN + "browser_storage_basic.js"]],
];
/**
* Test that the desired number of tree items are present
*/
function testTree(tests) {
let doc = gPanelWindow.document;
for (let [item] of tests) {
ok(doc.querySelector("[data-id='" + JSON.stringify(item) + "']"),
"Tree item " + item[0] + " should be present in the storage tree");
}
}
/**
* Test that correct table entries are shown for each of the tree item
*/
function* testTables(tests) {
let doc = gPanelWindow.document;
// Expand all nodes so that the synthesized click event actually works
gUI.tree.expandAll();
// First tree item is already selected so no clicking and waiting for update
for (let id of tests[0][1]) {
ok(doc.querySelector(".table-widget-cell[data-id='" + id + "']"),
"Table item " + id + " should be present");
}
// Click rest of the tree items and wait for the table to be updated
for (let [treeItem, items] of tests.slice(1)) {
yield selectTreeItem(treeItem);
// Check whether correct number of items are present in the table
is(doc.querySelectorAll(
".table-widget-wrapper:first-of-type .table-widget-cell"
).length, items.length, "Number of items in table is correct");
// Check if all the desired items are present in the table
for (let id of items) {
ok(doc.querySelector(".table-widget-cell[data-id='" + id + "']"),
"Table item " + id + " should be present");
}
}
}
add_task(function* () {
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
testTree(testCases);
yield testTables(testCases);
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings-usercontextid.html",
{userContextId: 1});
testTree(testCasesUserContextId);
yield testTables(testCasesUserContextId);
yield finishTests();
});

Просмотреть файл

@ -0,0 +1,174 @@
/* 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/. */
/* import-globals-from ../../framework/test/shared-head.js */
"use strict";
// Test deleting storage items with userContextId.
// The items that will be deleted.
const TEST_CASES = [
[["localStorage", "http://test1.example.org"],
"ls1", "name"],
[["sessionStorage", "http://test1.example.org"],
"ss1", "name"],
[
["cookies", "http://test1.example.org"],
getCookieId("c1", "test1.example.org", "/browser"), "name"
],
[["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
1, "name"],
[["Cache", "http://test1.example.org", "plop"],
MAIN_DOMAIN + "404_cached_file.js", "url"],
];
// The storage items that should exist for default userContextId
const storageItemsForDefault = [
[
["cookies", "http://test1.example.org"],
[
getCookieId("c1", "test1.example.org", "/browser"),
getCookieId("cs2", ".example.org", "/"),
getCookieId("c3", "test1.example.org", "/"),
getCookieId("uc1", ".example.org", "/")
]
],
[
["cookies", "https://sectest1.example.org"],
[
getCookieId("uc1", ".example.org", "/"),
getCookieId("cs2", ".example.org", "/"),
getCookieId("sc1", "sectest1.example.org", "/browser/devtools/client/storage/test/")
]
],
[["localStorage", "http://test1.example.org"],
["ls1", "ls2"]],
[["localStorage", "http://sectest1.example.org"],
["iframe-u-ls1"]],
[["localStorage", "https://sectest1.example.org"],
["iframe-s-ls1"]],
[["sessionStorage", "http://test1.example.org"],
["ss1"]],
[["sessionStorage", "http://sectest1.example.org"],
["iframe-u-ss1", "iframe-u-ss2"]],
[["sessionStorage", "https://sectest1.example.org"],
["iframe-s-ss1"]],
[["indexedDB", "http://test1.example.org"],
["idb1 (default)", "idb2 (default)"]],
[["indexedDB", "http://test1.example.org", "idb1 (default)"],
["obj1", "obj2"]],
[["indexedDB", "http://test1.example.org", "idb2 (default)"],
["obj3"]],
[["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
[1, 2, 3]],
[["indexedDB", "http://test1.example.org", "idb1 (default)", "obj2"],
[1]],
[["indexedDB", "http://test1.example.org", "idb2 (default)", "obj3"],
[]],
[["indexedDB", "http://sectest1.example.org"],
[]],
[["indexedDB", "https://sectest1.example.org"],
["idb-s1 (default)", "idb-s2 (default)"]],
[["indexedDB", "https://sectest1.example.org", "idb-s1 (default)"],
["obj-s1"]],
[["indexedDB", "https://sectest1.example.org", "idb-s2 (default)"],
["obj-s2"]],
[["indexedDB", "https://sectest1.example.org", "idb-s1 (default)", "obj-s1"],
[6, 7]],
[["indexedDB", "https://sectest1.example.org", "idb-s2 (default)", "obj-s2"],
[16]],
[["Cache", "http://test1.example.org", "plop"],
[MAIN_DOMAIN + "404_cached_file.js",
MAIN_DOMAIN + "browser_storage_basic.js"]],
];
/**
* Test that the desired number of tree items are present
*/
function testTree(tests) {
let doc = gPanelWindow.document;
for (let [item] of tests) {
ok(doc.querySelector("[data-id='" + JSON.stringify(item) + "']"),
"Tree item " + item[0] + " should be present in the storage tree");
}
}
/**
* Test that correct table entries are shown for each of the tree item
*/
function* testTables(tests) {
let doc = gPanelWindow.document;
// Expand all nodes so that the synthesized click event actually works
gUI.tree.expandAll();
// First tree item is already selected so no clicking and waiting for update
for (let id of tests[0][1]) {
ok(doc.querySelector(".table-widget-cell[data-id='" + id + "']"),
"Table item " + id + " should be present");
}
// Click rest of the tree items and wait for the table to be updated
for (let [treeItem, items] of tests.slice(1)) {
yield selectTreeItem(treeItem);
// Check whether correct number of items are present in the table
is(doc.querySelectorAll(
".table-widget-wrapper:first-of-type .table-widget-cell"
).length, items.length, "Number of items in table is correct");
// Check if all the desired items are present in the table
for (let id of items) {
ok(doc.querySelector(".table-widget-cell[data-id='" + id + "']"),
"Table item " + id + " should be present");
}
}
}
add_task(function* () {
// First, open a tab with the default userContextId and setup its storages.
let tabDefault = yield openTab(MAIN_DOMAIN + "storage-listings.html");
// Second, start testing for userContextId 1.
// We use the same item name as the default page has to see deleting items
// from userContextId 1 will affect default one or not.
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html", {userContextId: 1});
let contextMenu = gPanelWindow.document.getElementById("storage-table-popup");
let menuDeleteItem = contextMenu.querySelector("#storage-table-popup-delete");
for (let [ treeItem, rowName, cellToClick] of TEST_CASES) {
let treeItemName = treeItem.join(" > ");
info(`Selecting tree item ${treeItemName}`);
yield selectTreeItem(treeItem);
let row = getRowCells(rowName);
ok(gUI.table.items.has(rowName), `There is a row '${rowName}' in ${treeItemName}`);
let eventWait = gUI.once("store-objects-updated");
yield waitForContextMenu(contextMenu, row[cellToClick], () => {
info(`Opened context menu in ${treeItemName}, row '${rowName}'`);
menuDeleteItem.click();
let truncatedRowName = String(rowName).replace(SEPARATOR_GUID, "-").substr(0, 16);
ok(menuDeleteItem.getAttribute("label").includes(truncatedRowName),
`Context menu item label contains '${rowName}' (maybe truncated)`);
});
yield eventWait;
ok(!gUI.table.items.has(rowName),
`There is no row '${rowName}' in ${treeItemName} after deletion`);
}
// Final, we see that the default tab is intact or not.
yield BrowserTestUtils.switchTab(gBrowser, tabDefault);
yield openStoragePanel();
testTree(storageItemsForDefault);
yield testTables(storageItemsForDefault);
yield finishTests();
});

Просмотреть файл

@ -49,16 +49,15 @@ registerCleanupFunction(() => {
/**
* This generator function opens the given url in a new tab, then sets up the
* page by waiting for all cookies, indexedDB items etc. to be created; Then
* opens the storage inspector and waits for the storage tree and table to be
* populated.
* page by waiting for all cookies, indexedDB items etc.
*
* @param url {String} The url to be opened in the new tab
* @param options {Object} The tab options for the new tab
*
* @return {Promise} A promise that resolves after storage inspector is ready
* @return {Promise} A promise that resolves after the tab is ready
*/
function* openTabAndSetupStorage(url) {
let tab = yield addTab(url);
function* openTab(url, options = {}) {
let tab = yield addTab(url, options);
let content = tab.linkedBrowser.contentWindow;
gWindow = content.wrappedJSObject;
@ -108,6 +107,24 @@ function* openTabAndSetupStorage(url) {
}
});
return tab;
}
/**
* This generator function opens the given url in a new tab, then sets up the
* page by waiting for all cookies, indexedDB items etc. to be created; Then
* opens the storage inspector and waits for the storage tree and table to be
* populated.
*
* @param url {String} The url to be opened in the new tab
* @param options {Object} The tab options for the new tab
*
* @return {Promise} A promise that resolves after storage inspector is ready
*/
function* openTabAndSetupStorage(url, options = {}) {
// open tab
yield openTab(url, options);
// open storage inspector
return yield openStoragePanel();
}
@ -204,46 +221,50 @@ function forceCollections() {
function* finishTests() {
// Bug 1233497 makes it so that we can no longer yield CPOWs from Tasks.
// We work around this by calling clear() via a ContentTask instead.
yield ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
/**
* Get all windows including frames recursively.
*
* @param {Window} [baseWindow]
* The base window at which to start looking for child windows
* (optional).
* @return {Set}
* A set of windows.
*/
function getAllWindows(baseWindow) {
let windows = new Set();
while (gBrowser.tabs.length > 1) {
yield ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
/**
* Get all windows including frames recursively.
*
* @param {Window} [baseWindow]
* The base window at which to start looking for child windows
* (optional).
* @return {Set}
* A set of windows.
*/
function getAllWindows(baseWindow) {
let windows = new Set();
let _getAllWindows = function (win) {
windows.add(win.wrappedJSObject);
let _getAllWindows = function (win) {
windows.add(win.wrappedJSObject);
for (let i = 0; i < win.length; i++) {
_getAllWindows(win[i]);
for (let i = 0; i < win.length; i++) {
_getAllWindows(win[i]);
}
};
_getAllWindows(baseWindow);
return windows;
}
let windows = getAllWindows(content);
for (let win of windows) {
// Some windows (e.g., about: URLs) don't have storage available
try {
win.localStorage.clear();
win.sessionStorage.clear();
} catch (ex) {
// ignore
}
};
_getAllWindows(baseWindow);
return windows;
}
let windows = getAllWindows(content);
for (let win of windows) {
// Some windows (e.g., about: URLs) don't have storage available
try {
win.localStorage.clear();
win.sessionStorage.clear();
} catch (ex) {
// ignore
if (win.clear) {
yield win.clear();
}
}
});
if (win.clear) {
yield win.clear();
}
}
});
yield closeTabAndToolbox(gBrowser.selectedTab);
}
Services.cookies.removeAll();
forceCollections();

Просмотреть файл

@ -0,0 +1,131 @@
<!DOCTYPE HTML>
<html>
<!--
Storage inspector front end for userContextId - tests
-->
<head>
<meta charset="utf-8">
<title>Storage inspector test for listing hosts and storages</title>
</head>
<body>
<iframe src="http://sectest1.example.org/browser/devtools/client/storage/test/storage-unsecured-iframe-usercontextid.html"></iframe>
<iframe src="https://sectest1.example.org:443/browser/devtools/client/storage/test/storage-secured-iframe-usercontextid.html"></iframe>
<script type="application/javascript;version=1.7">
"use strict";
let partialHostname = location.hostname.match(/^[^.]+(\..*)$/)[1];
let cookieExpiresTime1 = 2000000000000;
let cookieExpiresTime2 = 2000000001000;
// Setting up some cookies to eat.
document.cookie = "c1uc1=foobar; expires=" +
new Date(cookieExpiresTime1).toGMTString() + "; path=/browser";
document.cookie = "cs2uc1=sessionCookie; path=/; domain=" + partialHostname;
document.cookie = "c3uc1=foobar-2; expires=" +
new Date(cookieExpiresTime2).toGMTString() + "; path=/";
// ... and some local storage items ..
localStorage.setItem("ls1uc1", "foobar");
localStorage.setItem("ls2uc1", "foobar-2");
// ... and finally some session storage items too
sessionStorage.setItem("ss1uc1", "foobar-3");
dump("added cookies and storage from main page\n");
let idbGenerator = async function() {
let request = indexedDB.open("idb1uc1", 1);
request.onerror = function() {
throw new Error("error opening db connection");
};
let db = await new Promise(done => {
request.onupgradeneeded = event => {
let db = event.target.result;
let store1 = db.createObjectStore("obj1uc1", { keyPath: "id" });
store1.createIndex("name", "name", { unique: false });
store1.createIndex("email", "email", { unique: true });
let store2 = db.createObjectStore("obj2uc1", { keyPath: "id2" });
store1.transaction.oncomplete = () => {
done(db);
};
};
});
// Prevents AbortError
await new Promise(done => {
request.onsuccess = done;
});
let transaction = db.transaction(["obj1uc1", "obj2uc1"], "readwrite");
let store1 = transaction.objectStore("obj1uc1");
let store2 = transaction.objectStore("obj2uc1");
store1.add({id: 1, name: "foo", email: "foo@bar.com"});
store1.add({id: 2, name: "foo2", email: "foo2@bar.com"});
store1.add({id: 3, name: "foo2", email: "foo3@bar.com"});
store2.add({
id2: 1,
name: "foo",
email: "foo@bar.com",
extra: "baz"
});
// Prevents AbortError during close()
await new Promise(success => {
transaction.oncomplete = success;
});
db.close();
request = indexedDB.open("idb2uc1", 1);
let db2 = await new Promise(done => {
request.onupgradeneeded = event => {
let db2 = event.target.result;
let store3 = db2.createObjectStore("obj3uc1", { keyPath: "id3" });
store3.createIndex("name2", "name2", { unique: true });
store3.transaction.oncomplete = () => {
done(db2);
}
};
});
// Prevents AbortError during close()
await new Promise(done => {
request.onsuccess = done;
});
db2.close();
dump("added indexedDB from main page\n");
};
function deleteDB(dbName) {
return new Promise(resolve => {
dump("removing database " + dbName + " from " + document.location + "\n");
indexedDB.deleteDatabase(dbName).onsuccess = resolve;
});
}
async function fetchPut(cache, url) {
let response = await fetch(url);
await cache.put(url, response);
}
let cacheGenerator = async function() {
let cache = await caches.open("plopuc1");
await fetchPut(cache, "404_cached_file.js");
await fetchPut(cache, "browser_storage_basic.js");
};
window.setup = function*() {
yield idbGenerator();
if (window.caches) {
yield cacheGenerator();
}
};
window.clear = function*() {
yield deleteDB("idb1uc1");
yield deleteDB("idb2uc1");
if (window.caches) {
yield caches.delete("plopuc1");
}
dump("removed indexedDB and cache data from " + document.location + "\n");
};
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,91 @@
<!DOCTYPE HTML>
<html>
<!--
Iframe for testing multiple host detetion in storage actor
-->
<head>
<meta charset="utf-8">
</head>
<body>
<script type="application/javascript;version=1.7">
"use strict";
document.cookie = "sc1uc1=foobar;";
localStorage.setItem("iframe-s-ls1uc1", "foobar");
sessionStorage.setItem("iframe-s-ss1uc1", "foobar-2");
dump("added cookies and storage from secured iframe\n");
let idbGenerator = function*() {
let request = indexedDB.open("idb-s1uc1", 1);
request.onerror = function() {
throw new Error("error opening db connection");
};
let db = yield new Promise(done => {
request.onupgradeneeded = event => {
let db = event.target.result;
let store1 = db.createObjectStore("obj-s1uc1", { keyPath: "id" });
store1.transaction.oncomplete = () => {
done(db);
};
};
});
yield new Promise(done => {
request.onsuccess = done;
});
let transaction = db.transaction(["obj-s1uc1"], "readwrite");
let store1 = transaction.objectStore("obj-s1uc1");
store1.add({id: 6, name: "foo", email: "foo@bar.com"});
store1.add({id: 7, name: "foo2", email: "foo2@bar.com"});
yield new Promise(success => {
transaction.oncomplete = success;
});
db.close();
request = indexedDB.open("idb-s2uc1", 1);
let db2 = yield new Promise(done => {
request.onupgradeneeded = event => {
let db2 = event.target.result;
let store3 =
db2.createObjectStore("obj-s2uc1", { keyPath: "id3", autoIncrement: true });
store3.createIndex("name2", "name2", { unique: true });
store3.transaction.oncomplete = () => {
done(db2);
};
};
});
yield new Promise(done => {
request.onsuccess = done;
});
transaction = db2.transaction(["obj-s2uc1"], "readwrite");
let store3 = transaction.objectStore("obj-s2uc1");
store3.add({id3: 16, name2: "foo", email: "foo@bar.com"});
yield new Promise(success => {
transaction.oncomplete = success;
});
db2.close();
dump("added indexedDB from secured iframe\n");
};
function deleteDB(dbName) {
return new Promise(resolve => {
dump("removing database " + dbName + " from " + document.location + "\n");
indexedDB.deleteDatabase(dbName).onsuccess = resolve;
});
}
window.setup = function*() {
yield idbGenerator();
};
window.clear = function*() {
yield deleteDB("idb-s1uc1");
yield deleteDB("idb-s2uc1");
dump("removed indexedDB data from " + document.location + "\n");
};
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,19 @@
<!DOCTYPE HTML>
<html>
<!--
Iframe for testing multiple host detetion in storage actor
-->
<head>
<meta charset="utf-8">
</head>
<body>
<script>
"use strict";
document.cookie = "uc1uc1=foobar; domain=.example.org; path=/";
localStorage.setItem("iframe-u-ls1uc1", "foobar");
sessionStorage.setItem("iframe-u-ss1uc1", "foobar1");
sessionStorage.setItem("iframe-u-ss2uc1", "foobar2");
dump("added cookies and storage from unsecured iframe\n");
</script>
</body>
</html>

Просмотреть файл

@ -37,6 +37,7 @@ const FilterButton = createClass({
}
return dom.button({
"aria-pressed": active === true,
className: classList.join(" "),
onClick: this.onClick
}, label);

Просмотреть файл

@ -20,7 +20,8 @@ describe("FilterButton component:", () => {
it("displays as active when turned on", () => {
const wrapper = render(FilterButton(props));
expect(wrapper.html()).toBe(
"<button class=\"menu-filter-button error checked\">Error</button>"
"<button aria-pressed=\"true\" class=\"menu-filter-button error checked\">" +
"Error</button>"
);
});
@ -28,7 +29,7 @@ describe("FilterButton component:", () => {
const inactiveProps = Object.assign({}, props, { active: false });
const wrapper = render(FilterButton(inactiveProps));
expect(wrapper.html()).toBe(
"<button class=\"menu-filter-button error\">Error</button>"
"<button aria-pressed=\"false\" class=\"menu-filter-button error\">Error</button>"
);
});
});

Просмотреть файл

@ -1219,8 +1219,12 @@ StorageActors.createActor({
}, {
getCachesForHost: Task.async(function* (host) {
let uri = Services.io.newURI(host);
let attrs = this.storageActor
.document
.nodePrincipal
.originAttributes;
let principal =
Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
Services.scriptSecurityManager.createCodebasePrincipal(uri, attrs);
// The first argument tells if you want to get |content| cache or |chrome|
// cache.
@ -1664,11 +1668,11 @@ StorageActors.createActor({
populateStoresForHost: Task.async(function* (host) {
let storeMap = new Map();
let {names} = yield this.getDBNamesForHost(host);
let win = this.storageActor.getWindowFromHost(host);
if (win) {
let principal = win.document.nodePrincipal;
let {names} = yield this.getDBNamesForHost(host, principal);
for (let {name, storage} of names) {
let metadata = yield this.getDBMetaData(host, principal, name, storage);
@ -2025,8 +2029,8 @@ var indexedDBHelpers = {
/**
* Fetches all the databases and their metadata for the given `host`.
*/
getDBNamesForHost: Task.async(function* (host) {
let sanitizedHost = this.getSanitizedHost(host);
getDBNamesForHost: Task.async(function* (host, principal) {
let sanitizedHost = this.getSanitizedHost(host) + principal.originSuffix;
let profileDir = OS.Constants.Path.profileDir;
let files = [];
let names = [];
@ -2363,8 +2367,8 @@ var indexedDBHelpers = {
return indexedDBHelpers.splitNameAndStorage(name);
}
case "getDBNamesForHost": {
let [host] = args;
return indexedDBHelpers.getDBNamesForHost(host);
let [host, principal] = args;
return indexedDBHelpers.getDBNamesForHost(host, principal);
}
case "getValuesForHost": {
let [host, name, options, hostVsStores, principal] = args;

Просмотреть файл

@ -3,6 +3,10 @@
"use strict";
/* exported Cr, CC, NetUtil, defer, errorCount, initTestDebuggerServer,
writeTestTempFile, socket_transport, local_transport, really_long
*/
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
@ -17,7 +21,6 @@ const defer = require("devtools/shared/defer");
const { Task } = require("devtools/shared/task");
const Services = require("Services");
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
// We do not want to log packets by default, because in some tests,
// we can be sending large amounts of data. The test harness has
@ -31,27 +34,21 @@ Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true);
const { DebuggerServer } = require("devtools/server/main");
const { DebuggerClient } = require("devtools/shared/client/main");
function testExceptionHook(ex) {
try {
do_report_unexpected_exception(ex);
} catch (ex) {
return {throw: ex};
}
return undefined;
}
// Convert an nsIScriptError 'aFlags' value into an appropriate string.
function scriptErrorFlagsToKind(aFlags) {
var kind;
if (aFlags & Ci.nsIScriptError.warningFlag)
// Convert an nsIScriptError 'flags' value into an appropriate string.
function scriptErrorFlagsToKind(flags) {
let kind;
if (flags & Ci.nsIScriptError.warningFlag) {
kind = "warning";
if (aFlags & Ci.nsIScriptError.exceptionFlag)
}
if (flags & Ci.nsIScriptError.exceptionFlag) {
kind = "exception";
else
} else {
kind = "error";
}
if (aFlags & Ci.nsIScriptError.strictFlag)
if (flags & Ci.nsIScriptError.strictFlag) {
kind = "strict " + kind;
}
return kind;
}
@ -60,23 +57,24 @@ function scriptErrorFlagsToKind(aFlags) {
// into the ether.
var errorCount = 0;
var listener = {
observe: function (aMessage) {
observe: function (message) {
errorCount++;
let string = "";
try {
// If we've been given an nsIScriptError, then we can print out
// something nicely formatted, for tools like Emacs to pick up.
var scriptError = aMessage.QueryInterface(Ci.nsIScriptError);
dump(aMessage.sourceName + ":" + aMessage.lineNumber + ": " +
scriptErrorFlagsToKind(aMessage.flags) + ": " +
aMessage.errorMessage + "\n");
var string = aMessage.errorMessage;
message.QueryInterface(Ci.nsIScriptError);
dump(message.sourceName + ":" + message.lineNumber + ": " +
scriptErrorFlagsToKind(message.flags) + ": " +
message.errorMessage + "\n");
string = message.errorMessage;
} catch (x) {
// Be a little paranoid with message, as the whole goal here is to lose
// no information.
try {
var string = "" + aMessage.message;
} catch (x) {
var string = "<error converting error message to string>";
string = message.message;
} catch (e) {
string = "<error converting error message to string>";
}
}
@ -86,7 +84,7 @@ var listener = {
}
// Throw in most cases, but ignore the "strict" messages
if (!(aMessage.flags & Ci.nsIScriptError.strictFlag)) {
if (!(message.flags & Ci.nsIScriptError.strictFlag)) {
do_throw("head_dbg.js got console message: " + string + "\n");
}
}
@ -96,80 +94,6 @@ var consoleService = Cc["@mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService);
consoleService.registerListener(listener);
function check_except(func) {
try {
func();
} catch (e) {
do_check_true(true);
return;
}
dump("Should have thrown an exception: " + func.toString());
do_check_true(false);
}
function testGlobal(aName) {
let systemPrincipal = Cc["@mozilla.org/systemprincipal;1"]
.createInstance(Ci.nsIPrincipal);
let sandbox = Cu.Sandbox(systemPrincipal);
sandbox.__name = aName;
return sandbox;
}
function addTestGlobal(aName)
{
let global = testGlobal(aName);
DebuggerServer.addTestGlobal(global);
return global;
}
// List the DebuggerClient |aClient|'s tabs, look for one whose title is
// |aTitle|, and apply |aCallback| to the packet's entry for that tab.
function getTestTab(aClient, aTitle, aCallback) {
aClient.listTabs(function (aResponse) {
for (let tab of aResponse.tabs) {
if (tab.title === aTitle) {
aCallback(tab);
return;
}
}
aCallback(null);
});
}
// Attach to |aClient|'s tab whose title is |aTitle|; pass |aCallback| the
// response packet and a TabClient instance referring to that tab.
function attachTestTab(aClient, aTitle, aCallback) {
getTestTab(aClient, aTitle, function (aTab) {
aClient.attachTab(aTab.actor, aCallback);
});
}
// Attach to |aClient|'s tab whose title is |aTitle|, and then attach to
// that tab's thread. Pass |aCallback| the thread attach response packet, a
// TabClient referring to the tab, and a ThreadClient referring to the
// thread.
function attachTestThread(aClient, aTitle, aCallback) {
attachTestTab(aClient, aTitle, function (aResponse, aTabClient) {
function onAttach(aResponse, aThreadClient) {
aCallback(aResponse, aTabClient, aThreadClient);
}
aTabClient.attachThread({ useSourceMaps: true }, onAttach);
});
}
// Attach to |aClient|'s tab whose title is |aTitle|, attach to the tab's
// thread, and then resume it. Pass |aCallback| the thread's response to
// the 'resume' packet, a TabClient for the tab, and a ThreadClient for the
// thread.
function attachTestTabAndResume(aClient, aTitle, aCallback) {
attachTestThread(aClient, aTitle, function (aResponse, aTabClient, aThreadClient) {
aThreadClient.resume(function (aResponse) {
aCallback(aResponse, aTabClient, aThreadClient);
});
});
}
/**
* Initialize the testing debugger server.
*/
@ -184,35 +108,6 @@ function initTestDebuggerServer() {
DebuggerServer.init();
}
function finishClient(aClient) {
aClient.close().then(function () {
do_test_finished();
});
}
/**
* Takes a relative file path and returns the absolute file url for it.
*/
function getFileUrl(aName, aAllowMissing = false) {
let file = do_get_file(aName, aAllowMissing);
return Services.io.newFileURI(file).spec;
}
/**
* Returns the full path of the file with the specified name in a
* platform-independent and URL-like form.
*/
function getFilePath(aName, aAllowMissing = false) {
let file = do_get_file(aName, aAllowMissing);
let path = Services.io.newFileURI(file).spec;
let filePrePath = "file://";
if ("nsILocalFileWin" in Ci &&
file instanceof Ci.nsILocalFileWin) {
filePrePath += "/";
}
return path.slice(filePrePath.length);
}
/**
* Wrapper around do_get_file to prefix files with the name of current test to
* avoid collisions when running in parallel.
@ -224,16 +119,16 @@ function getTestTempFile(fileName, allowMissing) {
return do_get_file(fileName + "-" + thisTest, allowMissing);
}
function writeTestTempFile(aFileName, aContent) {
let file = getTestTempFile(aFileName, true);
function writeTestTempFile(fileName, content) {
let file = getTestTempFile(fileName, true);
let stream = Cc["@mozilla.org/network/file-output-stream;1"]
.createInstance(Ci.nsIFileOutputStream);
stream.init(file, -1, -1, 0);
try {
do {
let numWritten = stream.write(aContent, aContent.length);
aContent = aContent.slice(numWritten);
} while (aContent.length > 0);
let numWritten = stream.write(content, content.length);
content = content.slice(numWritten);
} while (content.length > 0);
} finally {
stream.close();
}
@ -248,10 +143,10 @@ var socket_transport = Task.async(function* () {
authenticator.allowConnection = () => {
return DebuggerServer.AuthenticationResult.ALLOW;
};
let listener = DebuggerServer.createListener();
listener.portOrPath = -1;
listener.authenticator = authenticator;
yield listener.open();
let debuggerListener = DebuggerServer.createListener();
debuggerListener.portOrPath = -1;
debuggerListener.authenticator = authenticator;
yield debuggerListener.open();
}
let port = DebuggerServer._listeners[0].port;
do_print("Debugger server port is " + port);

Просмотреть файл

@ -73,8 +73,8 @@ function json_reply(client, response) {
// Send bulk data to server
let copyDeferred = defer();
request.on("bulk-send-ready", ({writer, done}) => {
let input = Cc["@mozilla.org/io/string-input-stream;1"].
createInstance(Ci.nsIStringInputStream);
let input = Cc["@mozilla.org/io/string-input-stream;1"]
.createInstance(Ci.nsIStringInputStream);
input.setData(reallyLong, reallyLong.length);
try {
writer.copyFrom(input, () => {

Просмотреть файл

@ -150,6 +150,18 @@ var test_bulk_request_cs = Task.async(function* (transportFactory, actorType, re
client.listTabs(clientDeferred.resolve);
});
function bulkSendReadyCallback({copyFrom}) {
NetUtil.asyncFetch({
uri: NetUtil.newURI(getTestTempFile("bulk-input")),
loadUsingSystemPrincipal: true
}, input => {
copyFrom(input).then(() => {
input.close();
bulkCopyDeferred.resolve();
});
});
}
clientDeferred.promise.then(response => {
let request = client.startBulkRequest({
actor: response.testBulk,
@ -158,17 +170,7 @@ var test_bulk_request_cs = Task.async(function* (transportFactory, actorType, re
});
// Send bulk data to server
request.on("bulk-send-ready", ({copyFrom}) => {
NetUtil.asyncFetch({
uri: NetUtil.newURI(getTestTempFile("bulk-input")),
loadUsingSystemPrincipal: true
}, input => {
copyFrom(input).then(() => {
input.close();
bulkCopyDeferred.resolve();
});
});
});
request.on("bulk-send-ready", bulkSendReadyCallback);
// Set up reply handling for this type
replyHandlers[replyType](request).then(() => {

Просмотреть файл

@ -1,11 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var gPort;
var gExtraListener;
function run_test()
{
function run_test() {
do_print("Starting test at " + new Date().toTimeString());
initTestDebuggerServer();
@ -16,8 +16,7 @@ function run_test()
run_next_test();
}
function* test_socket_conn()
{
function* test_socket_conn() {
do_check_eq(DebuggerServer.listeningSockets, 0);
let AuthenticatorType = DebuggerServer.Authenticators.get("PROMPT");
let authenticator = new AuthenticatorType.Server();
@ -53,9 +52,9 @@ function* test_socket_conn()
let closedDeferred = defer();
transport.hooks = {
onPacket: function (aPacket) {
this.onPacket = function (aPacket) {
do_check_eq(aPacket.unicode, unicodeString);
onPacket: function (packet) {
this.onPacket = function ({unicode}) {
do_check_eq(unicode, unicodeString);
transport.close();
};
// Verify that things work correctly when bigger than the output
@ -64,9 +63,9 @@ function* test_socket_conn()
type: "echo",
reallylong: really_long(),
unicode: unicodeString});
do_check_eq(aPacket.from, "root");
do_check_eq(packet.from, "root");
},
onClosed: function (aStatus) {
onClosed: function (status) {
closedDeferred.resolve();
},
};
@ -74,8 +73,7 @@ function* test_socket_conn()
return closedDeferred.promise;
}
function* test_socket_shutdown()
{
function* test_socket_shutdown() {
do_check_eq(DebuggerServer.listeningSockets, 2);
gExtraListener.close();
do_check_eq(DebuggerServer.listeningSockets, 1);
@ -87,7 +85,7 @@ function* test_socket_shutdown()
do_print("Connecting to a server socket at " + new Date().toTimeString());
try {
let transport = yield DebuggerClient.socketConnect({
yield DebuggerClient.socketConnect({
host: "127.0.0.1",
port: gPort
});
@ -98,24 +96,22 @@ function* test_socket_shutdown()
// machines it may just time out.
do_check_true(true);
return;
} else {
throw e;
}
throw e;
}
// Shouldn't reach this, should never connect.
do_check_true(false);
}
function test_pipe_conn()
{
function test_pipe_conn() {
let transport = DebuggerServer.connectPipe();
transport.hooks = {
onPacket: function (aPacket) {
do_check_eq(aPacket.from, "root");
onPacket: function (packet) {
do_check_eq(packet.from, "root");
transport.close();
},
onClosed: function (aStatus) {
onClosed: function (status) {
run_next_test();
}
};

Просмотреть файл

@ -7,6 +7,7 @@
* Bug 755412 - checks if the server drops the connection on an improperly
* framed packet, i.e. when the length header is invalid.
*/
"use strict";
const { RawPacket } = require("devtools/shared/transport/packets");
@ -61,8 +62,8 @@ var test_helper = Task.async(function* (payload) {
});
let closedDeferred = defer();
transport.hooks = {
onPacket: function (aPacket) {
this.onPacket = function (aPacket) {
onPacket: function (packet) {
this.onPacket = function () {
do_throw(new Error("This connection should be dropped."));
transport.close();
};
@ -71,7 +72,7 @@ var test_helper = Task.async(function* (payload) {
transport._outgoing.push(new RawPacket(transport, payload));
transport._flushOutgoing();
},
onClosed: function (aStatus) {
onClosed: function (status) {
do_check_true(true);
closedDeferred.resolve();
},

Просмотреть файл

@ -1,5 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const StreamUtils = require("devtools/shared/transport/stream-utils");

Просмотреть файл

@ -20,7 +20,6 @@ function run_test() {
/** * Tests ***/
var test_bulk_send_error = Task.async(function* (transportFactory) {
let deferred = defer();
let transport = yield transportFactory();
let client = new DebuggerClient(transport);
@ -33,6 +32,5 @@ var test_bulk_send_error = Task.async(function* (transportFactory) {
} catch (e) {
do_check_true(true);
}
});
});

Просмотреть файл

@ -1,5 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { JSONPacket, BulkPacket } =
require("devtools/shared/transport/packets");

Просмотреть файл

@ -74,9 +74,9 @@ var test_bulk_transfer_transport = Task.async(function* (transportFactory) {
// Client
transport.hooks = {
onPacket: function (aPacket) {
onPacket: function (packet) {
// We've received the initial start up packet
do_check_eq(aPacket.from, "root");
do_check_eq(packet.from, "root");
// Server
do_check_eq(Object.keys(DebuggerServer._connections).length, 1);

Просмотреть файл

@ -1,5 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { RootActor } = require("devtools/server/actors/root");
const { DebuggerServer } = require("devtools/server/main");
@ -7,8 +8,8 @@ const { DebuggerServer } = require("devtools/server/main");
/**
* Root actor that doesn't have the bulk trait.
*/
function createRootActor(aConnection) {
let root = new RootActor(aConnection, {
function createRootActor(connection) {
let root = new RootActor(connection, {
globalActorFactories: DebuggerServer.globalActorFactories
});
root.applicationType = "xpcshell-tests";

Просмотреть файл

@ -1,5 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { ActorPool, appendExtraActors, createExtraActors } =
require("devtools/server/actors/common");
@ -9,8 +10,8 @@ const { DebuggerServer } = require("devtools/server/main");
const promise = require("promise");
var gTestGlobals = [];
DebuggerServer.addTestGlobal = function (aGlobal) {
gTestGlobals.push(aGlobal);
DebuggerServer.addTestGlobal = function (global) {
gTestGlobals.push(global);
};
// A mock tab list, for use by tests. This simply presents each global in
@ -20,18 +21,18 @@ DebuggerServer.addTestGlobal = function (aGlobal) {
// As implemented now, we consult gTestGlobals when we're constructed, not
// when we're iterated over, so tests have to add their globals before the
// root actor is created.
function TestTabList(aConnection) {
this.conn = aConnection;
function TestTabList(connection) {
this.conn = connection;
// An array of actors for each global added with
// DebuggerServer.addTestGlobal.
this._tabActors = [];
// A pool mapping those actors' names to the actors.
this._tabActorPool = new ActorPool(aConnection);
this._tabActorPool = new ActorPool(connection);
for (let global of gTestGlobals) {
let actor = new TestTabActor(aConnection, global);
let actor = new TestTabActor(connection, global);
actor.selected = false;
this._tabActors.push(actor);
this._tabActorPool.addActor(actor);
@ -40,7 +41,7 @@ function TestTabList(aConnection) {
this._tabActors[0].selected = true;
}
aConnection.addActorPool(this._tabActorPool);
connection.addActorPool(this._tabActorPool);
}
TestTabList.prototype = {
@ -50,18 +51,18 @@ TestTabList.prototype = {
}
};
function createRootActor(aConnection) {
let root = new RootActor(aConnection, {
tabList: new TestTabList(aConnection),
function createRootActor(connection) {
let root = new RootActor(connection, {
tabList: new TestTabList(connection),
globalActorFactories: DebuggerServer.globalActorFactories
});
root.applicationType = "xpcshell-tests";
return root;
}
function TestTabActor(aConnection, aGlobal) {
this.conn = aConnection;
this._global = aGlobal;
function TestTabActor(connection, global) {
this.conn = connection;
this._global = global;
this._threadActor = new ThreadActor(this, this._global);
this.conn.addActor(this._threadActor);
this._attached = false;
@ -96,7 +97,7 @@ TestTabActor.prototype = {
return response;
},
onAttach: function (aRequest) {
onAttach: function (request) {
this._attached = true;
let response = { type: "tabAttached", threadActor: this._threadActor.actorID };
@ -105,9 +106,9 @@ TestTabActor.prototype = {
return response;
},
onDetach: function (aRequest) {
onDetach: function (request) {
if (!this._attached) {
return { "error":"wrongState" };
return { "error": "wrongState" };
}
return { type: "detached" };
},

Просмотреть файл

@ -7572,7 +7572,13 @@ nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
nsCOMPtr<nsIConsoleReportCollector> reporter = do_QueryInterface(aChannel);
if (reporter) {
reporter->FlushConsoleReports(GetDocument());
nsCOMPtr<nsILoadGroup> loadGroup;
aChannel->GetLoadGroup(getter_AddRefs(loadGroup));
if (loadGroup) {
reporter->FlushConsoleReports(loadGroup);
} else {
reporter->FlushConsoleReports(GetDocument());
}
}
nsCOMPtr<nsIURI> url;

Просмотреть файл

@ -464,7 +464,9 @@ promise_test(function(t) {
return watcher.wait_for('transitionend');
}).then(function(evt) {
transition.cancel();
return watcher.wait_for('transitioncancel');
// Then wait a couple of frames and check that no event was dispatched
return waitForAnimationFrames(2);
});
}, 'Cancel the transition after clearing the target effect');

Просмотреть файл

@ -933,18 +933,28 @@ TimeoutManager::Timeouts::ResetTimersForThrottleReduction(int32_t aPreviousThrot
// current timeout in the list.
Timeout* nextTimeout = timeout->getNext();
// It is safe to remove and re-insert because When() is now
// strictly smaller than it used to be, so we know we'll insert
// |timeout| before nextTimeout.
NS_ASSERTION(!nextTimeout ||
timeout->When() < nextTimeout->When(), "How did that happen?");
timeout->remove();
// Insert() will addref |timeout| and reset mFiringDepth. Make sure to
// undo that after calling it.
uint32_t firingDepth = timeout->mFiringDepth;
Insert(timeout, aSortBy);
timeout->mFiringDepth = firingDepth;
timeout->Release();
// Since we are only reducing intervals in this method we can
// make an optimization here. If the reduction does not cause us
// to fall before our previous timeout then we do not have to
// remove and re-insert the current timeout. This is important
// because re-insertion makes this algorithm O(n^2). Since we
// will typically be shifting a lot of timers at once this
// optimization saves us a lot of work.
Timeout* prevTimeout = timeout->getPrevious();
if (prevTimeout && prevTimeout->When() > timeout->When()) {
// It is safe to remove and re-insert because When() is now
// strictly smaller than it used to be, so we know we'll insert
// |timeout| before nextTimeout.
NS_ASSERTION(!nextTimeout ||
timeout->When() < nextTimeout->When(), "How did that happen?");
timeout->remove();
// Insert() will addref |timeout| and reset mFiringDepth. Make sure to
// undo that after calling it.
uint32_t firingDepth = timeout->mFiringDepth;
Insert(timeout, aSortBy);
timeout->mFiringDepth = firingDepth;
timeout->Release();
}
nsresult rv = timeout->InitTimer(aQueue, delay.ToMilliseconds());

Просмотреть файл

@ -1797,8 +1797,7 @@ nsContentUtils::ParseLegacyFontSize(const nsAString& aValue)
bool
nsContentUtils::IsControlledByServiceWorker(nsIDocument* aDocument)
{
if (aDocument &&
aDocument->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId) {
if (nsContentUtils::IsInPrivateBrowsing(aDocument)) {
return false;
}
@ -2084,11 +2083,8 @@ nsContentUtils::CallerHasPermission(JSContext* aCx, const nsAString& aPerm)
return true;
}
JSCompartment* c = js::GetContextCompartment(aCx);
nsIPrincipal* p = nsJSPrincipals::get(JS_GetCompartmentPrincipals(c));
// Otherwise, only allow if caller is an addon with the permission.
return BasePrincipal::Cast(p)->AddonHasPermission(aPerm);
return BasePrincipal::Cast(SubjectPrincipal(aCx))->AddonHasPermission(aPerm);
}
//static
@ -2174,16 +2170,8 @@ nsContentUtils::IsCallerContentXBL()
bool
nsContentUtils::IsSystemCaller(JSContext* aCx)
{
MOZ_ASSERT(NS_IsMainThread());
// This is similar to what SubjectPrincipal() does, except we do in fact
// assume that we're in a compartment here; anyone who calls this function in
// situations where that's not the case is doing it wrong.
JSCompartment *compartment = js::GetContextCompartment(aCx);
MOZ_ASSERT(compartment);
JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
return nsJSPrincipals::get(principals) == sSystemPrincipal;
// Note that SubjectPrincipal() assumes we are in a compartment here.
return SubjectPrincipal(aCx) == sSystemPrincipal;
}
bool
@ -2777,6 +2765,22 @@ nsContentUtils::GenerateStateKey(nsIContent* aContent,
return NS_OK;
}
// static
nsIPrincipal*
nsContentUtils::SubjectPrincipal(JSContext* aCx)
{
MOZ_ASSERT(NS_IsMainThread());
// As opposed to SubjectPrincipal(), we do in fact assume that
// we're in a compartment here; anyone who calls this function
// in situations where that's not the case is doing it wrong.
JSCompartment* compartment = js::GetContextCompartment(aCx);
MOZ_ASSERT(compartment);
JSPrincipals* principals = JS_GetCompartmentPrincipals(compartment);
return nsJSPrincipals::get(principals);
}
// static
nsIPrincipal*
nsContentUtils::SubjectPrincipal()
@ -2803,7 +2807,7 @@ nsContentUtils::SubjectPrincipal()
// The natural thing to return is a null principal. Ideally, we'd return a
// different null principal each time, to avoid any unexpected interactions
// when the principal accidentally gets inherited somewhere. But
// GetSubjectPrincipal doesn't return strong references, so there's no way to
// SubjectPrincipal doesn't return strong references, so there's no way to
// sanely manage the lifetime of multiple null principals.
//
// So we use a singleton null principal. To avoid it being accidentally
@ -2814,8 +2818,7 @@ nsContentUtils::SubjectPrincipal()
return sNullSubjectPrincipal;
}
JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
return nsJSPrincipals::get(principals);
return SubjectPrincipal(cx);
}
// static
@ -3202,6 +3205,40 @@ nsContentUtils::GetOriginAttributes(nsILoadGroup* aLoadGroup)
return attrs;
}
// static
bool
nsContentUtils::IsInPrivateBrowsing(nsIDocument* aDoc)
{
if (!aDoc) {
return false;
}
nsCOMPtr<nsILoadGroup> loadGroup = aDoc->GetDocumentLoadGroup();
if (loadGroup) {
return IsInPrivateBrowsing(loadGroup);
}
nsCOMPtr<nsIChannel> channel = aDoc->GetChannel();
return channel && NS_UsePrivateBrowsing(channel);
}
// static
bool
nsContentUtils::IsInPrivateBrowsing(nsILoadGroup* aLoadGroup)
{
if (!aLoadGroup) {
return false;
}
bool isPrivate = false;
nsCOMPtr<nsIInterfaceRequestor> callbacks;
aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
if (callbacks) {
nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
isPrivate = loadContext && loadContext->UsePrivateBrowsing();
}
return isPrivate;
}
bool
nsContentUtils::DocumentInactiveForImageLoads(nsIDocument* aDocument)
{
@ -3221,26 +3258,9 @@ nsContentUtils::GetImgLoaderForDocument(nsIDocument* aDoc)
if (!aDoc) {
return imgLoader::NormalLoader();
}
nsCOMPtr<nsILoadGroup> loadGroup = aDoc->GetDocumentLoadGroup();
if (loadGroup) {
nsCOMPtr<nsIInterfaceRequestor> callbacks;
loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
if (callbacks) {
nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
if (loadContext && loadContext->UsePrivateBrowsing()) {
return imgLoader::PrivateBrowsingLoader();
}
}
return imgLoader::NormalLoader();
}
nsCOMPtr<nsIChannel> channel = aDoc->GetChannel();
if (channel && NS_UsePrivateBrowsing(channel)) {
return imgLoader::PrivateBrowsingLoader();
}
return imgLoader::NormalLoader();
bool isPrivate = IsInPrivateBrowsing(aDoc);
return isPrivate ? imgLoader::PrivateBrowsingLoader()
: imgLoader::NormalLoader();
}
// static
@ -3672,6 +3692,22 @@ nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText,
innerWindowID = aDocument->InnerWindowID();
}
return ReportToConsoleByWindowID(aErrorText, aErrorFlags, aCategory,
innerWindowID, aURI, aSourceLine,
aLineNumber, aColumnNumber, aLocationMode);
}
/* static */ nsresult
nsContentUtils::ReportToConsoleByWindowID(const nsAString& aErrorText,
uint32_t aErrorFlags,
const nsACString& aCategory,
uint64_t aInnerWindowID,
nsIURI* aURI,
const nsAFlatString& aSourceLine,
uint32_t aLineNumber,
uint32_t aColumnNumber,
MissingErrorLocationMode aLocationMode)
{
nsresult rv;
if (!sConsoleService) { // only need to bother null-checking here
rv = CallGetService(NS_CONSOLESERVICE_CONTRACTID, &sConsoleService);
@ -3698,7 +3734,7 @@ nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText,
aSourceLine,
aLineNumber, aColumnNumber,
aErrorFlags, aCategory,
innerWindowID);
aInnerWindowID);
NS_ENSURE_SUCCESS(rv, rv);
return sConsoleService->LogMessage(errorObject);
@ -7337,8 +7373,18 @@ nsContentUtils::GetInnerWindowID(nsIRequest* aRequest)
return 0;
}
return GetInnerWindowID(loadGroup);
}
uint64_t
nsContentUtils::GetInnerWindowID(nsILoadGroup* aLoadGroup)
{
if (!aLoadGroup) {
return 0;
}
nsCOMPtr<nsIInterfaceRequestor> callbacks;
rv = loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
nsresult rv = aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
if (NS_FAILED(rv) || !callbacks) {
return 0;
}
@ -8621,7 +8667,7 @@ nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal,
}
// Check if we are in private browsing, and record that fact
if (document->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId) {
if (IsInPrivateBrowsing(document)) {
access = StorageAccess::ePrivateBrowsing;
}
}

Просмотреть файл

@ -545,6 +545,10 @@ public:
return sSecurityManager;
}
// Returns the subject principal from the JSContext. May only be called
// from the main thread and assumes an existing compartment.
static nsIPrincipal* SubjectPrincipal(JSContext* aCx);
// Returns the subject principal. Guaranteed to return non-null. May only
// be called when nsContentUtils is initialized.
static nsIPrincipal* SubjectPrincipal();
@ -817,6 +821,16 @@ public:
static mozilla::OriginAttributes
GetOriginAttributes(nsILoadGroup* aLoadGroup);
/**
* Returns true if this document is in a Private Browsing window.
*/
static bool IsInPrivateBrowsing(nsIDocument* aDoc);
/**
* Returns true if this loadGroup uses Private Browsing.
*/
static bool IsInPrivateBrowsing(nsILoadGroup* aLoadGroup);
/**
* If aNode is not an element, return true exactly when aContent's binding
* parent is null.
@ -884,6 +898,37 @@ public:
MissingErrorLocationMode aLocationMode
= eUSE_CALLING_LOCATION);
/**
* Report a non-localized error message to the error console base on the
* innerWindowID.
* @param aErrorText the error message
* @param aErrorFlags See nsIScriptError.
* @param aCategory Name of module reporting error.
* @param [aInnerWindowID] Inner window ID for document which triggered the
* message.
* @param [aURI=nullptr] (Optional) URI of resource containing error.
* @param [aSourceLine=EmptyString()] (Optional) The text of the line that
contains the error (may be empty).
* @param [aLineNumber=0] (Optional) Line number within resource
containing error.
* @param [aColumnNumber=0] (Optional) Column number within resource
containing error.
If aURI is null, then aDocument->GetDocumentURI() is used.
* @param [aLocationMode] (Optional) Specifies the behavior if
error location information is omitted.
*/
static nsresult ReportToConsoleByWindowID(const nsAString& aErrorText,
uint32_t aErrorFlags,
const nsACString& aCategory,
uint64_t aInnerWindowID,
nsIURI* aURI = nullptr,
const nsAFlatString& aSourceLine
= EmptyString(),
uint32_t aLineNumber = 0,
uint32_t aColumnNumber = 0,
MissingErrorLocationMode aLocationMode
= eUSE_CALLING_LOCATION);
/**
* Report a localized error message to the error console.
* @param aErrorFlags See nsIScriptError.
@ -2447,10 +2492,15 @@ public:
static bool IsForbiddenResponseHeader(const nsACString& aHeader);
/**
* Returns the inner window ID for the window associated with a request,
* Returns the inner window ID for the window associated with a request.
*/
static uint64_t GetInnerWindowID(nsIRequest* aRequest);
/**
* Returns the inner window ID for the window associated with a load group.
*/
static uint64_t GetInnerWindowID(nsILoadGroup* aLoadGroup);
/**
* If the hostname for aURI is an IPv6 it encloses it in brackets,
* otherwise it just outputs the hostname in aHost.

Просмотреть файл

@ -8579,14 +8579,18 @@ nsDocument::CanSavePresentation(nsIRequest *aNewRequest)
}
}
#ifdef MOZ_WEBSPEECH
if (win) {
auto* globalWindow = nsGlobalWindow::Cast(win);
#ifdef MOZ_WEBSPEECH
if (globalWindow->HasActiveSpeechSynthesis()) {
return false;
}
}
#endif
if (globalWindow->HasUsedVR()) {
return false;
}
}
return true;
}

Просмотреть файл

@ -13239,6 +13239,14 @@ nsGlobalWindow::NotifyVREventListenerAdded()
EnableVRUpdates();
}
bool
nsGlobalWindow::HasUsedVR() const
{
MOZ_ASSERT(IsInnerWindow());
return mHasVREvents;
}
void
nsGlobalWindow::EnableTimeChangeNotifications()
{

Просмотреть файл

@ -448,6 +448,7 @@ public:
// Inner windows only.
virtual void SetHasGamepadEventListener(bool aHasGamepad = true) override;
void NotifyVREventListenerAdded();
bool HasUsedVR() const;
virtual void EventListenerAdded(nsIAtom* aType) override;
// nsIInterfaceRequestor

Просмотреть файл

@ -2488,7 +2488,12 @@ nsScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
}
rv = aSRIDataVerifier->Verify(aRequest->mIntegrity, channel, sourceUri,
mReporter);
mReporter->FlushConsoleReports(mDocument);
if (channelRequest) {
mReporter->FlushReportsToConsole(
nsContentUtils::GetInnerWindowID(channelRequest));
} else {
mReporter->FlushConsoleReports(mDocument);
}
if (NS_FAILED(rv)) {
rv = NS_ERROR_SRI_CORRUPT;
}

Просмотреть файл

@ -4,6 +4,9 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
with Files("**"):
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
EXPORTS.mozilla.dom.battery += [
'Constants.h',
'Types.h',

Просмотреть файл

@ -15446,6 +15446,7 @@ class CGCallback(CGClass):
setupCall = fill(
"""
MOZ_ASSERT(!aRv.Failed(), "Don't pass an already-failed ErrorResult to a callback!");
if (!aExecutionReason) {
aExecutionReason = "${executionReason}";
}

Просмотреть файл

@ -4,6 +4,9 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
with Files("**"):
BUG_COMPONENT = ("Core", "DOM")
TEST_DIRS += ['test']
XPIDL_SOURCES += [

Просмотреть файл

@ -4,6 +4,9 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
with Files("**"):
BUG_COMPONENT = ("Core", "DOM")
EXPORTS.mozilla.dom += [
'BroadcastChannel.h',
]

Просмотреть файл

@ -4,6 +4,9 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
with Files("**"):
BUG_COMPONENT = ("Core", "DOM")
EXPORTS.mozilla += [
'BrowserElementParent.h',
]

4
dom/cache/moz.build поставляемый
Просмотреть файл

@ -4,6 +4,10 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
with Files("**"):
BUG_COMPONENT = ("Core", "DOM")
EXPORTS.mozilla.dom.cache += [
'Action.h',
'ActorChild.h',

Просмотреть файл

@ -4,6 +4,9 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
with Files("**"):
BUG_COMPONENT = ("Core", "Embedding: APIs")
XPIDL_SOURCES += [
'nsICommandManager.idl',
'nsICommandParams.idl',

Просмотреть файл

@ -39,11 +39,9 @@ ConsoleReportCollector::AddConsoleReport(uint32_t aErrorFlags,
}
void
ConsoleReportCollector::FlushConsoleReports(nsIDocument* aDocument,
ReportAction aAction)
ConsoleReportCollector::FlushReportsToConsole(uint64_t aInnerWindowID,
ReportAction aAction)
{
MOZ_ASSERT(NS_IsMainThread());
nsTArray<PendingReport> reports;
{
@ -58,6 +56,22 @@ ConsoleReportCollector::FlushConsoleReports(nsIDocument* aDocument,
for (uint32_t i = 0; i < reports.Length(); ++i) {
PendingReport& report = reports[i];
nsXPIDLString errorText;
nsresult rv;
if (!report.mStringParams.IsEmpty()) {
rv = nsContentUtils::FormatLocalizedString(report.mPropertiesFile,
report.mMessageName.get(),
report.mStringParams,
errorText);
} else {
rv = nsContentUtils::GetLocalizedString(report.mPropertiesFile,
report.mMessageName.get(),
errorText);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
// It would be nice if we did not have to do this since ReportToConsole()
// just turns around and converts it back to a spec.
nsCOMPtr<nsIURI> uri;
@ -69,26 +83,33 @@ ConsoleReportCollector::FlushConsoleReports(nsIDocument* aDocument,
}
}
// Convert back from nsTArray<nsString> to the char16_t** format required
// by our l10n libraries and ReportToConsole. (bug 1219762)
UniquePtr<const char16_t*[]> params;
uint32_t paramsLength = report.mStringParams.Length();
if (paramsLength > 0) {
params = MakeUnique<const char16_t*[]>(paramsLength);
for (uint32_t j = 0; j < paramsLength; ++j) {
params[j] = report.mStringParams[j].get();
}
}
nsContentUtils::ReportToConsole(report.mErrorFlags, report.mCategory,
aDocument, report.mPropertiesFile,
report.mMessageName.get(),
params.get(),
paramsLength, uri, EmptyString(),
report.mLineNumber, report.mColumnNumber);
nsContentUtils::ReportToConsoleByWindowID(errorText,
report.mErrorFlags,
report.mCategory,
aInnerWindowID,
uri,
EmptyString(),
report.mLineNumber,
report.mColumnNumber);
}
}
void
ConsoleReportCollector::FlushConsoleReports(nsIDocument* aDocument,
ReportAction aAction)
{
MOZ_ASSERT(NS_IsMainThread());
FlushReportsToConsole(aDocument ? aDocument->InnerWindowID() : 0, aAction);
}
void
ConsoleReportCollector::FlushConsoleReports(nsILoadGroup* aLoadGroup,
ReportAction aAction)
{
FlushReportsToConsole(nsContentUtils::GetInnerWindowID(aLoadGroup), aAction);
}
void
ConsoleReportCollector::FlushConsoleReports(nsIConsoleReportCollector* aCollector)
{
@ -110,71 +131,6 @@ ConsoleReportCollector::FlushConsoleReports(nsIConsoleReportCollector* aCollecto
}
}
void
ConsoleReportCollector::FlushReportsByWindowId(uint64_t aWindowId,
ReportAction aAction)
{
MOZ_ASSERT(NS_IsMainThread());
nsTArray<PendingReport> reports;
{
MutexAutoLock lock(mMutex);
if (aAction == ReportAction::Forget) {
mPendingReports.SwapElements(reports);
} else {
reports = mPendingReports;
}
}
nsCOMPtr<nsIConsoleService> consoleService =
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
if (!consoleService) {
NS_WARNING("GetConsoleService failed");
return;
}
nsresult rv;
for (uint32_t i = 0; i < reports.Length(); ++i) {
PendingReport& report = reports[i];
nsXPIDLString errorText;
if (!report.mStringParams.IsEmpty()) {
rv = nsContentUtils::FormatLocalizedString(report.mPropertiesFile,
report.mMessageName.get(),
report.mStringParams,
errorText);
} else {
rv = nsContentUtils::GetLocalizedString(report.mPropertiesFile,
report.mMessageName.get(),
errorText);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
nsCOMPtr<nsIScriptError> errorObject =
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
rv = errorObject->InitWithWindowID(errorText,
NS_ConvertUTF8toUTF16(report.mSourceFileURI),
EmptyString(),
report.mLineNumber,
report.mColumnNumber,
report.mErrorFlags,
report.mCategory,
aWindowId);
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
consoleService->LogMessage(errorObject);
}
}
void
ConsoleReportCollector::ClearConsoleReports()
{

Просмотреть файл

@ -26,16 +26,20 @@ public:
const nsACString& aMessageName,
const nsTArray<nsString>& aStringParams) override;
void
FlushReportsToConsole(uint64_t aInnerWindowID,
ReportAction aAction = ReportAction::Forget) override;
void
FlushConsoleReports(nsIDocument* aDocument,
ReportAction aAction = ReportAction::Forget) override;
void
FlushConsoleReports(nsIConsoleReportCollector* aCollector) override;
FlushConsoleReports(nsILoadGroup* aLoadGroup,
ReportAction aAction = ReportAction::Forget) override;
void
FlushReportsByWindowId(uint64_t aWindowId,
ReportAction aAction = ReportAction::Forget) override;
FlushConsoleReports(nsIConsoleReportCollector* aCollector) override;
void
ClearConsoleReports() override;

Просмотреть файл

@ -4,6 +4,9 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
with Files("**"):
BUG_COMPONENT = ("Core", "DOM")
XPIDL_SOURCES += [
'nsIConsoleAPIStorage.idl',
]

Просмотреть файл

@ -74,6 +74,15 @@ public:
Save
};
// Flush all pending reports to the console. May be called from any thread.
//
// aInnerWindowID A inner window ID representing where to flush the reports.
// aAction An action to determine whether to reserve the pending
// reports. Defalut action is to forget the report.
virtual void
FlushReportsToConsole(uint64_t aInnerWindowID,
ReportAction aAction = ReportAction::Forget) = 0;
// Flush all pending reports to the console. Main thread only.
//
// aDocument An optional document representing where to flush the
@ -86,6 +95,19 @@ public:
FlushConsoleReports(nsIDocument* aDocument,
ReportAction aAction = ReportAction::Forget) = 0;
// Flush all pending reports to the console. May be called from any thread.
//
// aLoadGroup An optional loadGroup representing where to flush the
// reports. If provided, then the corresponding window's
// web console will get the reports. Otherwise the reports
// go to the browser console.
// aAction An action to determine whether to reserve the pending
// reports. Defalut action is to forget the report.
virtual void
FlushConsoleReports(nsILoadGroup* aLoadGroup,
ReportAction aAction = ReportAction::Forget) = 0;
// Flush all pending reports to another collector. May be called from any
// thread.
//
@ -94,17 +116,6 @@ public:
virtual void
FlushConsoleReports(nsIConsoleReportCollector* aCollector) = 0;
// Flush all pending reports to the console accroding to window ID. Main
// thread only.
//
// aWindowId A window ID representing where to flush the reports and it's
// typically the inner window ID.
//
// aAction An action to decide whether free the pending reports or not.
virtual void
FlushReportsByWindowId(uint64_t aWindowId,
ReportAction aAction = ReportAction::Forget) = 0;
// Clear all pending reports.
virtual void
ClearConsoleReports() = 0;

Просмотреть файл

@ -4,6 +4,9 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
with Files("**"):
BUG_COMPONENT = ("Core", "DOM: Security")
EXPORTS.mozilla.dom += [
'CryptoBuffer.h',
'CryptoKey.h',

Просмотреть файл

@ -4,6 +4,10 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
with Files("**"):
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
EXPORTS += [
'DeviceStorage.h',
'DeviceStorageFileDescriptor.h',

Просмотреть файл

@ -100,7 +100,7 @@ class MainThreadFetchResolver final : public FetchDriverObserver
RefPtr<Promise> mPromise;
RefPtr<Response> mResponse;
nsCOMPtr<nsIDocument> mDocument;
nsCOMPtr<nsILoadGroup> mLoadGroup;
NS_DECL_OWNINGTHREAD
public:
@ -109,9 +109,9 @@ public:
void
OnResponseAvailableInternal(InternalResponse* aResponse) override;
void SetDocument(nsIDocument* aDocument)
void SetLoadGroup(nsILoadGroup* aLoadGroup)
{
mDocument = aDocument;
mLoadGroup = aLoadGroup;
}
virtual void OnResponseEnd() override
@ -124,7 +124,7 @@ private:
void FlushConsoleReport() override
{
mReporter->FlushConsoleReports(mDocument);
mReporter->FlushConsoleReports(mLoadGroup);
}
};
@ -238,7 +238,7 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
RefPtr<MainThreadFetchResolver> resolver = new MainThreadFetchResolver(p);
RefPtr<FetchDriver> fetch = new FetchDriver(r, principal, loadGroup);
fetch->SetDocument(doc);
resolver->SetDocument(doc);
resolver->SetLoadGroup(loadGroup);
aRv = fetch->Fetch(resolver);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
@ -453,7 +453,7 @@ WorkerFetchResolver::FlushConsoleReport()
workers::WorkerPrivate* worker = mPromiseProxy->GetWorkerPrivate();
if (!worker) {
mReporter->FlushConsoleReports((nsIDocument*)nullptr);
mReporter->FlushReportsToConsole(0);
return;
}
@ -461,7 +461,7 @@ WorkerFetchResolver::FlushConsoleReport()
// Flush to service worker
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) {
mReporter->FlushConsoleReports((nsIDocument*)nullptr);
mReporter->FlushReportsToConsole(0);
return;
}
@ -476,7 +476,7 @@ WorkerFetchResolver::FlushConsoleReport()
}
// Flush to dedicated worker
mReporter->FlushConsoleReports(worker->GetDocument());
mReporter->FlushConsoleReports(worker->GetLoadGroup());
}
nsresult

Просмотреть файл

@ -36,6 +36,7 @@
#include "mozilla/dom/BlobBinding.h"
#include "mozilla/dom/DOMError.h"
#include "mozilla/dom/FileBinding.h"
#include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerRunnable.h"
#include "nsThreadUtils.h"
@ -470,15 +471,18 @@ File::GetName(nsAString& aFileName) const
}
void
File::GetPath(nsAString& aPath) const
File::GetRelativePath(nsAString& aPath) const
{
mImpl->GetPath(aPath);
}
aPath.Truncate();
void
File::SetPath(const nsAString& aPath)
{
mImpl->SetPath(aPath);
nsAutoString path;
mImpl->GetDOMPath(path);
// WebkitRelativePath doesn't start with '/'
if (!path.IsEmpty()) {
MOZ_ASSERT(path[0] == FILESYSTEM_DOM_PATH_SEPARATOR_CHAR);
aPath.Assign(Substring(path, 1));
}
}
Date
@ -670,14 +674,14 @@ BlobImplBase::GetName(nsAString& aName) const
}
void
BlobImplBase::GetPath(nsAString& aPath) const
BlobImplBase::GetDOMPath(nsAString& aPath) const
{
MOZ_ASSERT(mIsFile, "Should only be called on files");
aPath = mPath;
}
void
BlobImplBase::SetPath(const nsAString& aPath)
BlobImplBase::SetDOMPath(const nsAString& aPath)
{
MOZ_ASSERT(mIsFile, "Should only be called on files");
mPath = aPath;

Просмотреть файл

@ -225,13 +225,7 @@ public:
Date GetLastModifiedDate(ErrorResult& aRv);
// GetPath and SetPath are currently used only for the webkitRelativePath
// attribute and they are only used when this File object is created from a
// Directory, generated by a Directory Picker.
void GetPath(nsAString& aName) const;
void SetPath(const nsAString& aName);
void GetRelativePath(nsAString& aPath) const;
void GetMozFullPath(nsAString& aFilename, SystemCallerGuarantee aGuarantee,
ErrorResult& aRv) const;
@ -260,9 +254,9 @@ public:
virtual void GetName(nsAString& aName) const = 0;
virtual void GetPath(nsAString& aName) const = 0;
virtual void GetDOMPath(nsAString& aName) const = 0;
virtual void SetPath(const nsAString& aName) = 0;
virtual void SetDOMPath(const nsAString& aName) = 0;
virtual int64_t GetLastModified(ErrorResult& aRv) = 0;
@ -406,9 +400,9 @@ public:
virtual void GetName(nsAString& aName) const override;
virtual void GetPath(nsAString& aName) const override;
virtual void GetDOMPath(nsAString& aName) const override;
virtual void SetPath(const nsAString& aName) override;
virtual void SetDOMPath(const nsAString& aName) override;
virtual int64_t GetLastModified(ErrorResult& aRv) override;

Просмотреть файл

@ -2071,10 +2071,10 @@ public:
GetName(nsAString& aName) const override;
void
GetPath(nsAString& aPath) const override;
GetDOMPath(nsAString& aPath) const override;
void
SetPath(const nsAString& aPath) override;
SetDOMPath(const nsAString& aPath) override;
int64_t
GetLastModified(ErrorResult& aRv) override;
@ -2175,7 +2175,7 @@ RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
BlobImpl* aRemoteBlobImpl,
const nsAString& aName,
const nsAString& aContentType,
const nsAString& aPath,
const nsAString& aDOMPath,
uint64_t aLength,
int64_t aModDate,
BlobImplIsDirectory aIsDirectory,
@ -2185,7 +2185,7 @@ RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
, mMutex("BlobChild::RemoteBlobImpl::mMutex")
, mIsSlice(false), mIsDirectory(aIsDirectory == eDirectory)
{
SetPath(aPath);
SetDOMPath(aDOMPath);
if (aIsSameProcessBlob) {
MOZ_ASSERT(aRemoteBlobImpl);
@ -2843,16 +2843,16 @@ RemoteBlobImpl::GetName(nsAString& aName) const
void
BlobParent::
RemoteBlobImpl::GetPath(nsAString& aPath) const
RemoteBlobImpl::GetDOMPath(nsAString& aPath) const
{
mBlobImpl->GetPath(aPath);
mBlobImpl->GetDOMPath(aPath);
}
void
BlobParent::
RemoteBlobImpl::SetPath(const nsAString& aPath)
RemoteBlobImpl::SetDOMPath(const nsAString& aPath)
{
mBlobImpl->SetPath(aPath);
mBlobImpl->SetDOMPath(aPath);
}
int64_t
@ -3196,8 +3196,8 @@ BlobChild::CommonInit(BlobChild* aOther, BlobImpl* aBlobImpl)
nsAutoString name;
otherImpl->GetName(name);
nsAutoString path;
otherImpl->GetPath(path);
nsAutoString domPath;
otherImpl->GetDOMPath(domPath);
int64_t modDate = otherImpl->GetLastModified(rv);
MOZ_ASSERT(!rv.Failed());
@ -3207,7 +3207,7 @@ BlobChild::CommonInit(BlobChild* aOther, BlobImpl* aBlobImpl)
RemoteBlobImpl::BlobImplIsDirectory::eNotDirectory;
remoteBlob =
new RemoteBlobImpl(this, otherImpl, name, contentType, path,
new RemoteBlobImpl(this, otherImpl, name, contentType, domPath,
length, modDate, directory,
false /* SameProcessBlobImpl */);
} else {
@ -3291,8 +3291,8 @@ BlobChild::CommonInit(const ChildBlobConstructorParams& aParams)
nsAutoString name;
blobImpl->GetName(name);
nsAutoString path;
blobImpl->GetPath(path);
nsAutoString domPath;
blobImpl->GetDOMPath(domPath);
int64_t lastModifiedDate = blobImpl->GetLastModified(rv);
MOZ_ASSERT(!rv.Failed());
@ -3307,7 +3307,7 @@ BlobChild::CommonInit(const ChildBlobConstructorParams& aParams)
blobImpl,
name,
contentType,
path,
domPath,
size,
lastModifiedDate,
directory,
@ -3490,14 +3490,14 @@ BlobChild::GetOrCreateFromImpl(ChildManagerType* aManager,
nsAutoString name;
aBlobImpl->GetName(name);
nsAutoString path;
aBlobImpl->GetPath(path);
nsAutoString domPath;
aBlobImpl->GetDOMPath(domPath);
int64_t modDate = aBlobImpl->GetLastModified(rv);
MOZ_ASSERT(!rv.Failed());
blobParams =
FileBlobConstructorParams(name, contentType, path, length, modDate,
FileBlobConstructorParams(name, contentType, domPath, length, modDate,
aBlobImpl->IsDirectory(), blobData);
} else {
blobParams = NormalBlobConstructorParams(contentType, length, blobData);
@ -4043,14 +4043,14 @@ BlobParent::GetOrCreateFromImpl(ParentManagerType* aManager,
nsAutoString name;
aBlobImpl->GetName(name);
nsAutoString path;
aBlobImpl->GetPath(path);
nsAutoString domPath;
aBlobImpl->GetDOMPath(domPath);
int64_t modDate = aBlobImpl->GetLastModified(rv);
MOZ_ASSERT(!rv.Failed());
blobParams =
FileBlobConstructorParams(name, contentType, path, length, modDate,
FileBlobConstructorParams(name, contentType, domPath, length, modDate,
aBlobImpl->IsDirectory(), void_t());
} else {
blobParams = NormalBlobConstructorParams(contentType, length, void_t());

Просмотреть файл

@ -23,6 +23,7 @@ EXPORTS.mozilla.dom += [
'File.h',
'FileList.h',
'FileReader.h',
'MultipartBlobImpl.h',
'MutableBlobStorage.h',
'MutableBlobStreamListener.h',
]

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше