зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to graphics
This commit is contained in:
Коммит
5e2990dc18
10
.cron.yml
10
.cron.yml
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -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
|
||||
|
|
|
@ -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 browser’s 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
|
||||
|
@ -66,40 +70,55 @@ 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 this.getRemoteTypeForURIObject(uri, aMultiProcess,
|
||||
aPreferredRemoteType);
|
||||
},
|
||||
|
||||
getRemoteTypeForURIObject(aURI, aMultiProcess,
|
||||
aPreferredRemoteType = DEFAULT_REMOTE_TYPE) {
|
||||
if (!aMultiProcess) {
|
||||
return NOT_REMOTE;
|
||||
}
|
||||
|
||||
switch (aURI.scheme) {
|
||||
case "javascript":
|
||||
// javascript URIs can load in any, they apply to the current document.
|
||||
return aPreferredRemoteType;
|
||||
|
||||
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 (aURL.startsWith("file:")) {
|
||||
return Services.prefs.getBoolPref("browser.tabs.remote.separateFileUriProcess")
|
||||
? FILE_REMOTE_TYPE : DEFAULT_REMOTE_TYPE;
|
||||
}
|
||||
case "file":
|
||||
return useSeparateFileUriProcess ? 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);
|
||||
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(url);
|
||||
let flags = module.getURIFlags(aURI);
|
||||
if (flags & Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD) {
|
||||
return DEFAULT_REMOTE_TYPE;
|
||||
}
|
||||
|
@ -111,47 +130,45 @@ this.E10SUtils = {
|
|||
}
|
||||
|
||||
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) {
|
||||
return aPreferredRemoteType;
|
||||
}
|
||||
|
||||
case "chrome":
|
||||
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
|
||||
getService(Ci.nsIXULChromeRegistry);
|
||||
if (chromeReg.mustLoadURLRemotely(url)) {
|
||||
if (chromeReg.mustLoadURLRemotely(aURI)) {
|
||||
return DEFAULT_REMOTE_TYPE;
|
||||
}
|
||||
|
||||
if (chromeReg.canLoadURLRemotely(url) &&
|
||||
if (chromeReg.canLoadURLRemotely(aURI) &&
|
||||
aPreferredRemoteType != NOT_REMOTE) {
|
||||
return DEFAULT_REMOTE_TYPE;
|
||||
}
|
||||
|
||||
return NOT_REMOTE;
|
||||
}
|
||||
|
||||
if (aURL.startsWith("moz-extension:")) {
|
||||
case "moz-extension":
|
||||
return useRemoteWebExtensions ? EXTENSION_REMOTE_TYPE : NOT_REMOTE;
|
||||
}
|
||||
|
||||
if (aURL.startsWith("view-source:")) {
|
||||
return this.getRemoteTypeForURI(aURL.substr("view-source:".length),
|
||||
aMultiProcess, aPreferredRemoteType);
|
||||
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);
|
||||
}
|
||||
},
|
||||
|
||||
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,7 +19,8 @@ function* getPriority(aBrowser) {
|
|||
aBrowser = aBrowser.linkedBrowser;
|
||||
|
||||
return yield ContentTask.spawn(aBrowser, null, function* () {
|
||||
return docShell.QueryInterface(Components.interfaces.nsIWebNavigation)
|
||||
return content.document.docShell
|
||||
.QueryInterface(Components.interfaces.nsIWebNavigation)
|
||||
.QueryInterface(Components.interfaces.nsIDocumentLoader)
|
||||
.loadGroup
|
||||
.QueryInterface(Components.interfaces.nsISupportsPriority)
|
||||
|
@ -32,7 +33,8 @@ function* setPriority(aBrowser, aPriority) {
|
|||
aBrowser = aBrowser.linkedBrowser;
|
||||
|
||||
yield ContentTask.spawn(aBrowser, aPriority, function* (contentPriority) {
|
||||
docShell.QueryInterface(Components.interfaces.nsIWebNavigation)
|
||||
content.document.docShell
|
||||
.QueryInterface(Components.interfaces.nsIWebNavigation)
|
||||
.QueryInterface(Components.interfaces.nsIDocumentLoader)
|
||||
.loadGroup
|
||||
.QueryInterface(Ci.nsISupportsPriority)
|
||||
|
|
|
@ -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,7 +40,7 @@ addMessageListener(TEST_MSG, msg => {
|
|||
|
||||
function waitForLoadAndStopIt(expectedURL, callback) {
|
||||
let Ci = Components.interfaces;
|
||||
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
let webProgress = content.document.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebProgress);
|
||||
let listener = {
|
||||
onStateChange(webProg, req, flags, status) {
|
||||
|
|
|
@ -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,6 +221,7 @@ 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.
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
|
||||
/**
|
||||
* Get all windows including frames recursively.
|
||||
|
@ -245,6 +263,9 @@ function* finishTests() {
|
|||
}
|
||||
});
|
||||
|
||||
yield closeTabAndToolbox(gBrowser.selectedTab);
|
||||
}
|
||||
|
||||
Services.cookies.removeAll();
|
||||
forceCollections();
|
||||
finish();
|
||||
|
|
|
@ -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,15 +150,7 @@ var test_bulk_request_cs = Task.async(function* (transportFactory, actorType, re
|
|||
client.listTabs(clientDeferred.resolve);
|
||||
});
|
||||
|
||||
clientDeferred.promise.then(response => {
|
||||
let request = client.startBulkRequest({
|
||||
actor: response.testBulk,
|
||||
type: actorType,
|
||||
length: really_long().length
|
||||
});
|
||||
|
||||
// Send bulk data to server
|
||||
request.on("bulk-send-ready", ({copyFrom}) => {
|
||||
function bulkSendReadyCallback({copyFrom}) {
|
||||
NetUtil.asyncFetch({
|
||||
uri: NetUtil.newURI(getTestTempFile("bulk-input")),
|
||||
loadUsingSystemPrincipal: true
|
||||
|
@ -168,8 +160,18 @@ var test_bulk_request_cs = Task.async(function* (transportFactory, actorType, re
|
|||
bulkCopyDeferred.resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
clientDeferred.promise.then(response => {
|
||||
let request = client.startBulkRequest({
|
||||
actor: response.testBulk,
|
||||
type: actorType,
|
||||
length: really_long().length
|
||||
});
|
||||
|
||||
// Send bulk data to server
|
||||
request.on("bulk-send-ready", bulkSendReadyCallback);
|
||||
|
||||
// Set up reply handling for this type
|
||||
replyHandlers[replyType](request).then(() => {
|
||||
client.close();
|
||||
|
|
|
@ -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,7 +106,7 @@ TestTabActor.prototype = {
|
|||
return response;
|
||||
},
|
||||
|
||||
onDetach: function (aRequest) {
|
||||
onDetach: function (request) {
|
||||
if (!this._attached) {
|
||||
return { "error": "wrongState" };
|
||||
}
|
||||
|
|
|
@ -7572,8 +7572,14 @@ nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
|
|||
|
||||
nsCOMPtr<nsIConsoleReportCollector> reporter = do_QueryInterface(aChannel);
|
||||
if (reporter) {
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
aChannel->GetLoadGroup(getter_AddRefs(loadGroup));
|
||||
if (loadGroup) {
|
||||
reporter->FlushConsoleReports(loadGroup);
|
||||
} else {
|
||||
reporter->FlushConsoleReports(GetDocument());
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> url;
|
||||
nsresult rv = aChannel->GetURI(getter_AddRefs(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,6 +933,15 @@ TimeoutManager::Timeouts::ResetTimersForThrottleReduction(int32_t aPreviousThrot
|
|||
// current timeout in the list.
|
||||
Timeout* nextTimeout = timeout->getNext();
|
||||
|
||||
// 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.
|
||||
|
@ -945,6 +954,7 @@ TimeoutManager::Timeouts::ResetTimersForThrottleReduction(int32_t aPreviousThrot
|
|||
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);
|
||||
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,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,
|
||||
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,24 +83,31 @@ 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::ReportToConsoleByWindowID(errorText,
|
||||
report.mErrorFlags,
|
||||
report.mCategory,
|
||||
aInnerWindowID,
|
||||
uri,
|
||||
EmptyString(),
|
||||
report.mLineNumber,
|
||||
report.mColumnNumber);
|
||||
}
|
||||
}
|
||||
|
||||
nsContentUtils::ReportToConsole(report.mErrorFlags, report.mCategory,
|
||||
aDocument, report.mPropertiesFile,
|
||||
report.mMessageName.get(),
|
||||
params.get(),
|
||||
paramsLength, 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
|
||||
|
@ -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',
|
||||
]
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче