UPGRADE_NSPR_RELEASE UPGRADE_NSS_RELEASE

--HG--
extra : amend_source : a7800e9214d5a8325af0d1f5e5dcc77273f4ce95
This commit is contained in:
Ryan VanderMeulen 2017-06-07 22:52:40 -04:00
Родитель 086a61dfbf b08f42f77d
Коммит e886d1846a
261 изменённых файлов: 11896 добавлений и 6086 удалений

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

@ -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(&current)));
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(&current)));
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);

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