зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to m-c. a=merge
UPGRADE_NSPR_RELEASE UPGRADE_NSS_RELEASE --HG-- extra : amend_source : a7800e9214d5a8325af0d1f5e5dcc77273f4ce95
This commit is contained in:
Коммит
e886d1846a
|
@ -5058,10 +5058,10 @@ nsBrowserAccess.prototype = {
|
|||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserDOMWindow, Ci.nsISupports]),
|
||||
|
||||
_openURIInNewTab(aURI, aReferrer, aReferrerPolicy, aIsPrivate,
|
||||
aIsExternal, aForceNotRemote = false,
|
||||
aUserContextId = Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID,
|
||||
aOpener = null, aTriggeringPrincipal = null,
|
||||
aNextTabParentId = 0) {
|
||||
aIsExternal, aForceNotRemote = false,
|
||||
aUserContextId = Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID,
|
||||
aOpener = null, aTriggeringPrincipal = null,
|
||||
aNextTabParentId = 0, aName = "") {
|
||||
let win, needToFocusWin;
|
||||
|
||||
// try the current window. if we're in a popup, fall back on the most recent browser window
|
||||
|
@ -5095,6 +5095,7 @@ nsBrowserAccess.prototype = {
|
|||
forceNotRemote: aForceNotRemote,
|
||||
opener: aOpener,
|
||||
nextTabParentId: aNextTabParentId,
|
||||
name: aName,
|
||||
});
|
||||
let browser = win.gBrowser.getBrowserForTab(tab);
|
||||
|
||||
|
@ -5198,7 +5199,7 @@ nsBrowserAccess.prototype = {
|
|||
},
|
||||
|
||||
openURIInFrame: function browser_openURIInFrame(aURI, aParams, aWhere, aFlags,
|
||||
aNextTabParentId) {
|
||||
aNextTabParentId, aName) {
|
||||
if (aWhere != Ci.nsIBrowserDOMWindow.OPEN_NEWTAB) {
|
||||
dump("Error: openURIInFrame can only open in new tabs");
|
||||
return null;
|
||||
|
@ -5218,7 +5219,7 @@ nsBrowserAccess.prototype = {
|
|||
isExternal, false,
|
||||
userContextId, null,
|
||||
aParams.triggeringPrincipal,
|
||||
aNextTabParentId);
|
||||
aNextTabParentId, aName);
|
||||
if (browser)
|
||||
return browser.QueryInterface(Ci.nsIFrameLoaderOwner);
|
||||
|
||||
|
|
|
@ -1558,6 +1558,7 @@
|
|||
var aCreateLazyBrowser;
|
||||
var aNextTabParentId;
|
||||
var aFocusUrlBar;
|
||||
var aName;
|
||||
if (arguments.length == 2 &&
|
||||
typeof arguments[1] == "object" &&
|
||||
!(arguments[1] instanceof Ci.nsIURI)) {
|
||||
|
@ -1584,6 +1585,7 @@
|
|||
aCreateLazyBrowser = params.createLazyBrowser;
|
||||
aNextTabParentId = params.nextTabParentId;
|
||||
aFocusUrlBar = params.focusUrlBar;
|
||||
aName = params.name;
|
||||
}
|
||||
|
||||
var bgLoad = (aLoadInBackground != null) ? aLoadInBackground :
|
||||
|
@ -1612,7 +1614,8 @@
|
|||
opener: aOpener,
|
||||
isPrerendered: aIsPrerendered,
|
||||
nextTabParentId: aNextTabParentId,
|
||||
focusUrlBar: aFocusUrlBar });
|
||||
focusUrlBar: aFocusUrlBar,
|
||||
name: aName });
|
||||
if (!bgLoad)
|
||||
this.selectedTab = tab;
|
||||
|
||||
|
@ -2058,6 +2061,14 @@
|
|||
b.sameProcessAsFrameLoader = aParams.sameProcessAsFrameLoader;
|
||||
}
|
||||
|
||||
// This will be used by gecko to control the name of the opened
|
||||
// window.
|
||||
if (aParams.name) {
|
||||
// XXX: The `name` property is special in HTML and XUL. Should
|
||||
// we use a different attribute name for this?
|
||||
b.setAttribute("name", aParams.name);
|
||||
}
|
||||
|
||||
// Create the browserStack container
|
||||
var stack = document.createElementNS(NS_XUL, "stack");
|
||||
stack.className = "browserStack";
|
||||
|
@ -2318,6 +2329,7 @@
|
|||
var aNextTabParentId;
|
||||
var aNoInitialLabel;
|
||||
var aFocusUrlBar;
|
||||
var aName;
|
||||
if (arguments.length == 2 &&
|
||||
typeof arguments[1] == "object" &&
|
||||
!(arguments[1] instanceof Ci.nsIURI)) {
|
||||
|
@ -2348,6 +2360,7 @@
|
|||
aNextTabParentId = params.nextTabParentId;
|
||||
aNoInitialLabel = params.noInitialLabel;
|
||||
aFocusUrlBar = params.focusUrlBar;
|
||||
aName = params.name;
|
||||
}
|
||||
|
||||
// if we're adding tabs, we're past interrupt mode, ditch the owner
|
||||
|
@ -2474,7 +2487,8 @@
|
|||
sameProcessAsFrameLoader: aSameProcessAsFrameLoader,
|
||||
opener: aOpener,
|
||||
isPrerendered: aIsPrerendered,
|
||||
nextTabParentId: aNextTabParentId });
|
||||
nextTabParentId: aNextTabParentId,
|
||||
name: aName });
|
||||
}
|
||||
|
||||
t.linkedBrowser = b;
|
||||
|
|
|
@ -9,6 +9,7 @@ support-files =
|
|||
skip-if = (os == "linux" && debug) # linux: bug 976544
|
||||
[browser_devices_get_user_media_anim.js]
|
||||
[browser_devices_get_user_media_in_frame.js]
|
||||
skip-if = debug # bug 1369731
|
||||
[browser_devices_get_user_media_multi_process.js]
|
||||
skip-if = e10s && (asan || debug) # bug 1347625
|
||||
[browser_devices_get_user_media_screen.js]
|
||||
|
|
|
@ -107,6 +107,8 @@ class BasePopup {
|
|||
|
||||
this.destroyed = true;
|
||||
this.browserLoadedDeferred.reject(new Error("Popup destroyed"));
|
||||
// Ignore unhandled rejections if the "attach" method is not called.
|
||||
this.browserLoaded.catch(() => {});
|
||||
|
||||
BasePopup.instances.get(this.window).delete(this.extension);
|
||||
|
||||
|
|
|
@ -1310,7 +1310,7 @@ var SessionStoreInternal = {
|
|||
// Let everyone know we're done.
|
||||
this._deferredInitialized.resolve();
|
||||
}
|
||||
}, console.error);
|
||||
}).catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -270,9 +270,11 @@ FormAutofillParent.prototype = {
|
|||
let {address} = data;
|
||||
|
||||
if (address.guid) {
|
||||
// TODO: Show update doorhanger(bug 1303513) and set probe(bug 990200)
|
||||
// if (!profileStorage.addresses.mergeIfPossible(address.guid, address.record)) {
|
||||
// }
|
||||
if (!this.profileStorage.addresses.mergeIfPossible(address.guid, address.record)) {
|
||||
// TODO: Show update doorhanger(bug 1303513) and set probe(bug 990200)
|
||||
return;
|
||||
}
|
||||
this.profileStorage.addresses.notifyUsed(address.guid);
|
||||
} else {
|
||||
// TODO: Add first time use probe(bug 990199) and doorhanger(bug 1303510)
|
||||
// profileStorage.addresses.add(address.record);
|
||||
|
|
|
@ -379,6 +379,12 @@ class AutofillRecords {
|
|||
|
||||
// An interface to be inherited.
|
||||
_recordWriteProcessor(record) {}
|
||||
|
||||
// An interface to be inherited.
|
||||
mergeIfPossible(guid, record) {}
|
||||
|
||||
// An interface to be inherited.
|
||||
mergeToStorage(targetRecord) {}
|
||||
}
|
||||
|
||||
class Addresses extends AutofillRecords {
|
||||
|
@ -454,6 +460,85 @@ class Addresses extends AutofillRecords {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge new address into the specified address if mergeable.
|
||||
*
|
||||
* @param {string} guid
|
||||
* Indicates which address to merge.
|
||||
* @param {Object} address
|
||||
* The new address used to merge into the old one.
|
||||
* @returns {boolean}
|
||||
* Return true if address is merged into target with specific guid or false if not.
|
||||
*/
|
||||
mergeIfPossible(guid, address) {
|
||||
this.log.debug("mergeIfPossible:", guid, address);
|
||||
|
||||
let addressFound = this._findByGUID(guid);
|
||||
if (!addressFound) {
|
||||
throw new Error("No matching address.");
|
||||
}
|
||||
|
||||
let addressToMerge = this._clone(address);
|
||||
this._normalizeRecord(addressToMerge);
|
||||
let hasMatchingField = false;
|
||||
|
||||
for (let field of this.VALID_FIELDS) {
|
||||
if (addressToMerge[field] !== undefined && addressFound[field] !== undefined) {
|
||||
if (addressToMerge[field] != addressFound[field]) {
|
||||
this.log.debug("Conflicts: field", field, "has different value.");
|
||||
return false;
|
||||
}
|
||||
hasMatchingField = true;
|
||||
}
|
||||
}
|
||||
|
||||
// We merge the address only when at least one field has the same value.
|
||||
if (!hasMatchingField) {
|
||||
this.log.debug("Unable to merge because no field has the same value");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Early return if the data is the same.
|
||||
let exactlyMatch = this.VALID_FIELDS.every((field) =>
|
||||
addressFound[field] === addressToMerge[field]
|
||||
);
|
||||
if (exactlyMatch) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (let field in addressToMerge) {
|
||||
if (this.VALID_FIELDS.includes(field)) {
|
||||
addressFound[field] = addressToMerge[field];
|
||||
}
|
||||
}
|
||||
|
||||
addressFound.timeLastModified = Date.now();
|
||||
this._store.saveSoon();
|
||||
let str = Cc["@mozilla.org/supports-string;1"]
|
||||
.createInstance(Ci.nsISupportsString);
|
||||
str.data = guid;
|
||||
Services.obs.notifyObservers(str, "formautofill-storage-changed", "merge");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the address if storage has multiple mergeable records.
|
||||
* @param {Object} targetAddress
|
||||
* The address for merge.
|
||||
* @returns {boolean}
|
||||
* Return true if the target address is mergeable or false if not.
|
||||
*/
|
||||
mergeToStorage(targetAddress) {
|
||||
let merged = false;
|
||||
for (let address of this._store.data[this._collectionName]) {
|
||||
if (this.mergeIfPossible(address.guid, targetAddress)) {
|
||||
merged = true;
|
||||
}
|
||||
}
|
||||
this.log.debug("Existing records matching and merging is", merged);
|
||||
return merged;
|
||||
}
|
||||
}
|
||||
|
||||
class CreditCards extends AutofillRecords {
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
* Provides infrastructure for automated formautofill components tests.
|
||||
*/
|
||||
|
||||
/* exported getTempFile, loadFormAutofillContent, runHeuristicsTest, sinon */
|
||||
/* exported getTempFile, loadFormAutofillContent, runHeuristicsTest, sinon,
|
||||
* initProfileStorage
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
|
@ -79,6 +81,26 @@ function getTempFile(leafName) {
|
|||
return file;
|
||||
}
|
||||
|
||||
async function initProfileStorage(fileName, records) {
|
||||
let {ProfileStorage} = Cu.import("resource://formautofill/ProfileStorage.jsm", {});
|
||||
let path = getTempFile(fileName).path;
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
if (!records || !Array.isArray(records)) {
|
||||
return profileStorage;
|
||||
}
|
||||
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
|
||||
(subject, data) => data == "add");
|
||||
for (let record of records) {
|
||||
do_check_true(profileStorage.addresses.add(record));
|
||||
await onChanged;
|
||||
}
|
||||
await profileStorage._saveImmediately();
|
||||
return profileStorage;
|
||||
}
|
||||
|
||||
function runHeuristicsTest(patterns, fixturePathPrefix) {
|
||||
Cu.import("resource://gre/modules/FormLikeFactory.jsm");
|
||||
Cu.import("resource://formautofill/FormAutofillHeuristics.jsm");
|
||||
|
@ -115,7 +137,7 @@ function runHeuristicsTest(patterns, fixturePathPrefix) {
|
|||
});
|
||||
}
|
||||
|
||||
add_task(function* head_initialize() {
|
||||
add_task(async function head_initialize() {
|
||||
Services.prefs.setBoolPref("extensions.formautofill.experimental", true);
|
||||
Services.prefs.setBoolPref("extensions.formautofill.heuristics.enabled", true);
|
||||
Services.prefs.setBoolPref("dom.forms.autocomplete.experimental", true);
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {ProfileStorage} = Cu.import("resource://formautofill/ProfileStorage.jsm", {});
|
||||
|
||||
const TEST_STORE_FILE_NAME = "test-profile.json";
|
||||
|
||||
const TEST_ADDRESS_1 = {
|
||||
|
@ -32,22 +30,79 @@ const TEST_ADDRESS_3 = {
|
|||
"postal-code": "12345",
|
||||
};
|
||||
|
||||
const TEST_ADDRESS_4 = {
|
||||
"given-name": "Timothy",
|
||||
"additional-name": "John",
|
||||
"family-name": "Berners-Lee",
|
||||
organization: "World Wide Web Consortium",
|
||||
};
|
||||
|
||||
const TEST_ADDRESS_WITH_INVALID_FIELD = {
|
||||
"street-address": "Another Address",
|
||||
invalidField: "INVALID",
|
||||
};
|
||||
|
||||
let prepareTestRecords = async function(path) {
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
|
||||
(subject, data) => data == "add");
|
||||
do_check_true(profileStorage.addresses.add(TEST_ADDRESS_1));
|
||||
await onChanged;
|
||||
do_check_true(profileStorage.addresses.add(TEST_ADDRESS_2));
|
||||
await profileStorage._saveImmediately();
|
||||
};
|
||||
const MERGE_TESTCASES = [
|
||||
{
|
||||
description: "Merge a superset",
|
||||
addressInStorage: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue",
|
||||
"tel": "1-650-903-0800",
|
||||
},
|
||||
addressToMerge: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue",
|
||||
"tel": "1-650-903-0800",
|
||||
country: "US",
|
||||
},
|
||||
expectedAddress: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue",
|
||||
"tel": "1-650-903-0800",
|
||||
country: "US",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Merge a subset",
|
||||
addressInStorage: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue",
|
||||
"tel": "1-650-903-0800",
|
||||
country: "US",
|
||||
},
|
||||
addressToMerge: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue",
|
||||
"tel": "1-650-903-0800",
|
||||
},
|
||||
expectedAddress: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue",
|
||||
"tel": "1-650-903-0800",
|
||||
country: "US",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Merge an address with partial overlaps",
|
||||
addressInStorage: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue",
|
||||
"tel": "1-650-903-0800",
|
||||
},
|
||||
addressToMerge: {
|
||||
"street-address": "331 E. Evelyn Avenue",
|
||||
"tel": "1-650-903-0800",
|
||||
country: "US",
|
||||
},
|
||||
expectedAddress: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue",
|
||||
"tel": "1-650-903-0800",
|
||||
country: "US",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
let do_check_record_matches = (recordWithMeta, record) => {
|
||||
for (let key in record) {
|
||||
|
@ -56,9 +111,7 @@ let do_check_record_matches = (recordWithMeta, record) => {
|
|||
};
|
||||
|
||||
add_task(async function test_initialize() {
|
||||
let path = getTempFile(TEST_STORE_FILE_NAME).path;
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
await profileStorage.initialize();
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME);
|
||||
|
||||
do_check_eq(profileStorage._store.data.version, 1);
|
||||
do_check_eq(profileStorage._store.data.addresses.length, 0);
|
||||
|
@ -68,18 +121,14 @@ add_task(async function test_initialize() {
|
|||
|
||||
await profileStorage._saveImmediately();
|
||||
|
||||
profileStorage = new ProfileStorage(path);
|
||||
await profileStorage.initialize();
|
||||
profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME);
|
||||
|
||||
Assert.deepEqual(profileStorage._store.data, data);
|
||||
});
|
||||
|
||||
add_task(async function test_getAll() {
|
||||
let path = getTempFile(TEST_STORE_FILE_NAME).path;
|
||||
await prepareTestRecords(path);
|
||||
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
await profileStorage.initialize();
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
|
||||
|
@ -104,11 +153,8 @@ add_task(async function test_getAll() {
|
|||
});
|
||||
|
||||
add_task(async function test_get() {
|
||||
let path = getTempFile(TEST_STORE_FILE_NAME).path;
|
||||
await prepareTestRecords(path);
|
||||
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
await profileStorage.initialize();
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
let guid = addresses[0].guid;
|
||||
|
@ -124,11 +170,8 @@ add_task(async function test_get() {
|
|||
});
|
||||
|
||||
add_task(async function test_getByFilter() {
|
||||
let path = getTempFile(TEST_STORE_FILE_NAME).path;
|
||||
await prepareTestRecords(path);
|
||||
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
await profileStorage.initialize();
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
|
||||
let filter = {info: {fieldName: "street-address"}, searchString: "Some"};
|
||||
let addresses = profileStorage.addresses.getByFilter(filter);
|
||||
|
@ -161,11 +204,8 @@ add_task(async function test_getByFilter() {
|
|||
});
|
||||
|
||||
add_task(async function test_add() {
|
||||
let path = getTempFile(TEST_STORE_FILE_NAME).path;
|
||||
await prepareTestRecords(path);
|
||||
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
await profileStorage.initialize();
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
|
||||
|
@ -186,11 +226,8 @@ add_task(async function test_add() {
|
|||
});
|
||||
|
||||
add_task(async function test_update() {
|
||||
let path = getTempFile(TEST_STORE_FILE_NAME).path;
|
||||
await prepareTestRecords(path);
|
||||
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
await profileStorage.initialize();
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
let guid = addresses[1].guid;
|
||||
|
@ -205,9 +242,6 @@ add_task(async function test_update() {
|
|||
await onChanged;
|
||||
await profileStorage._saveImmediately();
|
||||
|
||||
profileStorage = new ProfileStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
let address = profileStorage.addresses.get(guid);
|
||||
|
||||
do_check_eq(address.country, undefined);
|
||||
|
@ -226,11 +260,8 @@ add_task(async function test_update() {
|
|||
});
|
||||
|
||||
add_task(async function test_notifyUsed() {
|
||||
let path = getTempFile(TEST_STORE_FILE_NAME).path;
|
||||
await prepareTestRecords(path);
|
||||
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
await profileStorage.initialize();
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
let guid = addresses[1].guid;
|
||||
|
@ -244,9 +275,6 @@ add_task(async function test_notifyUsed() {
|
|||
await onChanged;
|
||||
await profileStorage._saveImmediately();
|
||||
|
||||
profileStorage = new ProfileStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
let address = profileStorage.addresses.get(guid);
|
||||
|
||||
do_check_eq(address.timesUsed, timesUsed + 1);
|
||||
|
@ -257,11 +285,8 @@ add_task(async function test_notifyUsed() {
|
|||
});
|
||||
|
||||
add_task(async function test_remove() {
|
||||
let path = getTempFile(TEST_STORE_FILE_NAME).path;
|
||||
await prepareTestRecords(path);
|
||||
|
||||
let profileStorage = new ProfileStorage(path);
|
||||
await profileStorage.initialize();
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
let guid = addresses[1].guid;
|
||||
|
@ -275,12 +300,66 @@ add_task(async function test_remove() {
|
|||
await onChanged;
|
||||
await profileStorage._saveImmediately();
|
||||
|
||||
profileStorage = new ProfileStorage(path);
|
||||
await profileStorage.initialize();
|
||||
|
||||
addresses = profileStorage.addresses.getAll();
|
||||
|
||||
do_check_eq(addresses.length, 1);
|
||||
|
||||
do_check_eq(profileStorage.addresses.get(guid), null);
|
||||
});
|
||||
|
||||
MERGE_TESTCASES.forEach((testcase) => {
|
||||
add_task(async function test_merge() {
|
||||
do_print("Starting testcase: " + testcase.description);
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[testcase.addressInStorage]);
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
// Merge address and verify the guid in notifyObservers subject
|
||||
let onMerged = TestUtils.topicObserved(
|
||||
"formautofill-storage-changed",
|
||||
(subject, data) =>
|
||||
data == "merge" && subject.QueryInterface(Ci.nsISupportsString).data == addresses[0].guid
|
||||
);
|
||||
let timeLastModified = addresses[0].timeLastModified;
|
||||
Assert.equal(
|
||||
profileStorage.addresses.mergeIfPossible(addresses[0].guid, testcase.addressToMerge),
|
||||
true);
|
||||
await onMerged;
|
||||
addresses = profileStorage.addresses.getAll();
|
||||
Assert.equal(addresses.length, 1);
|
||||
Assert.notEqual(addresses[0].timeLastModified, timeLastModified);
|
||||
do_check_record_matches(addresses[0], testcase.expectedAddress);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_merge_same_address() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME, [TEST_ADDRESS_1]);
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
let timeLastModified = addresses[0].timeLastModified;
|
||||
// Merge same address will still return true but it won't update timeLastModified.
|
||||
Assert.equal(profileStorage.addresses.mergeIfPossible(addresses[0].guid, TEST_ADDRESS_1), true);
|
||||
Assert.equal(addresses[0].timeLastModified, timeLastModified);
|
||||
});
|
||||
|
||||
add_task(async function test_merge_unable_merge() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
|
||||
let addresses = profileStorage.addresses.getAll();
|
||||
// Unable to merge because of conflict
|
||||
do_check_eq(profileStorage.addresses.mergeIfPossible(addresses[1].guid, TEST_ADDRESS_3), false);
|
||||
|
||||
// Unable to merge because no overlap
|
||||
do_check_eq(profileStorage.addresses.mergeIfPossible(addresses[1].guid, TEST_ADDRESS_4), false);
|
||||
});
|
||||
|
||||
add_task(async function test_mergeToStorage() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
// Merge an address to storage
|
||||
let anotherAddress = profileStorage.addresses._clone(TEST_ADDRESS_2);
|
||||
profileStorage.addresses.add(anotherAddress);
|
||||
anotherAddress.email = "timbl@w3.org";
|
||||
do_check_eq(profileStorage.addresses.mergeToStorage(anotherAddress), true);
|
||||
do_check_eq(profileStorage.addresses.getAll()[1].email, anotherAddress.email);
|
||||
do_check_eq(profileStorage.addresses.getAll()[2].email, anotherAddress.email);
|
||||
});
|
||||
|
|
|
@ -255,7 +255,8 @@ this.PreferenceExperiments = {
|
|||
preferenceName,
|
||||
observer(newValue) {
|
||||
if (newValue !== preferenceValue) {
|
||||
PreferenceExperiments.stop(experimentName, false);
|
||||
PreferenceExperiments.stop(experimentName, false)
|
||||
.catch(Cu.reportError);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -383,7 +383,7 @@ this.TabCrashHandler = {
|
|||
CrashSubmit.submit(dumpID, {
|
||||
recordSubmission: true,
|
||||
extraExtraKeyVals,
|
||||
}).then(null, Cu.reportError);
|
||||
}).catch(Cu.reportError);
|
||||
|
||||
this.prefs.setBoolPref("sendReport", true);
|
||||
this.prefs.setBoolPref("includeURL", includeURL);
|
||||
|
@ -881,7 +881,7 @@ this.UnsubmittedCrashHandler = {
|
|||
extraExtraKeyVals: {
|
||||
"SubmittedFromInfobar": true,
|
||||
},
|
||||
});
|
||||
}).catch(Cu.reportError);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -995,7 +995,7 @@ this.PluginCrashReporter = {
|
|||
});
|
||||
|
||||
if (browserDumpID)
|
||||
CrashSubmit.submit(browserDumpID);
|
||||
CrashSubmit.submit(browserDumpID).catch(Cu.reportError);
|
||||
|
||||
this.broadcastState(runID, "submitting");
|
||||
|
||||
|
|
|
@ -1027,3 +1027,8 @@ def security_hardening_cflags(value, c_compiler):
|
|||
|
||||
add_old_configure_assignment('HARDENING_CFLAGS', security_hardening_cflags)
|
||||
imply_option('--enable-pie', depends_if('--enable-hardening')(lambda v: v))
|
||||
|
||||
option(env='RUSTFLAGS',
|
||||
nargs=1,
|
||||
help='Rust compiler flags')
|
||||
set_config('RUSTFLAGS', depends('RUSTFLAGS')(lambda flags: flags))
|
||||
|
|
|
@ -936,15 +936,16 @@ endif
|
|||
# optimization levels in our Cargo.toml files all the time, and override the
|
||||
# optimization level here, if necessary. (The Cargo.toml files already
|
||||
# specify debug-assertions appropriately for --{disable,enable}-debug.)
|
||||
default_rustflags =
|
||||
ifndef MOZ_OPTIMIZE
|
||||
rustflags = -C opt-level=0
|
||||
default_rustflags = -C opt-level=0
|
||||
# Unfortunately, -C opt-level=0 implies -C debug-assertions, so we need
|
||||
# to explicitly disable them when MOZ_DEBUG_RUST is not set.
|
||||
ifndef MOZ_DEBUG_RUST
|
||||
rustflags += -C debug-assertions=no
|
||||
default_rustflags += -C debug-assertions=no
|
||||
endif
|
||||
rustflags_override = RUSTFLAGS='$(rustflags)'
|
||||
endif
|
||||
rustflags_override = RUSTFLAGS='$(default_rustflags) $(RUSTFLAGS)'
|
||||
|
||||
ifdef MOZ_MSVCBITS
|
||||
# If we are building a MozillaBuild shell, we want to clear out the
|
||||
|
|
|
@ -43,7 +43,15 @@
|
|||
transition: var(--base-transition);
|
||||
}
|
||||
|
||||
.landing-page .panel header input[type=button] {
|
||||
.landing-page .panel .hero {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.landing-page .panel input[type=button] {
|
||||
background-color: var(--theme-tab-toolbar-background);
|
||||
color: var(--theme-comment);
|
||||
font-size: var(--ui-element-font-size);
|
||||
|
@ -879,11 +887,6 @@ html .arrow.expanded svg {
|
|||
|
||||
.search-field.big {
|
||||
height: 40px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.search-field.big input {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.search-field i {
|
||||
|
@ -1063,6 +1066,72 @@ html .arrow.expanded svg {
|
|||
.theme-dark .result-list {
|
||||
background-color: var(--theme-body-background);
|
||||
}
|
||||
.tree {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
white-space: nowrap;
|
||||
overflow: auto;
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.tree button {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tree .node {
|
||||
padding: 2px 5px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tree .node.focused {
|
||||
color: white;
|
||||
background-color: var(--theme-selection-background);
|
||||
}
|
||||
|
||||
.theme-dark .tree .node.focused {
|
||||
background-color: var(--theme-selection-background-semitransparent);
|
||||
}
|
||||
|
||||
html:not([dir="rtl"]) .tree .node > div {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .tree .node > div {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.tree .node.focused svg {
|
||||
fill: white;
|
||||
}
|
||||
|
||||
.tree-node button {
|
||||
position: fixed;
|
||||
}
|
||||
.project-text-search .result {
|
||||
display: flex;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.project-text-search .file-result {
|
||||
font-weight: bold;
|
||||
margin-top: 20px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.project-text-search .line-match {
|
||||
font-family: monospace;
|
||||
display: "flex";
|
||||
grow: 1;
|
||||
}
|
||||
|
||||
.project-text-search .result .line-number {
|
||||
padding-right: 5px;
|
||||
}
|
||||
.sources-panel {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
|
@ -1129,9 +1198,59 @@ html .arrow.expanded svg {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
.sources-panel .source-footer {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sources-panel .outline {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sources-panel .outline.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.source-footer {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.source-footer .tab {
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
border: 1px solid transparent;
|
||||
border-bottom-left-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
transition: all 0.25s ease;
|
||||
overflow: hidden;
|
||||
padding: 5px;
|
||||
margin-bottom: 4px;
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.source-footer .tab:hover {
|
||||
background-color: var(--theme-toolbar-background-alt);
|
||||
border-color: var(--theme-splitter-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.source-footer .tab.active {
|
||||
color: var(--theme-body-color);
|
||||
background-color: var(--theme-body-background);
|
||||
border-color: var(--theme-splitter-color);
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
.source-footer .tab.active path,
|
||||
.source-footer .tab:hover path {
|
||||
fill: var(--theme-body-color);
|
||||
}
|
||||
.outline-list {
|
||||
list-style-type: "-";
|
||||
}
|
||||
|
@ -1161,52 +1280,6 @@ html .arrow.expanded svg {
|
|||
.function-signature .comma {
|
||||
color: var(--object-color);
|
||||
}
|
||||
.tree {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
white-space: nowrap;
|
||||
overflow: auto;
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.tree button {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tree .node {
|
||||
padding: 2px 5px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tree .node.focused {
|
||||
color: white;
|
||||
background-color: var(--theme-selection-background);
|
||||
}
|
||||
|
||||
.theme-dark .tree .node.focused {
|
||||
background-color: var(--theme-selection-background-semitransparent);
|
||||
}
|
||||
|
||||
html:not([dir="rtl"]) .tree .node > div {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .tree .node > div {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.tree .node.focused svg {
|
||||
fill: white;
|
||||
}
|
||||
|
||||
.tree-node button {
|
||||
position: fixed;
|
||||
}
|
||||
.conditional-breakpoint-panel {
|
||||
cursor: initial;
|
||||
margin: 1em 0;
|
||||
|
@ -1220,8 +1293,12 @@ html[dir="rtl"] .tree .node > div {
|
|||
|
||||
.conditional-breakpoint-panel .prompt {
|
||||
font-size: 1.8em;
|
||||
color: var(--theme-comment-alt);
|
||||
color: var(--theme-conditional-breakpoint-color);
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
padding-bottom: 3px;
|
||||
text-align: right;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.conditional-breakpoint-panel input {
|
||||
|
@ -1230,7 +1307,7 @@ html[dir="rtl"] .tree .node > div {
|
|||
border: none;
|
||||
background: var(--theme-toolbar-background);
|
||||
font-size: 14px;
|
||||
color: var(--theme-comment);
|
||||
color: var(--theme-conditional-breakpoint-color);
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
|
@ -1361,7 +1438,6 @@ html .toggle-button-end.vertical svg {
|
|||
.source-footer .blackbox-summary {
|
||||
color: var(--theme-body-color);
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -1571,7 +1647,7 @@ html .toggle-button-end.vertical svg {
|
|||
}
|
||||
|
||||
.selected-token {
|
||||
background-color: var(--theme-search-overlays-semitransparent);
|
||||
background-color: var(--theme-highlight-yellow);
|
||||
color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
|
@ -1651,6 +1727,9 @@ html .toggle-button-end.vertical svg {
|
|||
.editor-wrapper {
|
||||
--debug-line-background: rgba(226, 236, 247, 0.5);
|
||||
--debug-line-border: rgb(145, 188, 219);
|
||||
--editor-searchbar-height: 27px;
|
||||
--editor-second-searchbar-height: 27px;
|
||||
|
||||
}
|
||||
|
||||
.theme-dark .editor-wrapper {
|
||||
|
@ -1658,6 +1737,27 @@ html .toggle-button-end.vertical svg {
|
|||
--debug-line-border: rgb(119, 134, 162);
|
||||
}
|
||||
|
||||
.editor-wrapper .CodeMirror-linewidget {
|
||||
margin-right: -7px;
|
||||
}
|
||||
|
||||
.theme-dark {
|
||||
--theme-conditional-breakpoint-color: #9fa4a9;
|
||||
}
|
||||
|
||||
.theme-light {
|
||||
--theme-conditional-breakpoint-color: #ccd1d5;
|
||||
}
|
||||
|
||||
.theme-firebug {
|
||||
--theme-conditional-breakpoint-color: #ccd1d5;
|
||||
}
|
||||
|
||||
.out-of-scope .CodeMirror-line,
|
||||
.out-of-scope .CodeMirror-linenumber {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/**
|
||||
* There's a known codemirror flex issue with chrome that this addresses.
|
||||
* BUG https://github.com/devtools-html/debugger.html/issues/63
|
||||
|
@ -1669,8 +1769,6 @@ html .toggle-button-end.vertical svg {
|
|||
top: 30px;
|
||||
left: 0px;
|
||||
--editor-footer-height: 27px;
|
||||
--editor-searchbar-height: 27px;
|
||||
--editor-second-searchbar-height: 27px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .editor-mount {
|
||||
|
@ -2285,6 +2383,7 @@ html .breakpoints-list .breakpoint.paused {
|
|||
padding: 5px;
|
||||
transition: all 0.25s ease;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -8,7 +8,7 @@ function toggleBreakpoint(dbg, index) {
|
|||
}
|
||||
|
||||
function removeBreakpoint(dbg, index) {
|
||||
return Task.spawn(function* () {
|
||||
return Task.spawn(function*() {
|
||||
const bp = findElement(dbg, "breakpointItem", index);
|
||||
bp.querySelector(".close-btn").click();
|
||||
yield waitForDispatch(dbg, "REMOVE_BREAKPOINT");
|
||||
|
@ -16,21 +16,21 @@ function removeBreakpoint(dbg, index) {
|
|||
}
|
||||
|
||||
function disableBreakpoint(dbg, index) {
|
||||
return Task.spawn(function* () {
|
||||
return Task.spawn(function*() {
|
||||
toggleBreakpoint(dbg, index);
|
||||
yield waitForDispatch(dbg, "REMOVE_BREAKPOINT");
|
||||
yield waitForDispatch(dbg, "DISABLE_BREAKPOINT");
|
||||
});
|
||||
}
|
||||
|
||||
function enableBreakpoint(dbg, index) {
|
||||
return Task.spawn(function* () {
|
||||
return Task.spawn(function*() {
|
||||
toggleBreakpoint(dbg, index);
|
||||
yield waitForDispatch(dbg, "ADD_BREAKPOINT");
|
||||
yield waitForDispatch(dbg, "ENABLE_BREAKPOINT");
|
||||
});
|
||||
}
|
||||
|
||||
function toggleBreakpoints(dbg) {
|
||||
return Task.spawn(function* () {
|
||||
return Task.spawn(function*() {
|
||||
clickElement(dbg, "toggleBreakpoints");
|
||||
yield waitForDispatch(dbg, "TOGGLE_BREAKPOINTS");
|
||||
});
|
||||
|
@ -47,7 +47,7 @@ function findBreakpoints(dbg) {
|
|||
return getBreakpoints(getState());
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-scripts.html");
|
||||
|
||||
// Create two breakpoints
|
||||
|
@ -70,7 +70,7 @@ add_task(function* () {
|
|||
});
|
||||
|
||||
// toggle all
|
||||
add_task(function* () {
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-scripts.html");
|
||||
|
||||
// Create two breakpoints
|
||||
|
|
|
@ -21,12 +21,10 @@ function initChromeDebugger() {
|
|||
}
|
||||
|
||||
function onClose() {
|
||||
ok(!gProcess._dbgProcess.isRunning,
|
||||
"The remote debugger process isn't closed as it should be!");
|
||||
is(gProcess._dbgProcess.exitValue, (Services.appinfo.OS == "WINNT" ? 0 : 256),
|
||||
is(gProcess._dbgProcess.exitCode, (Services.appinfo.OS == "WINNT" ? -9 : -15),
|
||||
"The remote debugger process didn't die cleanly.");
|
||||
|
||||
info("process exit value: " + gProcess._dbgProcess.exitValue);
|
||||
info("process exit value: " + gProcess._dbgProcess.exitCode);
|
||||
|
||||
info("profile path: " + gProcess._dbgProfilePath);
|
||||
|
||||
|
@ -47,7 +45,7 @@ add_task(function* () {
|
|||
|
||||
ok(gProcess._dbgProcess,
|
||||
"The remote debugger process wasn't created properly!");
|
||||
ok(gProcess._dbgProcess.isRunning,
|
||||
ok(gProcess._dbgProcess.exitCode == null,
|
||||
"The remote debugger process isn't running!");
|
||||
is(typeof gProcess._dbgProcess.pid, "number",
|
||||
"The remote debugger process doesn't have a pid (?!)");
|
||||
|
@ -68,5 +66,5 @@ add_task(function* () {
|
|||
|
||||
info("profile path: " + gProcess._dbgProfilePath);
|
||||
|
||||
gProcess.close();
|
||||
yield gProcess.close();
|
||||
});
|
||||
|
|
|
@ -23,7 +23,7 @@ add_task(function*() {
|
|||
|
||||
toggleNode(dbg, 4);
|
||||
yield waitForDispatch(dbg, "LOAD_OBJECT_PROPERTIES");
|
||||
is(getLabel(dbg, 5), "length");
|
||||
is(getLabel(dbg, 5), "arguments");
|
||||
|
||||
yield stepOver(dbg);
|
||||
is(getLabel(dbg, 4), "foo()");
|
||||
|
|
|
@ -25,7 +25,7 @@ function test() {
|
|||
function performTest() {
|
||||
ok(gProcess._dbgProcess,
|
||||
"The remote debugger process wasn't created properly!");
|
||||
ok(gProcess._dbgProcess.isRunning,
|
||||
ok(gProcess._dbgProcess.exitCode == null,
|
||||
"The remote debugger process isn't running!");
|
||||
is(typeof gProcess._dbgProcess.pid, "number",
|
||||
"The remote debugger process doesn't have a pid (?!)");
|
||||
|
@ -46,9 +46,7 @@ function performTest() {
|
|||
}
|
||||
|
||||
function aOnClose() {
|
||||
ok(!gProcess._dbgProcess.isRunning,
|
||||
"The remote debugger process isn't closed as it should be!");
|
||||
is(gProcess._dbgProcess.exitValue, (Services.appinfo.OS == "WINNT" ? 0 : 256),
|
||||
is(gProcess._dbgProcess.exitCode, (Services.appinfo.OS == "WINNT" ? -9 : -15),
|
||||
"The remote debugger process didn't die cleanly.");
|
||||
|
||||
info("process exit value: " + gProcess._dbgProcess.exitValue);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
const { interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
const DBG_XUL = "chrome://devtools/content/framework/toolbox-process-window.xul";
|
||||
const CHROME_DEBUGGER_PROFILE_NAME = "chrome_debugger_profile";
|
||||
|
@ -14,6 +14,7 @@ const CHROME_DEBUGGER_PROFILE_NAME = "chrome_debugger_profile";
|
|||
const { require, DevToolsLoader } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Subprocess", "resource://gre/modules/Subprocess.jsm");
|
||||
XPCOMUtils.defineLazyGetter(this, "Telemetry", function () {
|
||||
return require("devtools/client/shared/telemetry");
|
||||
});
|
||||
|
@ -231,9 +232,8 @@ BrowserToolboxProcess.prototype = {
|
|||
*/
|
||||
_create: function () {
|
||||
dumpn("Initializing chrome debugging process.");
|
||||
let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
|
||||
this._dbgProcess = process;
|
||||
process.init(Services.dirsvc.get("XREExeF", Ci.nsIFile));
|
||||
|
||||
let command = Services.dirsvc.get("XREExeF", Ci.nsIFile).path;
|
||||
|
||||
let xulURI = DBG_XUL;
|
||||
|
||||
|
@ -260,28 +260,33 @@ BrowserToolboxProcess.prototype = {
|
|||
args.push("-purgecaches");
|
||||
}
|
||||
|
||||
// Disable safe mode for the new process in case this was opened via the
|
||||
// keyboard shortcut.
|
||||
let nsIEnvironment = Cc["@mozilla.org/process/environment;1"]
|
||||
.getService(Ci.nsIEnvironment);
|
||||
let originalValue = nsIEnvironment.get("MOZ_DISABLE_SAFE_MODE_KEY");
|
||||
nsIEnvironment.set("MOZ_DISABLE_SAFE_MODE_KEY", "1");
|
||||
this._dbgProcessPromise = Subprocess.call({
|
||||
command,
|
||||
arguments: args,
|
||||
environmentAppend: true,
|
||||
environment: {
|
||||
// Disable safe mode for the new process in case this was opened via the
|
||||
// keyboard shortcut.
|
||||
MOZ_DISABLE_SAFE_MODE_KEY: "1",
|
||||
},
|
||||
}).then(proc => {
|
||||
this._dbgProcess = proc;
|
||||
|
||||
process.runwAsync(args, args.length, { observe: () => this.close() });
|
||||
this._telemetry.toolOpened("jsbrowserdebugger");
|
||||
|
||||
// Now that the process has started, it's safe to reset the env variable.
|
||||
nsIEnvironment.set("MOZ_DISABLE_SAFE_MODE_KEY", originalValue);
|
||||
dumpn("Chrome toolbox is now running...");
|
||||
this.emit("run", this);
|
||||
|
||||
this._telemetry.toolOpened("jsbrowserdebugger");
|
||||
|
||||
dumpn("Chrome toolbox is now running...");
|
||||
this.emit("run", this);
|
||||
proc.stdin.close();
|
||||
proc.wait().then(() => this.close());
|
||||
return proc;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Closes the remote debugging server and kills the toolbox process.
|
||||
*/
|
||||
close: function () {
|
||||
close: async function () {
|
||||
if (this.closed) {
|
||||
return;
|
||||
}
|
||||
|
@ -289,9 +294,8 @@ BrowserToolboxProcess.prototype = {
|
|||
dumpn("Cleaning up the chrome debugging process.");
|
||||
Services.obs.removeObserver(this.close, "quit-application");
|
||||
|
||||
if (this._dbgProcess.isRunning) {
|
||||
this._dbgProcess.kill();
|
||||
}
|
||||
this._dbgProcess.stdout.close();
|
||||
await this._dbgProcess.kill();
|
||||
|
||||
this._telemetry.toolClosed("jsbrowserdebugger");
|
||||
if (this.debuggerServer) {
|
||||
|
|
|
@ -68,36 +68,6 @@ function openBoxModelView() {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the toolbox, with the inspector tool visible, and the layout view
|
||||
* sidebar tab selected to display the box model view with properties.
|
||||
*
|
||||
* @return {Promise} a promise that resolves when the inspector is ready and the box model
|
||||
* view is visible and ready.
|
||||
*/
|
||||
function openLayoutView() {
|
||||
return openInspectorSidebarTab("layoutview").then(data => {
|
||||
// The actual highligher show/hide methods are mocked in box model tests.
|
||||
// The highlighter is tested in devtools/inspector/test.
|
||||
function mockHighlighter({highlighter}) {
|
||||
highlighter.showBoxModel = function () {
|
||||
return promise.resolve();
|
||||
};
|
||||
highlighter.hideBoxModel = function () {
|
||||
return promise.resolve();
|
||||
};
|
||||
}
|
||||
mockHighlighter(data.toolbox);
|
||||
|
||||
return {
|
||||
toolbox: data.toolbox,
|
||||
inspector: data.inspector,
|
||||
boxmodel: data.inspector.getPanel("boxmodel"),
|
||||
testActor: data.testActor
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the boxmodel-view-updated event.
|
||||
*
|
||||
|
|
|
@ -95,7 +95,7 @@ module.exports = createClass({
|
|||
{
|
||||
className: "layout-no-grids",
|
||||
},
|
||||
getStr("layout.noGrids")
|
||||
getStr("layout.noGridsOnThisPage")
|
||||
);
|
||||
},
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ support-files =
|
|||
!/devtools/client/framework/test/shared-redux-head.js
|
||||
|
||||
[browser_grids_accordion-state.js]
|
||||
[browser_grids_color-in-rules-grid-toggle.js]
|
||||
[browser_grids_display-setting-extend-grid-lines.js]
|
||||
[browser_grids_display-setting-show-grid-line-numbers.js]
|
||||
[browser_grids_display-setting-show-grid-areas.js]
|
||||
|
@ -23,3 +24,4 @@ support-files =
|
|||
[browser_grids_grid-list-on-mutation-element-removed.js]
|
||||
[browser_grids_grid-list-toggle-multiple-grids.js]
|
||||
[browser_grids_grid-list-toggle-single-grid.js]
|
||||
[browser_grids_highlighter-setting-rules-grid-toggle.js]
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test toggling the grid highlighter in the rule view with changes to the grid color
|
||||
// from the layout view.
|
||||
|
||||
const TEST_URI = `
|
||||
<style type='text/css'>
|
||||
#grid {
|
||||
display: grid;
|
||||
}
|
||||
</style>
|
||||
<div id="grid">
|
||||
<div id="cell1">cell1</div>
|
||||
<div id="cell2">cell2</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
add_task(function* () {
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let { inspector, gridInspector } = yield openLayoutView();
|
||||
let { document: doc } = gridInspector;
|
||||
let { store } = inspector;
|
||||
let cPicker = gridInspector.getSwatchColorPickerTooltip();
|
||||
let spectrum = cPicker.spectrum;
|
||||
let swatch = doc.querySelector(".grid-color-swatch");
|
||||
|
||||
info("Scrolling into view of the #grid color swatch.");
|
||||
swatch.scrollIntoView();
|
||||
|
||||
info("Opening the color picker by clicking on the #grid color swatch.");
|
||||
let onColorPickerReady = cPicker.once("ready");
|
||||
swatch.click();
|
||||
yield onColorPickerReady;
|
||||
|
||||
yield simulateColorPickerChange(cPicker, [0, 255, 0, .5]);
|
||||
|
||||
is(swatch.style.backgroundColor, "rgba(0, 255, 0, 0.5)",
|
||||
"The color swatch's background was updated.");
|
||||
|
||||
info("Pressing RETURN to commit the color change.");
|
||||
let onGridColorUpdate = waitUntilState(store, state =>
|
||||
state.grids[0].color === "#00FF0080");
|
||||
let onColorPickerHidden = cPicker.tooltip.once("hidden");
|
||||
focusAndSendKey(spectrum.element.ownerDocument.defaultView, "RETURN");
|
||||
yield onColorPickerHidden;
|
||||
yield onGridColorUpdate;
|
||||
|
||||
is(swatch.style.backgroundColor, "rgba(0, 255, 0, 0.5)",
|
||||
"The color swatch's background was kept after RETURN.");
|
||||
|
||||
info("Selecting the rule view.");
|
||||
let ruleView = selectRuleView(inspector);
|
||||
let highlighters = ruleView.highlighters;
|
||||
|
||||
yield selectNode("#grid", inspector);
|
||||
|
||||
let container = getRuleViewProperty(ruleView, "#grid", "display").valueSpan;
|
||||
let gridToggle = container.querySelector(".ruleview-grid");
|
||||
|
||||
info("Toggling ON the CSS grid highlighter from the rule-view.");
|
||||
let onHighlighterShown = highlighters.once("grid-highlighter-shown",
|
||||
(event, nodeFront, options) => {
|
||||
info("Checking the grid highlighter display settings.");
|
||||
let {
|
||||
color,
|
||||
showGridAreasOverlay,
|
||||
showGridLineNumbers,
|
||||
showInfiniteLines,
|
||||
} = options;
|
||||
|
||||
is(color, "#00FF0080", "CSS grid highlighter color is correct.");
|
||||
ok(!showGridAreasOverlay, "Show grid areas overlay option is off.");
|
||||
ok(!showGridLineNumbers, "Show grid line numbers option is off.");
|
||||
ok(!showInfiniteLines, "Show infinite lines option is off.");
|
||||
}
|
||||
);
|
||||
gridToggle.click();
|
||||
yield onHighlighterShown;
|
||||
});
|
|
@ -0,0 +1,70 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test toggling the grid highlighter in the rule view with changes in the grid
|
||||
// display setting from the layout view.
|
||||
|
||||
const TEST_URI = `
|
||||
<style type='text/css'>
|
||||
#grid {
|
||||
display: grid;
|
||||
}
|
||||
</style>
|
||||
<div id="grid">
|
||||
<div id="cell1">cell1</div>
|
||||
<div id="cell2">cell2</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const SHOW_INFINITE_LINES_PREF = "devtools.gridinspector.showInfiniteLines";
|
||||
|
||||
add_task(function* () {
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let { inspector, gridInspector } = yield openLayoutView();
|
||||
let { document: doc } = gridInspector;
|
||||
let { store } = inspector;
|
||||
|
||||
let checkbox = doc.getElementById("grid-setting-extend-grid-lines");
|
||||
|
||||
ok(!Services.prefs.getBoolPref(SHOW_INFINITE_LINES_PREF),
|
||||
"'Extend grid lines infinitely' is pref off by default.");
|
||||
|
||||
info("Toggling ON the 'Extend grid lines infinitely' setting.");
|
||||
let onCheckboxChange = waitUntilState(store, state =>
|
||||
state.highlighterSettings.showInfiniteLines);
|
||||
checkbox.click();
|
||||
yield onCheckboxChange;
|
||||
|
||||
info("Selecting the rule view.");
|
||||
let ruleView = selectRuleView(inspector);
|
||||
let highlighters = ruleView.highlighters;
|
||||
|
||||
yield selectNode("#grid", inspector);
|
||||
|
||||
let container = getRuleViewProperty(ruleView, "#grid", "display").valueSpan;
|
||||
let gridToggle = container.querySelector(".ruleview-grid");
|
||||
|
||||
info("Toggling ON the CSS grid highlighter from the rule-view.");
|
||||
let onHighlighterShown = highlighters.once("grid-highlighter-shown",
|
||||
(event, nodeFront, options) => {
|
||||
info("Checking the grid highlighter display settings.");
|
||||
let {
|
||||
color,
|
||||
showGridAreasOverlay,
|
||||
showGridLineNumbers,
|
||||
showInfiniteLines,
|
||||
} = options;
|
||||
|
||||
is(color, "#4B0082", "CSS grid highlighter color is correct.");
|
||||
ok(!showGridAreasOverlay, "Show grid areas overlay option is off.");
|
||||
ok(!showGridLineNumbers, "Show grid line numbers option is off.");
|
||||
ok(showInfiniteLines, "Show infinite lines option is on.");
|
||||
}
|
||||
);
|
||||
gridToggle.click();
|
||||
yield onHighlighterShown;
|
||||
|
||||
Services.prefs.clearUserPref(SHOW_INFINITE_LINES_PREF);
|
||||
});
|
|
@ -25,36 +25,6 @@ registerCleanupFunction(() => {
|
|||
|
||||
const HIGHLIGHTER_TYPE = "CssGridHighlighter";
|
||||
|
||||
/**
|
||||
* Open the toolbox, with the inspector tool visible, and the layout view
|
||||
* sidebar tab selected to display the box model view with properties.
|
||||
*
|
||||
* @return {Promise} a promise that resolves when the inspector is ready and the box model
|
||||
* view is visible and ready.
|
||||
*/
|
||||
function openLayoutView() {
|
||||
return openInspectorSidebarTab("layoutview").then(data => {
|
||||
// The actual highligher show/hide methods are mocked in box model tests.
|
||||
// The highlighter is tested in devtools/inspector/test.
|
||||
function mockHighlighter({highlighter}) {
|
||||
highlighter.showBoxModel = function () {
|
||||
return promise.resolve();
|
||||
};
|
||||
highlighter.hideBoxModel = function () {
|
||||
return promise.resolve();
|
||||
};
|
||||
}
|
||||
mockHighlighter(data.toolbox);
|
||||
|
||||
return {
|
||||
toolbox: data.toolbox,
|
||||
inspector: data.inspector,
|
||||
gridInspector: data.inspector.gridInspector,
|
||||
testActor: data.testActor
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate a color change in a given color picker tooltip.
|
||||
*
|
||||
|
|
|
@ -60,16 +60,6 @@ const App = createClass({
|
|||
},
|
||||
Accordion({
|
||||
items: [
|
||||
{
|
||||
header: BOXMODEL_L10N.getStr("boxmodel.title"),
|
||||
component: BoxModel,
|
||||
componentProps: this.props,
|
||||
opened: Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF),
|
||||
onToggled: () => {
|
||||
let opened = Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF);
|
||||
Services.prefs.setBoolPref(BOXMODEL_OPENED_PREF, !opened);
|
||||
}
|
||||
},
|
||||
{
|
||||
header: LAYOUT_L10N.getStr("layout.header"),
|
||||
component: Grid,
|
||||
|
@ -80,6 +70,16 @@ const App = createClass({
|
|||
Services.prefs.setBoolPref(GRID_OPENED_PREF, !opened);
|
||||
}
|
||||
},
|
||||
{
|
||||
header: BOXMODEL_L10N.getStr("boxmodel.title"),
|
||||
component: BoxModel,
|
||||
componentProps: this.props,
|
||||
opened: Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF),
|
||||
onToggled: () => {
|
||||
let opened = Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF);
|
||||
Services.prefs.setBoolPref(BOXMODEL_OPENED_PREF, !opened);
|
||||
}
|
||||
},
|
||||
]
|
||||
})
|
||||
);
|
||||
|
|
|
@ -384,9 +384,14 @@ HighlightersOverlay.prototype = {
|
|||
}
|
||||
|
||||
event.stopPropagation();
|
||||
this.toggleGridHighlighter(this.inspector.selection.nodeFront, {
|
||||
color: DEFAULT_GRID_COLOR
|
||||
});
|
||||
|
||||
let { store } = this.inspector;
|
||||
let { grids, highlighterSettings } = store.getState();
|
||||
let grid = grids.find(g => g.nodeFront == this.inspector.selection.nodeFront);
|
||||
|
||||
highlighterSettings.color = grid ? grid.color : DEFAULT_GRID_COLOR;
|
||||
|
||||
this.toggleGridHighlighter(this.inspector.selection.nodeFront, highlighterSettings);
|
||||
},
|
||||
|
||||
onMouseMove: function (event) {
|
||||
|
|
|
@ -109,6 +109,37 @@ function openComputedView() {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the toolbox, with the inspector tool visible, and the layout view
|
||||
* sidebar tab selected to display the box model view with properties.
|
||||
*
|
||||
* @return {Promise} a promise that resolves when the inspector is ready and the layout
|
||||
* view is visible and ready.
|
||||
*/
|
||||
function openLayoutView() {
|
||||
return openInspectorSidebarTab("layoutview").then(data => {
|
||||
// The actual highligher show/hide methods are mocked in box model tests.
|
||||
// The highlighter is tested in devtools/inspector/test.
|
||||
function mockHighlighter({highlighter}) {
|
||||
highlighter.showBoxModel = function () {
|
||||
return promise.resolve();
|
||||
};
|
||||
highlighter.hideBoxModel = function () {
|
||||
return promise.resolve();
|
||||
};
|
||||
}
|
||||
mockHighlighter(data.toolbox);
|
||||
|
||||
return {
|
||||
toolbox: data.toolbox,
|
||||
inspector: data.inspector,
|
||||
boxmodel: data.inspector.getPanel("boxmodel"),
|
||||
gridInspector: data.inspector.gridInspector,
|
||||
testActor: data.testActor
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the rule view sidebar tab on an already opened inspector panel.
|
||||
*
|
||||
|
|
|
@ -31,9 +31,9 @@ layout.header=Grid
|
|||
# settings container in the CSS Grid pane.
|
||||
layout.gridDisplaySettings=Grid Display Settings
|
||||
|
||||
# LOCALIZATION NOTE (layout.noGrids): In the case where there are no CSS grid
|
||||
# LOCALIZATION NOTE (layout.noGridsOnThisPage): In the case where there are no CSS grid
|
||||
# containers to display.
|
||||
layout.noGrids=No grids
|
||||
layout.noGridsOnThisPage=CSS Grid is not in use on this page
|
||||
|
||||
# LOCALIZATION NOTE (layout.overlayMultipleGrids): The header for the list of grid
|
||||
# container elements that can be highlighted in the CSS Grid pane.
|
||||
|
|
|
@ -24,6 +24,7 @@ pref("devtools.debugger.auto-black-box", true);
|
|||
pref("devtools.debugger.workers", false);
|
||||
|
||||
// The default Debugger UI settings
|
||||
pref("devtools.debugger.prefs-schema-version", "1.0.0");
|
||||
pref("devtools.debugger.ui.panes-workers-and-sources-width", 200);
|
||||
pref("devtools.debugger.ui.panes-instruments-width", 300);
|
||||
pref("devtools.debugger.ui.panes-visible-on-startup", false);
|
||||
|
|
|
@ -171,12 +171,8 @@
|
|||
background-color: var(--theme-toolbar-hover-active);
|
||||
}
|
||||
|
||||
.theme-dark .devtools-tab:not(.selected).highlighted {
|
||||
background-color: hsla(99, 100%, 14%, .3);
|
||||
}
|
||||
|
||||
.theme-light .devtools-tab:not(.selected).highlighted {
|
||||
background-color: rgba(44, 187, 15, .2);
|
||||
.devtools-tab:not(.selected).highlighted {
|
||||
background-color: var(--theme-toolbar-background-alt);
|
||||
}
|
||||
|
||||
/* Display execution pointer in the Debugger tab to indicate
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
--theme-tab-toolbar-background: #fcfcfc;
|
||||
--theme-toolbar-background: #fcfcfc;
|
||||
--theme-toolbar-background-hover: rgba(221, 225, 228, 0.66);
|
||||
--theme-toolbar-background-alt: #f5f5f5;
|
||||
--theme-toolbar-hover: rgba(170, 170, 170, .2);
|
||||
--theme-toolbar-hover-active: rgba(170, 170, 170, .4);
|
||||
|
@ -47,6 +48,7 @@
|
|||
--theme-highlight-red: #ed2655;
|
||||
--theme-highlight-pink: #b82ee5;
|
||||
--theme-highlight-gray: #dde1e4;
|
||||
--theme-highlight-yellow: #ffffb4;
|
||||
|
||||
/* For accessibility purposes we want to enhance the focus styling. This
|
||||
* should improve keyboard navigation usability. */
|
||||
|
@ -85,6 +87,7 @@
|
|||
|
||||
--theme-tab-toolbar-background: #272b35;
|
||||
--theme-toolbar-background: #272b35;
|
||||
--theme-toolbar-background-hover: #20232B;
|
||||
--theme-toolbar-background-alt: #2F343E;
|
||||
--theme-toolbar-hover: rgba(110, 120, 130, 0.1);
|
||||
--theme-toolbar-hover-active: rgba(110, 120, 130, 0.2);
|
||||
|
@ -111,6 +114,7 @@
|
|||
--theme-highlight-red: #eb5368;
|
||||
--theme-highlight-pink: #df80ff;
|
||||
--theme-highlight-gray: #e9f4fe;
|
||||
--theme-highlight-yellow: #ffffb4;
|
||||
|
||||
/* For accessibility purposes we want to enhance the focus styling. This
|
||||
* should improve keyboard navigation usability. */
|
||||
|
|
|
@ -1054,10 +1054,13 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
|
|||
|
||||
let paddingTop = parseFloat(computedStyle.paddingTop);
|
||||
let paddingLeft = parseFloat(computedStyle.paddingLeft);
|
||||
let borderTop = parseFloat(computedStyle.borderTopWidth);
|
||||
let borderLeft = parseFloat(computedStyle.borderLeftWidth);
|
||||
|
||||
// Subtract padding values to compensate for top/left being moved by padding.
|
||||
let ox = origin[0] - paddingLeft;
|
||||
let oy = origin[1] - paddingTop;
|
||||
// Subtract padding and border values to compensate for top/left being moved by
|
||||
// padding and / or borders.
|
||||
let ox = origin[0] - paddingLeft - borderLeft;
|
||||
let oy = origin[1] - paddingTop - borderTop;
|
||||
|
||||
let m = identity();
|
||||
|
||||
|
@ -1067,8 +1070,8 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
|
|||
m = multiply(m, translate(bounds.p1.x, bounds.p1.y));
|
||||
// And scale based on the current zoom factor.
|
||||
m = multiply(m, scale(getCurrentZoom(this.win)));
|
||||
// Then translate the origin based on the node's padding values.
|
||||
m = multiply(m, translate(paddingLeft, paddingTop));
|
||||
// Then translate the origin based on the node's padding and border values.
|
||||
m = multiply(m, translate(paddingLeft + borderLeft, paddingTop + borderTop));
|
||||
// Finally, we can apply the current node's transformation matrix, taking in account
|
||||
// the `transform-origin` property and the node's top and left padding.
|
||||
if (nodeMatrix) {
|
||||
|
|
|
@ -346,7 +346,7 @@ var WebExtensionInspectedWindowActor = protocol.ActorClassWithSpec(
|
|||
})
|
||||
.catch(err => {
|
||||
delete this.customizedReload;
|
||||
throw err;
|
||||
console.error(err);
|
||||
});
|
||||
} catch (err) {
|
||||
// Cancel the customized reload (if any) on exception during the
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "nsDocShellLoadTypes.h"
|
||||
#include "nsIMultiPartChannel.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/dom/nsCSPUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
@ -85,14 +86,6 @@ nsDSURIContentListener::DoContent(const nsACString& aContentType,
|
|||
NS_ENSURE_ARG_POINTER(aContentHandler);
|
||||
NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
|
||||
|
||||
// Check whether X-Frame-Options permits us to load this content in an
|
||||
// iframe and abort the load (unless we've disabled x-frame-options
|
||||
// checking).
|
||||
if (!CheckFrameOptions(aRequest)) {
|
||||
*aAbortProcess = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aAbortProcess = false;
|
||||
|
||||
// determine if the channel has just been retargeted to us...
|
||||
|
@ -266,9 +259,10 @@ nsDSURIContentListener::SetParentContentListener(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
/* static */ bool
|
||||
nsDSURIContentListener::CheckOneFrameOptionsPolicy(nsIHttpChannel* aHttpChannel,
|
||||
const nsAString& aPolicy)
|
||||
const nsAString& aPolicy,
|
||||
nsIDocShell* aDocShell)
|
||||
{
|
||||
static const char allowFrom[] = "allow-from";
|
||||
const uint32_t allowFromLen = ArrayLength(allowFrom) - 1;
|
||||
|
@ -286,7 +280,7 @@ nsDSURIContentListener::CheckOneFrameOptionsPolicy(nsIHttpChannel* aHttpChannel,
|
|||
aHttpChannel->GetURI(getter_AddRefs(uri));
|
||||
|
||||
// XXXkhuey when does this happen? Is returning true safe here?
|
||||
if (!mDocShell) {
|
||||
if (!aDocShell) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -294,7 +288,7 @@ nsDSURIContentListener::CheckOneFrameOptionsPolicy(nsIHttpChannel* aHttpChannel,
|
|||
// window, if we're not the top. X-F-O: SAMEORIGIN requires that the
|
||||
// document must be same-origin with top window. X-F-O: DENY requires that
|
||||
// the document must never be framed.
|
||||
nsCOMPtr<nsPIDOMWindowOuter> thisWindow = mDocShell->GetWindow();
|
||||
nsCOMPtr<nsPIDOMWindowOuter> thisWindow = aDocShell->GetWindow();
|
||||
// If we don't have DOMWindow there is no risk of clickjacking
|
||||
if (!thisWindow) {
|
||||
return true;
|
||||
|
@ -314,7 +308,7 @@ nsDSURIContentListener::CheckOneFrameOptionsPolicy(nsIHttpChannel* aHttpChannel,
|
|||
// content-type docshell doesn't work because some chrome documents are
|
||||
// loaded in content docshells (see bug 593387).
|
||||
nsCOMPtr<nsIDocShellTreeItem> thisDocShellItem(
|
||||
do_QueryInterface(static_cast<nsIDocShell*>(mDocShell)));
|
||||
do_QueryInterface(static_cast<nsIDocShell*>(aDocShell)));
|
||||
nsCOMPtr<nsIDocShellTreeItem> parentDocShellItem;
|
||||
nsCOMPtr<nsIDocShellTreeItem> curDocShellItem = thisDocShellItem;
|
||||
nsCOMPtr<nsIDocument> topDoc;
|
||||
|
@ -403,22 +397,66 @@ nsDSURIContentListener::CheckOneFrameOptionsPolicy(nsIHttpChannel* aHttpChannel,
|
|||
return true;
|
||||
}
|
||||
|
||||
// Ignore x-frame-options if CSP with frame-ancestors exists
|
||||
static bool
|
||||
ShouldIgnoreFrameOptions(nsIChannel* aChannel, nsIPrincipal* aPrincipal)
|
||||
{
|
||||
NS_ENSURE_TRUE(aChannel, false);
|
||||
NS_ENSURE_TRUE(aPrincipal, false);
|
||||
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
aPrincipal->GetCsp(getter_AddRefs(csp));
|
||||
if (!csp) {
|
||||
// if there is no CSP, then there is nothing to do here
|
||||
return false;
|
||||
}
|
||||
|
||||
bool enforcesFrameAncestors = false;
|
||||
csp->GetEnforcesFrameAncestors(&enforcesFrameAncestors);
|
||||
if (!enforcesFrameAncestors) {
|
||||
// if CSP does not contain frame-ancestors, then there
|
||||
// is nothing to do here.
|
||||
return false;
|
||||
}
|
||||
|
||||
// log warning to console that xfo is ignored because of CSP
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
|
||||
uint64_t innerWindowID = loadInfo ? loadInfo->GetInnerWindowID() : 0;
|
||||
const char16_t* params[] = { u"x-frame-options",
|
||||
u"frame-ancestors" };
|
||||
CSP_LogLocalizedStr(u"IgnoringSrcBecauseOfDirective",
|
||||
params, ArrayLength(params),
|
||||
EmptyString(), // no sourcefile
|
||||
EmptyString(), // no scriptsample
|
||||
0, // no linenumber
|
||||
0, // no columnnumber
|
||||
nsIScriptError::warningFlag,
|
||||
"CSP", innerWindowID);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if X-Frame-Options permits this document to be loaded as a subdocument.
|
||||
// This will iterate through and check any number of X-Frame-Options policies
|
||||
// in the request (comma-separated in a header, multiple headers, etc).
|
||||
bool
|
||||
nsDSURIContentListener::CheckFrameOptions(nsIRequest* aRequest)
|
||||
/* static */ bool
|
||||
nsDSURIContentListener::CheckFrameOptions(nsIChannel* aChannel,
|
||||
nsIDocShell* aDocShell,
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIChannel> chan = do_QueryInterface(aRequest);
|
||||
if (!chan) {
|
||||
if (!aChannel || !aDocShell) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(chan);
|
||||
if (ShouldIgnoreFrameOptions(aChannel, aPrincipal)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
|
||||
if (!httpChannel) {
|
||||
// check if it is hiding in a multipart channel
|
||||
rv = mDocShell->GetHttpChannel(chan, getter_AddRefs(httpChannel));
|
||||
rv = nsDocShell::Cast(aDocShell)->GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -443,11 +481,11 @@ nsDSURIContentListener::CheckFrameOptions(nsIRequest* aRequest)
|
|||
nsCharSeparatedTokenizer tokenizer(xfoHeaderValue, ',');
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
const nsSubstring& tok = tokenizer.nextToken();
|
||||
if (!CheckOneFrameOptionsPolicy(httpChannel, tok)) {
|
||||
if (!CheckOneFrameOptionsPolicy(httpChannel, tok, aDocShell)) {
|
||||
// cancel the load and display about:blank
|
||||
httpChannel->Cancel(NS_BINDING_ABORTED);
|
||||
if (mDocShell) {
|
||||
nsCOMPtr<nsIWebNavigation> webNav(do_QueryObject(mDocShell));
|
||||
if (aDocShell) {
|
||||
nsCOMPtr<nsIWebNavigation> webNav(do_QueryObject(aDocShell));
|
||||
if (webNav) {
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = httpChannel->GetLoadInfo();
|
||||
nsCOMPtr<nsIPrincipal> triggeringPrincipal = loadInfo
|
||||
|
@ -465,7 +503,7 @@ nsDSURIContentListener::CheckFrameOptions(nsIRequest* aRequest)
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
/* static */ void
|
||||
nsDSURIContentListener::ReportXFOViolation(nsIDocShellTreeItem* aTopDocShellItem,
|
||||
nsIURI* aThisURI,
|
||||
XFOHeader aHeader)
|
||||
|
|
|
@ -28,6 +28,12 @@ public:
|
|||
|
||||
nsresult Init();
|
||||
|
||||
// Determine if X-Frame-Options allows content to be framed
|
||||
// as a subdocument
|
||||
static bool CheckFrameOptions(nsIChannel* aChannel,
|
||||
nsIDocShell* aDocShell,
|
||||
nsIPrincipal* aPrincipal);
|
||||
|
||||
protected:
|
||||
explicit nsDSURIContentListener(nsDocShell* aDocShell);
|
||||
virtual ~nsDSURIContentListener();
|
||||
|
@ -39,12 +45,9 @@ protected:
|
|||
mExistingJPEGStreamListener = nullptr;
|
||||
}
|
||||
|
||||
// Determine if X-Frame-Options allows content to be framed
|
||||
// as a subdocument
|
||||
bool CheckFrameOptions(nsIRequest* aRequest);
|
||||
bool CheckOneFrameOptionsPolicy(nsIHttpChannel* aHttpChannel,
|
||||
const nsAString& aPolicy);
|
||||
|
||||
static bool CheckOneFrameOptionsPolicy(nsIHttpChannel* aHttpChannel,
|
||||
const nsAString& aPolicy,
|
||||
nsIDocShell* aDocShell);
|
||||
enum XFOHeader
|
||||
{
|
||||
eDENY,
|
||||
|
@ -52,9 +55,9 @@ protected:
|
|||
eALLOWFROM
|
||||
};
|
||||
|
||||
void ReportXFOViolation(nsIDocShellTreeItem* aTopDocShellItem,
|
||||
nsIURI* aThisURI,
|
||||
XFOHeader aHeader);
|
||||
static void ReportXFOViolation(nsIDocShellTreeItem* aTopDocShellItem,
|
||||
nsIURI* aThisURI,
|
||||
XFOHeader aHeader);
|
||||
|
||||
protected:
|
||||
nsDocShell* mDocShell;
|
||||
|
|
|
@ -994,20 +994,8 @@ nsDocShellTreeOwner::HandleEvent(nsIDOMEvent* aEvent)
|
|||
if (webBrowserChrome) {
|
||||
nsCOMPtr<nsITabChild> tabChild = do_QueryInterface(webBrowserChrome);
|
||||
if (tabChild) {
|
||||
nsCOMPtr<nsIDOMDataTransfer> domDataTransfer;
|
||||
dragEvent->GetDataTransfer(getter_AddRefs(domDataTransfer));
|
||||
NS_ENSURE_TRUE(domDataTransfer, NS_ERROR_UNEXPECTED);
|
||||
nsCOMPtr<nsIDOMNode> domSourceNode;
|
||||
domDataTransfer->GetMozSourceNode(getter_AddRefs(domSourceNode));
|
||||
nsCOMPtr<nsINode> sourceNode = do_QueryInterface(domSourceNode);
|
||||
nsCOMPtr<nsIPrincipal> triggeringPrincipal;
|
||||
if (sourceNode) {
|
||||
triggeringPrincipal = sourceNode->NodePrincipal();
|
||||
} else {
|
||||
triggeringPrincipal = NullPrincipal::Create();
|
||||
}
|
||||
nsresult rv = tabChild->RemoteDropLinks(linksCount, links,
|
||||
triggeringPrincipal);
|
||||
// Bug 1370843 - Explicitly pass triggeringPrincipal
|
||||
nsresult rv = tabChild->RemoteDropLinks(linksCount, links);
|
||||
for (uint32_t i = 0; i < linksCount; i++) {
|
||||
NS_RELEASE(links[i]);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||
<xhtml:div id="root">
|
||||
<xhtml:div id="target">
|
||||
</xhtml:div>
|
||||
</xhtml:div>
|
||||
<script>
|
||||
<![CDATA[
|
||||
var io = new IntersectionObserver(function () {
|
||||
}, { root: document.getElementById('root') });
|
||||
io.observe(document.getElementById('target'));
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -214,4 +214,5 @@ pref(dom.IntersectionObserver.enabled,true) load 1326194-2.html
|
|||
pref(dom.IntersectionObserver.enabled,true) load 1332939.html
|
||||
pref(dom.IntersectionObserver.enabled,true) load 1353529.xul
|
||||
pref(dom.webcomponents.enabled,true) load 1341693.html
|
||||
pref(dom.IntersectionObserver.enabled,true) load 1369363.xul
|
||||
load 1370072.html
|
||||
|
|
|
@ -10569,3 +10569,13 @@ nsContentUtils::UserInteractionObserver::Observe(nsISupports* aSubject,
|
|||
|
||||
Atomic<bool> nsContentUtils::UserInteractionObserver::sUserActive(false);
|
||||
NS_IMPL_ISUPPORTS(nsContentUtils::UserInteractionObserver, nsIObserver)
|
||||
|
||||
/* static */ bool
|
||||
nsContentUtils::IsOverridingWindowName(const nsAString& aName)
|
||||
{
|
||||
return !aName.IsEmpty() &&
|
||||
!aName.LowerCaseEqualsLiteral("_blank") &&
|
||||
!aName.LowerCaseEqualsLiteral("_top") &&
|
||||
!aName.LowerCaseEqualsLiteral("_parent") &&
|
||||
!aName.LowerCaseEqualsLiteral("_self");
|
||||
}
|
||||
|
|
|
@ -2993,6 +2993,13 @@ public:
|
|||
// heuristic strategy should be used to trigger the caching of the bytecode.
|
||||
static int32_t BytecodeCacheStrategy() { return sBytecodeCacheStrategy; }
|
||||
|
||||
/**
|
||||
* Checks if the passed-in name should override an existing name on the
|
||||
* window. Values which should not override include: "", "_blank", "_top",
|
||||
* "_parent" and "_self".
|
||||
*/
|
||||
static bool IsOverridingWindowName(const nsAString& aName);
|
||||
|
||||
private:
|
||||
static bool InitializeEventTable();
|
||||
|
||||
|
|
|
@ -118,14 +118,11 @@ void
|
|||
nsDOMAttributeMap::DropAttribute(int32_t aNamespaceID, nsIAtom* aLocalName)
|
||||
{
|
||||
nsAttrKey attr(aNamespaceID, aLocalName);
|
||||
Attr *node = mAttributeCache.GetWeak(attr);
|
||||
if (node) {
|
||||
// Break link to map
|
||||
node->SetMap(nullptr);
|
||||
|
||||
// Remove from cache
|
||||
mAttributeCache.Remove(attr);
|
||||
}
|
||||
mAttributeCache.LookupRemoveIf(attr,
|
||||
[] (Attr* aNode) {
|
||||
aNode->SetMap(nullptr); // break link to map
|
||||
return true; // remove from cache
|
||||
});
|
||||
}
|
||||
|
||||
Attr*
|
||||
|
@ -135,13 +132,13 @@ nsDOMAttributeMap::GetAttribute(mozilla::dom::NodeInfo* aNodeInfo)
|
|||
|
||||
nsAttrKey attr(aNodeInfo->NamespaceID(), aNodeInfo->NameAtom());
|
||||
|
||||
Attr* node = mAttributeCache.GetWeak(attr);
|
||||
RefPtr<Attr>& entryValue = mAttributeCache.GetOrInsert(attr);
|
||||
Attr* node = entryValue;
|
||||
if (!node) {
|
||||
// Newly inserted entry!
|
||||
RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
|
||||
RefPtr<Attr> newAttr =
|
||||
new Attr(this, ni.forget(), EmptyString());
|
||||
mAttributeCache.Put(attr, newAttr);
|
||||
node = newAttr;
|
||||
entryValue = new Attr(this, ni.forget(), EmptyString());
|
||||
node = entryValue;
|
||||
}
|
||||
|
||||
return node;
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
#include "nsGenericHTMLElement.h"
|
||||
#include "mozilla/dom/CDATASection.h"
|
||||
#include "mozilla/dom/ProcessingInstruction.h"
|
||||
#include "nsDSURIContentListener.h"
|
||||
#include "nsDOMString.h"
|
||||
#include "nsNodeUtils.h"
|
||||
#include "nsLayoutUtils.h" // for GetFrameForPoint
|
||||
|
@ -2584,6 +2585,15 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// XFO needs to be checked after CSP because it is ignored if
|
||||
// the CSP defines frame-ancestors.
|
||||
if (!nsDSURIContentListener::CheckFrameOptions(aChannel, docShell, NodePrincipal())) {
|
||||
MOZ_LOG(gCspPRLog, LogLevel::Debug,
|
||||
("XFO doesn't like frame's ancestry, not loading."));
|
||||
// stop! ERROR page!
|
||||
aChannel->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -1564,7 +1564,6 @@ private:
|
|||
void PostUnblockOnloadEvent();
|
||||
void DoUnblockOnload();
|
||||
|
||||
nsresult CheckFrameOptions();
|
||||
nsresult InitCSP(nsIChannel* aChannel);
|
||||
|
||||
/**
|
||||
|
|
|
@ -3023,6 +3023,16 @@ nsFrameLoader::TryRemoteBrowser()
|
|||
mRemoteBrowser->SetBrowserDOMWindow(browserDOMWin);
|
||||
}
|
||||
|
||||
// Send down the name of the browser through mRemoteBrowser if it is set.
|
||||
// Only do this on xul:browsers for now.
|
||||
if (mOwnerContent->IsXULElement()) {
|
||||
nsAutoString frameName;
|
||||
mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, frameName);
|
||||
if (nsContentUtils::IsOverridingWindowName(frameName)) {
|
||||
Unused << mRemoteBrowser->SendSetWindowName(frameName);
|
||||
}
|
||||
}
|
||||
|
||||
ReallyLoadFrameScripts();
|
||||
InitializeBrowserAPI();
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ NS_IMPL_ISUPPORTS(nsOpenURIInFrameParams, nsIOpenURIInFrameParams)
|
|||
|
||||
nsOpenURIInFrameParams::nsOpenURIInFrameParams(const mozilla::OriginAttributes& aOriginAttributes)
|
||||
: mOpenerOriginAttributes(aOriginAttributes)
|
||||
, mIsPrivate(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -37,14 +36,7 @@ NS_IMETHODIMP
|
|||
nsOpenURIInFrameParams::GetIsPrivate(bool* aIsPrivate)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aIsPrivate);
|
||||
*aIsPrivate = mIsPrivate;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsOpenURIInFrameParams::SetIsPrivate(bool aIsPrivate)
|
||||
{
|
||||
mIsPrivate = aIsPrivate;
|
||||
*aIsPrivate = mOpenerOriginAttributes.mPrivateBrowsingId > 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,5 +25,4 @@ private:
|
|||
|
||||
mozilla::OriginAttributes mOpenerOriginAttributes;
|
||||
nsString mReferrer;
|
||||
bool mIsPrivate;
|
||||
};
|
||||
|
|
|
@ -1543,11 +1543,15 @@ ResolvePrototypeOrConstructor(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
|||
{
|
||||
JSAutoCompartment ac(cx, global);
|
||||
ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
|
||||
// This function is called when resolving the "constructor" and "prototype"
|
||||
// properties of Xrays for DOM prototypes and constructors respectively.
|
||||
// This means the relevant Xray exists, which means its _target_ exists.
|
||||
// And that means we managed to successfullly create the prototype or
|
||||
// constructor, respectively, and hence must have managed to create the
|
||||
// thing it's pointing to as well. So our entry slot must exist.
|
||||
JSObject* protoOrIface =
|
||||
protoAndIfaceCache.EntrySlotIfExists(protoAndIfaceCacheIndex);
|
||||
if (!protoOrIface) {
|
||||
return false;
|
||||
}
|
||||
protoAndIfaceCache.EntrySlotMustExist(protoAndIfaceCacheIndex);
|
||||
MOZ_RELEASE_ASSERT(protoOrIface, "How can this object not exist?");
|
||||
|
||||
cacheOnHolder = true;
|
||||
|
||||
|
|
|
@ -269,7 +269,7 @@ class ProtoAndIfaceCache
|
|||
class ArrayCache : public Array<JS::Heap<JSObject*>, kProtoAndIfaceCacheCount>
|
||||
{
|
||||
public:
|
||||
JSObject* EntrySlotIfExists(size_t i) {
|
||||
bool HasEntryInSlot(size_t i) {
|
||||
return (*this)[i];
|
||||
}
|
||||
|
||||
|
@ -305,13 +305,13 @@ class ProtoAndIfaceCache
|
|||
}
|
||||
}
|
||||
|
||||
JSObject* EntrySlotIfExists(size_t i) {
|
||||
bool HasEntryInSlot(size_t i) {
|
||||
MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
|
||||
size_t pageIndex = i / kPageSize;
|
||||
size_t leafIndex = i % kPageSize;
|
||||
Page* p = mPages[pageIndex];
|
||||
if (!p) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
return (*p)[leafIndex];
|
||||
}
|
||||
|
@ -397,10 +397,12 @@ public:
|
|||
} \
|
||||
} while(0)
|
||||
|
||||
// Return the JSObject stored in slot i, if that slot exists. If
|
||||
// the slot does not exist, return null.
|
||||
JSObject* EntrySlotIfExists(size_t i) {
|
||||
FORWARD_OPERATION(EntrySlotIfExists, (i));
|
||||
// Return whether slot i contains an object. This doesn't return the object
|
||||
// itself because in practice consumers just want to know whether it's there
|
||||
// or not, and that doesn't require barriering, which returning the object
|
||||
// pointer does.
|
||||
bool HasEntryInSlot(size_t i) {
|
||||
FORWARD_OPERATION(HasEntryInSlot, (i));
|
||||
}
|
||||
|
||||
// Return a reference to slot i, creating it if necessary. There
|
||||
|
|
|
@ -3289,7 +3289,7 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
|
|||
|
||||
/* Check to see whether the interface objects are already installed */
|
||||
ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
|
||||
if (!protoAndIfaceCache.EntrySlotIfExists(${id})) {
|
||||
if (!protoAndIfaceCache.HasEntryInSlot(${id})) {
|
||||
JS::Rooted<JSObject*> rootedGlobal(aCx, global);
|
||||
CreateInterfaceObjects(aCx, rootedGlobal, protoAndIfaceCache, aDefineOnGlobal);
|
||||
}
|
||||
|
|
|
@ -318,7 +318,7 @@ WebIDLGlobalNameHash::GetNames(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
|||
// If aNameType is not AllNames, only include things whose entry slot in the
|
||||
// ProtoAndIfaceCache is null.
|
||||
if ((aNameType == AllNames ||
|
||||
!cache->EntrySlotIfExists(entry->mConstructorId)) &&
|
||||
!cache->HasEntryInSlot(entry->mConstructorId)) &&
|
||||
(!entry->mEnabled || entry->mEnabled(aCx, aObj))) {
|
||||
JSString* str = JS_AtomizeStringN(aCx, sNames + entry->mNameOffset,
|
||||
entry->mNameLength);
|
||||
|
|
|
@ -1,742 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ActorsChild.h"
|
||||
|
||||
#include "BackgroundChildImpl.h"
|
||||
#include "FileHandleBase.h"
|
||||
#include "FileRequestBase.h"
|
||||
#include "js/Date.h"
|
||||
#include "mozilla/dom/EncodingUtils.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/ipc/PendingIPCBlobChild.h"
|
||||
#include "MutableFileBase.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/*******************************************************************************
|
||||
* Helpers
|
||||
******************************************************************************/
|
||||
|
||||
namespace {
|
||||
|
||||
class MOZ_STACK_CLASS AutoSetCurrentFileHandle final
|
||||
{
|
||||
typedef mozilla::ipc::BackgroundChildImpl BackgroundChildImpl;
|
||||
|
||||
FileHandleBase* const mFileHandle;
|
||||
FileHandleBase* mPreviousFileHandle;
|
||||
FileHandleBase** mThreadLocalSlot;
|
||||
|
||||
public:
|
||||
explicit AutoSetCurrentFileHandle(FileHandleBase* aFileHandle)
|
||||
: mFileHandle(aFileHandle)
|
||||
, mPreviousFileHandle(nullptr)
|
||||
, mThreadLocalSlot(nullptr)
|
||||
{
|
||||
if (aFileHandle) {
|
||||
BackgroundChildImpl::ThreadLocal* threadLocal =
|
||||
BackgroundChildImpl::GetThreadLocalForCurrentThread();
|
||||
MOZ_ASSERT(threadLocal);
|
||||
|
||||
// Hang onto this location for resetting later.
|
||||
mThreadLocalSlot = &threadLocal->mCurrentFileHandle;
|
||||
|
||||
// Save the current value.
|
||||
mPreviousFileHandle = *mThreadLocalSlot;
|
||||
|
||||
// Set the new value.
|
||||
*mThreadLocalSlot = aFileHandle;
|
||||
}
|
||||
}
|
||||
|
||||
~AutoSetCurrentFileHandle()
|
||||
{
|
||||
MOZ_ASSERT_IF(mThreadLocalSlot, mFileHandle);
|
||||
MOZ_ASSERT_IF(mThreadLocalSlot, *mThreadLocalSlot == mFileHandle);
|
||||
|
||||
if (mThreadLocalSlot) {
|
||||
// Reset old value.
|
||||
*mThreadLocalSlot = mPreviousFileHandle;
|
||||
}
|
||||
}
|
||||
|
||||
FileHandleBase*
|
||||
FileHandle() const
|
||||
{
|
||||
return mFileHandle;
|
||||
}
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS ResultHelper final
|
||||
: public FileRequestBase::ResultCallback
|
||||
{
|
||||
FileRequestBase* mFileRequest;
|
||||
AutoSetCurrentFileHandle mAutoFileHandle;
|
||||
|
||||
union
|
||||
{
|
||||
File* mFile;
|
||||
const nsCString* mString;
|
||||
const FileRequestMetadata* mMetadata;
|
||||
const JS::Handle<JS::Value>* mJSValHandle;
|
||||
} mResult;
|
||||
|
||||
enum
|
||||
{
|
||||
ResultTypeFile,
|
||||
ResultTypeString,
|
||||
ResultTypeMetadata,
|
||||
ResultTypeJSValHandle,
|
||||
} mResultType;
|
||||
|
||||
public:
|
||||
ResultHelper(FileRequestBase* aFileRequest,
|
||||
FileHandleBase* aFileHandle,
|
||||
File* aResult)
|
||||
: mFileRequest(aFileRequest)
|
||||
, mAutoFileHandle(aFileHandle)
|
||||
, mResultType(ResultTypeFile)
|
||||
{
|
||||
MOZ_ASSERT(aFileRequest);
|
||||
MOZ_ASSERT(aFileHandle);
|
||||
MOZ_ASSERT(aResult);
|
||||
|
||||
mResult.mFile = aResult;
|
||||
}
|
||||
|
||||
ResultHelper(FileRequestBase* aFileRequest,
|
||||
FileHandleBase* aFileHandle,
|
||||
const nsCString* aResult)
|
||||
: mFileRequest(aFileRequest)
|
||||
, mAutoFileHandle(aFileHandle)
|
||||
, mResultType(ResultTypeString)
|
||||
{
|
||||
MOZ_ASSERT(aFileRequest);
|
||||
MOZ_ASSERT(aFileHandle);
|
||||
MOZ_ASSERT(aResult);
|
||||
|
||||
mResult.mString = aResult;
|
||||
}
|
||||
|
||||
ResultHelper(FileRequestBase* aFileRequest,
|
||||
FileHandleBase* aFileHandle,
|
||||
const FileRequestMetadata* aResult)
|
||||
: mFileRequest(aFileRequest)
|
||||
, mAutoFileHandle(aFileHandle)
|
||||
, mResultType(ResultTypeMetadata)
|
||||
{
|
||||
MOZ_ASSERT(aFileRequest);
|
||||
MOZ_ASSERT(aFileHandle);
|
||||
MOZ_ASSERT(aResult);
|
||||
|
||||
mResult.mMetadata = aResult;
|
||||
}
|
||||
|
||||
|
||||
ResultHelper(FileRequestBase* aFileRequest,
|
||||
FileHandleBase* aFileHandle,
|
||||
const JS::Handle<JS::Value>* aResult)
|
||||
: mFileRequest(aFileRequest)
|
||||
, mAutoFileHandle(aFileHandle)
|
||||
, mResultType(ResultTypeJSValHandle)
|
||||
{
|
||||
MOZ_ASSERT(aFileRequest);
|
||||
MOZ_ASSERT(aFileHandle);
|
||||
MOZ_ASSERT(aResult);
|
||||
|
||||
mResult.mJSValHandle = aResult;
|
||||
}
|
||||
|
||||
FileRequestBase*
|
||||
FileRequest() const
|
||||
{
|
||||
return mFileRequest;
|
||||
}
|
||||
|
||||
FileHandleBase*
|
||||
FileHandle() const
|
||||
{
|
||||
return mAutoFileHandle.FileHandle();
|
||||
}
|
||||
|
||||
virtual nsresult
|
||||
GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult) override
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(mFileRequest);
|
||||
|
||||
switch (mResultType) {
|
||||
case ResultTypeFile:
|
||||
return GetResult(aCx, mResult.mFile, aResult);
|
||||
|
||||
case ResultTypeString:
|
||||
return GetResult(aCx, mResult.mString, aResult);
|
||||
|
||||
case ResultTypeMetadata:
|
||||
return GetResult(aCx, mResult.mMetadata, aResult);
|
||||
|
||||
case ResultTypeJSValHandle:
|
||||
aResult.set(*mResult.mJSValHandle);
|
||||
return NS_OK;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Unknown result type!");
|
||||
}
|
||||
|
||||
MOZ_CRASH("Should never get here!");
|
||||
}
|
||||
|
||||
private:
|
||||
nsresult
|
||||
GetResult(JSContext* aCx,
|
||||
File* aFile,
|
||||
JS::MutableHandle<JS::Value> aResult)
|
||||
{
|
||||
bool ok = GetOrCreateDOMReflector(aCx, aFile, aResult);
|
||||
if (NS_WARN_IF(!ok)) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetResult(JSContext* aCx,
|
||||
const nsCString* aString,
|
||||
JS::MutableHandle<JS::Value> aResult)
|
||||
{
|
||||
const nsCString& data = *aString;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (!mFileRequest->HasEncoding()) {
|
||||
JS::Rooted<JSObject*> arrayBuffer(aCx);
|
||||
rv = nsContentUtils::CreateArrayBuffer(aCx, data, arrayBuffer.address());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
aResult.setObject(*arrayBuffer);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString encoding;
|
||||
// The BOM sniffing is baked into the "decode" part of the Encoding
|
||||
// Standard, which the File API references.
|
||||
if (!nsContentUtils::CheckForBOM(
|
||||
reinterpret_cast<const unsigned char *>(data.get()),
|
||||
data.Length(),
|
||||
encoding)) {
|
||||
// BOM sniffing failed. Try the API argument.
|
||||
if (!EncodingUtils::FindEncodingForLabel(mFileRequest->GetEncoding(),
|
||||
encoding)) {
|
||||
// API argument failed. Since we are dealing with a file system file,
|
||||
// we don't have a meaningful type attribute for the blob available,
|
||||
// so proceeding to the next step, which is defaulting to UTF-8.
|
||||
encoding.AssignLiteral("UTF-8");
|
||||
}
|
||||
}
|
||||
|
||||
nsString tmpString;
|
||||
rv = nsContentUtils::ConvertStringFromEncoding(encoding, data, tmpString);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!xpc::StringToJsval(aCx, tmpString, aResult))) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetResult(JSContext* aCx,
|
||||
const FileRequestMetadata* aMetadata,
|
||||
JS::MutableHandle<JS::Value> aResult)
|
||||
{
|
||||
JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
|
||||
if (NS_WARN_IF(!obj)) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
const FileRequestSize& size = aMetadata->size();
|
||||
if (size.type() != FileRequestSize::Tvoid_t) {
|
||||
MOZ_ASSERT(size.type() == FileRequestSize::Tuint64_t);
|
||||
|
||||
JS::Rooted<JS::Value> number(aCx, JS_NumberValue(size.get_uint64_t()));
|
||||
|
||||
if (NS_WARN_IF(!JS_DefineProperty(aCx, obj, "size", number, 0))) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
const FileRequestLastModified& lastModified = aMetadata->lastModified();
|
||||
if (lastModified.type() != FileRequestLastModified::Tvoid_t) {
|
||||
MOZ_ASSERT(lastModified.type() == FileRequestLastModified::Tint64_t);
|
||||
|
||||
JS::Rooted<JSObject*> date(aCx,
|
||||
JS::NewDateObject(aCx, JS::TimeClip(lastModified.get_int64_t())));
|
||||
if (NS_WARN_IF(!date)) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!JS_DefineProperty(aCx, obj, "lastModified", date, 0))) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
aResult.setObject(*obj);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
already_AddRefed<File>
|
||||
ConvertActorToFile(FileHandleBase* aFileHandle,
|
||||
const FileRequestGetFileResponse& aResponse)
|
||||
{
|
||||
auto* actor = static_cast<PendingIPCBlobChild*>(aResponse.fileChild());
|
||||
|
||||
MutableFileBase* mutableFile = aFileHandle->MutableFile();
|
||||
MOZ_ASSERT(mutableFile);
|
||||
|
||||
const FileRequestMetadata& metadata = aResponse.metadata();
|
||||
|
||||
const FileRequestSize& size = metadata.size();
|
||||
MOZ_ASSERT(size.type() == FileRequestSize::Tuint64_t);
|
||||
|
||||
const FileRequestLastModified& lastModified = metadata.lastModified();
|
||||
MOZ_ASSERT(lastModified.type() == FileRequestLastModified::Tint64_t);
|
||||
|
||||
RefPtr<BlobImpl> blobImpl =
|
||||
actor->SetPendingInfoAndDeleteActor(mutableFile->Name(),
|
||||
mutableFile->Type(),
|
||||
size.get_uint64_t(),
|
||||
lastModified.get_int64_t());
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
RefPtr<File> file = mutableFile->CreateFileFor(blobImpl, aFileHandle);
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
void
|
||||
HandleSuccess(ResultHelper* aResultHelper)
|
||||
{
|
||||
MOZ_ASSERT(aResultHelper);
|
||||
|
||||
RefPtr<FileRequestBase> fileRequest = aResultHelper->FileRequest();
|
||||
MOZ_ASSERT(fileRequest);
|
||||
fileRequest->AssertIsOnOwningThread();
|
||||
|
||||
RefPtr<FileHandleBase> fileHandle = aResultHelper->FileHandle();
|
||||
MOZ_ASSERT(fileHandle);
|
||||
|
||||
if (fileHandle->IsAborted()) {
|
||||
fileRequest->SetError(NS_ERROR_DOM_FILEHANDLE_ABORT_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(fileHandle->IsOpen());
|
||||
|
||||
fileRequest->SetResultCallback(aResultHelper);
|
||||
|
||||
MOZ_ASSERT(fileHandle->IsOpen() || fileHandle->IsAborted());
|
||||
}
|
||||
|
||||
void
|
||||
HandleError(FileRequestBase* aFileRequest,
|
||||
nsresult aErrorCode,
|
||||
FileHandleBase* aFileHandle)
|
||||
{
|
||||
MOZ_ASSERT(aFileRequest);
|
||||
aFileRequest->AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(NS_FAILED(aErrorCode));
|
||||
MOZ_ASSERT(NS_ERROR_GET_MODULE(aErrorCode) == NS_ERROR_MODULE_DOM_FILEHANDLE);
|
||||
MOZ_ASSERT(aFileHandle);
|
||||
|
||||
RefPtr<FileRequestBase> fileRequest = aFileRequest;
|
||||
RefPtr<FileHandleBase> fileHandle = aFileHandle;
|
||||
|
||||
AutoSetCurrentFileHandle ascfh(aFileHandle);
|
||||
|
||||
fileRequest->SetError(aErrorCode);
|
||||
|
||||
MOZ_ASSERT(fileHandle->IsOpen() || fileHandle->IsAborted());
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/*******************************************************************************
|
||||
* BackgroundMutableFileChildBase
|
||||
******************************************************************************/
|
||||
|
||||
BackgroundMutableFileChildBase::BackgroundMutableFileChildBase(
|
||||
DEBUGONLY(PRThread* aOwningThread))
|
||||
: ThreadObject(DEBUGONLY(aOwningThread))
|
||||
, mMutableFile(nullptr)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
MOZ_COUNT_CTOR(BackgroundMutableFileChildBase);
|
||||
}
|
||||
|
||||
BackgroundMutableFileChildBase::~BackgroundMutableFileChildBase()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
MOZ_COUNT_DTOR(BackgroundMutableFileChildBase);
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundMutableFileChildBase::EnsureDOMObject()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mTemporaryStrongMutableFile) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTemporaryStrongMutableFile = CreateMutableFile();
|
||||
|
||||
MOZ_ASSERT(mTemporaryStrongMutableFile);
|
||||
mTemporaryStrongMutableFile->AssertIsOnOwningThread();
|
||||
|
||||
mMutableFile = mTemporaryStrongMutableFile;
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundMutableFileChildBase::ReleaseDOMObject()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mTemporaryStrongMutableFile);
|
||||
mTemporaryStrongMutableFile->AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mMutableFile == mTemporaryStrongMutableFile);
|
||||
|
||||
mTemporaryStrongMutableFile = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundMutableFileChildBase::SendDeleteMeInternal()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(!mTemporaryStrongMutableFile);
|
||||
|
||||
if (mMutableFile) {
|
||||
mMutableFile->ClearBackgroundActor();
|
||||
mMutableFile = nullptr;
|
||||
|
||||
MOZ_ALWAYS_TRUE(PBackgroundMutableFileChild::SendDeleteMe());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundMutableFileChildBase::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mMutableFile) {
|
||||
mMutableFile->ClearBackgroundActor();
|
||||
DEBUGONLY(mMutableFile = nullptr;)
|
||||
}
|
||||
}
|
||||
|
||||
PBackgroundFileHandleChild*
|
||||
BackgroundMutableFileChildBase::AllocPBackgroundFileHandleChild(
|
||||
const FileMode& aMode)
|
||||
{
|
||||
MOZ_CRASH("PBackgroundFileHandleChild actors should be manually "
|
||||
"constructed!");
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundMutableFileChildBase::DeallocPBackgroundFileHandleChild(
|
||||
PBackgroundFileHandleChild* aActor)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
delete static_cast<BackgroundFileHandleChild*>(aActor);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* BackgroundFileHandleChild
|
||||
******************************************************************************/
|
||||
|
||||
BackgroundFileHandleChild::BackgroundFileHandleChild(
|
||||
DEBUGONLY(PRThread* aOwningThread,)
|
||||
FileHandleBase* aFileHandle)
|
||||
: ThreadObject(DEBUGONLY(aOwningThread))
|
||||
, mTemporaryStrongFileHandle(aFileHandle)
|
||||
, mFileHandle(aFileHandle)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aFileHandle);
|
||||
aFileHandle->AssertIsOnOwningThread();
|
||||
|
||||
MOZ_COUNT_CTOR(BackgroundFileHandleChild);
|
||||
}
|
||||
|
||||
BackgroundFileHandleChild::~BackgroundFileHandleChild()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
MOZ_COUNT_DTOR(BackgroundFileHandleChild);
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileHandleChild::SendDeleteMeInternal()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mFileHandle) {
|
||||
NoteActorDestroyed();
|
||||
|
||||
MOZ_ALWAYS_TRUE(PBackgroundFileHandleChild::SendDeleteMe());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileHandleChild::NoteActorDestroyed()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT_IF(mTemporaryStrongFileHandle, mFileHandle);
|
||||
|
||||
if (mFileHandle) {
|
||||
mFileHandle->ClearBackgroundActor();
|
||||
|
||||
// Normally this would be DEBUG-only but NoteActorDestroyed is also called
|
||||
// from SendDeleteMeInternal. In that case we're going to receive an actual
|
||||
// ActorDestroy call later and we don't want to touch a dead object.
|
||||
mTemporaryStrongFileHandle = nullptr;
|
||||
mFileHandle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileHandleChild::NoteComplete()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT_IF(mFileHandle, mTemporaryStrongFileHandle);
|
||||
|
||||
mTemporaryStrongFileHandle = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileHandleChild::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
NoteActorDestroyed();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BackgroundFileHandleChild::RecvComplete(const bool& aAborted)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mFileHandle);
|
||||
|
||||
mFileHandle->HandleCompleteOrAbort(aAborted);
|
||||
|
||||
NoteComplete();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
PBackgroundFileRequestChild*
|
||||
BackgroundFileHandleChild::AllocPBackgroundFileRequestChild(
|
||||
const FileRequestParams& aParams)
|
||||
{
|
||||
MOZ_CRASH("PBackgroundFileRequestChild actors should be manually "
|
||||
"constructed!");
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundFileHandleChild::DeallocPBackgroundFileRequestChild(
|
||||
PBackgroundFileRequestChild* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
delete static_cast<BackgroundFileRequestChild*>(aActor);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* BackgroundFileRequestChild
|
||||
******************************************************************************/
|
||||
|
||||
BackgroundFileRequestChild::BackgroundFileRequestChild(
|
||||
DEBUGONLY(PRThread* aOwningThread,)
|
||||
FileRequestBase* aFileRequest)
|
||||
: ThreadObject(DEBUGONLY(aOwningThread))
|
||||
, mFileRequest(aFileRequest)
|
||||
, mFileHandle(aFileRequest->FileHandle())
|
||||
, mActorDestroyed(false)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aFileRequest);
|
||||
aFileRequest->AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mFileHandle);
|
||||
mFileHandle->AssertIsOnOwningThread();
|
||||
|
||||
MOZ_COUNT_CTOR(BackgroundFileRequestChild);
|
||||
}
|
||||
|
||||
BackgroundFileRequestChild::~BackgroundFileRequestChild()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(!mFileHandle);
|
||||
|
||||
MOZ_COUNT_DTOR(BackgroundFileRequestChild);
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileRequestChild::HandleResponse(nsresult aResponse)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(NS_FAILED(aResponse));
|
||||
MOZ_ASSERT(NS_ERROR_GET_MODULE(aResponse) == NS_ERROR_MODULE_DOM_FILEHANDLE);
|
||||
MOZ_ASSERT(mFileHandle);
|
||||
|
||||
HandleError(mFileRequest, aResponse, mFileHandle);
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileRequestChild::HandleResponse(
|
||||
const FileRequestGetFileResponse& aResponse)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
RefPtr<File> file = ConvertActorToFile(mFileHandle, aResponse);
|
||||
|
||||
ResultHelper helper(mFileRequest, mFileHandle, file);
|
||||
|
||||
HandleSuccess(&helper);
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileRequestChild::HandleResponse(const nsCString& aResponse)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
ResultHelper helper(mFileRequest, mFileHandle, &aResponse);
|
||||
|
||||
HandleSuccess(&helper);
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileRequestChild::HandleResponse(const FileRequestMetadata& aResponse)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
ResultHelper helper(mFileRequest, mFileHandle, &aResponse);
|
||||
|
||||
HandleSuccess(&helper);
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileRequestChild::HandleResponse(JS::Handle<JS::Value> aResponse)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
ResultHelper helper(mFileRequest, mFileHandle, &aResponse);
|
||||
|
||||
HandleSuccess(&helper);
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileRequestChild::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
MOZ_ASSERT(!mActorDestroyed);
|
||||
|
||||
mActorDestroyed = true;
|
||||
|
||||
if (mFileHandle) {
|
||||
mFileHandle->AssertIsOnOwningThread();
|
||||
|
||||
mFileHandle->OnRequestFinished(/* aActorDestroyedNormally */
|
||||
aWhy == Deletion);
|
||||
|
||||
DEBUGONLY(mFileHandle = nullptr;)
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BackgroundFileRequestChild::Recv__delete__(const FileRequestResponse& aResponse)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mFileRequest);
|
||||
MOZ_ASSERT(mFileHandle);
|
||||
|
||||
if (mFileHandle->IsAborted()) {
|
||||
// Always handle an "error" with ABORT_ERR if the file handle was aborted,
|
||||
// even if the request succeeded or failed with another error.
|
||||
HandleResponse(NS_ERROR_DOM_FILEHANDLE_ABORT_ERR);
|
||||
} else {
|
||||
switch (aResponse.type()) {
|
||||
case FileRequestResponse::Tnsresult:
|
||||
HandleResponse(aResponse.get_nsresult());
|
||||
break;
|
||||
|
||||
case FileRequestResponse::TFileRequestGetFileResponse:
|
||||
HandleResponse(aResponse.get_FileRequestGetFileResponse());
|
||||
break;
|
||||
|
||||
case FileRequestResponse::TFileRequestReadResponse:
|
||||
HandleResponse(aResponse.get_FileRequestReadResponse().data());
|
||||
break;
|
||||
|
||||
case FileRequestResponse::TFileRequestWriteResponse:
|
||||
HandleResponse(JS::UndefinedHandleValue);
|
||||
break;
|
||||
|
||||
case FileRequestResponse::TFileRequestTruncateResponse:
|
||||
HandleResponse(JS::UndefinedHandleValue);
|
||||
break;
|
||||
|
||||
case FileRequestResponse::TFileRequestFlushResponse:
|
||||
HandleResponse(JS::UndefinedHandleValue);
|
||||
break;
|
||||
|
||||
case FileRequestResponse::TFileRequestGetMetadataResponse:
|
||||
HandleResponse(aResponse.get_FileRequestGetMetadataResponse()
|
||||
.metadata());
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Unknown response type!");
|
||||
}
|
||||
}
|
||||
|
||||
mFileHandle->OnRequestFinished(/* aActorDestroyedNormally */ true);
|
||||
|
||||
// Null this out so that we don't try to call OnRequestFinished() again in
|
||||
// ActorDestroy.
|
||||
mFileHandle = nullptr;
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BackgroundFileRequestChild::RecvProgress(const uint64_t& aProgress,
|
||||
const uint64_t& aProgressMax)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mFileRequest);
|
||||
|
||||
mFileRequest->OnProgress(aProgress, aProgressMax);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,174 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_filehandle_ActorsChild_h
|
||||
#define mozilla_dom_filehandle_ActorsChild_h
|
||||
|
||||
#include "js/RootingAPI.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/FileHandleCommon.h"
|
||||
#include "mozilla/dom/PBackgroundFileHandleChild.h"
|
||||
#include "mozilla/dom/PBackgroundFileRequestChild.h"
|
||||
#include "mozilla/dom/PBackgroundMutableFileChild.h"
|
||||
|
||||
class nsCString;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class FileHandleBase;
|
||||
class FileRequestBase;
|
||||
class MutableFileBase;
|
||||
|
||||
class BackgroundMutableFileChildBase
|
||||
: public ThreadObject
|
||||
, public PBackgroundMutableFileChild
|
||||
{
|
||||
protected:
|
||||
friend class MutableFileBase;
|
||||
|
||||
RefPtr<MutableFileBase> mTemporaryStrongMutableFile;
|
||||
MutableFileBase* mMutableFile;
|
||||
|
||||
public:
|
||||
void
|
||||
EnsureDOMObject();
|
||||
|
||||
MutableFileBase*
|
||||
GetDOMObject() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return mMutableFile;
|
||||
}
|
||||
|
||||
void
|
||||
ReleaseDOMObject();
|
||||
|
||||
protected:
|
||||
BackgroundMutableFileChildBase(DEBUGONLY(PRThread* aOwningThread));
|
||||
|
||||
~BackgroundMutableFileChildBase();
|
||||
|
||||
void
|
||||
SendDeleteMeInternal();
|
||||
|
||||
virtual already_AddRefed<MutableFileBase>
|
||||
CreateMutableFile() = 0;
|
||||
|
||||
// IPDL methods are only called by IPDL.
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
virtual PBackgroundFileHandleChild*
|
||||
AllocPBackgroundFileHandleChild(const FileMode& aMode) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPBackgroundFileHandleChild(PBackgroundFileHandleChild* aActor)
|
||||
override;
|
||||
|
||||
bool
|
||||
SendDeleteMe() = delete;
|
||||
};
|
||||
|
||||
class BackgroundFileHandleChild
|
||||
: public ThreadObject
|
||||
, public PBackgroundFileHandleChild
|
||||
{
|
||||
friend class BackgroundMutableFileChildBase;
|
||||
friend class MutableFileBase;
|
||||
|
||||
// mTemporaryStrongFileHandle is strong and is only valid until the end of
|
||||
// NoteComplete() member function or until the NoteActorDestroyed() member
|
||||
// function is called.
|
||||
RefPtr<FileHandleBase> mTemporaryStrongFileHandle;
|
||||
|
||||
// mFileHandle is weak and is valid until the NoteActorDestroyed() member
|
||||
// function is called.
|
||||
FileHandleBase* mFileHandle;
|
||||
|
||||
public:
|
||||
explicit BackgroundFileHandleChild(DEBUGONLY(PRThread* aOwningThread,)
|
||||
FileHandleBase* aFileHandle);
|
||||
|
||||
void
|
||||
SendDeleteMeInternal();
|
||||
|
||||
private:
|
||||
~BackgroundFileHandleChild();
|
||||
|
||||
void
|
||||
NoteActorDestroyed();
|
||||
|
||||
void
|
||||
NoteComplete();
|
||||
|
||||
// IPDL methods are only called by IPDL.
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvComplete(const bool& aAborted) override;
|
||||
|
||||
virtual PBackgroundFileRequestChild*
|
||||
AllocPBackgroundFileRequestChild(const FileRequestParams& aParams)
|
||||
override;
|
||||
|
||||
virtual bool
|
||||
DeallocPBackgroundFileRequestChild(PBackgroundFileRequestChild* aActor)
|
||||
override;
|
||||
|
||||
bool
|
||||
SendDeleteMe() = delete;
|
||||
};
|
||||
|
||||
class BackgroundFileRequestChild final
|
||||
: public ThreadObject
|
||||
, public PBackgroundFileRequestChild
|
||||
{
|
||||
friend class BackgroundFileHandleChild;
|
||||
friend class FileHandleBase;
|
||||
|
||||
RefPtr<FileRequestBase> mFileRequest;
|
||||
RefPtr<FileHandleBase> mFileHandle;
|
||||
bool mActorDestroyed;
|
||||
|
||||
private:
|
||||
// Only created by FileHandleBase.
|
||||
explicit BackgroundFileRequestChild(DEBUGONLY(PRThread* aOwningThread,)
|
||||
FileRequestBase* aFileRequest);
|
||||
|
||||
// Only destroyed by BackgroundFileHandleChild.
|
||||
~BackgroundFileRequestChild();
|
||||
|
||||
void
|
||||
HandleResponse(nsresult aResponse);
|
||||
|
||||
void
|
||||
HandleResponse(const FileRequestGetFileResponse& aResponse);
|
||||
|
||||
void
|
||||
HandleResponse(const nsCString& aResponse);
|
||||
|
||||
void
|
||||
HandleResponse(const FileRequestMetadata& aResponse);
|
||||
|
||||
void
|
||||
HandleResponse(JS::Handle<JS::Value> aResponse);
|
||||
|
||||
// IPDL methods are only called by IPDL.
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
Recv__delete__(const FileRequestResponse& aResponse) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvProgress(const uint64_t& aProgress,
|
||||
const uint64_t& aProgressMax) override;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_filehandle_ActorsChild_h
|
|
@ -9,7 +9,6 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileHandleCommon.h"
|
||||
#include "mozilla/dom/PBackgroundFileHandleParent.h"
|
||||
#include "mozilla/dom/PBackgroundFileRequestParent.h"
|
||||
#include "mozilla/dom/indexedDB/ActorsParent.h"
|
||||
|
@ -201,7 +200,9 @@ class FileHandle
|
|||
bool mFinishedOrAborted;
|
||||
bool mForceAborted;
|
||||
|
||||
DEBUGONLY(nsCOMPtr<nsIEventTarget> mThreadPoolEventTarget;)
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsIEventTarget> mThreadPoolEventTarget;
|
||||
#endif
|
||||
|
||||
public:
|
||||
void
|
||||
|
@ -457,7 +458,9 @@ class NormalFileHandleOp
|
|||
bool mActorDestroyed;
|
||||
const bool mFileHandleIsAborted;
|
||||
|
||||
DEBUGONLY(bool mResponseSent;)
|
||||
#ifdef DEBUG
|
||||
bool mResponseSent;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsISupports> mFileStream;
|
||||
|
@ -507,7 +510,9 @@ protected:
|
|||
, mOperationMayProceed(true)
|
||||
, mActorDestroyed(false)
|
||||
, mFileHandleIsAborted(aFileHandle->IsAborted())
|
||||
DEBUGONLY(, mResponseSent(false))
|
||||
#ifdef DEBUG
|
||||
, mResponseSent(false)
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(aFileHandle);
|
||||
}
|
||||
|
@ -2069,7 +2074,9 @@ NormalFileHandleOp::SendSuccessResult()
|
|||
}
|
||||
}
|
||||
|
||||
DEBUGONLY(mResponseSent = true;)
|
||||
#ifdef DEBUG
|
||||
mResponseSent = true;
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2087,7 +2094,9 @@ NormalFileHandleOp::SendFailureResult(nsresult aResultCode)
|
|||
PBackgroundFileRequestParent::Send__delete__(this, aResultCode);
|
||||
}
|
||||
|
||||
DEBUGONLY(mResponseSent = true;)
|
||||
#ifdef DEBUG
|
||||
mResponseSent = true;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -1,638 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "FileHandleBase.h"
|
||||
|
||||
#include "ActorsChild.h"
|
||||
#include "BackgroundChildImpl.h"
|
||||
#include "FileRequestBase.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/IPCBlobUtils.h"
|
||||
#include "mozilla/dom/PBackgroundFileHandle.h"
|
||||
#include "mozilla/dom/UnionConversions.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "MutableFileBase.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsError.h"
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
FileHandleBase::FileHandleBase(DEBUGONLY(PRThread* aOwningThread,)
|
||||
FileMode aMode)
|
||||
: RefCountedThreadObject(DEBUGONLY(aOwningThread))
|
||||
, mBackgroundActor(nullptr)
|
||||
, mLocation(0)
|
||||
, mPendingRequestCount(0)
|
||||
, mReadyState(INITIAL)
|
||||
, mMode(aMode)
|
||||
, mAborted(false)
|
||||
, mCreating(false)
|
||||
DEBUGONLY(, mSentFinishOrAbort(false))
|
||||
DEBUGONLY(, mFiredCompleteOrAbort(false))
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
FileHandleBase::~FileHandleBase()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(!mPendingRequestCount);
|
||||
MOZ_ASSERT(!mCreating);
|
||||
MOZ_ASSERT(mSentFinishOrAbort);
|
||||
MOZ_ASSERT_IF(mBackgroundActor, mFiredCompleteOrAbort);
|
||||
|
||||
if (mBackgroundActor) {
|
||||
mBackgroundActor->SendDeleteMeInternal();
|
||||
|
||||
MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
FileHandleBase*
|
||||
FileHandleBase::GetCurrent()
|
||||
{
|
||||
MOZ_ASSERT(BackgroundChild::GetForCurrentThread());
|
||||
|
||||
BackgroundChildImpl::ThreadLocal* threadLocal =
|
||||
BackgroundChildImpl::GetThreadLocalForCurrentThread();
|
||||
MOZ_ASSERT(threadLocal);
|
||||
|
||||
return threadLocal->mCurrentFileHandle;
|
||||
}
|
||||
|
||||
void
|
||||
FileHandleBase::SetBackgroundActor(BackgroundFileHandleChild* aActor)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
MOZ_ASSERT(!mBackgroundActor);
|
||||
|
||||
mBackgroundActor = aActor;
|
||||
}
|
||||
|
||||
void
|
||||
FileHandleBase::StartRequest(FileRequestBase* aFileRequest,
|
||||
const FileRequestParams& aParams)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aFileRequest);
|
||||
MOZ_ASSERT(aParams.type() != FileRequestParams::T__None);
|
||||
|
||||
BackgroundFileRequestChild* actor =
|
||||
new BackgroundFileRequestChild(DEBUGONLY(mBackgroundActor->OwningThread(),)
|
||||
aFileRequest);
|
||||
|
||||
mBackgroundActor->SendPBackgroundFileRequestConstructor(actor, aParams);
|
||||
|
||||
// Balanced in BackgroundFileRequestChild::Recv__delete__().
|
||||
OnNewRequest();
|
||||
}
|
||||
|
||||
void
|
||||
FileHandleBase::OnNewRequest()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (!mPendingRequestCount) {
|
||||
MOZ_ASSERT(mReadyState == INITIAL);
|
||||
mReadyState = LOADING;
|
||||
}
|
||||
|
||||
++mPendingRequestCount;
|
||||
}
|
||||
|
||||
void
|
||||
FileHandleBase::OnRequestFinished(bool aActorDestroyedNormally)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mPendingRequestCount);
|
||||
|
||||
--mPendingRequestCount;
|
||||
|
||||
if (!mPendingRequestCount && !MutableFile()->IsInvalidated()) {
|
||||
mReadyState = FINISHING;
|
||||
|
||||
if (aActorDestroyedNormally) {
|
||||
if (!mAborted) {
|
||||
SendFinish();
|
||||
} else {
|
||||
SendAbort();
|
||||
}
|
||||
} else {
|
||||
// Don't try to send any more messages to the parent if the request actor
|
||||
// was killed.
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(!mSentFinishOrAbort);
|
||||
mSentFinishOrAbort = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
FileHandleBase::IsOpen() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// If we haven't started anything then we're open.
|
||||
if (mReadyState == INITIAL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we've already started then we need to check to see if we still have the
|
||||
// mCreating flag set. If we do (i.e. we haven't returned to the event loop
|
||||
// from the time we were created) then we are open. Otherwise check the
|
||||
// currently running file handles to see if it's the same. We only allow other
|
||||
// requests to be made if this file handle is currently running.
|
||||
if (mReadyState == LOADING && (mCreating || GetCurrent() == this)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
FileHandleBase::Abort()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (IsFinishingOrDone()) {
|
||||
// Already started (and maybe finished) the finish or abort so there is
|
||||
// nothing to do here.
|
||||
return;
|
||||
}
|
||||
|
||||
const bool isInvalidated = MutableFile()->IsInvalidated();
|
||||
bool needToSendAbort = mReadyState == INITIAL && !isInvalidated;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (isInvalidated) {
|
||||
mSentFinishOrAbort = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
mAborted = true;
|
||||
mReadyState = DONE;
|
||||
|
||||
// Fire the abort event if there are no outstanding requests. Otherwise the
|
||||
// abort event will be fired when all outstanding requests finish.
|
||||
if (needToSendAbort) {
|
||||
SendAbort();
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<FileRequestBase>
|
||||
FileHandleBase::Read(uint64_t aSize, bool aHasEncoding,
|
||||
const nsAString& aEncoding, ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// State and argument checking for read
|
||||
if (!CheckStateAndArgumentsForRead(aSize, aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Do nothing if the window is closed
|
||||
if (!CheckWindow()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileRequestReadParams params;
|
||||
params.offset() = mLocation;
|
||||
params.size() = aSize;
|
||||
|
||||
RefPtr<FileRequestBase> fileRequest = GenerateFileRequest();
|
||||
if (aHasEncoding) {
|
||||
fileRequest->SetEncoding(aEncoding);
|
||||
}
|
||||
|
||||
StartRequest(fileRequest, params);
|
||||
|
||||
mLocation += aSize;
|
||||
|
||||
return fileRequest.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<FileRequestBase>
|
||||
FileHandleBase::Truncate(const Optional<uint64_t>& aSize, ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// State checking for write
|
||||
if (!CheckStateForWrite(aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Getting location and additional state checking for truncate
|
||||
uint64_t location;
|
||||
if (aSize.WasPassed()) {
|
||||
// Just in case someone calls us from C++
|
||||
MOZ_ASSERT(aSize.Value() != UINT64_MAX, "Passed wrong size!");
|
||||
location = aSize.Value();
|
||||
} else {
|
||||
if (mLocation == UINT64_MAX) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
location = mLocation;
|
||||
}
|
||||
|
||||
// Do nothing if the window is closed
|
||||
if (!CheckWindow()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileRequestTruncateParams params;
|
||||
params.offset() = location;
|
||||
|
||||
RefPtr<FileRequestBase> fileRequest = GenerateFileRequest();
|
||||
|
||||
StartRequest(fileRequest, params);
|
||||
|
||||
if (aSize.WasPassed()) {
|
||||
mLocation = aSize.Value();
|
||||
}
|
||||
|
||||
return fileRequest.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<FileRequestBase>
|
||||
FileHandleBase::Flush(ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// State checking for write
|
||||
if (!CheckStateForWrite(aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Do nothing if the window is closed
|
||||
if (!CheckWindow()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileRequestFlushParams params;
|
||||
|
||||
RefPtr<FileRequestBase> fileRequest = GenerateFileRequest();
|
||||
|
||||
StartRequest(fileRequest, params);
|
||||
|
||||
return fileRequest.forget();
|
||||
}
|
||||
|
||||
void
|
||||
FileHandleBase::Abort(ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// This method is special enough for not using generic state checking methods.
|
||||
|
||||
if (IsFinishingOrDone()) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
Abort();
|
||||
}
|
||||
|
||||
void
|
||||
FileHandleBase::HandleCompleteOrAbort(bool aAborted)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(!mFiredCompleteOrAbort);
|
||||
|
||||
mReadyState = DONE;
|
||||
|
||||
DEBUGONLY(mFiredCompleteOrAbort = true;)
|
||||
}
|
||||
|
||||
void
|
||||
FileHandleBase::OnReturnToEventLoop()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// We're back at the event loop, no longer newborn.
|
||||
mCreating = false;
|
||||
|
||||
// Maybe finish if there were no requests generated.
|
||||
if (mReadyState == INITIAL) {
|
||||
mReadyState = DONE;
|
||||
|
||||
SendFinish();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
FileHandleBase::CheckState(ErrorResult& aRv)
|
||||
{
|
||||
if (!IsOpen()) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_INACTIVE_ERR);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FileHandleBase::CheckStateAndArgumentsForRead(uint64_t aSize, ErrorResult& aRv)
|
||||
{
|
||||
// Common state checking
|
||||
if (!CheckState(aRv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Additional state checking for read
|
||||
if (mLocation == UINT64_MAX) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Argument checking for read
|
||||
if (!aSize) {
|
||||
aRv.ThrowTypeError<MSG_INVALID_READ_SIZE>();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FileHandleBase::CheckStateForWrite(ErrorResult& aRv)
|
||||
{
|
||||
// Common state checking
|
||||
if (!CheckState(aRv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Additional state checking for write
|
||||
if (mMode != FileMode::Readwrite) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_READ_ONLY_ERR);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FileHandleBase::CheckStateForWriteOrAppend(bool aAppend, ErrorResult& aRv)
|
||||
{
|
||||
// State checking for write
|
||||
if (!CheckStateForWrite(aRv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Additional state checking for write
|
||||
if (!aAppend && mLocation == UINT64_MAX) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<FileRequestBase>
|
||||
FileHandleBase::WriteOrAppend(
|
||||
const StringOrArrayBufferOrArrayBufferViewOrBlob& aValue,
|
||||
bool aAppend,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (aValue.IsString()) {
|
||||
return WriteOrAppend(aValue.GetAsString(), aAppend, aRv);
|
||||
}
|
||||
|
||||
if (aValue.IsArrayBuffer()) {
|
||||
return WriteOrAppend(aValue.GetAsArrayBuffer(), aAppend, aRv);
|
||||
}
|
||||
|
||||
if (aValue.IsArrayBufferView()) {
|
||||
return WriteOrAppend(aValue.GetAsArrayBufferView(), aAppend, aRv);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aValue.IsBlob());
|
||||
return WriteOrAppend(aValue.GetAsBlob(), aAppend, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<FileRequestBase>
|
||||
FileHandleBase::WriteOrAppend(const nsAString& aValue,
|
||||
bool aAppend,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// State checking for write or append
|
||||
if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_ConvertUTF16toUTF8 cstr(aValue);
|
||||
|
||||
uint64_t dataLength = cstr.Length();;
|
||||
if (!dataLength) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileRequestStringData stringData(cstr);
|
||||
|
||||
// Do nothing if the window is closed
|
||||
if (!CheckWindow()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return WriteInternal(stringData, dataLength, aAppend, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<FileRequestBase>
|
||||
FileHandleBase::WriteOrAppend(const ArrayBuffer& aValue,
|
||||
bool aAppend,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// State checking for write or append
|
||||
if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aValue.ComputeLengthAndData();
|
||||
|
||||
uint64_t dataLength = aValue.Length();;
|
||||
if (!dataLength) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* data = reinterpret_cast<const char*>(aValue.Data());
|
||||
|
||||
FileRequestStringData stringData;
|
||||
if (NS_WARN_IF(!stringData.string().Assign(data, aValue.Length(),
|
||||
fallible_t()))) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Do nothing if the window is closed
|
||||
if (!CheckWindow()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return WriteInternal(stringData, dataLength, aAppend, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<FileRequestBase>
|
||||
FileHandleBase::WriteOrAppend(const ArrayBufferView& aValue,
|
||||
bool aAppend,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// State checking for write or append
|
||||
if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aValue.ComputeLengthAndData();
|
||||
|
||||
uint64_t dataLength = aValue.Length();;
|
||||
if (!dataLength) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* data = reinterpret_cast<const char*>(aValue.Data());
|
||||
|
||||
FileRequestStringData stringData;
|
||||
if (NS_WARN_IF(!stringData.string().Assign(data, aValue.Length(),
|
||||
fallible_t()))) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Do nothing if the window is closed
|
||||
if (!CheckWindow()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return WriteInternal(stringData, dataLength, aAppend, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<FileRequestBase>
|
||||
FileHandleBase::WriteOrAppend(Blob& aValue,
|
||||
bool aAppend,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// State checking for write or append
|
||||
if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
uint64_t dataLength = aValue.GetSize(error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!dataLength) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PBackgroundChild* backgroundActor = BackgroundChild::GetForCurrentThread();
|
||||
MOZ_ASSERT(backgroundActor);
|
||||
|
||||
IPCBlob ipcBlob;
|
||||
nsresult rv =
|
||||
IPCBlobUtils::Serialize(aValue.Impl(), backgroundActor, ipcBlob);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileRequestBlobData blobData;
|
||||
blobData.blob() = ipcBlob;
|
||||
|
||||
// Do nothing if the window is closed
|
||||
if (!CheckWindow()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return WriteInternal(blobData, dataLength, aAppend, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<FileRequestBase>
|
||||
FileHandleBase::WriteInternal(const FileRequestData& aData,
|
||||
uint64_t aDataLength,
|
||||
bool aAppend,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
DebugOnly<ErrorResult> error;
|
||||
MOZ_ASSERT(CheckStateForWrite(error));
|
||||
MOZ_ASSERT_IF(!aAppend, mLocation != UINT64_MAX);
|
||||
MOZ_ASSERT(aDataLength);
|
||||
MOZ_ASSERT(CheckWindow());
|
||||
|
||||
FileRequestWriteParams params;
|
||||
params.offset() = aAppend ? UINT64_MAX : mLocation;
|
||||
params.data() = aData;
|
||||
params.dataLength() = aDataLength;
|
||||
|
||||
RefPtr<FileRequestBase> fileRequest = GenerateFileRequest();
|
||||
MOZ_ASSERT(fileRequest);
|
||||
|
||||
StartRequest(fileRequest, params);
|
||||
|
||||
if (aAppend) {
|
||||
mLocation = UINT64_MAX;
|
||||
}
|
||||
else {
|
||||
mLocation += aDataLength;
|
||||
}
|
||||
|
||||
return fileRequest.forget();
|
||||
}
|
||||
|
||||
void
|
||||
FileHandleBase::SendFinish()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(!mAborted);
|
||||
MOZ_ASSERT(IsFinishingOrDone());
|
||||
MOZ_ASSERT(!mSentFinishOrAbort);
|
||||
MOZ_ASSERT(!mPendingRequestCount);
|
||||
|
||||
MOZ_ASSERT(mBackgroundActor);
|
||||
mBackgroundActor->SendFinish();
|
||||
|
||||
DEBUGONLY(mSentFinishOrAbort = true;)
|
||||
}
|
||||
|
||||
void
|
||||
FileHandleBase::SendAbort()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mAborted);
|
||||
MOZ_ASSERT(IsFinishingOrDone());
|
||||
MOZ_ASSERT(!mSentFinishOrAbort);
|
||||
|
||||
MOZ_ASSERT(mBackgroundActor);
|
||||
mBackgroundActor->SendAbort();
|
||||
|
||||
DEBUGONLY(mSentFinishOrAbort = true;)
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,246 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_FileHandle_h
|
||||
#define mozilla_dom_FileHandle_h
|
||||
|
||||
#include "FileHandleCommon.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/FileModeBinding.h"
|
||||
#include "mozilla/dom/Nullable.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
|
||||
template <class> struct already_AddRefed;
|
||||
class nsAString;
|
||||
struct PRThread;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class BackgroundFileHandleChild;
|
||||
class Blob;
|
||||
class FileRequestBase;
|
||||
class FileRequestData;
|
||||
class FileRequestParams;
|
||||
class MutableFileBase;
|
||||
class StringOrArrayBufferOrArrayBufferViewOrBlob;
|
||||
|
||||
/**
|
||||
* This class provides a base for FileHandle implementations.
|
||||
*/
|
||||
class FileHandleBase
|
||||
: public RefCountedThreadObject
|
||||
{
|
||||
public:
|
||||
enum ReadyState
|
||||
{
|
||||
INITIAL = 0,
|
||||
LOADING,
|
||||
FINISHING,
|
||||
DONE
|
||||
};
|
||||
|
||||
private:
|
||||
BackgroundFileHandleChild* mBackgroundActor;
|
||||
|
||||
uint64_t mLocation;
|
||||
|
||||
uint32_t mPendingRequestCount;
|
||||
|
||||
ReadyState mReadyState;
|
||||
FileMode mMode;
|
||||
|
||||
bool mAborted;
|
||||
bool mCreating;
|
||||
|
||||
DEBUGONLY(bool mSentFinishOrAbort;)
|
||||
DEBUGONLY(bool mFiredCompleteOrAbort;)
|
||||
|
||||
public:
|
||||
static FileHandleBase*
|
||||
GetCurrent();
|
||||
|
||||
void
|
||||
SetBackgroundActor(BackgroundFileHandleChild* aActor);
|
||||
|
||||
void
|
||||
ClearBackgroundActor()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
mBackgroundActor = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
StartRequest(FileRequestBase* aFileRequest, const FileRequestParams& aParams);
|
||||
|
||||
void
|
||||
OnNewRequest();
|
||||
|
||||
void
|
||||
OnRequestFinished(bool aActorDestroyedNormally);
|
||||
|
||||
bool
|
||||
IsOpen() const;
|
||||
|
||||
bool
|
||||
IsFinishingOrDone() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return mReadyState == FINISHING || mReadyState == DONE;
|
||||
}
|
||||
|
||||
bool
|
||||
IsDone() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return mReadyState == DONE;
|
||||
}
|
||||
|
||||
bool
|
||||
IsAborted() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return mAborted;
|
||||
}
|
||||
|
||||
void
|
||||
SetCreating()
|
||||
{
|
||||
mCreating = true;
|
||||
}
|
||||
|
||||
void
|
||||
Abort();
|
||||
|
||||
// Shared WebIDL (IndexedDB FileHandle and FileSystem FileHandle)
|
||||
FileMode
|
||||
Mode() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return mMode;
|
||||
}
|
||||
|
||||
bool
|
||||
Active() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return IsOpen();
|
||||
}
|
||||
|
||||
Nullable<uint64_t>
|
||||
GetLocation() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mLocation == UINT64_MAX) {
|
||||
return Nullable<uint64_t>();
|
||||
}
|
||||
|
||||
return Nullable<uint64_t>(mLocation);
|
||||
}
|
||||
|
||||
void
|
||||
SetLocation(const Nullable<uint64_t>& aLocation)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// Null means the end-of-file.
|
||||
if (aLocation.IsNull()) {
|
||||
mLocation = UINT64_MAX;
|
||||
} else {
|
||||
mLocation = aLocation.Value();
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<FileRequestBase>
|
||||
Read(uint64_t aSize, bool aHasEncoding, const nsAString& aEncoding,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<FileRequestBase>
|
||||
Truncate(const Optional<uint64_t>& aSize, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<FileRequestBase>
|
||||
Flush(ErrorResult& aRv);
|
||||
|
||||
void
|
||||
Abort(ErrorResult& aRv);
|
||||
|
||||
// Must be overridden in subclasses.
|
||||
virtual MutableFileBase*
|
||||
MutableFile() const = 0;
|
||||
|
||||
// May be overridden in subclasses.
|
||||
virtual void
|
||||
HandleCompleteOrAbort(bool aAborted);
|
||||
|
||||
protected:
|
||||
FileHandleBase(DEBUGONLY(PRThread* aOwningThread,)
|
||||
FileMode aMode);
|
||||
|
||||
~FileHandleBase();
|
||||
|
||||
void
|
||||
OnReturnToEventLoop();
|
||||
|
||||
bool
|
||||
CheckState(ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
CheckStateAndArgumentsForRead(uint64_t aSize, ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
CheckStateForWrite(ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
CheckStateForWriteOrAppend(bool aAppend, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<FileRequestBase>
|
||||
WriteOrAppend(const StringOrArrayBufferOrArrayBufferViewOrBlob& aValue,
|
||||
bool aAppend,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// Must be overridden in subclasses.
|
||||
virtual bool
|
||||
CheckWindow() = 0;
|
||||
|
||||
// Must be overridden in subclasses.
|
||||
virtual already_AddRefed<FileRequestBase>
|
||||
GenerateFileRequest() = 0;
|
||||
|
||||
private:
|
||||
already_AddRefed<FileRequestBase>
|
||||
WriteOrAppend(const nsAString& aValue, bool aAppend, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<FileRequestBase>
|
||||
WriteOrAppend(const ArrayBuffer& aValue, bool aAppend, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<FileRequestBase>
|
||||
WriteOrAppend(const ArrayBufferView& aValue, bool aAppend, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<FileRequestBase>
|
||||
WriteOrAppend(Blob& aValue, bool aAppend, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<FileRequestBase>
|
||||
WriteInternal(const FileRequestData& aData, uint64_t aDataLength,
|
||||
bool aAppend, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
SendFinish();
|
||||
|
||||
void
|
||||
SendAbort();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_FileHandle_h
|
|
@ -1,34 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "FileHandleCommon.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "prthread.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
ThreadObject::AssertIsOnOwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread);
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
|
||||
}
|
||||
|
||||
PRThread*
|
||||
ThreadObject::OwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread);
|
||||
return mOwningThread;
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,70 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_FileHandleCommon_h
|
||||
#define mozilla_dom_FileHandleCommon_h
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUGONLY(...) __VA_ARGS__
|
||||
#else
|
||||
#define DEBUGONLY(...) /* nothing */
|
||||
#endif
|
||||
|
||||
struct PRThread;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class RefCountedObject
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
|
||||
|
||||
protected:
|
||||
virtual ~RefCountedObject()
|
||||
{ }
|
||||
};
|
||||
|
||||
class ThreadObject
|
||||
{
|
||||
DEBUGONLY(PRThread* mOwningThread;)
|
||||
|
||||
public:
|
||||
explicit ThreadObject(DEBUGONLY(PRThread* aOwningThread))
|
||||
DEBUGONLY(: mOwningThread(aOwningThread))
|
||||
{ }
|
||||
|
||||
virtual ~ThreadObject()
|
||||
{ }
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
AssertIsOnOwningThread() const;
|
||||
|
||||
PRThread*
|
||||
OwningThread() const;
|
||||
#else
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
{ }
|
||||
#endif
|
||||
};
|
||||
|
||||
class RefCountedThreadObject
|
||||
: public RefCountedObject
|
||||
, public ThreadObject
|
||||
{
|
||||
public:
|
||||
explicit RefCountedThreadObject(DEBUGONLY(PRThread* aOwningThread))
|
||||
: ThreadObject(DEBUGONLY(aOwningThread))
|
||||
{ }
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_FileHandleCommon_h
|
|
@ -1,93 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_FileRequest_h
|
||||
#define mozilla_dom_FileRequest_h
|
||||
|
||||
#include "FileHandleCommon.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "nsString.h"
|
||||
|
||||
struct PRThread;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class FileHandleBase;
|
||||
|
||||
/**
|
||||
* This class provides a base for FileRequest implementations.
|
||||
*/
|
||||
class FileRequestBase
|
||||
: public RefCountedThreadObject
|
||||
{
|
||||
nsString mEncoding;
|
||||
|
||||
bool mHasEncoding;
|
||||
|
||||
public:
|
||||
class ResultCallback;
|
||||
|
||||
void
|
||||
SetEncoding(const nsAString& aEncoding)
|
||||
{
|
||||
mEncoding = aEncoding;
|
||||
mHasEncoding = true;
|
||||
}
|
||||
|
||||
const nsAString&
|
||||
GetEncoding() const
|
||||
{
|
||||
return mEncoding;
|
||||
}
|
||||
|
||||
bool
|
||||
HasEncoding() const
|
||||
{
|
||||
return mHasEncoding;
|
||||
}
|
||||
|
||||
virtual FileHandleBase*
|
||||
FileHandle() const = 0;
|
||||
|
||||
virtual void
|
||||
OnProgress(uint64_t aProgress, uint64_t aProgressMax) = 0;
|
||||
|
||||
virtual void
|
||||
SetResultCallback(ResultCallback* aCallback) = 0;
|
||||
|
||||
virtual void
|
||||
SetError(nsresult aError) = 0;
|
||||
|
||||
protected:
|
||||
FileRequestBase(DEBUGONLY(PRThread* aOwningThread))
|
||||
: RefCountedThreadObject(DEBUGONLY(aOwningThread))
|
||||
, mHasEncoding(false)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
virtual ~FileRequestBase()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
}
|
||||
};
|
||||
|
||||
class NS_NO_VTABLE FileRequestBase::ResultCallback
|
||||
{
|
||||
public:
|
||||
virtual nsresult
|
||||
GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult) = 0;
|
||||
|
||||
protected:
|
||||
ResultCallback()
|
||||
{ }
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_FileRequest_h
|
|
@ -1,36 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MutableFileBase.h"
|
||||
|
||||
#include "ActorsChild.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "prthread.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
MutableFileBase::MutableFileBase(DEBUGONLY(PRThread* aOwningThread,)
|
||||
BackgroundMutableFileChildBase* aActor)
|
||||
: RefCountedThreadObject(DEBUGONLY(aOwningThread))
|
||||
, mBackgroundActor(aActor)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
}
|
||||
|
||||
MutableFileBase::~MutableFileBase()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mBackgroundActor) {
|
||||
mBackgroundActor->SendDeleteMeInternal();
|
||||
MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,76 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_MutableFile_h
|
||||
#define mozilla_dom_MutableFile_h
|
||||
|
||||
#include "mozilla/dom/FileHandleCommon.h"
|
||||
#include "nscore.h"
|
||||
|
||||
template <class> struct already_AddRefed;
|
||||
class nsISupports;
|
||||
class nsString;
|
||||
struct PRThread;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class BackgroundMutableFileChildBase;
|
||||
class BlobImpl;
|
||||
class File;
|
||||
class FileHandleBase;
|
||||
|
||||
/**
|
||||
* This class provides a base for MutableFile implementations.
|
||||
* (for example IDBMutableFile provides IndexedDB specific implementation).
|
||||
*/
|
||||
class MutableFileBase
|
||||
: public RefCountedThreadObject
|
||||
{
|
||||
protected:
|
||||
BackgroundMutableFileChildBase* mBackgroundActor;
|
||||
|
||||
public:
|
||||
BackgroundMutableFileChildBase*
|
||||
GetBackgroundActor() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return mBackgroundActor;
|
||||
}
|
||||
|
||||
void
|
||||
ClearBackgroundActor()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
mBackgroundActor = nullptr;
|
||||
}
|
||||
|
||||
virtual const nsString&
|
||||
Name() const = 0;
|
||||
|
||||
virtual const nsString&
|
||||
Type() const = 0;
|
||||
|
||||
virtual bool
|
||||
IsInvalidated() = 0;
|
||||
|
||||
virtual already_AddRefed<File>
|
||||
CreateFileFor(BlobImpl* aBlobImpl,
|
||||
FileHandleBase* aFileHandle) = 0;
|
||||
|
||||
protected:
|
||||
MutableFileBase(DEBUGONLY(PRThread* aOwningThread,)
|
||||
BackgroundMutableFileChildBase* aActor);
|
||||
|
||||
virtual ~MutableFileBase();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_MutableFile_h
|
|
@ -8,25 +8,16 @@ with Files("**"):
|
|||
BUG_COMPONENT = ("Core", "DOM")
|
||||
|
||||
EXPORTS.mozilla.dom.filehandle += [
|
||||
'ActorsChild.h',
|
||||
'ActorsParent.h',
|
||||
'SerializationHelpers.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'FileHandleBase.h',
|
||||
'FileHandleCommon.h',
|
||||
'FileHandleStorage.h',
|
||||
'FileRequestBase.h',
|
||||
'MutableFileBase.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'ActorsChild.cpp',
|
||||
'ActorsParent.cpp',
|
||||
'FileHandleBase.cpp',
|
||||
'FileHandleCommon.cpp',
|
||||
'MutableFileBase.cpp',
|
||||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
|
|
|
@ -7,13 +7,14 @@
|
|||
#include "ActorsChild.h"
|
||||
|
||||
#include "BackgroundChildImpl.h"
|
||||
#include "FileSnapshot.h"
|
||||
#include "IDBDatabase.h"
|
||||
#include "IDBEvents.h"
|
||||
#include "IDBFactory.h"
|
||||
#include "IDBFileHandle.h"
|
||||
#include "IDBIndex.h"
|
||||
#include "IDBMutableFile.h"
|
||||
#include "IDBObjectStore.h"
|
||||
#include "IDBMutableFile.h"
|
||||
#include "IDBRequest.h"
|
||||
#include "IDBTransaction.h"
|
||||
#include "IndexedDatabase.h"
|
||||
|
@ -23,10 +24,12 @@
|
|||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/EncodingUtils.h"
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseFileChild.h"
|
||||
#include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestChild.h"
|
||||
#include "mozilla/dom/ipc/PendingIPCBlobChild.h"
|
||||
#include "mozilla/dom/IPCBlobUtils.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "mozilla/TaskQueue.h"
|
||||
|
@ -80,12 +83,7 @@ namespace indexedDB {
|
|||
ThreadLocal::ThreadLocal(const nsID& aBackgroundChildLoggingId)
|
||||
: mLoggingInfo(aBackgroundChildLoggingId, 1, -1, 1)
|
||||
, mCurrentTransaction(0)
|
||||
#ifdef DEBUG
|
||||
, mOwningThread(PR_GetCurrentThread())
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread);
|
||||
|
||||
MOZ_COUNT_CTOR(mozilla::dom::indexedDB::ThreadLocal);
|
||||
|
||||
// NSID_LENGTH counts the null terminator, SetLength() does not.
|
||||
|
@ -100,16 +98,6 @@ ThreadLocal::~ThreadLocal()
|
|||
MOZ_COUNT_DTOR(mozilla::dom::indexedDB::ThreadLocal);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
ThreadLocal::AssertIsOnOwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
/*******************************************************************************
|
||||
* Helpers
|
||||
******************************************************************************/
|
||||
|
@ -1141,6 +1129,354 @@ WorkerPermissionRequestChildProcessActor::Recv__delete__(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS AutoSetCurrentFileHandle final
|
||||
{
|
||||
typedef mozilla::ipc::BackgroundChildImpl BackgroundChildImpl;
|
||||
|
||||
IDBFileHandle* const mFileHandle;
|
||||
IDBFileHandle* mPreviousFileHandle;
|
||||
IDBFileHandle** mThreadLocalSlot;
|
||||
|
||||
public:
|
||||
explicit AutoSetCurrentFileHandle(IDBFileHandle* aFileHandle)
|
||||
: mFileHandle(aFileHandle)
|
||||
, mPreviousFileHandle(nullptr)
|
||||
, mThreadLocalSlot(nullptr)
|
||||
{
|
||||
if (aFileHandle) {
|
||||
BackgroundChildImpl::ThreadLocal* threadLocal =
|
||||
BackgroundChildImpl::GetThreadLocalForCurrentThread();
|
||||
MOZ_ASSERT(threadLocal);
|
||||
|
||||
// Hang onto this location for resetting later.
|
||||
mThreadLocalSlot = &threadLocal->mCurrentFileHandle;
|
||||
|
||||
// Save the current value.
|
||||
mPreviousFileHandle = *mThreadLocalSlot;
|
||||
|
||||
// Set the new value.
|
||||
*mThreadLocalSlot = aFileHandle;
|
||||
}
|
||||
}
|
||||
|
||||
~AutoSetCurrentFileHandle()
|
||||
{
|
||||
MOZ_ASSERT_IF(mThreadLocalSlot, mFileHandle);
|
||||
MOZ_ASSERT_IF(mThreadLocalSlot, *mThreadLocalSlot == mFileHandle);
|
||||
|
||||
if (mThreadLocalSlot) {
|
||||
// Reset old value.
|
||||
*mThreadLocalSlot = mPreviousFileHandle;
|
||||
}
|
||||
}
|
||||
|
||||
IDBFileHandle*
|
||||
FileHandle() const
|
||||
{
|
||||
return mFileHandle;
|
||||
}
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS FileHandleResultHelper final
|
||||
: public IDBFileRequest::ResultCallback
|
||||
{
|
||||
IDBFileRequest* mFileRequest;
|
||||
AutoSetCurrentFileHandle mAutoFileHandle;
|
||||
|
||||
union
|
||||
{
|
||||
File* mFile;
|
||||
const nsCString* mString;
|
||||
const FileRequestMetadata* mMetadata;
|
||||
const JS::Handle<JS::Value>* mJSValHandle;
|
||||
} mResult;
|
||||
|
||||
enum
|
||||
{
|
||||
ResultTypeFile,
|
||||
ResultTypeString,
|
||||
ResultTypeMetadata,
|
||||
ResultTypeJSValHandle,
|
||||
} mResultType;
|
||||
|
||||
public:
|
||||
FileHandleResultHelper(IDBFileRequest* aFileRequest,
|
||||
IDBFileHandle* aFileHandle,
|
||||
File* aResult)
|
||||
: mFileRequest(aFileRequest)
|
||||
, mAutoFileHandle(aFileHandle)
|
||||
, mResultType(ResultTypeFile)
|
||||
{
|
||||
MOZ_ASSERT(aFileRequest);
|
||||
MOZ_ASSERT(aFileHandle);
|
||||
MOZ_ASSERT(aResult);
|
||||
|
||||
mResult.mFile = aResult;
|
||||
}
|
||||
|
||||
FileHandleResultHelper(IDBFileRequest* aFileRequest,
|
||||
IDBFileHandle* aFileHandle,
|
||||
const nsCString* aResult)
|
||||
: mFileRequest(aFileRequest)
|
||||
, mAutoFileHandle(aFileHandle)
|
||||
, mResultType(ResultTypeString)
|
||||
{
|
||||
MOZ_ASSERT(aFileRequest);
|
||||
MOZ_ASSERT(aFileHandle);
|
||||
MOZ_ASSERT(aResult);
|
||||
|
||||
mResult.mString = aResult;
|
||||
}
|
||||
|
||||
FileHandleResultHelper(IDBFileRequest* aFileRequest,
|
||||
IDBFileHandle* aFileHandle,
|
||||
const FileRequestMetadata* aResult)
|
||||
: mFileRequest(aFileRequest)
|
||||
, mAutoFileHandle(aFileHandle)
|
||||
, mResultType(ResultTypeMetadata)
|
||||
{
|
||||
MOZ_ASSERT(aFileRequest);
|
||||
MOZ_ASSERT(aFileHandle);
|
||||
MOZ_ASSERT(aResult);
|
||||
|
||||
mResult.mMetadata = aResult;
|
||||
}
|
||||
|
||||
|
||||
FileHandleResultHelper(IDBFileRequest* aFileRequest,
|
||||
IDBFileHandle* aFileHandle,
|
||||
const JS::Handle<JS::Value>* aResult)
|
||||
: mFileRequest(aFileRequest)
|
||||
, mAutoFileHandle(aFileHandle)
|
||||
, mResultType(ResultTypeJSValHandle)
|
||||
{
|
||||
MOZ_ASSERT(aFileRequest);
|
||||
MOZ_ASSERT(aFileHandle);
|
||||
MOZ_ASSERT(aResult);
|
||||
|
||||
mResult.mJSValHandle = aResult;
|
||||
}
|
||||
|
||||
IDBFileRequest*
|
||||
FileRequest() const
|
||||
{
|
||||
return mFileRequest;
|
||||
}
|
||||
|
||||
IDBFileHandle*
|
||||
FileHandle() const
|
||||
{
|
||||
return mAutoFileHandle.FileHandle();
|
||||
}
|
||||
|
||||
virtual nsresult
|
||||
GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult) override
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(mFileRequest);
|
||||
|
||||
switch (mResultType) {
|
||||
case ResultTypeFile:
|
||||
return GetResult(aCx, mResult.mFile, aResult);
|
||||
|
||||
case ResultTypeString:
|
||||
return GetResult(aCx, mResult.mString, aResult);
|
||||
|
||||
case ResultTypeMetadata:
|
||||
return GetResult(aCx, mResult.mMetadata, aResult);
|
||||
|
||||
case ResultTypeJSValHandle:
|
||||
aResult.set(*mResult.mJSValHandle);
|
||||
return NS_OK;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Unknown result type!");
|
||||
}
|
||||
|
||||
MOZ_CRASH("Should never get here!");
|
||||
}
|
||||
|
||||
private:
|
||||
nsresult
|
||||
GetResult(JSContext* aCx,
|
||||
File* aFile,
|
||||
JS::MutableHandle<JS::Value> aResult)
|
||||
{
|
||||
bool ok = GetOrCreateDOMReflector(aCx, aFile, aResult);
|
||||
if (NS_WARN_IF(!ok)) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetResult(JSContext* aCx,
|
||||
const nsCString* aString,
|
||||
JS::MutableHandle<JS::Value> aResult)
|
||||
{
|
||||
const nsCString& data = *aString;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (!mFileRequest->HasEncoding()) {
|
||||
JS::Rooted<JSObject*> arrayBuffer(aCx);
|
||||
rv = nsContentUtils::CreateArrayBuffer(aCx, data, arrayBuffer.address());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
aResult.setObject(*arrayBuffer);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString encoding;
|
||||
// The BOM sniffing is baked into the "decode" part of the Encoding
|
||||
// Standard, which the File API references.
|
||||
if (!nsContentUtils::CheckForBOM(
|
||||
reinterpret_cast<const unsigned char *>(data.get()),
|
||||
data.Length(),
|
||||
encoding)) {
|
||||
// BOM sniffing failed. Try the API argument.
|
||||
if (!EncodingUtils::FindEncodingForLabel(mFileRequest->GetEncoding(),
|
||||
encoding)) {
|
||||
// API argument failed. Since we are dealing with a file system file,
|
||||
// we don't have a meaningful type attribute for the blob available,
|
||||
// so proceeding to the next step, which is defaulting to UTF-8.
|
||||
encoding.AssignLiteral("UTF-8");
|
||||
}
|
||||
}
|
||||
|
||||
nsString tmpString;
|
||||
rv = nsContentUtils::ConvertStringFromEncoding(encoding, data, tmpString);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!xpc::StringToJsval(aCx, tmpString, aResult))) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetResult(JSContext* aCx,
|
||||
const FileRequestMetadata* aMetadata,
|
||||
JS::MutableHandle<JS::Value> aResult)
|
||||
{
|
||||
JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
|
||||
if (NS_WARN_IF(!obj)) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
const FileRequestSize& size = aMetadata->size();
|
||||
if (size.type() != FileRequestSize::Tvoid_t) {
|
||||
MOZ_ASSERT(size.type() == FileRequestSize::Tuint64_t);
|
||||
|
||||
JS::Rooted<JS::Value> number(aCx, JS_NumberValue(size.get_uint64_t()));
|
||||
|
||||
if (NS_WARN_IF(!JS_DefineProperty(aCx, obj, "size", number, 0))) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
const FileRequestLastModified& lastModified = aMetadata->lastModified();
|
||||
if (lastModified.type() != FileRequestLastModified::Tvoid_t) {
|
||||
MOZ_ASSERT(lastModified.type() == FileRequestLastModified::Tint64_t);
|
||||
|
||||
JS::Rooted<JSObject*> date(aCx,
|
||||
JS::NewDateObject(aCx, JS::TimeClip(lastModified.get_int64_t())));
|
||||
if (NS_WARN_IF(!date)) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!JS_DefineProperty(aCx, obj, "lastModified", date, 0))) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
aResult.setObject(*obj);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
already_AddRefed<File>
|
||||
ConvertActorToFile(IDBFileHandle* aFileHandle,
|
||||
const FileRequestGetFileResponse& aResponse)
|
||||
{
|
||||
auto* actor = static_cast<PendingIPCBlobChild*>(aResponse.fileChild());
|
||||
|
||||
IDBMutableFile* mutableFile = aFileHandle->GetMutableFile();
|
||||
MOZ_ASSERT(mutableFile);
|
||||
|
||||
const FileRequestMetadata& metadata = aResponse.metadata();
|
||||
|
||||
const FileRequestSize& size = metadata.size();
|
||||
MOZ_ASSERT(size.type() == FileRequestSize::Tuint64_t);
|
||||
|
||||
const FileRequestLastModified& lastModified = metadata.lastModified();
|
||||
MOZ_ASSERT(lastModified.type() == FileRequestLastModified::Tint64_t);
|
||||
|
||||
RefPtr<BlobImpl> blobImpl =
|
||||
actor->SetPendingInfoAndDeleteActor(mutableFile->Name(),
|
||||
mutableFile->Type(),
|
||||
size.get_uint64_t(),
|
||||
lastModified.get_int64_t());
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
RefPtr<BlobImpl> blobImplSnapshot =
|
||||
new BlobImplSnapshot(blobImpl, static_cast<IDBFileHandle*>(aFileHandle));
|
||||
|
||||
RefPtr<File> file = File::Create(mutableFile->GetOwner(), blobImplSnapshot);
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
void
|
||||
DispatchFileHandleErrorEvent(IDBFileRequest* aFileRequest,
|
||||
nsresult aErrorCode,
|
||||
IDBFileHandle* aFileHandle)
|
||||
{
|
||||
MOZ_ASSERT(aFileRequest);
|
||||
aFileRequest->AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(NS_FAILED(aErrorCode));
|
||||
MOZ_ASSERT(NS_ERROR_GET_MODULE(aErrorCode) == NS_ERROR_MODULE_DOM_FILEHANDLE);
|
||||
MOZ_ASSERT(aFileHandle);
|
||||
|
||||
RefPtr<IDBFileRequest> fileRequest = aFileRequest;
|
||||
RefPtr<IDBFileHandle> fileHandle = aFileHandle;
|
||||
|
||||
AutoSetCurrentFileHandle ascfh(aFileHandle);
|
||||
|
||||
fileRequest->FireError(aErrorCode);
|
||||
|
||||
MOZ_ASSERT(fileHandle->IsOpen() || fileHandle->IsAborted());
|
||||
}
|
||||
|
||||
void
|
||||
DispatchFileHandleSuccessEvent(FileHandleResultHelper* aResultHelper)
|
||||
{
|
||||
MOZ_ASSERT(aResultHelper);
|
||||
|
||||
RefPtr<IDBFileRequest> fileRequest = aResultHelper->FileRequest();
|
||||
MOZ_ASSERT(fileRequest);
|
||||
fileRequest->AssertIsOnOwningThread();
|
||||
|
||||
RefPtr<IDBFileHandle> fileHandle = aResultHelper->FileHandle();
|
||||
MOZ_ASSERT(fileHandle);
|
||||
|
||||
if (fileHandle->IsAborted()) {
|
||||
fileRequest->FireError(NS_ERROR_DOM_FILEHANDLE_ABORT_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(fileHandle->IsOpen());
|
||||
|
||||
fileRequest->SetResultCallback(aResultHelper);
|
||||
|
||||
MOZ_ASSERT(fileHandle->IsOpen() || fileHandle->IsAborted());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -1317,9 +1653,6 @@ BackgroundRequestChildBase::AssertIsOnOwningThread() const
|
|||
|
||||
BackgroundFactoryChild::BackgroundFactoryChild(IDBFactory* aFactory)
|
||||
: mFactory(aFactory)
|
||||
#ifdef DEBUG
|
||||
, mOwningThread(NS_GetCurrentThread())
|
||||
#endif
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aFactory);
|
||||
|
@ -1333,27 +1666,6 @@ BackgroundFactoryChild::~BackgroundFactoryChild()
|
|||
MOZ_COUNT_DTOR(indexedDB::BackgroundFactoryChild);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
BackgroundFactoryChild::AssertIsOnOwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread);
|
||||
|
||||
bool current;
|
||||
MOZ_ASSERT(NS_SUCCEEDED(mOwningThread->IsOnCurrentThread(¤t)));
|
||||
MOZ_ASSERT(current);
|
||||
}
|
||||
|
||||
nsIEventTarget*
|
||||
BackgroundFactoryChild::OwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread);
|
||||
return mOwningThread;
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
BackgroundFactoryChild::SendDeleteMeInternal()
|
||||
{
|
||||
|
@ -1735,6 +2047,16 @@ BackgroundDatabaseChild::~BackgroundDatabaseChild()
|
|||
MOZ_COUNT_DTOR(indexedDB::BackgroundDatabaseChild);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
BackgroundDatabaseChild::AssertIsOnOwningThread() const
|
||||
{
|
||||
static_cast<BackgroundFactoryChild*>(Manager())->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
BackgroundDatabaseChild::SendDeleteMeInternal()
|
||||
{
|
||||
|
@ -1961,16 +2283,7 @@ BackgroundDatabaseChild::AllocPBackgroundMutableFileChild(const nsString& aName,
|
|||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsIThread> owningThread = do_QueryInterface(OwningThread());
|
||||
|
||||
PRThread* owningPRThread;
|
||||
owningThread->GetPRThread(&owningPRThread);
|
||||
#endif
|
||||
|
||||
return new BackgroundMutableFileChild(DEBUGONLY(owningPRThread,)
|
||||
aName,
|
||||
aType);
|
||||
return new BackgroundMutableFileChild(aName, aType);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -2488,11 +2801,9 @@ BackgroundVersionChangeTransactionChild::DeallocPBackgroundIDBCursorChild(
|
|||
* BackgroundMutableFileChild
|
||||
******************************************************************************/
|
||||
|
||||
BackgroundMutableFileChild::BackgroundMutableFileChild(
|
||||
DEBUGONLY(PRThread* aOwningThread,)
|
||||
const nsAString& aName,
|
||||
const nsAString& aType)
|
||||
: BackgroundMutableFileChildBase(DEBUGONLY(aOwningThread))
|
||||
BackgroundMutableFileChild::BackgroundMutableFileChild(const nsAString& aName,
|
||||
const nsAString& aType)
|
||||
: mMutableFile(nullptr)
|
||||
, mName(aName)
|
||||
, mType(aType)
|
||||
{
|
||||
|
@ -2505,17 +2816,93 @@ BackgroundMutableFileChild::~BackgroundMutableFileChild()
|
|||
MOZ_COUNT_DTOR(indexedDB::BackgroundMutableFileChild);
|
||||
}
|
||||
|
||||
already_AddRefed<MutableFileBase>
|
||||
BackgroundMutableFileChild::CreateMutableFile()
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
BackgroundMutableFileChild::AssertIsOnOwningThread() const
|
||||
{
|
||||
static_cast<BackgroundDatabaseChild*>(Manager())->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
BackgroundMutableFileChild::EnsureDOMObject()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mTemporaryStrongMutableFile) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto database =
|
||||
static_cast<BackgroundDatabaseChild*>(Manager())->GetDOMObject();
|
||||
MOZ_ASSERT(database);
|
||||
|
||||
RefPtr<IDBMutableFile> mutableFile =
|
||||
mTemporaryStrongMutableFile =
|
||||
new IDBMutableFile(database, this, mName, mType);
|
||||
|
||||
return mutableFile.forget();
|
||||
MOZ_ASSERT(mTemporaryStrongMutableFile);
|
||||
mTemporaryStrongMutableFile->AssertIsOnOwningThread();
|
||||
|
||||
mMutableFile = mTemporaryStrongMutableFile;
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundMutableFileChild::ReleaseDOMObject()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mTemporaryStrongMutableFile);
|
||||
mTemporaryStrongMutableFile->AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mMutableFile == mTemporaryStrongMutableFile);
|
||||
|
||||
mTemporaryStrongMutableFile = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundMutableFileChild::SendDeleteMeInternal()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(!mTemporaryStrongMutableFile);
|
||||
|
||||
if (mMutableFile) {
|
||||
mMutableFile->ClearBackgroundActor();
|
||||
mMutableFile = nullptr;
|
||||
|
||||
MOZ_ALWAYS_TRUE(PBackgroundMutableFileChild::SendDeleteMe());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundMutableFileChild::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mMutableFile) {
|
||||
mMutableFile->ClearBackgroundActor();
|
||||
#ifdef DEBUG
|
||||
mMutableFile = nullptr;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
PBackgroundFileHandleChild*
|
||||
BackgroundMutableFileChild::AllocPBackgroundFileHandleChild(
|
||||
const FileMode& aMode)
|
||||
{
|
||||
MOZ_CRASH("PBackgroundFileHandleChild actors should be manually "
|
||||
"constructed!");
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundMutableFileChild::DeallocPBackgroundFileHandleChild(
|
||||
PBackgroundFileHandleChild* aActor)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
delete static_cast<BackgroundFileHandleChild*>(aActor);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -3308,11 +3695,6 @@ BackgroundCursorChild::BackgroundCursorChild(IDBRequest* aRequest,
|
|||
MOZ_ASSERT(mTransaction);
|
||||
|
||||
MOZ_COUNT_CTOR(indexedDB::BackgroundCursorChild);
|
||||
|
||||
#ifdef DEBUG
|
||||
mOwningThread = PR_GetCurrentThread();
|
||||
MOZ_ASSERT(mOwningThread);
|
||||
#endif
|
||||
}
|
||||
|
||||
BackgroundCursorChild::BackgroundCursorChild(IDBRequest* aRequest,
|
||||
|
@ -3331,11 +3713,6 @@ BackgroundCursorChild::BackgroundCursorChild(IDBRequest* aRequest,
|
|||
MOZ_ASSERT(mTransaction);
|
||||
|
||||
MOZ_COUNT_CTOR(indexedDB::BackgroundCursorChild);
|
||||
|
||||
#ifdef DEBUG
|
||||
mOwningThread = PR_GetCurrentThread();
|
||||
MOZ_ASSERT(mOwningThread);
|
||||
#endif
|
||||
}
|
||||
|
||||
BackgroundCursorChild::~BackgroundCursorChild()
|
||||
|
@ -3343,16 +3720,6 @@ BackgroundCursorChild::~BackgroundCursorChild()
|
|||
MOZ_COUNT_DTOR(indexedDB::BackgroundCursorChild);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
BackgroundCursorChild::AssertIsOnOwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread == PR_GetCurrentThread());
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
BackgroundCursorChild::SendContinueInternal(const CursorRequestParams& aParams)
|
||||
{
|
||||
|
@ -3685,15 +4052,299 @@ DelayedActionRunnable::Cancel()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* BackgroundFileHandleChild
|
||||
******************************************************************************/
|
||||
|
||||
BackgroundFileHandleChild::BackgroundFileHandleChild(IDBFileHandle* aFileHandle)
|
||||
: mTemporaryStrongFileHandle(aFileHandle)
|
||||
, mFileHandle(aFileHandle)
|
||||
{
|
||||
MOZ_ASSERT(aFileHandle);
|
||||
aFileHandle->AssertIsOnOwningThread();
|
||||
|
||||
MOZ_COUNT_CTOR(BackgroundFileHandleChild);
|
||||
}
|
||||
|
||||
BackgroundFileHandleChild::~BackgroundFileHandleChild()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
MOZ_COUNT_DTOR(BackgroundFileHandleChild);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
BackgroundFileHandleChild::AssertIsOnOwningThread() const
|
||||
{
|
||||
static_cast<BackgroundMutableFileChild*>(Manager())->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
BackgroundFileHandleChild::SendDeleteMeInternal()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mFileHandle) {
|
||||
NoteActorDestroyed();
|
||||
|
||||
MOZ_ALWAYS_TRUE(PBackgroundFileHandleChild::SendDeleteMe());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileHandleChild::NoteActorDestroyed()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT_IF(mTemporaryStrongFileHandle, mFileHandle);
|
||||
|
||||
if (mFileHandle) {
|
||||
mFileHandle->ClearBackgroundActor();
|
||||
|
||||
// Normally this would be DEBUG-only but NoteActorDestroyed is also called
|
||||
// from SendDeleteMeInternal. In that case we're going to receive an actual
|
||||
// ActorDestroy call later and we don't want to touch a dead object.
|
||||
mTemporaryStrongFileHandle = nullptr;
|
||||
mFileHandle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileHandleChild::NoteComplete()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT_IF(mFileHandle, mTemporaryStrongFileHandle);
|
||||
|
||||
mTemporaryStrongFileHandle = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileHandleChild::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
NoteActorDestroyed();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BackgroundFileHandleChild::RecvComplete(const bool& aAborted)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mFileHandle);
|
||||
|
||||
mFileHandle->FireCompleteOrAbortEvents(aAborted);
|
||||
|
||||
NoteComplete();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
PBackgroundFileRequestChild*
|
||||
BackgroundFileHandleChild::AllocPBackgroundFileRequestChild(
|
||||
const FileRequestParams& aParams)
|
||||
{
|
||||
MOZ_CRASH("PBackgroundFileRequestChild actors should be manually "
|
||||
"constructed!");
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundFileHandleChild::DeallocPBackgroundFileRequestChild(
|
||||
PBackgroundFileRequestChild* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
delete static_cast<BackgroundFileRequestChild*>(aActor);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* BackgroundFileRequestChild
|
||||
******************************************************************************/
|
||||
|
||||
BackgroundFileRequestChild::BackgroundFileRequestChild(
|
||||
IDBFileRequest* aFileRequest)
|
||||
: mFileRequest(aFileRequest)
|
||||
, mFileHandle(aFileRequest->GetFileHandle())
|
||||
, mActorDestroyed(false)
|
||||
{
|
||||
MOZ_ASSERT(aFileRequest);
|
||||
aFileRequest->AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mFileHandle);
|
||||
mFileHandle->AssertIsOnOwningThread();
|
||||
|
||||
MOZ_COUNT_CTOR(BackgroundFileRequestChild);
|
||||
}
|
||||
|
||||
BackgroundFileRequestChild::~BackgroundFileRequestChild()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(!mFileHandle);
|
||||
|
||||
MOZ_COUNT_DTOR(BackgroundFileRequestChild);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
BackgroundFileRequestChild::AssertIsOnOwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mFileRequest);
|
||||
mFileRequest->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
BackgroundFileRequestChild::HandleResponse(nsresult aResponse)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(NS_FAILED(aResponse));
|
||||
MOZ_ASSERT(NS_ERROR_GET_MODULE(aResponse) == NS_ERROR_MODULE_DOM_FILEHANDLE);
|
||||
MOZ_ASSERT(mFileHandle);
|
||||
|
||||
DispatchFileHandleErrorEvent(mFileRequest, aResponse, mFileHandle);
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileRequestChild::HandleResponse(
|
||||
const FileRequestGetFileResponse& aResponse)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
RefPtr<File> file = ConvertActorToFile(mFileHandle, aResponse);
|
||||
|
||||
FileHandleResultHelper helper(mFileRequest, mFileHandle, file);
|
||||
|
||||
DispatchFileHandleSuccessEvent(&helper);
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileRequestChild::HandleResponse(const nsCString& aResponse)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
FileHandleResultHelper helper(mFileRequest, mFileHandle, &aResponse);
|
||||
|
||||
DispatchFileHandleSuccessEvent(&helper);
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileRequestChild::HandleResponse(const FileRequestMetadata& aResponse)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
FileHandleResultHelper helper(mFileRequest, mFileHandle, &aResponse);
|
||||
|
||||
DispatchFileHandleSuccessEvent(&helper);
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileRequestChild::HandleResponse(JS::Handle<JS::Value> aResponse)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
FileHandleResultHelper helper(mFileRequest, mFileHandle, &aResponse);
|
||||
|
||||
DispatchFileHandleSuccessEvent(&helper);
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFileRequestChild::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
MOZ_ASSERT(!mActorDestroyed);
|
||||
|
||||
mActorDestroyed = true;
|
||||
|
||||
if (mFileHandle) {
|
||||
mFileHandle->AssertIsOnOwningThread();
|
||||
|
||||
mFileHandle->OnRequestFinished(/* aActorDestroyedNormally */
|
||||
aWhy == Deletion);
|
||||
|
||||
#ifdef DEBUG
|
||||
mFileHandle = nullptr;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BackgroundFileRequestChild::Recv__delete__(const FileRequestResponse& aResponse)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mFileRequest);
|
||||
MOZ_ASSERT(mFileHandle);
|
||||
|
||||
if (mFileHandle->IsAborted()) {
|
||||
// Always handle an "error" with ABORT_ERR if the file handle was aborted,
|
||||
// even if the request succeeded or failed with another error.
|
||||
HandleResponse(NS_ERROR_DOM_FILEHANDLE_ABORT_ERR);
|
||||
} else {
|
||||
switch (aResponse.type()) {
|
||||
case FileRequestResponse::Tnsresult:
|
||||
HandleResponse(aResponse.get_nsresult());
|
||||
break;
|
||||
|
||||
case FileRequestResponse::TFileRequestGetFileResponse:
|
||||
HandleResponse(aResponse.get_FileRequestGetFileResponse());
|
||||
break;
|
||||
|
||||
case FileRequestResponse::TFileRequestReadResponse:
|
||||
HandleResponse(aResponse.get_FileRequestReadResponse().data());
|
||||
break;
|
||||
|
||||
case FileRequestResponse::TFileRequestWriteResponse:
|
||||
HandleResponse(JS::UndefinedHandleValue);
|
||||
break;
|
||||
|
||||
case FileRequestResponse::TFileRequestTruncateResponse:
|
||||
HandleResponse(JS::UndefinedHandleValue);
|
||||
break;
|
||||
|
||||
case FileRequestResponse::TFileRequestFlushResponse:
|
||||
HandleResponse(JS::UndefinedHandleValue);
|
||||
break;
|
||||
|
||||
case FileRequestResponse::TFileRequestGetMetadataResponse:
|
||||
HandleResponse(aResponse.get_FileRequestGetMetadataResponse()
|
||||
.metadata());
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Unknown response type!");
|
||||
}
|
||||
}
|
||||
|
||||
mFileHandle->OnRequestFinished(/* aActorDestroyedNormally */ true);
|
||||
|
||||
// Null this out so that we don't try to call OnRequestFinished() again in
|
||||
// ActorDestroy.
|
||||
mFileHandle = nullptr;
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BackgroundFileRequestChild::RecvProgress(const uint64_t& aProgress,
|
||||
const uint64_t& aProgressMax)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mFileRequest);
|
||||
|
||||
mFileRequest->FireProgressEvent(aProgress, aProgressMax);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* BackgroundUtilsChild
|
||||
******************************************************************************/
|
||||
|
||||
BackgroundUtilsChild::BackgroundUtilsChild(IndexedDatabaseManager* aManager)
|
||||
: mManager(aManager)
|
||||
#ifdef DEBUG
|
||||
, mOwningThread(NS_GetCurrentThread())
|
||||
#endif
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aManager);
|
||||
|
@ -3706,20 +4357,6 @@ BackgroundUtilsChild::~BackgroundUtilsChild()
|
|||
MOZ_COUNT_DTOR(indexedDB::BackgroundUtilsChild);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
BackgroundUtilsChild::AssertIsOnOwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread);
|
||||
|
||||
bool current;
|
||||
MOZ_ASSERT(NS_SUCCEEDED(mOwningThread->IsOnCurrentThread(¤t)));
|
||||
MOZ_ASSERT(current);
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
BackgroundUtilsChild::SendDeleteMeInternal()
|
||||
{
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "IDBTransaction.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/filehandle/ActorsChild.h"
|
||||
#include "mozilla/dom/indexedDB/PBackgroundIDBCursorChild.h"
|
||||
#include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseChild.h"
|
||||
#include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseRequestChild.h"
|
||||
|
@ -21,13 +20,15 @@
|
|||
#include "mozilla/dom/indexedDB/PBackgroundIDBTransactionChild.h"
|
||||
#include "mozilla/dom/indexedDB/PBackgroundIDBVersionChangeTransactionChild.h"
|
||||
#include "mozilla/dom/indexedDB/PBackgroundIndexedDBUtilsChild.h"
|
||||
#include "mozilla/dom/PBackgroundFileHandleChild.h"
|
||||
#include "mozilla/dom/PBackgroundFileRequestChild.h"
|
||||
#include "mozilla/dom/PBackgroundMutableFileChild.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsIEventTarget;
|
||||
struct nsID;
|
||||
struct PRThread;
|
||||
|
||||
namespace JS {
|
||||
struct WasmModule;
|
||||
|
@ -45,6 +46,8 @@ namespace dom {
|
|||
class IDBCursor;
|
||||
class IDBDatabase;
|
||||
class IDBFactory;
|
||||
class IDBFileHandle;
|
||||
class IDBFileRequest;
|
||||
class IDBMutableFile;
|
||||
class IDBOpenDBRequest;
|
||||
class IDBRequest;
|
||||
|
@ -66,18 +69,14 @@ class ThreadLocal
|
|||
IDBTransaction* mCurrentTransaction;
|
||||
nsCString mLoggingIdString;
|
||||
|
||||
#ifdef DEBUG
|
||||
PRThread* mOwningThread;
|
||||
#endif
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
public:
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
#ifdef DEBUG
|
||||
;
|
||||
#else
|
||||
{ }
|
||||
#endif
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(ThreadLocal);
|
||||
}
|
||||
|
||||
const LoggingInfo&
|
||||
GetLoggingInfo() const
|
||||
|
@ -159,22 +158,14 @@ class BackgroundFactoryChild final
|
|||
|
||||
IDBFactory* mFactory;
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsIEventTarget> mOwningThread;
|
||||
#endif
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
public:
|
||||
#ifdef DEBUG
|
||||
void
|
||||
AssertIsOnOwningThread() const;
|
||||
|
||||
nsIEventTarget*
|
||||
OwningThread() const;
|
||||
#else
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
{ }
|
||||
#endif
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(BackgroundFactoryChild);
|
||||
}
|
||||
|
||||
IDBFactory*
|
||||
GetDOMObject() const
|
||||
|
@ -317,16 +308,10 @@ class BackgroundDatabaseChild final
|
|||
public:
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
{
|
||||
static_cast<BackgroundFactoryChild*>(Manager())->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsIEventTarget*
|
||||
OwningThread() const
|
||||
{
|
||||
return static_cast<BackgroundFactoryChild*>(Manager())->OwningThread();
|
||||
}
|
||||
;
|
||||
#else
|
||||
{ }
|
||||
#endif
|
||||
|
||||
const DatabaseSpec*
|
||||
|
@ -621,25 +606,62 @@ private:
|
|||
};
|
||||
|
||||
class BackgroundMutableFileChild final
|
||||
: public mozilla::dom::BackgroundMutableFileChildBase
|
||||
: public PBackgroundMutableFileChild
|
||||
{
|
||||
friend class BackgroundDatabaseChild;
|
||||
friend IDBMutableFile;
|
||||
|
||||
RefPtr<IDBMutableFile> mTemporaryStrongMutableFile;
|
||||
IDBMutableFile* mMutableFile;
|
||||
nsString mName;
|
||||
nsString mType;
|
||||
|
||||
public:
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
#ifdef DEBUG
|
||||
;
|
||||
#else
|
||||
{ }
|
||||
#endif
|
||||
|
||||
void
|
||||
EnsureDOMObject();
|
||||
|
||||
IDBMutableFile*
|
||||
GetDOMObject() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return mMutableFile;
|
||||
}
|
||||
|
||||
void
|
||||
ReleaseDOMObject();
|
||||
|
||||
private:
|
||||
// Only constructed by BackgroundDatabaseChild.
|
||||
BackgroundMutableFileChild(DEBUGONLY(PRThread* aOwningThread,)
|
||||
const nsAString& aName,
|
||||
BackgroundMutableFileChild(const nsAString& aName,
|
||||
const nsAString& aType);
|
||||
|
||||
// Only destroyed by BackgroundDatabaseChild.
|
||||
~BackgroundMutableFileChild();
|
||||
|
||||
// BackgroundMutableFileChildBase
|
||||
virtual already_AddRefed<MutableFileBase>
|
||||
CreateMutableFile() override;
|
||||
void
|
||||
SendDeleteMeInternal();
|
||||
|
||||
// IPDL methods are only called by IPDL.
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
virtual PBackgroundFileHandleChild*
|
||||
AllocPBackgroundFileHandleChild(const FileMode& aMode) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPBackgroundFileHandleChild(PBackgroundFileHandleChild* aActor)
|
||||
override;
|
||||
|
||||
bool
|
||||
SendDeleteMe() = delete;
|
||||
};
|
||||
|
||||
class BackgroundRequestChild final
|
||||
|
@ -740,9 +762,7 @@ class BackgroundCursorChild final
|
|||
|
||||
Direction mDirection;
|
||||
|
||||
#ifdef DEBUG
|
||||
PRThread* mOwningThread;
|
||||
#endif
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
public:
|
||||
BackgroundCursorChild(IDBRequest* aRequest,
|
||||
|
@ -755,11 +775,9 @@ public:
|
|||
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
#ifdef DEBUG
|
||||
;
|
||||
#else
|
||||
{ }
|
||||
#endif
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(BackgroundCursorChild);
|
||||
}
|
||||
|
||||
void
|
||||
SendContinueInternal(const CursorRequestParams& aParams);
|
||||
|
@ -837,17 +855,20 @@ private:
|
|||
SendDeleteMe() = delete;
|
||||
};
|
||||
|
||||
class BackgroundUtilsChild final
|
||||
: public PBackgroundIndexedDBUtilsChild
|
||||
class BackgroundFileHandleChild
|
||||
: public PBackgroundFileHandleChild
|
||||
{
|
||||
friend class mozilla::ipc::BackgroundChildImpl;
|
||||
friend IndexedDatabaseManager;
|
||||
friend class BackgroundMutableFileChild;
|
||||
friend IDBMutableFile;
|
||||
|
||||
IndexedDatabaseManager* mManager;
|
||||
// mTemporaryStrongFileHandle is strong and is only valid until the end of
|
||||
// NoteComplete() member function or until the NoteActorDestroyed() member
|
||||
// function is called.
|
||||
RefPtr<IDBFileHandle> mTemporaryStrongFileHandle;
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsIEventTarget> mOwningThread;
|
||||
#endif
|
||||
// mFileHandle is weak and is valid until the NoteActorDestroyed() member
|
||||
// function is called.
|
||||
IDBFileHandle* mFileHandle;
|
||||
|
||||
public:
|
||||
void
|
||||
|
@ -858,6 +879,110 @@ public:
|
|||
{ }
|
||||
#endif
|
||||
|
||||
void
|
||||
SendDeleteMeInternal();
|
||||
|
||||
private:
|
||||
// Only created by IDBMutableFile.
|
||||
explicit BackgroundFileHandleChild(IDBFileHandle* aFileHandle);
|
||||
|
||||
~BackgroundFileHandleChild();
|
||||
|
||||
void
|
||||
NoteActorDestroyed();
|
||||
|
||||
void
|
||||
NoteComplete();
|
||||
|
||||
// IPDL methods are only called by IPDL.
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvComplete(const bool& aAborted) override;
|
||||
|
||||
virtual PBackgroundFileRequestChild*
|
||||
AllocPBackgroundFileRequestChild(const FileRequestParams& aParams)
|
||||
override;
|
||||
|
||||
virtual bool
|
||||
DeallocPBackgroundFileRequestChild(PBackgroundFileRequestChild* aActor)
|
||||
override;
|
||||
|
||||
bool
|
||||
SendDeleteMe() = delete;
|
||||
};
|
||||
|
||||
class BackgroundFileRequestChild final
|
||||
: public PBackgroundFileRequestChild
|
||||
{
|
||||
friend class BackgroundFileHandleChild;
|
||||
friend IDBFileHandle;
|
||||
|
||||
RefPtr<IDBFileRequest> mFileRequest;
|
||||
RefPtr<IDBFileHandle> mFileHandle;
|
||||
bool mActorDestroyed;
|
||||
|
||||
public:
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
#ifdef DEBUG
|
||||
;
|
||||
#else
|
||||
{ }
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Only created by IDBFileHandle.
|
||||
explicit BackgroundFileRequestChild(IDBFileRequest* aFileRequest);
|
||||
|
||||
// Only destroyed by BackgroundFileHandleChild.
|
||||
~BackgroundFileRequestChild();
|
||||
|
||||
void
|
||||
HandleResponse(nsresult aResponse);
|
||||
|
||||
void
|
||||
HandleResponse(const FileRequestGetFileResponse& aResponse);
|
||||
|
||||
void
|
||||
HandleResponse(const nsCString& aResponse);
|
||||
|
||||
void
|
||||
HandleResponse(const FileRequestMetadata& aResponse);
|
||||
|
||||
void
|
||||
HandleResponse(JS::Handle<JS::Value> aResponse);
|
||||
|
||||
// IPDL methods are only called by IPDL.
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
Recv__delete__(const FileRequestResponse& aResponse) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvProgress(const uint64_t& aProgress,
|
||||
const uint64_t& aProgressMax) override;
|
||||
};
|
||||
|
||||
class BackgroundUtilsChild final
|
||||
: public PBackgroundIndexedDBUtilsChild
|
||||
{
|
||||
friend class mozilla::ipc::BackgroundChildImpl;
|
||||
friend IndexedDatabaseManager;
|
||||
|
||||
IndexedDatabaseManager* mManager;
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
public:
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(BackgroundUtilsChild);
|
||||
}
|
||||
|
||||
private:
|
||||
// Only created by IndexedDatabaseManager.
|
||||
explicit BackgroundUtilsChild(IndexedDatabaseManager* aManager);
|
||||
|
|
|
@ -5129,15 +5129,15 @@ private:
|
|||
|
||||
#ifdef DEBUG
|
||||
uint32_t mDEBUGSavepointCount;
|
||||
PRThread* mDEBUGThread;
|
||||
#endif
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
public:
|
||||
void
|
||||
AssertIsOnConnectionThread() const
|
||||
{
|
||||
MOZ_ASSERT(mDEBUGThread);
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mDEBUGThread);
|
||||
NS_ASSERT_OWNINGTHREAD(DatabaseConnection);
|
||||
}
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DatabaseConnection)
|
||||
|
@ -5470,20 +5470,14 @@ private:
|
|||
bool mShutdownRequested;
|
||||
bool mShutdownComplete;
|
||||
|
||||
#ifdef DEBUG
|
||||
PRThread* mDEBUGOwningThread;
|
||||
#endif
|
||||
|
||||
public:
|
||||
ConnectionPool();
|
||||
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
#ifdef DEBUG
|
||||
;
|
||||
#else
|
||||
{ }
|
||||
#endif
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(ConnectionPool);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetOrCreateConnection(const Database* aDatabase,
|
||||
|
@ -5663,7 +5657,7 @@ struct ConnectionPool::DatabaseInfo final
|
|||
AssertIsOnConnectionThread() const
|
||||
{
|
||||
MOZ_ASSERT(mDEBUGConnectionThread);
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mDEBUGConnectionThread);
|
||||
MOZ_ASSERT(GetCurrentPhysicalThread() == mDEBUGConnectionThread);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
|
@ -10646,7 +10640,6 @@ DatabaseConnection::DatabaseConnection(
|
|||
, mInWriteTransaction(false)
|
||||
#ifdef DEBUG
|
||||
, mDEBUGSavepointCount(0)
|
||||
, mDEBUGThread(PR_GetCurrentThread())
|
||||
#endif
|
||||
{
|
||||
AssertIsOnConnectionThread();
|
||||
|
@ -12126,9 +12119,6 @@ ConnectionPool::ConnectionPool()
|
|||
, mTotalThreadCount(0)
|
||||
, mShutdownRequested(false)
|
||||
, mShutdownComplete(false)
|
||||
#ifdef DEBUG
|
||||
, mDEBUGOwningThread(PR_GetCurrentThread())
|
||||
#endif
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
@ -12151,17 +12141,6 @@ ConnectionPool::~ConnectionPool()
|
|||
MOZ_ASSERT(mShutdownComplete);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
ConnectionPool::AssertIsOnOwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mDEBUGOwningThread);
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mDEBUGOwningThread);
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
// static
|
||||
void
|
||||
ConnectionPool::IdleTimerCallback(nsITimer* aTimer, void* aClosure)
|
||||
|
@ -12278,7 +12257,7 @@ ConnectionPool::GetOrCreateConnection(const Database* aDatabase,
|
|||
NS_ConvertUTF16toUTF8(aDatabase->FilePath()).get()));
|
||||
|
||||
#ifdef DEBUG
|
||||
dbInfo->mDEBUGConnectionThread = PR_GetCurrentThread();
|
||||
dbInfo->mDEBUGConnectionThread = GetCurrentPhysicalThread();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -22487,8 +22466,8 @@ OpenDatabaseOp::NoteDatabaseClosed(Database* aDatabase)
|
|||
rv = NS_OK;
|
||||
}
|
||||
|
||||
// We are being called with an assuption that mWaitingFactoryOp holds a strong
|
||||
// reference to us.
|
||||
// We are being called with an assumption that mWaitingFactoryOp holds
|
||||
// a strong reference to us.
|
||||
RefPtr<OpenDatabaseOp> kungFuDeathGrip;
|
||||
|
||||
if (mMaybeBlockedDatabases.RemoveElement(aDatabase) &&
|
||||
|
@ -23314,8 +23293,8 @@ DeleteDatabaseOp::NoteDatabaseClosed(Database* aDatabase)
|
|||
rv = NS_OK;
|
||||
}
|
||||
|
||||
// We are being called with an assuption that mWaitingFactoryOp holds a strong
|
||||
// reference to us.
|
||||
// We are being called with an assumption that mWaitingFactoryOp holds
|
||||
// a strong reference to us.
|
||||
RefPtr<OpenDatabaseOp> kungFuDeathGrip;
|
||||
|
||||
if (mMaybeBlockedDatabases.RemoveElement(aDatabase) &&
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
#include "FileSnapshot.h"
|
||||
|
||||
#include "IDBDatabase.h"
|
||||
#include "IDBFileHandle.h"
|
||||
#include "IDBMutableFile.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsICloneableInputStream.h"
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
using namespace mozilla::dom::indexedDB;
|
||||
using namespace mozilla::dom::quota;
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::services;
|
||||
|
@ -250,13 +251,6 @@ IDBDatabase::AssertIsOnOwningThread() const
|
|||
mFactory->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
PRThread*
|
||||
IDBDatabase::OwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mFactory);
|
||||
return mFactory->OwningThread();
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
nsIEventTarget*
|
||||
|
|
|
@ -94,15 +94,11 @@ public:
|
|||
indexedDB::BackgroundDatabaseChild* aActor,
|
||||
DatabaseSpec* aSpec);
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
AssertIsOnOwningThread() const;
|
||||
|
||||
PRThread*
|
||||
OwningThread() const;
|
||||
#else
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
#ifdef DEBUG
|
||||
;
|
||||
#else
|
||||
{ }
|
||||
#endif
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
using namespace mozilla::dom::indexedDB;
|
||||
using namespace mozilla::dom::quota;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
|
@ -100,9 +101,6 @@ IDBFactory::IDBFactory()
|
|||
, mBackgroundActorFailed(false)
|
||||
, mPrivateBrowsingMode(false)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
mOwningThread = PR_GetCurrentThread();
|
||||
#endif
|
||||
AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
|
@ -419,24 +417,6 @@ IDBFactory::AllowedForPrincipal(nsIPrincipal* aPrincipal,
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
IDBFactory::AssertIsOnOwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread);
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
|
||||
}
|
||||
|
||||
PRThread*
|
||||
IDBFactory::OwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread);
|
||||
return mOwningThread;
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
bool
|
||||
IDBFactory::IsChrome() const
|
||||
{
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
class nsIEventTarget;
|
||||
class nsIPrincipal;
|
||||
class nsPIDOMWindowInner;
|
||||
struct PRThread;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -79,10 +78,6 @@ class IDBFactory final
|
|||
// NS_GetCurrentThread() off main thread.
|
||||
nsCOMPtr<nsIEventTarget> mEventTarget;
|
||||
|
||||
#ifdef DEBUG
|
||||
PRThread* mOwningThread;
|
||||
#endif
|
||||
|
||||
uint64_t mInnerWindowID;
|
||||
|
||||
bool mBackgroundActorFailed;
|
||||
|
@ -112,17 +107,11 @@ public:
|
|||
AllowedForPrincipal(nsIPrincipal* aPrincipal,
|
||||
bool* aIsSystemPrincipal = nullptr);
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
AssertIsOnOwningThread() const;
|
||||
|
||||
PRThread*
|
||||
OwningThread() const;
|
||||
#else
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
{ }
|
||||
#endif
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(IDBFactory);
|
||||
}
|
||||
|
||||
nsIEventTarget*
|
||||
EventTarget() const
|
||||
|
|
|
@ -6,12 +6,19 @@
|
|||
|
||||
#include "IDBFileHandle.h"
|
||||
|
||||
#include "ActorsChild.h"
|
||||
#include "BackgroundChildImpl.h"
|
||||
#include "IDBEvents.h"
|
||||
#include "IDBMutableFile.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/IDBFileHandleBinding.h"
|
||||
#include "mozilla/dom/filehandle/ActorsChild.h"
|
||||
#include "mozilla/dom/IPCBlobUtils.h"
|
||||
#include "mozilla/dom/PBackgroundFileHandle.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsQueryObject.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsWidgetsCID.h"
|
||||
|
||||
|
@ -19,21 +26,59 @@ namespace mozilla {
|
|||
namespace dom {
|
||||
|
||||
using namespace mozilla::dom::indexedDB;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
IDBFileHandle::IDBFileHandle(FileMode aMode,
|
||||
IDBMutableFile* aMutableFile)
|
||||
: FileHandleBase(DEBUGONLY(aMutableFile->OwningThread(),)
|
||||
aMode)
|
||||
, mMutableFile(aMutableFile)
|
||||
namespace {
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
GenerateFileRequest(IDBFileHandle* aFileHandle)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aFileHandle);
|
||||
aFileHandle->AssertIsOnOwningThread();
|
||||
|
||||
RefPtr<IDBFileRequest> fileRequest =
|
||||
IDBFileRequest::Create(aFileHandle, /* aWrapAsDOMRequest */ false);
|
||||
MOZ_ASSERT(fileRequest);
|
||||
|
||||
return fileRequest.forget();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
IDBFileHandle::IDBFileHandle(IDBMutableFile* aMutableFile,
|
||||
FileMode aMode)
|
||||
: mMutableFile(aMutableFile)
|
||||
, mBackgroundActor(nullptr)
|
||||
, mLocation(0)
|
||||
, mPendingRequestCount(0)
|
||||
, mReadyState(INITIAL)
|
||||
, mMode(aMode)
|
||||
, mAborted(false)
|
||||
, mCreating(false)
|
||||
#ifdef DEBUG
|
||||
, mSentFinishOrAbort(false)
|
||||
, mFiredCompleteOrAbort(false)
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(aMutableFile);
|
||||
aMutableFile->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
IDBFileHandle::~IDBFileHandle()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(!mPendingRequestCount);
|
||||
MOZ_ASSERT(!mCreating);
|
||||
MOZ_ASSERT(mSentFinishOrAbort);
|
||||
MOZ_ASSERT_IF(mBackgroundActor, mFiredCompleteOrAbort);
|
||||
|
||||
mMutableFile->UnregisterFileHandle(this);
|
||||
|
||||
if (mBackgroundActor) {
|
||||
mBackgroundActor->SendDeleteMeInternal();
|
||||
|
||||
MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -46,7 +91,7 @@ IDBFileHandle::Create(IDBMutableFile* aMutableFile,
|
|||
MOZ_ASSERT(aMode == FileMode::Readonly || aMode == FileMode::Readwrite);
|
||||
|
||||
RefPtr<IDBFileHandle> fileHandle =
|
||||
new IDBFileHandle(aMode, aMutableFile);
|
||||
new IDBFileHandle(aMutableFile, aMode);
|
||||
|
||||
fileHandle->BindToOwner(aMutableFile);
|
||||
|
||||
|
@ -56,13 +101,187 @@ IDBFileHandle::Create(IDBMutableFile* aMutableFile,
|
|||
nsCOMPtr<nsIRunnable> runnable = do_QueryObject(fileHandle);
|
||||
nsContentUtils::RunInMetastableState(runnable.forget());
|
||||
|
||||
fileHandle->SetCreating();
|
||||
fileHandle->mCreating = true;
|
||||
|
||||
aMutableFile->RegisterFileHandle(fileHandle);
|
||||
|
||||
return fileHandle.forget();
|
||||
}
|
||||
|
||||
// static
|
||||
IDBFileHandle*
|
||||
IDBFileHandle::GetCurrent()
|
||||
{
|
||||
MOZ_ASSERT(BackgroundChild::GetForCurrentThread());
|
||||
|
||||
BackgroundChildImpl::ThreadLocal* threadLocal =
|
||||
BackgroundChildImpl::GetThreadLocalForCurrentThread();
|
||||
MOZ_ASSERT(threadLocal);
|
||||
|
||||
return threadLocal->mCurrentFileHandle;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
IDBFileHandle::AssertIsOnOwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mMutableFile);
|
||||
mMutableFile->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
IDBFileHandle::SetBackgroundActor(BackgroundFileHandleChild* aActor)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
MOZ_ASSERT(!mBackgroundActor);
|
||||
|
||||
mBackgroundActor = aActor;
|
||||
}
|
||||
|
||||
void
|
||||
IDBFileHandle::StartRequest(IDBFileRequest* aFileRequest,
|
||||
const FileRequestParams& aParams)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aFileRequest);
|
||||
MOZ_ASSERT(aParams.type() != FileRequestParams::T__None);
|
||||
|
||||
BackgroundFileRequestChild* actor =
|
||||
new BackgroundFileRequestChild(aFileRequest);
|
||||
|
||||
mBackgroundActor->SendPBackgroundFileRequestConstructor(actor, aParams);
|
||||
|
||||
// Balanced in BackgroundFileRequestChild::Recv__delete__().
|
||||
OnNewRequest();
|
||||
}
|
||||
|
||||
void
|
||||
IDBFileHandle::OnNewRequest()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (!mPendingRequestCount) {
|
||||
MOZ_ASSERT(mReadyState == INITIAL);
|
||||
mReadyState = LOADING;
|
||||
}
|
||||
|
||||
++mPendingRequestCount;
|
||||
}
|
||||
|
||||
void
|
||||
IDBFileHandle::OnRequestFinished(bool aActorDestroyedNormally)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mPendingRequestCount);
|
||||
|
||||
--mPendingRequestCount;
|
||||
|
||||
if (!mPendingRequestCount && !mMutableFile->IsInvalidated()) {
|
||||
mReadyState = FINISHING;
|
||||
|
||||
if (aActorDestroyedNormally) {
|
||||
if (!mAborted) {
|
||||
SendFinish();
|
||||
} else {
|
||||
SendAbort();
|
||||
}
|
||||
} else {
|
||||
// Don't try to send any more messages to the parent if the request actor
|
||||
// was killed.
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(!mSentFinishOrAbort);
|
||||
mSentFinishOrAbort = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IDBFileHandle::FireCompleteOrAbortEvents(bool aAborted)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(!mFiredCompleteOrAbort);
|
||||
|
||||
mReadyState = DONE;
|
||||
|
||||
#ifdef DEBUG
|
||||
mFiredCompleteOrAbort = true;
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
if (aAborted) {
|
||||
event = CreateGenericEvent(this, nsDependentString(kAbortEventType),
|
||||
eDoesBubble, eNotCancelable);
|
||||
} else {
|
||||
event = CreateGenericEvent(this, nsDependentString(kCompleteEventType),
|
||||
eDoesNotBubble, eNotCancelable);
|
||||
}
|
||||
if (NS_WARN_IF(!event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool dummy;
|
||||
if (NS_FAILED(DispatchEvent(event, &dummy))) {
|
||||
NS_WARNING("DispatchEvent failed!");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
IDBFileHandle::IsOpen() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// If we haven't started anything then we're open.
|
||||
if (mReadyState == INITIAL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we've already started then we need to check to see if we still have the
|
||||
// mCreating flag set. If we do (i.e. we haven't returned to the event loop
|
||||
// from the time we were created) then we are open. Otherwise check the
|
||||
// currently running file handles to see if it's the same. We only allow other
|
||||
// requests to be made if this file handle is currently running.
|
||||
if (mReadyState == LOADING && (mCreating || GetCurrent() == this)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
IDBFileHandle::Abort()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (IsFinishingOrDone()) {
|
||||
// Already started (and maybe finished) the finish or abort so there is
|
||||
// nothing to do here.
|
||||
return;
|
||||
}
|
||||
|
||||
const bool isInvalidated = mMutableFile->IsInvalidated();
|
||||
bool needToSendAbort = mReadyState == INITIAL && !isInvalidated;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (isInvalidated) {
|
||||
mSentFinishOrAbort = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
mAborted = true;
|
||||
mReadyState = DONE;
|
||||
|
||||
// Fire the abort event if there are no outstanding requests. Otherwise the
|
||||
// abort event will be fired when all outstanding requests finish.
|
||||
if (needToSendAbort) {
|
||||
SendAbort();
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
IDBFileHandle::GetMetadata(const IDBFileMetadataParameters& aParameters,
|
||||
ErrorResult& aRv)
|
||||
|
@ -89,11 +308,438 @@ IDBFileHandle::GetMetadata(const IDBFileMetadataParameters& aParameters,
|
|||
params.size() = aParameters.mSize;
|
||||
params.lastModified() = aParameters.mLastModified;
|
||||
|
||||
RefPtr<FileRequestBase> fileRequest = GenerateFileRequest();
|
||||
RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
|
||||
|
||||
StartRequest(fileRequest, params);
|
||||
|
||||
return fileRequest.forget().downcast<IDBFileRequest>();
|
||||
return fileRequest.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
IDBFileHandle::Truncate(const Optional<uint64_t>& aSize, ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// State checking for write
|
||||
if (!CheckStateForWrite(aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Getting location and additional state checking for truncate
|
||||
uint64_t location;
|
||||
if (aSize.WasPassed()) {
|
||||
// Just in case someone calls us from C++
|
||||
MOZ_ASSERT(aSize.Value() != UINT64_MAX, "Passed wrong size!");
|
||||
location = aSize.Value();
|
||||
} else {
|
||||
if (mLocation == UINT64_MAX) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
location = mLocation;
|
||||
}
|
||||
|
||||
// Do nothing if the window is closed
|
||||
if (!CheckWindow()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileRequestTruncateParams params;
|
||||
params.offset() = location;
|
||||
|
||||
RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
|
||||
|
||||
StartRequest(fileRequest, params);
|
||||
|
||||
if (aSize.WasPassed()) {
|
||||
mLocation = aSize.Value();
|
||||
}
|
||||
|
||||
return fileRequest.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
IDBFileHandle::Flush(ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// State checking for write
|
||||
if (!CheckStateForWrite(aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Do nothing if the window is closed
|
||||
if (!CheckWindow()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileRequestFlushParams params;
|
||||
|
||||
RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
|
||||
|
||||
StartRequest(fileRequest, params);
|
||||
|
||||
return fileRequest.forget();
|
||||
}
|
||||
|
||||
void
|
||||
IDBFileHandle::Abort(ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// This method is special enough for not using generic state checking methods.
|
||||
|
||||
if (IsFinishingOrDone()) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
Abort();
|
||||
}
|
||||
|
||||
bool
|
||||
IDBFileHandle::CheckState(ErrorResult& aRv)
|
||||
{
|
||||
if (!IsOpen()) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_INACTIVE_ERR);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IDBFileHandle::CheckStateAndArgumentsForRead(uint64_t aSize, ErrorResult& aRv)
|
||||
{
|
||||
// Common state checking
|
||||
if (!CheckState(aRv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Additional state checking for read
|
||||
if (mLocation == UINT64_MAX) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Argument checking for read
|
||||
if (!aSize) {
|
||||
aRv.ThrowTypeError<MSG_INVALID_READ_SIZE>();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IDBFileHandle::CheckStateForWrite(ErrorResult& aRv)
|
||||
{
|
||||
// Common state checking
|
||||
if (!CheckState(aRv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Additional state checking for write
|
||||
if (mMode != FileMode::Readwrite) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_READ_ONLY_ERR);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IDBFileHandle::CheckStateForWriteOrAppend(bool aAppend, ErrorResult& aRv)
|
||||
{
|
||||
// State checking for write
|
||||
if (!CheckStateForWrite(aRv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Additional state checking for write
|
||||
if (!aAppend && mLocation == UINT64_MAX) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IDBFileHandle::CheckWindow()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return GetOwner();
|
||||
}
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
IDBFileHandle::Read(uint64_t aSize, bool aHasEncoding,
|
||||
const nsAString& aEncoding, ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// State and argument checking for read
|
||||
if (!CheckStateAndArgumentsForRead(aSize, aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Do nothing if the window is closed
|
||||
if (!CheckWindow()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileRequestReadParams params;
|
||||
params.offset() = mLocation;
|
||||
params.size() = aSize;
|
||||
|
||||
RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
|
||||
if (aHasEncoding) {
|
||||
fileRequest->SetEncoding(aEncoding);
|
||||
}
|
||||
|
||||
StartRequest(fileRequest, params);
|
||||
|
||||
mLocation += aSize;
|
||||
|
||||
return fileRequest.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
IDBFileHandle::WriteOrAppend(
|
||||
const StringOrArrayBufferOrArrayBufferViewOrBlob& aValue,
|
||||
bool aAppend,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (aValue.IsString()) {
|
||||
return WriteOrAppend(aValue.GetAsString(), aAppend, aRv);
|
||||
}
|
||||
|
||||
if (aValue.IsArrayBuffer()) {
|
||||
return WriteOrAppend(aValue.GetAsArrayBuffer(), aAppend, aRv);
|
||||
}
|
||||
|
||||
if (aValue.IsArrayBufferView()) {
|
||||
return WriteOrAppend(aValue.GetAsArrayBufferView(), aAppend, aRv);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aValue.IsBlob());
|
||||
return WriteOrAppend(aValue.GetAsBlob(), aAppend, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
IDBFileHandle::WriteOrAppend(const nsAString& aValue,
|
||||
bool aAppend,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// State checking for write or append
|
||||
if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_ConvertUTF16toUTF8 cstr(aValue);
|
||||
|
||||
uint64_t dataLength = cstr.Length();;
|
||||
if (!dataLength) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileRequestStringData stringData(cstr);
|
||||
|
||||
// Do nothing if the window is closed
|
||||
if (!CheckWindow()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return WriteInternal(stringData, dataLength, aAppend, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
IDBFileHandle::WriteOrAppend(const ArrayBuffer& aValue,
|
||||
bool aAppend,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// State checking for write or append
|
||||
if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aValue.ComputeLengthAndData();
|
||||
|
||||
uint64_t dataLength = aValue.Length();;
|
||||
if (!dataLength) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* data = reinterpret_cast<const char*>(aValue.Data());
|
||||
|
||||
FileRequestStringData stringData;
|
||||
if (NS_WARN_IF(!stringData.string().Assign(data, aValue.Length(),
|
||||
fallible_t()))) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Do nothing if the window is closed
|
||||
if (!CheckWindow()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return WriteInternal(stringData, dataLength, aAppend, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
IDBFileHandle::WriteOrAppend(const ArrayBufferView& aValue,
|
||||
bool aAppend,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// State checking for write or append
|
||||
if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aValue.ComputeLengthAndData();
|
||||
|
||||
uint64_t dataLength = aValue.Length();;
|
||||
if (!dataLength) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* data = reinterpret_cast<const char*>(aValue.Data());
|
||||
|
||||
FileRequestStringData stringData;
|
||||
if (NS_WARN_IF(!stringData.string().Assign(data, aValue.Length(),
|
||||
fallible_t()))) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Do nothing if the window is closed
|
||||
if (!CheckWindow()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return WriteInternal(stringData, dataLength, aAppend, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
IDBFileHandle::WriteOrAppend(Blob& aValue,
|
||||
bool aAppend,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// State checking for write or append
|
||||
if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
uint64_t dataLength = aValue.GetSize(error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!dataLength) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PBackgroundChild* backgroundActor = BackgroundChild::GetForCurrentThread();
|
||||
MOZ_ASSERT(backgroundActor);
|
||||
|
||||
IPCBlob ipcBlob;
|
||||
nsresult rv =
|
||||
IPCBlobUtils::Serialize(aValue.Impl(), backgroundActor, ipcBlob);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileRequestBlobData blobData;
|
||||
blobData.blob() = ipcBlob;
|
||||
|
||||
// Do nothing if the window is closed
|
||||
if (!CheckWindow()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return WriteInternal(blobData, dataLength, aAppend, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
IDBFileHandle::WriteInternal(const FileRequestData& aData,
|
||||
uint64_t aDataLength,
|
||||
bool aAppend,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
DebugOnly<ErrorResult> error;
|
||||
MOZ_ASSERT(CheckStateForWrite(error));
|
||||
MOZ_ASSERT_IF(!aAppend, mLocation != UINT64_MAX);
|
||||
MOZ_ASSERT(aDataLength);
|
||||
MOZ_ASSERT(CheckWindow());
|
||||
|
||||
FileRequestWriteParams params;
|
||||
params.offset() = aAppend ? UINT64_MAX : mLocation;
|
||||
params.data() = aData;
|
||||
params.dataLength() = aDataLength;
|
||||
|
||||
RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
|
||||
MOZ_ASSERT(fileRequest);
|
||||
|
||||
StartRequest(fileRequest, params);
|
||||
|
||||
if (aAppend) {
|
||||
mLocation = UINT64_MAX;
|
||||
}
|
||||
else {
|
||||
mLocation += aDataLength;
|
||||
}
|
||||
|
||||
return fileRequest.forget();
|
||||
}
|
||||
|
||||
void
|
||||
IDBFileHandle::SendFinish()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(!mAborted);
|
||||
MOZ_ASSERT(IsFinishingOrDone());
|
||||
MOZ_ASSERT(!mSentFinishOrAbort);
|
||||
MOZ_ASSERT(!mPendingRequestCount);
|
||||
|
||||
MOZ_ASSERT(mBackgroundActor);
|
||||
mBackgroundActor->SendFinish();
|
||||
|
||||
#ifdef DEBUG
|
||||
mSentFinishOrAbort = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
IDBFileHandle::SendAbort()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mAborted);
|
||||
MOZ_ASSERT(IsFinishingOrDone());
|
||||
MOZ_ASSERT(!mSentFinishOrAbort);
|
||||
|
||||
MOZ_ASSERT(mBackgroundActor);
|
||||
mBackgroundActor->SendAbort();
|
||||
|
||||
#ifdef DEBUG
|
||||
mSentFinishOrAbort = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(IDBFileHandle, DOMEventTargetHelper)
|
||||
|
@ -121,7 +767,15 @@ IDBFileHandle::Run()
|
|||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
OnReturnToEventLoop();
|
||||
// We're back at the event loop, no longer newborn.
|
||||
mCreating = false;
|
||||
|
||||
// Maybe finish if there were no requests generated.
|
||||
if (mReadyState == INITIAL) {
|
||||
mReadyState = DONE;
|
||||
|
||||
SendFinish();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -145,55 +799,5 @@ IDBFileHandle::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|||
return IDBFileHandleBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
mozilla::dom::MutableFileBase*
|
||||
IDBFileHandle::MutableFile() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return mMutableFile;
|
||||
}
|
||||
|
||||
void
|
||||
IDBFileHandle::HandleCompleteOrAbort(bool aAborted)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
FileHandleBase::HandleCompleteOrAbort(aAborted);
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
if (aAborted) {
|
||||
event = CreateGenericEvent(this, nsDependentString(kAbortEventType),
|
||||
eDoesBubble, eNotCancelable);
|
||||
} else {
|
||||
event = CreateGenericEvent(this, nsDependentString(kCompleteEventType),
|
||||
eDoesNotBubble, eNotCancelable);
|
||||
}
|
||||
if (NS_WARN_IF(!event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool dummy;
|
||||
if (NS_FAILED(DispatchEvent(event, &dummy))) {
|
||||
NS_WARNING("DispatchEvent failed!");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
IDBFileHandle::CheckWindow()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return GetOwner();
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::dom::FileRequestBase>
|
||||
IDBFileHandle::GenerateFileRequest()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return IDBFileRequest::Create(GetOwner(), this,
|
||||
/* aWrapAsDOMRequest */ false);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "IDBFileRequest.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/FileHandleBase.h"
|
||||
#include "mozilla/dom/FileModeBinding.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIRunnable.h"
|
||||
|
@ -21,23 +21,120 @@ class nsPIDOMWindowInner;
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class Blob;
|
||||
class FileRequestData;
|
||||
class FileRequestParams;
|
||||
struct IDBFileMetadataParameters;
|
||||
class IDBFileRequest;
|
||||
class IDBMutableFile;
|
||||
class StringOrArrayBufferOrArrayBufferViewOrBlob;
|
||||
|
||||
namespace indexedDB {
|
||||
class BackgroundFileHandleChild;
|
||||
}
|
||||
|
||||
class IDBFileHandle final
|
||||
: public DOMEventTargetHelper
|
||||
, public nsIRunnable
|
||||
, public FileHandleBase
|
||||
, public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
enum ReadyState
|
||||
{
|
||||
INITIAL = 0,
|
||||
LOADING,
|
||||
FINISHING,
|
||||
DONE
|
||||
};
|
||||
|
||||
private:
|
||||
RefPtr<IDBMutableFile> mMutableFile;
|
||||
|
||||
indexedDB::BackgroundFileHandleChild* mBackgroundActor;
|
||||
|
||||
uint64_t mLocation;
|
||||
|
||||
uint32_t mPendingRequestCount;
|
||||
|
||||
ReadyState mReadyState;
|
||||
FileMode mMode;
|
||||
|
||||
bool mAborted;
|
||||
bool mCreating;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool mSentFinishOrAbort;
|
||||
bool mFiredCompleteOrAbort;
|
||||
#endif
|
||||
|
||||
public:
|
||||
static already_AddRefed<IDBFileHandle>
|
||||
Create(IDBMutableFile* aMutableFile,
|
||||
FileMode aMode);
|
||||
|
||||
static IDBFileHandle*
|
||||
GetCurrent();
|
||||
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
#ifdef DEBUG
|
||||
;
|
||||
#else
|
||||
{ }
|
||||
#endif
|
||||
|
||||
void
|
||||
SetBackgroundActor(indexedDB::BackgroundFileHandleChild* aActor);
|
||||
|
||||
void
|
||||
ClearBackgroundActor()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
mBackgroundActor = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
StartRequest(IDBFileRequest* aFileRequest, const FileRequestParams& aParams);
|
||||
|
||||
void
|
||||
OnNewRequest();
|
||||
|
||||
void
|
||||
OnRequestFinished(bool aActorDestroyedNormally);
|
||||
|
||||
void
|
||||
FireCompleteOrAbortEvents(bool aAborted);
|
||||
|
||||
bool
|
||||
IsOpen() const;
|
||||
|
||||
bool
|
||||
IsFinishingOrDone() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return mReadyState == FINISHING || mReadyState == DONE;
|
||||
}
|
||||
|
||||
bool
|
||||
IsDone() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return mReadyState == DONE;
|
||||
}
|
||||
|
||||
bool
|
||||
IsAborted() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return mAborted;
|
||||
}
|
||||
|
||||
void
|
||||
Abort();
|
||||
|
||||
// WebIDL
|
||||
nsPIDOMWindowInner*
|
||||
GetParentObject() const
|
||||
|
@ -60,6 +157,45 @@ public:
|
|||
return GetMutableFile();
|
||||
}
|
||||
|
||||
FileMode
|
||||
Mode() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return mMode;
|
||||
}
|
||||
|
||||
bool
|
||||
Active() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return IsOpen();
|
||||
}
|
||||
|
||||
Nullable<uint64_t>
|
||||
GetLocation() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mLocation == UINT64_MAX) {
|
||||
return Nullable<uint64_t>();
|
||||
}
|
||||
|
||||
return Nullable<uint64_t>(mLocation);
|
||||
}
|
||||
|
||||
void
|
||||
SetLocation(const Nullable<uint64_t>& aLocation)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// Null means the end-of-file.
|
||||
if (aLocation.IsNull()) {
|
||||
mLocation = UINT64_MAX;
|
||||
} else {
|
||||
mLocation = aLocation.Value();
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
GetMetadata(const IDBFileMetadataParameters& aParameters, ErrorResult& aRv);
|
||||
|
||||
|
@ -67,14 +203,14 @@ public:
|
|||
ReadAsArrayBuffer(uint64_t aSize, ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return Read(aSize, false, NullString(), aRv).downcast<IDBFileRequest>();
|
||||
return Read(aSize, false, NullString(), aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
ReadAsText(uint64_t aSize, const nsAString& aEncoding, ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return Read(aSize, true, aEncoding, aRv).downcast<IDBFileRequest>();
|
||||
return Read(aSize, true, aEncoding, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
|
@ -82,7 +218,7 @@ public:
|
|||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return WriteOrAppend(aValue, false, aRv).downcast<IDBFileRequest>();
|
||||
return WriteOrAppend(aValue, false, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
|
@ -90,22 +226,17 @@ public:
|
|||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return WriteOrAppend(aValue, true, aRv).downcast<IDBFileRequest>();
|
||||
return WriteOrAppend(aValue, true, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
Truncate(const Optional<uint64_t>& aSize, ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return FileHandleBase::Truncate(aSize, aRv).downcast<IDBFileRequest>();
|
||||
}
|
||||
Truncate(const Optional<uint64_t>& aSize, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
Flush(ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return FileHandleBase::Flush(aRv).downcast<IDBFileRequest>();
|
||||
}
|
||||
Flush(ErrorResult& aRv);
|
||||
|
||||
void
|
||||
Abort(ErrorResult& aRv);
|
||||
|
||||
IMPL_EVENT_HANDLER(complete)
|
||||
IMPL_EVENT_HANDLER(abort)
|
||||
|
@ -123,24 +254,56 @@ public:
|
|||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// FileHandleBase
|
||||
virtual MutableFileBase*
|
||||
MutableFile() const override;
|
||||
|
||||
virtual void
|
||||
HandleCompleteOrAbort(bool aAborted) override;
|
||||
|
||||
private:
|
||||
IDBFileHandle(FileMode aMode,
|
||||
IDBMutableFile* aMutableFile);
|
||||
IDBFileHandle(IDBMutableFile* aMutableFile,
|
||||
FileMode aMode);
|
||||
~IDBFileHandle();
|
||||
|
||||
// FileHandleBase
|
||||
virtual bool
|
||||
CheckWindow() override;
|
||||
bool
|
||||
CheckState(ErrorResult& aRv);
|
||||
|
||||
virtual already_AddRefed<FileRequestBase>
|
||||
GenerateFileRequest() override;
|
||||
bool
|
||||
CheckStateAndArgumentsForRead(uint64_t aSize, ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
CheckStateForWrite(ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
CheckStateForWriteOrAppend(bool aAppend, ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
CheckWindow();
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
Read(uint64_t aSize, bool aHasEncoding, const nsAString& aEncoding,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
WriteOrAppend(const StringOrArrayBufferOrArrayBufferViewOrBlob& aValue,
|
||||
bool aAppend,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
WriteOrAppend(const nsAString& aValue, bool aAppend, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
WriteOrAppend(const ArrayBuffer& aValue, bool aAppend, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
WriteOrAppend(const ArrayBufferView& aValue, bool aAppend, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
WriteOrAppend(Blob& aValue, bool aAppend, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<IDBFileRequest>
|
||||
WriteInternal(const FileRequestData& aData, uint64_t aDataLength,
|
||||
bool aAppend, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
SendFinish();
|
||||
|
||||
void
|
||||
SendAbort();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -24,15 +24,15 @@ namespace dom {
|
|||
|
||||
using namespace mozilla::dom::indexedDB;
|
||||
|
||||
IDBFileRequest::IDBFileRequest(nsPIDOMWindowInner* aWindow,
|
||||
IDBFileHandle* aFileHandle,
|
||||
IDBFileRequest::IDBFileRequest(IDBFileHandle* aFileHandle,
|
||||
bool aWrapAsDOMRequest)
|
||||
: DOMRequest(aWindow)
|
||||
, FileRequestBase(DEBUGONLY(aFileHandle->OwningThread()))
|
||||
: DOMRequest(aFileHandle->GetOwner())
|
||||
, mFileHandle(aFileHandle)
|
||||
, mWrapAsDOMRequest(aWrapAsDOMRequest)
|
||||
, mHasEncoding(false)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aFileHandle);
|
||||
aFileHandle->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
IDBFileRequest::~IDBFileRequest()
|
||||
|
@ -42,18 +42,62 @@ IDBFileRequest::~IDBFileRequest()
|
|||
|
||||
// static
|
||||
already_AddRefed<IDBFileRequest>
|
||||
IDBFileRequest::Create(nsPIDOMWindowInner* aOwner, IDBFileHandle* aFileHandle,
|
||||
IDBFileRequest::Create(IDBFileHandle* aFileHandle,
|
||||
bool aWrapAsDOMRequest)
|
||||
{
|
||||
MOZ_ASSERT(aFileHandle);
|
||||
aFileHandle->AssertIsOnOwningThread();
|
||||
|
||||
RefPtr<IDBFileRequest> request =
|
||||
new IDBFileRequest(aOwner, aFileHandle, aWrapAsDOMRequest);
|
||||
new IDBFileRequest(aFileHandle, aWrapAsDOMRequest);
|
||||
|
||||
return request.forget();
|
||||
}
|
||||
|
||||
void
|
||||
IDBFileRequest::FireProgressEvent(uint64_t aLoaded, uint64_t aTotal)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (NS_FAILED(CheckInnerWindowCorrectness())) {
|
||||
return;
|
||||
}
|
||||
|
||||
ProgressEventInit init;
|
||||
init.mBubbles = false;
|
||||
init.mCancelable = false;
|
||||
init.mLengthComputable = false;
|
||||
init.mLoaded = aLoaded;
|
||||
init.mTotal = aTotal;
|
||||
|
||||
RefPtr<ProgressEvent> event =
|
||||
ProgressEvent::Constructor(this, NS_LITERAL_STRING("progress"), init);
|
||||
DispatchTrustedEvent(event);
|
||||
}
|
||||
|
||||
void
|
||||
IDBFileRequest::SetResultCallback(ResultCallback* aCallback)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aCallback);
|
||||
|
||||
AutoJSAPI autoJS;
|
||||
if (NS_WARN_IF(!autoJS.Init(GetOwner()))) {
|
||||
FireError(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext* cx = autoJS.cx();
|
||||
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
nsresult rv = aCallback->GetResult(cx, &result);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
FireError(rv);
|
||||
} else {
|
||||
FireSuccess(result);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(IDBFileRequest, DOMRequest)
|
||||
NS_IMPL_RELEASE_INHERITED(IDBFileRequest, DOMRequest)
|
||||
|
||||
|
@ -85,73 +129,5 @@ IDBFileRequest::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|||
return IDBFileRequestBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
mozilla::dom::FileHandleBase*
|
||||
IDBFileRequest::FileHandle() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return mFileHandle;
|
||||
}
|
||||
|
||||
void
|
||||
IDBFileRequest::OnProgress(uint64_t aProgress, uint64_t aProgressMax)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
FireProgressEvent(aProgress, aProgressMax);
|
||||
}
|
||||
|
||||
void
|
||||
IDBFileRequest::SetResultCallback(ResultCallback* aCallback)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aCallback);
|
||||
|
||||
AutoJSAPI autoJS;
|
||||
if (NS_WARN_IF(!autoJS.Init(GetOwner()))) {
|
||||
FireError(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext* cx = autoJS.cx();
|
||||
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
nsresult rv = aCallback->GetResult(cx, &result);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
FireError(rv);
|
||||
} else {
|
||||
FireSuccess(result);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IDBFileRequest::SetError(nsresult aError)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
FireError(aError);
|
||||
}
|
||||
|
||||
void
|
||||
IDBFileRequest::FireProgressEvent(uint64_t aLoaded, uint64_t aTotal)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (NS_FAILED(CheckInnerWindowCorrectness())) {
|
||||
return;
|
||||
}
|
||||
|
||||
ProgressEventInit init;
|
||||
init.mBubbles = false;
|
||||
init.mCancelable = false;
|
||||
init.mLengthComputable = false;
|
||||
init.mLoaded = aLoaded;
|
||||
init.mTotal = aTotal;
|
||||
|
||||
RefPtr<ProgressEvent> event =
|
||||
ProgressEvent::Constructor(this, NS_LITERAL_STRING("progress"), init);
|
||||
DispatchTrustedEvent(event);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -10,11 +10,10 @@
|
|||
#include "DOMRequest.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/FileRequestBase.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsString.h"
|
||||
|
||||
template <class> struct already_AddRefed;
|
||||
class nsPIDOMWindowInner;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -24,18 +23,48 @@ namespace dom {
|
|||
|
||||
class IDBFileHandle;
|
||||
|
||||
class IDBFileRequest final : public DOMRequest,
|
||||
public FileRequestBase
|
||||
class IDBFileRequest final
|
||||
: public DOMRequest
|
||||
{
|
||||
RefPtr<IDBFileHandle> mFileHandle;
|
||||
|
||||
nsString mEncoding;
|
||||
|
||||
bool mWrapAsDOMRequest;
|
||||
bool mHasEncoding;
|
||||
|
||||
public:
|
||||
class ResultCallback;
|
||||
|
||||
static already_AddRefed<IDBFileRequest>
|
||||
Create(nsPIDOMWindowInner* aOwner, IDBFileHandle* aFileHandle,
|
||||
Create(IDBFileHandle* aFileHandle,
|
||||
bool aWrapAsDOMRequest);
|
||||
|
||||
void
|
||||
SetEncoding(const nsAString& aEncoding)
|
||||
{
|
||||
mEncoding = aEncoding;
|
||||
mHasEncoding = true;
|
||||
}
|
||||
|
||||
const nsAString&
|
||||
GetEncoding() const
|
||||
{
|
||||
return mEncoding;
|
||||
}
|
||||
|
||||
bool
|
||||
HasEncoding() const
|
||||
{
|
||||
return mHasEncoding;
|
||||
}
|
||||
|
||||
void
|
||||
FireProgressEvent(uint64_t aLoaded, uint64_t aTotal);
|
||||
|
||||
void
|
||||
SetResultCallback(ResultCallback* aCallback);
|
||||
|
||||
// WebIDL
|
||||
IDBFileHandle*
|
||||
GetFileHandle() const
|
||||
|
@ -53,6 +82,12 @@ public:
|
|||
|
||||
IMPL_EVENT_HANDLER(progress)
|
||||
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(IDBFileRequest);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBFileRequest, DOMRequest)
|
||||
|
||||
|
@ -64,28 +99,22 @@ public:
|
|||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// FileRequestBase
|
||||
virtual FileHandleBase*
|
||||
FileHandle() const override;
|
||||
|
||||
virtual void
|
||||
OnProgress(uint64_t aProgress, uint64_t aProgressMax) override;
|
||||
|
||||
virtual void
|
||||
SetResultCallback(ResultCallback* aCallback) override;
|
||||
|
||||
virtual void
|
||||
SetError(nsresult aError) override;
|
||||
|
||||
private:
|
||||
IDBFileRequest(nsPIDOMWindowInner* aWindow,
|
||||
IDBFileHandle* aFileHandle,
|
||||
IDBFileRequest(IDBFileHandle* aFileHandle,
|
||||
bool aWrapAsDOMRequest);
|
||||
|
||||
~IDBFileRequest();
|
||||
};
|
||||
|
||||
void
|
||||
FireProgressEvent(uint64_t aLoaded, uint64_t aTotal);
|
||||
class NS_NO_VTABLE IDBFileRequest::ResultCallback
|
||||
{
|
||||
public:
|
||||
virtual nsresult
|
||||
GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult) = 0;
|
||||
|
||||
protected:
|
||||
ResultCallback()
|
||||
{ }
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
using namespace mozilla::dom::indexedDB;
|
||||
|
||||
namespace {
|
||||
|
||||
already_AddRefed<IDBRequest>
|
||||
|
|
|
@ -53,9 +53,6 @@ IDBKeyRange::IDBKeyRange(nsISupports* aGlobal,
|
|||
, mHaveCachedUpperVal(false)
|
||||
, mRooted(false)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
mOwningThread = PR_GetCurrentThread();
|
||||
#endif
|
||||
AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
|
@ -70,9 +67,6 @@ IDBLocaleAwareKeyRange::IDBLocaleAwareKeyRange(nsISupports* aGlobal,
|
|||
bool aIsOnly)
|
||||
: IDBKeyRange(aGlobal, aLowerOpen, aUpperOpen, aIsOnly)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
mOwningThread = PR_GetCurrentThread();
|
||||
#endif
|
||||
AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
|
@ -81,17 +75,6 @@ IDBLocaleAwareKeyRange::~IDBLocaleAwareKeyRange()
|
|||
DropJSObjects();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
IDBKeyRange::AssertIsOnOwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread);
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IDBKeyRange::FromJSVal(JSContext* aCx,
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "nsString.h"
|
||||
|
||||
class mozIStorageStatement;
|
||||
struct PRThread;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -49,10 +48,6 @@ protected:
|
|||
bool mHaveCachedUpperVal : 1;
|
||||
bool mRooted : 1;
|
||||
|
||||
#ifdef DEBUG
|
||||
PRThread* mOwningThread;
|
||||
#endif
|
||||
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IDBKeyRange)
|
||||
|
@ -93,11 +88,9 @@ public:
|
|||
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
#ifdef DEBUG
|
||||
;
|
||||
#else
|
||||
{ }
|
||||
#endif
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(IDBKeyRange);
|
||||
}
|
||||
|
||||
void
|
||||
ToSerialized(indexedDB::SerializedKeyRange& aKeyRange) const;
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include "ActorsChild.h"
|
||||
#include "FileInfo.h"
|
||||
#include "FileSnapshot.h"
|
||||
#include "IDBDatabase.h"
|
||||
#include "IDBFactory.h"
|
||||
#include "IDBFileHandle.h"
|
||||
|
@ -19,7 +18,6 @@
|
|||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/IDBMutableFileBinding.h"
|
||||
#include "mozilla/dom/filehandle/ActorsChild.h"
|
||||
#include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
|
||||
#include "mozilla/dom/quota/FileStreams.h"
|
||||
#include "mozilla/dom/quota/QuotaManager.h"
|
||||
|
@ -43,16 +41,15 @@ IDBMutableFile::IDBMutableFile(IDBDatabase* aDatabase,
|
|||
const nsAString& aName,
|
||||
const nsAString& aType)
|
||||
: DOMEventTargetHelper(aDatabase)
|
||||
, MutableFileBase(DEBUGONLY(aDatabase->OwningThread(),)
|
||||
aActor)
|
||||
, mDatabase(aDatabase)
|
||||
, mBackgroundActor(aActor)
|
||||
, mName(aName)
|
||||
, mType(aType)
|
||||
, mInvalidated(false)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aDatabase);
|
||||
aDatabase->AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
mDatabase->NoteLiveMutableFile(this);
|
||||
}
|
||||
|
@ -62,8 +59,24 @@ IDBMutableFile::~IDBMutableFile()
|
|||
AssertIsOnOwningThread();
|
||||
|
||||
mDatabase->NoteFinishedMutableFile(this);
|
||||
|
||||
if (mBackgroundActor) {
|
||||
mBackgroundActor->SendDeleteMeInternal();
|
||||
MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
IDBMutableFile::AssertIsOnOwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mDatabase);
|
||||
mDatabase->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
int64_t
|
||||
IDBMutableFile::GetFileId() const
|
||||
{
|
||||
|
@ -183,9 +196,7 @@ IDBMutableFile::Open(FileMode aMode, ErrorResult& aError)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
BackgroundFileHandleChild* actor =
|
||||
new BackgroundFileHandleChild(DEBUGONLY(mBackgroundActor->OwningThread(),)
|
||||
fileHandle);
|
||||
BackgroundFileHandleChild* actor = new BackgroundFileHandleChild(fileHandle);
|
||||
|
||||
MOZ_ALWAYS_TRUE(
|
||||
mBackgroundActor->SendPBackgroundFileHandleConstructor(actor, aMode));
|
||||
|
@ -206,9 +217,7 @@ IDBMutableFile::GetFile(ErrorResult& aError)
|
|||
FileRequestGetFileParams params;
|
||||
|
||||
RefPtr<IDBFileRequest> request =
|
||||
IDBFileRequest::Create(GetOwner(),
|
||||
fileHandle,
|
||||
/* aWrapAsDOMRequest */ true);
|
||||
IDBFileRequest::Create(fileHandle, /* aWrapAsDOMRequest */ true);
|
||||
|
||||
fileHandle->StartRequest(request, params);
|
||||
|
||||
|
@ -242,42 +251,5 @@ IDBMutableFile::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|||
return IDBMutableFileBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
const nsString&
|
||||
IDBMutableFile::Name() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return mName;
|
||||
}
|
||||
|
||||
const nsString&
|
||||
IDBMutableFile::Type() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return mType;
|
||||
}
|
||||
|
||||
bool
|
||||
IDBMutableFile::IsInvalidated()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return mInvalidated;
|
||||
}
|
||||
|
||||
already_AddRefed<File>
|
||||
IDBMutableFile::CreateFileFor(BlobImpl* aBlobImpl,
|
||||
FileHandleBase* aFileHandle)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
RefPtr<BlobImpl> blobImplSnapshot =
|
||||
new BlobImplSnapshot(aBlobImpl, static_cast<IDBFileHandle*>(aFileHandle));
|
||||
|
||||
RefPtr<File> file = File::Create(GetOwner(), blobImplSnapshot);
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/dom/FileModeBinding.h"
|
||||
#include "mozilla/dom/MutableFileBase.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsString.h"
|
||||
|
@ -37,10 +36,11 @@ class BackgroundMutableFileChild;
|
|||
|
||||
class IDBMutableFile final
|
||||
: public DOMEventTargetHelper
|
||||
, public MutableFileBase
|
||||
{
|
||||
RefPtr<IDBDatabase> mDatabase;
|
||||
|
||||
indexedDB::BackgroundMutableFileChild* mBackgroundActor;
|
||||
|
||||
nsTHashtable<nsPtrHashKey<IDBFileHandle>> mFileHandles;
|
||||
|
||||
nsString mName;
|
||||
|
@ -54,6 +54,46 @@ public:
|
|||
const nsAString& aName,
|
||||
const nsAString& aType);
|
||||
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
#ifdef DEBUG
|
||||
;
|
||||
#else
|
||||
{ }
|
||||
#endif
|
||||
|
||||
indexedDB::BackgroundMutableFileChild*
|
||||
GetBackgroundActor() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return mBackgroundActor;
|
||||
}
|
||||
|
||||
void
|
||||
ClearBackgroundActor()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
mBackgroundActor = nullptr;
|
||||
}
|
||||
|
||||
const nsString&
|
||||
Name() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return mName;
|
||||
}
|
||||
|
||||
const nsString&
|
||||
Type() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return mType;
|
||||
}
|
||||
|
||||
void
|
||||
SetLazyData(const nsAString& aName,
|
||||
const nsAString& aType)
|
||||
|
@ -68,6 +108,14 @@ public:
|
|||
void
|
||||
Invalidate();
|
||||
|
||||
bool
|
||||
IsInvalidated() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return mInvalidated;
|
||||
}
|
||||
|
||||
void
|
||||
RegisterFileHandle(IDBFileHandle* aFileHandle);
|
||||
|
||||
|
@ -115,20 +163,6 @@ public:
|
|||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// MutableFileBase
|
||||
virtual const nsString&
|
||||
Name() const override;
|
||||
|
||||
virtual const nsString&
|
||||
Type() const override;
|
||||
|
||||
virtual bool
|
||||
IsInvalidated() override;
|
||||
|
||||
virtual already_AddRefed<File>
|
||||
CreateFileFor(BlobImpl* aBlobImpl,
|
||||
FileHandleBase* aFileHandle) override;
|
||||
|
||||
private:
|
||||
~IDBMutableFile();
|
||||
};
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
using namespace mozilla::dom::indexedDB;
|
||||
using namespace mozilla::dom::quota;
|
||||
using namespace mozilla::dom::workers;
|
||||
using namespace mozilla::ipc;
|
||||
|
|
|
@ -51,9 +51,6 @@ NS_DEFINE_IID(kIDBRequestIID, PRIVATE_IDBREQUEST_IID);
|
|||
|
||||
IDBRequest::IDBRequest(IDBDatabase* aDatabase)
|
||||
: IDBWrapperCache(aDatabase)
|
||||
#ifdef DEBUG
|
||||
, mOwningThread(nullptr)
|
||||
#endif
|
||||
, mLoggingSerialNumber(0)
|
||||
, mLineNo(0)
|
||||
, mColumn(0)
|
||||
|
@ -67,9 +64,6 @@ IDBRequest::IDBRequest(IDBDatabase* aDatabase)
|
|||
|
||||
IDBRequest::IDBRequest(nsPIDOMWindowInner* aOwner)
|
||||
: IDBWrapperCache(aOwner)
|
||||
#ifdef DEBUG
|
||||
, mOwningThread(nullptr)
|
||||
#endif
|
||||
, mLoggingSerialNumber(0)
|
||||
, mLineNo(0)
|
||||
, mColumn(0)
|
||||
|
@ -83,23 +77,9 @@ IDBRequest::~IDBRequest()
|
|||
AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
IDBRequest::AssertIsOnOwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread);
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
IDBRequest::InitMembers()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
mOwningThread = PR_GetCurrentThread();
|
||||
#endif
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
mResultVal.setUndefined();
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
{0xe68901e5, 0x1d50, 0x4ee9, {0xaf, 0x49, 0x90, 0x99, 0x4a, 0xff, 0xc8, 0x39}}
|
||||
|
||||
class nsPIDOMWindowInner;
|
||||
struct PRThread;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -49,10 +48,6 @@ protected:
|
|||
|
||||
RefPtr<IDBTransaction> mTransaction;
|
||||
|
||||
#ifdef DEBUG
|
||||
PRThread* mOwningThread;
|
||||
#endif
|
||||
|
||||
JS::Heap<JS::Value> mResultVal;
|
||||
RefPtr<DOMError> mError;
|
||||
|
||||
|
@ -186,11 +181,9 @@ public:
|
|||
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
#ifdef DEBUG
|
||||
;
|
||||
#else
|
||||
{ }
|
||||
#endif
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(IDBRequest);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(IDBRequest,
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsQueryObject.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "ProfilerHelpers.h"
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
#ifndef mozilla_dom_indexeddb_scripterrorhelper_h__
|
||||
#define mozilla_dom_indexeddb_scripterrorhelper_h__
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
class nsACString;
|
||||
class nsAString;
|
||||
|
||||
namespace mozilla {
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIFrameLoader;
|
||||
interface nsIPrincipal;
|
||||
|
||||
[scriptable, uuid(14e5a0cb-e223-4202-95e8-fe53275193ea)]
|
||||
interface nsIBrowser : nsISupports
|
||||
|
@ -28,8 +27,7 @@ interface nsIBrowser : nsISupports
|
|||
* of the dropped links
|
||||
*/
|
||||
void dropLinks(in unsigned long linksCount,
|
||||
[array, size_is(linksCount)] in wstring links,
|
||||
in nsIPrincipal aTriggeringPrincipal);
|
||||
[array, size_is(linksCount)] in wstring links);
|
||||
|
||||
/**
|
||||
* Flags for controlling the behavior of swapBrowsers
|
||||
|
|
|
@ -14,7 +14,7 @@ interface nsIFrameLoaderOwner;
|
|||
interface nsIOpenURIInFrameParams : nsISupports
|
||||
{
|
||||
attribute DOMString referrer;
|
||||
attribute boolean isPrivate;
|
||||
readonly attribute boolean isPrivate;
|
||||
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval openerOriginAttributes;
|
||||
|
@ -105,12 +105,18 @@ interface nsIBrowserDOMWindow : nsISupports
|
|||
|
||||
/**
|
||||
* As above, but return the nsIFrameLoaderOwner for the new window.
|
||||
*
|
||||
* Additional Parameters:
|
||||
* @param aNextTabParentId The TabParent to associate the window with
|
||||
* @param aName The name to give the window opened in the new tab.
|
||||
* @return The nsIFrameLoaderOwner for the newly opened window.
|
||||
// XXXbz is this the right API?
|
||||
// See bug 537428
|
||||
*/
|
||||
nsIFrameLoaderOwner openURIInFrame(in nsIURI aURI, in nsIOpenURIInFrameParams params,
|
||||
in short aWhere, in long aFlags,
|
||||
in unsigned long long aNextTabParentId);
|
||||
in unsigned long long aNextTabParentId,
|
||||
in AString aName);
|
||||
|
||||
/**
|
||||
* @param aWindow the window to test.
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
interface nsIContentFrameMessageManager;
|
||||
interface nsIWebBrowserChrome3;
|
||||
interface nsIPrincipal;
|
||||
|
||||
native CommandsArray(nsTArray<nsCString>);
|
||||
[ref] native CommandsArrayRef(nsTArray<nsCString>);
|
||||
|
@ -32,8 +31,7 @@ interface nsITabChild : nsISupports
|
|||
in int32_t shellItemWidth, in int32_t shellItemHeight);
|
||||
|
||||
[noscript] void remoteDropLinks(in unsigned long linksCount,
|
||||
[array, size_is(linksCount)] in nsIDroppedLinkItem links,
|
||||
in nsIPrincipal triggeringPrincipal);
|
||||
[array, size_is(linksCount)] in nsIDroppedLinkItem links);
|
||||
|
||||
readonly attribute uint64_t tabId;
|
||||
|
||||
|
|
|
@ -98,6 +98,11 @@ interface nsIContentSecurityPolicy : nsISerializable
|
|||
*/
|
||||
readonly attribute bool blockAllMixedContent;
|
||||
|
||||
/**
|
||||
* Returns whether this policy enforces the frame-ancestors directive.
|
||||
*/
|
||||
readonly attribute bool enforcesFrameAncestors;
|
||||
|
||||
/**
|
||||
* Obtains the referrer policy (as integer) for this browsing context as
|
||||
* specified in CSP. If there are multiple policies and...
|
||||
|
|
|
@ -684,8 +684,7 @@ ContentChild::ProvideWindow(mozIDOMWindowProxy* aParent,
|
|||
|
||||
static nsresult
|
||||
GetWindowParamsFromParent(mozIDOMWindowProxy* aParent,
|
||||
nsACString& aBaseURIString, float* aFullZoom,
|
||||
OriginAttributes& aOriginAttributes)
|
||||
nsACString& aBaseURIString, float* aFullZoom)
|
||||
{
|
||||
*aFullZoom = 1.0f;
|
||||
auto* opener = nsPIDOMWindowOuter::From(aParent);
|
||||
|
@ -708,8 +707,6 @@ GetWindowParamsFromParent(mozIDOMWindowProxy* aParent,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
aOriginAttributes = openerDocShell->GetOriginAttributes();
|
||||
|
||||
nsCOMPtr<nsIContentViewer> cv;
|
||||
nsresult rv = openerDocShell->GetContentViewer(getter_AddRefs(cv));
|
||||
if (NS_SUCCEEDED(rv) && cv) {
|
||||
|
@ -739,42 +736,66 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
|||
nsAutoPtr<IPCTabContext> ipcContext;
|
||||
TabId openerTabId = TabId(0);
|
||||
nsAutoCString features(aFeatures);
|
||||
nsAutoString name(aName);
|
||||
|
||||
nsresult rv;
|
||||
if (aTabOpener) {
|
||||
// Check to see if the target URI can be loaded in this process.
|
||||
// If not create and load it in an unrelated tab/window.
|
||||
|
||||
MOZ_ASSERT(!aParent || aTabOpener,
|
||||
"If aParent is non-null, we should have an aTabOpener");
|
||||
|
||||
// Cache the boolean preference for allowing noopener windows to open in a
|
||||
// separate process.
|
||||
static bool sNoopenerNewProcess = false;
|
||||
static bool sNoopenerNewProcessInited = false;
|
||||
if (!sNoopenerNewProcessInited) {
|
||||
Preferences::AddBoolVarCache(&sNoopenerNewProcess,
|
||||
"dom.noopener.newprocess.enabled");
|
||||
sNoopenerNewProcessInited = true;
|
||||
}
|
||||
|
||||
// Check if we should load in a different process. We always want to load in a
|
||||
// different process if we have noopener set, but we also might if we can't
|
||||
// load in the current process.
|
||||
bool loadInDifferentProcess = aForceNoOpener && sNoopenerNewProcess;
|
||||
if (aTabOpener && !loadInDifferentProcess) {
|
||||
nsCOMPtr<nsIWebBrowserChrome3> browserChrome3;
|
||||
rv = aTabOpener->GetWebBrowserChrome(getter_AddRefs(browserChrome3));
|
||||
if (NS_SUCCEEDED(rv) && browserChrome3) {
|
||||
bool shouldLoad;
|
||||
rv = browserChrome3->ShouldLoadURIInThisProcess(aURI, &shouldLoad);
|
||||
if (NS_SUCCEEDED(rv) && !shouldLoad) {
|
||||
nsAutoCString baseURIString;
|
||||
float fullZoom;
|
||||
OriginAttributes originAttributes;
|
||||
rv = GetWindowParamsFromParent(aParent, baseURIString, &fullZoom,
|
||||
originAttributes);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
loadInDifferentProcess = NS_SUCCEEDED(rv) && !shouldLoad;
|
||||
}
|
||||
}
|
||||
|
||||
URIParams uriToLoad;
|
||||
SerializeURI(aURI, uriToLoad);
|
||||
Unused << SendCreateWindowInDifferentProcess(aTabOpener, aChromeFlags,
|
||||
aCalledFromJS,
|
||||
aPositionSpecified,
|
||||
aSizeSpecified,
|
||||
uriToLoad, features,
|
||||
baseURIString,
|
||||
originAttributes, fullZoom);
|
||||
|
||||
// We return NS_ERROR_ABORT, so that the caller knows that we've abandoned
|
||||
// the window open as far as it is concerned.
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
// If we're in a content process and we have noopener set, there's no reason
|
||||
// to load in our process, so let's load it elsewhere!
|
||||
if (loadInDifferentProcess) {
|
||||
nsAutoCString baseURIString;
|
||||
float fullZoom;
|
||||
rv = GetWindowParamsFromParent(aParent, baseURIString, &fullZoom);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
URIParams uriToLoad;
|
||||
SerializeURI(aURI, uriToLoad);
|
||||
Unused << SendCreateWindowInDifferentProcess(aTabOpener,
|
||||
aChromeFlags,
|
||||
aCalledFromJS,
|
||||
aPositionSpecified,
|
||||
aSizeSpecified,
|
||||
uriToLoad,
|
||||
features,
|
||||
baseURIString,
|
||||
fullZoom,
|
||||
name);
|
||||
|
||||
// We return NS_ERROR_ABORT, so that the caller knows that we've abandoned
|
||||
// the window open as far as it is concerned.
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
if (aTabOpener) {
|
||||
PopupIPCTabContext context;
|
||||
openerTabId = aTabOpener->GetTabId();
|
||||
context.opener() = openerTabId;
|
||||
|
@ -822,7 +843,6 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
|||
tabId, TabId(0), *ipcContext, aChromeFlags,
|
||||
GetID(), IsForBrowser());
|
||||
|
||||
nsString name(aName);
|
||||
nsTArray<FrameScriptInfo> frameScripts;
|
||||
nsCString urlToLoad;
|
||||
|
||||
|
@ -851,9 +871,7 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
|||
} else {
|
||||
nsAutoCString baseURIString;
|
||||
float fullZoom;
|
||||
OriginAttributes originAttributes;
|
||||
rv = GetWindowParamsFromParent(aParent, baseURIString, &fullZoom,
|
||||
originAttributes);
|
||||
rv = GetWindowParamsFromParent(aParent, baseURIString, &fullZoom);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -863,7 +881,6 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
|||
aSizeSpecified,
|
||||
features,
|
||||
baseURIString,
|
||||
originAttributes,
|
||||
fullZoom,
|
||||
&rv,
|
||||
aWindowIsNew,
|
||||
|
|
|
@ -4409,9 +4409,9 @@ ContentParent::CommonCreateWindow(PBrowserParent* aThisTab,
|
|||
nsIURI* aURIToLoad,
|
||||
const nsCString& aFeatures,
|
||||
const nsCString& aBaseURI,
|
||||
const OriginAttributes& aOpenerOriginAttributes,
|
||||
const float& aFullZoom,
|
||||
uint64_t aNextTabParentId,
|
||||
const nsString& aName,
|
||||
nsresult& aResult,
|
||||
nsCOMPtr<nsITabParent>& aNewTabParent,
|
||||
bool* aWindowIsNew)
|
||||
|
@ -4474,27 +4474,29 @@ ContentParent::CommonCreateWindow(PBrowserParent* aThisTab,
|
|||
MOZ_ASSERT(openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
|
||||
openLocation == nsIBrowserDOMWindow::OPEN_NEWWINDOW);
|
||||
|
||||
// Read the origin attributes for the tab from the opener tabParent.
|
||||
OriginAttributes openerOriginAttributes;
|
||||
if (thisTabParent) {
|
||||
nsCOMPtr<nsILoadContext> loadContext = thisTabParent->GetLoadContext();
|
||||
loadContext->GetOriginAttributes(openerOriginAttributes);
|
||||
} else if (Preferences::GetBool("browser.privatebrowsing.autostart")) {
|
||||
openerOriginAttributes.mPrivateBrowsingId = 1;
|
||||
}
|
||||
|
||||
if (openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB) {
|
||||
if (NS_WARN_IF(!browserDOMWin)) {
|
||||
aResult = NS_ERROR_ABORT;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool isPrivate = false;
|
||||
if (thisTabParent) {
|
||||
nsCOMPtr<nsILoadContext> loadContext = thisTabParent->GetLoadContext();
|
||||
loadContext->GetUsePrivateBrowsing(&isPrivate);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIOpenURIInFrameParams> params =
|
||||
new nsOpenURIInFrameParams(aOpenerOriginAttributes);
|
||||
new nsOpenURIInFrameParams(openerOriginAttributes);
|
||||
params->SetReferrer(NS_ConvertUTF8toUTF16(aBaseURI));
|
||||
params->SetIsPrivate(isPrivate);
|
||||
|
||||
nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner;
|
||||
aResult = browserDOMWin->OpenURIInFrame(aURIToLoad, params, openLocation,
|
||||
nsIBrowserDOMWindow::OPEN_NEW,
|
||||
aNextTabParentId,
|
||||
aNextTabParentId, aName,
|
||||
getter_AddRefs(frameLoaderOwner));
|
||||
if (NS_SUCCEEDED(aResult) && frameLoaderOwner) {
|
||||
RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
|
||||
|
@ -4514,14 +4516,32 @@ ContentParent::CommonCreateWindow(PBrowserParent* aThisTab,
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
aResult = pwwatch->OpenWindowWithTabParent(aSetOpener ? thisTabParent : nullptr,
|
||||
aResult = pwwatch->OpenWindowWithTabParent(thisTabParent,
|
||||
aFeatures, aCalledFromJS, aFullZoom,
|
||||
aNextTabParentId,
|
||||
!aSetOpener,
|
||||
getter_AddRefs(aNewTabParent));
|
||||
if (NS_WARN_IF(NS_FAILED(aResult))) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aNewTabParent);
|
||||
// If we were passed a name for the window which would override the default,
|
||||
// we should send it down to the new tab.
|
||||
if (nsContentUtils::IsOverridingWindowName(aName)) {
|
||||
Unused << TabParent::GetFrom(aNewTabParent)->SendSetWindowName(aName);
|
||||
}
|
||||
|
||||
// Don't send down the OriginAttributes if the content process is handling
|
||||
// setting up the window for us. We only want to send them in the async case.
|
||||
//
|
||||
// If we send it down in the non-async case, then we might set the
|
||||
// OriginAttributes after the document has already navigated.
|
||||
if (!aSetOpener) {
|
||||
Unused << TabParent::GetFrom(aNewTabParent)
|
||||
->SendSetOriginAttributes(openerOriginAttributes);
|
||||
}
|
||||
|
||||
if (aURIToLoad) {
|
||||
nsCOMPtr<mozIDOMWindowProxy> openerWindow;
|
||||
if (aSetOpener && thisTabParent) {
|
||||
|
@ -4553,7 +4573,6 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
|
|||
const bool& aSizeSpecified,
|
||||
const nsCString& aFeatures,
|
||||
const nsCString& aBaseURI,
|
||||
const OriginAttributes& aOpenerOriginAttributes,
|
||||
const float& aFullZoom,
|
||||
nsresult* aResult,
|
||||
bool* aWindowIsNew,
|
||||
|
@ -4591,8 +4610,8 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
|
|||
mozilla::ipc::IPCResult ipcResult =
|
||||
CommonCreateWindow(aThisTab, /* aSetOpener = */ true, aChromeFlags,
|
||||
aCalledFromJS, aPositionSpecified, aSizeSpecified,
|
||||
nullptr, aFeatures, aBaseURI, aOpenerOriginAttributes,
|
||||
aFullZoom, nextTabParentId, *aResult,
|
||||
nullptr, aFeatures, aBaseURI, aFullZoom,
|
||||
nextTabParentId, NullString(), *aResult,
|
||||
newRemoteTab, aWindowIsNew);
|
||||
if (!ipcResult) {
|
||||
return ipcResult;
|
||||
|
@ -4632,8 +4651,8 @@ ContentParent::RecvCreateWindowInDifferentProcess(
|
|||
const URIParams& aURIToLoad,
|
||||
const nsCString& aFeatures,
|
||||
const nsCString& aBaseURI,
|
||||
const OriginAttributes& aOpenerOriginAttributes,
|
||||
const float& aFullZoom)
|
||||
const float& aFullZoom,
|
||||
const nsString& aName)
|
||||
{
|
||||
nsCOMPtr<nsITabParent> newRemoteTab;
|
||||
bool windowIsNew;
|
||||
|
@ -4642,8 +4661,8 @@ ContentParent::RecvCreateWindowInDifferentProcess(
|
|||
mozilla::ipc::IPCResult ipcResult =
|
||||
CommonCreateWindow(aThisTab, /* aSetOpener = */ false, aChromeFlags,
|
||||
aCalledFromJS, aPositionSpecified, aSizeSpecified,
|
||||
uriToLoad, aFeatures, aBaseURI, aOpenerOriginAttributes,
|
||||
aFullZoom, /* aNextTabParentId = */ 0, rv,
|
||||
uriToLoad, aFeatures, aBaseURI, aFullZoom,
|
||||
/* aNextTabParentId = */ 0, aName, rv,
|
||||
newRemoteTab, &windowIsNew);
|
||||
if (!ipcResult) {
|
||||
return ipcResult;
|
||||
|
|
|
@ -535,7 +535,6 @@ public:
|
|||
const bool& aSizeSpecified,
|
||||
const nsCString& aFeatures,
|
||||
const nsCString& aBaseURI,
|
||||
const OriginAttributes& aOpenerOriginAttributes,
|
||||
const float& aFullZoom,
|
||||
nsresult* aResult,
|
||||
bool* aWindowIsNew,
|
||||
|
@ -555,8 +554,8 @@ public:
|
|||
const URIParams& aURIToLoad,
|
||||
const nsCString& aFeatures,
|
||||
const nsCString& aBaseURI,
|
||||
const OriginAttributes& aOpenerOriginAttributes,
|
||||
const float& aFullZoom) override;
|
||||
const float& aFullZoom,
|
||||
const nsString& aName) override;
|
||||
|
||||
static bool AllocateLayerTreeId(TabParent* aTabParent, uint64_t* aId);
|
||||
|
||||
|
@ -712,9 +711,9 @@ private:
|
|||
nsIURI* aURIToLoad,
|
||||
const nsCString& aFeatures,
|
||||
const nsCString& aBaseURI,
|
||||
const OriginAttributes& aOpenerOriginAttributes,
|
||||
const float& aFullZoom,
|
||||
uint64_t aNextTabParentId,
|
||||
const nsString& aName,
|
||||
nsresult& aResult,
|
||||
nsCOMPtr<nsITabParent>& aNewTabParent,
|
||||
bool* aWindowIsNew);
|
||||
|
|
|
@ -21,7 +21,6 @@ include protocol PFileDescriptorSet;
|
|||
include protocol PIPCBlobInputStream;
|
||||
include protocol PPaymentRequest;
|
||||
|
||||
include PBackgroundSharedTypes;
|
||||
include DOMTypes;
|
||||
include IPCBlob;
|
||||
include IPCStream;
|
||||
|
@ -84,6 +83,7 @@ using mozilla::widget::CandidateWindowPosition from "ipc/nsGUIEventIPC.h";
|
|||
using class mozilla::NativeEventData from "ipc/nsGUIEventIPC.h";
|
||||
using mozilla::FontRange from "ipc/nsGUIEventIPC.h";
|
||||
using mozilla::a11y::IAccessibleHolder from "mozilla/a11y/IPCTypes.h";
|
||||
using mozilla::OriginAttributes from "mozilla/ipc/BackgroundUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -196,7 +196,7 @@ parent:
|
|||
*
|
||||
* aLinks A flat array of url, name, and type for each link
|
||||
*/
|
||||
async DropLinks(nsString[] aLinks, PrincipalInfo aTriggeringPrincipalInfo);
|
||||
async DropLinks(nsString[] aLinks);
|
||||
|
||||
async Event(RemoteDOMEvent aEvent);
|
||||
|
||||
|
@ -891,6 +891,17 @@ child:
|
|||
*/
|
||||
async AwaitLargeAlloc();
|
||||
|
||||
/**
|
||||
* Tell the TabChild to set the name of its toplevel docshell to the given name.
|
||||
*/
|
||||
async SetWindowName(nsString aName);
|
||||
|
||||
/**
|
||||
* Tell the TabChild what OriginAttributes it should inherit from. This must
|
||||
* be called before the first non-blank document is loaded in the TabChild.
|
||||
*/
|
||||
async SetOriginAttributes(OriginAttributes aOriginAttributes);
|
||||
|
||||
/*
|
||||
* FIXME: write protocol!
|
||||
|
||||
|
|
|
@ -988,7 +988,6 @@ parent:
|
|||
bool aSizeSpecified,
|
||||
nsCString aFeatures,
|
||||
nsCString aBaseURI,
|
||||
OriginAttributes aOpenerOriginAttributes,
|
||||
float aFullZoom)
|
||||
returns (nsresult rv,
|
||||
bool windowOpened,
|
||||
|
@ -1008,8 +1007,8 @@ parent:
|
|||
URIParams aURIToLoad,
|
||||
nsCString aFeatures,
|
||||
nsCString aBaseURI,
|
||||
OriginAttributes aOpenerOriginAttributes,
|
||||
float aFullZoom);
|
||||
float aFullZoom,
|
||||
nsString aName);
|
||||
|
||||
sync GetAndroidSystemInfo()
|
||||
returns (AndroidSystemInfo info);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "nsIPropertyBag2.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsTHashtable.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -149,6 +150,8 @@ public:
|
|||
*/
|
||||
virtual void Notify(const WakeLockInformation& aInfo) override;
|
||||
|
||||
void TabActivityChanged(TabParent* aTabParent, bool aIsActive);
|
||||
|
||||
/**
|
||||
* Call ShutDown before destroying the ProcessPriorityManager because
|
||||
* WakeLockObserver hols a strong reference to it.
|
||||
|
@ -267,6 +270,8 @@ public:
|
|||
void ResetPriorityNow();
|
||||
void SetPriorityNow(ProcessPriority aPriority);
|
||||
|
||||
void TabActivityChanged(TabParent* aTabParent, bool aIsActive);
|
||||
|
||||
void ShutDown();
|
||||
|
||||
private:
|
||||
|
@ -293,6 +298,9 @@ private:
|
|||
nsAutoCString mNameWithComma;
|
||||
|
||||
nsCOMPtr<nsITimer> mResetPriorityTimer;
|
||||
|
||||
// This hashtable contains the list of active TabId for this process.
|
||||
nsTHashtable<nsUint64HashKey> mActiveTabParents;
|
||||
};
|
||||
|
||||
/* static */ bool ProcessPriorityManagerImpl::sInitialized = false;
|
||||
|
@ -324,7 +332,7 @@ ProcessPriorityManagerImpl::PrefChangedCallback(const char* aPref,
|
|||
/* static */ bool
|
||||
ProcessPriorityManagerImpl::PrefsEnabled()
|
||||
{
|
||||
return sPrefsEnabled && !sRemoteTabsDisabled;
|
||||
return sPrefsEnabled && hal::SetProcessPrioritySupported() && !sRemoteTabsDisabled;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
|
@ -538,6 +546,20 @@ ProcessPriorityManagerImpl::Notify(const WakeLockInformation& aInfo)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ProcessPriorityManagerImpl::TabActivityChanged(TabParent* aTabParent,
|
||||
bool aIsActive)
|
||||
{
|
||||
ContentParent* cp = aTabParent->Manager()->AsContentParent();
|
||||
RefPtr<ParticularProcessPriorityManager> pppm =
|
||||
GetParticularProcessPriorityManager(cp);
|
||||
if (!pppm) {
|
||||
return;
|
||||
}
|
||||
|
||||
pppm->TabActivityChanged(aTabParent, aIsActive);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(ParticularProcessPriorityManager,
|
||||
nsIObserver,
|
||||
nsITimerCallback,
|
||||
|
@ -724,6 +746,13 @@ ParticularProcessPriorityManager::OnTabParentDestroyed(nsISupports* aSubject)
|
|||
return;
|
||||
}
|
||||
|
||||
uint64_t tabId;
|
||||
if (NS_WARN_IF(NS_FAILED(tp->GetTabId(&tabId)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
mActiveTabParents.RemoveEntry(tabId);
|
||||
|
||||
ResetPriority();
|
||||
}
|
||||
|
||||
|
@ -799,8 +828,9 @@ ParticularProcessPriorityManager::CurrentPriority()
|
|||
ProcessPriority
|
||||
ParticularProcessPriorityManager::ComputePriority()
|
||||
{
|
||||
// TODO...
|
||||
return PROCESS_PRIORITY_FOREGROUND;
|
||||
if (!mActiveTabParents.IsEmpty()) {
|
||||
return PROCESS_PRIORITY_FOREGROUND;
|
||||
}
|
||||
|
||||
if (mHoldsCPUWakeLock || mHoldsHighPriorityWakeLock) {
|
||||
return PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE;
|
||||
|
@ -848,6 +878,21 @@ ParticularProcessPriorityManager::SetPriorityNow(ProcessPriority aPriority)
|
|||
ProcessPriorityToString(mPriority));
|
||||
}
|
||||
|
||||
void
|
||||
ParticularProcessPriorityManager::TabActivityChanged(TabParent* aTabParent,
|
||||
bool aIsActive)
|
||||
{
|
||||
MOZ_ASSERT(aTabParent);
|
||||
|
||||
if (!aIsActive) {
|
||||
mActiveTabParents.RemoveEntry(aTabParent->GetTabId());
|
||||
} else {
|
||||
mActiveTabParents.PutEntry(aTabParent->GetTabId());
|
||||
}
|
||||
|
||||
ResetPriority();
|
||||
}
|
||||
|
||||
void
|
||||
ParticularProcessPriorityManager::ShutDown()
|
||||
{
|
||||
|
@ -1023,4 +1068,19 @@ ProcessPriorityManager::CurrentProcessIsForeground()
|
|||
CurrentProcessIsForeground();
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
ProcessPriorityManager::TabActivityChanged(TabParent* aTabParent,
|
||||
bool aIsActive)
|
||||
{
|
||||
MOZ_ASSERT(aTabParent);
|
||||
|
||||
ProcessPriorityManagerImpl* singleton =
|
||||
ProcessPriorityManagerImpl::GetSingleton();
|
||||
if (!singleton) {
|
||||
return;
|
||||
}
|
||||
|
||||
singleton->TabActivityChanged(aTabParent, aIsActive);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
class ContentParent;
|
||||
class TabParent;
|
||||
} // namespace dom
|
||||
|
||||
/**
|
||||
|
@ -68,6 +69,8 @@ public:
|
|||
*/
|
||||
static bool CurrentProcessIsForeground();
|
||||
|
||||
static void TabActivityChanged(dom::TabParent* aTabParent, bool aIsActive);
|
||||
|
||||
private:
|
||||
ProcessPriorityManager();
|
||||
DISALLOW_EVIL_CONSTRUCTORS(ProcessPriorityManager);
|
||||
|
|
|
@ -749,8 +749,7 @@ TabChild::RemoteSizeShellTo(int32_t aWidth, int32_t aHeight,
|
|||
|
||||
NS_IMETHODIMP
|
||||
TabChild::RemoteDropLinks(uint32_t aLinksCount,
|
||||
nsIDroppedLinkItem** aLinks,
|
||||
nsIPrincipal* aTriggeringPrincipal)
|
||||
nsIDroppedLinkItem** aLinks)
|
||||
{
|
||||
nsTArray<nsString> linksArray;
|
||||
nsresult rv = NS_OK;
|
||||
|
@ -774,10 +773,7 @@ TabChild::RemoteDropLinks(uint32_t aLinksCount,
|
|||
}
|
||||
linksArray.AppendElement(tmp);
|
||||
}
|
||||
|
||||
PrincipalInfo triggeringPrincipalInfo;
|
||||
PrincipalToPrincipalInfo(aTriggeringPrincipal, &triggeringPrincipalInfo);
|
||||
bool sent = SendDropLinks(linksArray, triggeringPrincipalInfo);
|
||||
bool sent = SendDropLinks(linksArray);
|
||||
|
||||
return sent ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -3162,6 +3158,25 @@ TabChild::StopAwaitingLargeAlloc()
|
|||
return awaiting;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
TabChild::RecvSetWindowName(const nsString& aName)
|
||||
{
|
||||
nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(WebNavigation());
|
||||
if (item) {
|
||||
item->SetName(aName);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
TabChild::RecvSetOriginAttributes(const OriginAttributes& aOriginAttributes)
|
||||
{
|
||||
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
|
||||
nsDocShell::Cast(docShell)->SetOriginAttributes(aOriginAttributes);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::plugins::PPluginWidgetChild*
|
||||
TabChild::AllocPPluginWidgetChild()
|
||||
{
|
||||
|
|
|
@ -735,6 +735,10 @@ protected:
|
|||
|
||||
virtual mozilla::ipc::IPCResult RecvAwaitLargeAlloc() override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvSetWindowName(const nsString& aName) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvSetOriginAttributes(const OriginAttributes& aOriginAttributes) override;
|
||||
|
||||
private:
|
||||
void HandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers,
|
||||
const ScrollableLayerGuid& aGuid);
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче