зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to fx-team. a=merge
This commit is contained in:
Коммит
84b872d09e
|
@ -366,18 +366,33 @@ Target.prototype = {
|
|||
} else {
|
||||
let histogramName = CUSTOM_HISTOGRAM_PREFIX + metricAppName + '_'
|
||||
+ metricName;
|
||||
if (!developerHUD._customHistograms.has(histogramName)) {
|
||||
try {
|
||||
Services.telemetry.registerAddonHistogram(metricAppName,
|
||||
CUSTOM_HISTOGRAM_PREFIX + metricName,
|
||||
Services.telemetry.HISTOGRAM_LINEAR, 1, 10000, 10);
|
||||
developerHUD._customHistograms.add(histogramName);
|
||||
} catch(err) {
|
||||
console.error('Histogram error: ' + err);
|
||||
}
|
||||
// This is a call to add a value to an existing histogram.
|
||||
if (typeof metric.value !== 'undefined') {
|
||||
Services.telemetry.getAddonHistogram(metricAppName,
|
||||
CUSTOM_HISTOGRAM_PREFIX + metricName).add(parseInt(metric.value, 10));
|
||||
return;
|
||||
}
|
||||
|
||||
// The histogram already exists and are not adding data to it.
|
||||
if (developerHUD._customHistograms.has(histogramName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This is a call to create a new histogram.
|
||||
try {
|
||||
let metricType = parseInt(metric.type, 10);
|
||||
if (metricType === Services.telemetry.HISTOGRAM_COUNT) {
|
||||
Services.telemetry.registerAddonHistogram(metricAppName,
|
||||
CUSTOM_HISTOGRAM_PREFIX + metricName, metricType);
|
||||
} else {
|
||||
Services.telemetry.registerAddonHistogram(metricAppName,
|
||||
CUSTOM_HISTOGRAM_PREFIX + metricName, metricType, metric.min,
|
||||
metric.max, metric.buckets);
|
||||
}
|
||||
developerHUD._customHistograms.add(histogramName);
|
||||
} catch (err) {
|
||||
console.error('Histogram error: ' + err);
|
||||
}
|
||||
Services.telemetry.getAddonHistogram(metricAppName,
|
||||
CUSTOM_HISTOGRAM_PREFIX + metricName).add(parseInt(metric.value, 10));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -588,24 +603,40 @@ let consoleWatcher = {
|
|||
let TELEMETRY_IDENTIFIER_IDX = 0;
|
||||
let NAME_IDX = 1;
|
||||
let VALUE_IDX = 2;
|
||||
let TYPE_IDX = 2;
|
||||
let MIN_IDX = 3;
|
||||
let MAX_IDX = 4;
|
||||
let BUCKETS_IDX = 5;
|
||||
let MAX_CUSTOM_ARGS = 6;
|
||||
let MIN_CUSTOM_ARGS = 3;
|
||||
|
||||
if (telemetryData[TELEMETRY_IDENTIFIER_IDX] != 'telemetry' ||
|
||||
telemetryData.length < 3 || telemetryData.length > 4) {
|
||||
telemetryData.length < MIN_CUSTOM_ARGS ||
|
||||
telemetryData.length > MAX_CUSTOM_ARGS) {
|
||||
return;
|
||||
}
|
||||
|
||||
let metric = {
|
||||
name: telemetryData[NAME_IDX],
|
||||
value: telemetryData[VALUE_IDX]
|
||||
name: telemetryData[NAME_IDX]
|
||||
};
|
||||
if (metric.name == 'MGMT') {
|
||||
if (metric.value == 'TIMETOSHIP') {
|
||||
|
||||
if (metric.name === 'MGMT') {
|
||||
metric.value = telemetryData[VALUE_IDX];
|
||||
if (metric.value === 'TIMETOSHIP') {
|
||||
telemetryDebug('Received a Ship event');
|
||||
target._sendTelemetryData();
|
||||
} else if (metric.value == 'CLEARMETRICS') {
|
||||
} else if (metric.value === 'CLEARMETRICS') {
|
||||
target._clearTelemetryData();
|
||||
}
|
||||
} else {
|
||||
if (telemetryData.length === MIN_CUSTOM_ARGS) {
|
||||
metric.value = telemetryData[VALUE_IDX];
|
||||
} else if (telemetryData.length === MAX_CUSTOM_ARGS) {
|
||||
metric.type = telemetryData[TYPE_IDX];
|
||||
metric.min = telemetryData[MIN_IDX];
|
||||
metric.max = telemetryData[MAX_IDX];
|
||||
metric.buckets = telemetryData[BUCKETS_IDX];
|
||||
}
|
||||
metric.custom = true;
|
||||
target._logHistogram(metric);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ Cu.import('resource://gre/modules/SystemUpdateService.jsm');
|
|||
Cu.import('resource://gre/modules/NetworkStatsService.jsm');
|
||||
Cu.import('resource://gre/modules/ResourceStatsService.jsm');
|
||||
#endif
|
||||
Cu.import('resource://gre/modules/KillSwitchMain.jsm');
|
||||
|
||||
// Identity
|
||||
Cu.import('resource://gre/modules/SignInToWebsite.jsm');
|
||||
|
|
|
@ -128,3 +128,7 @@ contract @mozilla.org/presentation-device/prompt;1 {4a300c26-e99b-4018-ab9b-c48c
|
|||
# PresentationRequestUIGlue.js
|
||||
component {ccc8a839-0b64-422b-8a60-fb2af0e376d0} PresentationRequestUIGlue.js
|
||||
contract @mozilla.org/presentation/requestuiglue;1 {ccc8a839-0b64-422b-8a60-fb2af0e376d0}
|
||||
|
||||
# KillSwitch.js
|
||||
component {b6eae5c6-971c-4772-89e5-5df626bf3f09} KillSwitch.js
|
||||
contract @mozilla.org/moz-kill-switch;1 {b6eae5c6-971c-4772-89e5-5df626bf3f09}
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const DEBUG = false;
|
||||
|
||||
function debug(s) {
|
||||
dump("-*- KillSwitch.js: " + s + "\n");
|
||||
}
|
||||
|
||||
const {interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsIMessageSender");
|
||||
|
||||
const KILLSWITCH_CID = "{b6eae5c6-971c-4772-89e5-5df626bf3f09}";
|
||||
const KILLSWITCH_CONTRACTID = "@mozilla.org/moz-kill-switch;1";
|
||||
|
||||
const kEnableKillSwitch = "KillSwitch:Enable";
|
||||
const kEnableKillSwitchOK = "KillSwitch:Enable:OK";
|
||||
const kEnableKillSwitchKO = "KillSwitch:Enable:KO";
|
||||
|
||||
const kDisableKillSwitch = "KillSwitch:Disable";
|
||||
const kDisableKillSwitchOK = "KillSwitch:Disable:OK";
|
||||
const kDisableKillSwitchKO = "KillSwitch:Disable:KO";
|
||||
|
||||
function KillSwitch() {
|
||||
this._window = null;
|
||||
}
|
||||
|
||||
KillSwitch.prototype = {
|
||||
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
init: function(aWindow) {
|
||||
DEBUG && debug("init");
|
||||
this._window = aWindow;
|
||||
this.initDOMRequestHelper(this._window);
|
||||
},
|
||||
|
||||
enable: function() {
|
||||
DEBUG && debug("KillSwitch: enable");
|
||||
|
||||
cpmm.addMessageListener(kEnableKillSwitchOK, this);
|
||||
cpmm.addMessageListener(kEnableKillSwitchKO, this);
|
||||
return this.createPromise((aResolve, aReject) => {
|
||||
cpmm.sendAsyncMessage(kEnableKillSwitch, {
|
||||
requestID: this.getPromiseResolverId({
|
||||
resolve: aResolve,
|
||||
reject: aReject
|
||||
})
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
disable: function() {
|
||||
DEBUG && debug("KillSwitch: disable");
|
||||
|
||||
cpmm.addMessageListener(kDisableKillSwitchOK, this);
|
||||
cpmm.addMessageListener(kDisableKillSwitchKO, this);
|
||||
return this.createPromise((aResolve, aReject) => {
|
||||
cpmm.sendAsyncMessage(kDisableKillSwitch, {
|
||||
requestID: this.getPromiseResolverId({
|
||||
resolve: aResolve,
|
||||
reject: aReject
|
||||
})
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
receiveMessage: function(message) {
|
||||
DEBUG && debug("Received: " + message.name);
|
||||
|
||||
cpmm.removeMessageListener(kEnableKillSwitchOK, this);
|
||||
cpmm.removeMessageListener(kEnableKillSwitchKO, this);
|
||||
cpmm.removeMessageListener(kDisableKillSwitchOK, this);
|
||||
cpmm.removeMessageListener(kDisableKillSwitchKO, this);
|
||||
|
||||
let req = this.takePromiseResolver(message.data.requestID);
|
||||
|
||||
switch (message.name) {
|
||||
case kEnableKillSwitchKO:
|
||||
case kDisableKillSwitchKO:
|
||||
req.reject(false);
|
||||
break;
|
||||
|
||||
case kEnableKillSwitchOK:
|
||||
case kDisableKillSwitchOK:
|
||||
req.resolve(true);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG && debug("Unrecognized message: " + message.name);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
classID : Components.ID(KILLSWITCH_CID),
|
||||
contractID : KILLSWITCH_CONTRACTID,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIKillSwitch,
|
||||
Ci.nsIDOMGlobalPropertyInitializer,
|
||||
Ci.nsIObserver,
|
||||
Ci.nsIMessageListener,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([KillSwitch]);
|
|
@ -0,0 +1,505 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = [ "KillSwitchMain" ];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "settings",
|
||||
"@mozilla.org/settingsService;1",
|
||||
"nsISettingsService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
"nsIMessageBroadcaster");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "permMgr", function() {
|
||||
return Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Ci.nsIPermissionManager);
|
||||
});
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
XPCOMUtils.defineLazyGetter(this, "libcutils", function () {
|
||||
Cu.import("resource://gre/modules/systemlibs.js");
|
||||
return libcutils;
|
||||
});
|
||||
#else
|
||||
this.libcutils = null;
|
||||
#endif
|
||||
|
||||
const DEBUG = false;
|
||||
|
||||
const kEnableKillSwitch = "KillSwitch:Enable";
|
||||
const kEnableKillSwitchOK = "KillSwitch:Enable:OK";
|
||||
const kEnableKillSwitchKO = "KillSwitch:Enable:KO";
|
||||
|
||||
const kDisableKillSwitch = "KillSwitch:Disable";
|
||||
const kDisableKillSwitchOK = "KillSwitch:Disable:OK";
|
||||
const kDisableKillSwitchKO = "KillSwitch:Disable:KO";
|
||||
|
||||
const kMessages = [kEnableKillSwitch, kDisableKillSwitch];
|
||||
|
||||
const kXpcomShutdownObserverTopic = "xpcom-shutdown";
|
||||
|
||||
const kProperty = "persist.moz.killswitch";
|
||||
|
||||
const kUserValues =
|
||||
OS.Path.join(OS.Constants.Path.profileDir, "killswitch.json");
|
||||
|
||||
let inParent = Cc["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Ci.nsIXULRuntime)
|
||||
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
||||
|
||||
function debug(aStr) {
|
||||
dump("--*-- KillSwitchMain: " + aStr + "\n");
|
||||
}
|
||||
|
||||
this.KillSwitchMain = {
|
||||
_ksState: null,
|
||||
_libcutils: null,
|
||||
|
||||
_enabledValues: {
|
||||
// List of settings to set to a specific value
|
||||
settings: {
|
||||
"debugger.remote-mode": "disabled",
|
||||
"developer.menu.enabled": false,
|
||||
"devtools.unrestricted": false,
|
||||
"lockscreen.enabled": true,
|
||||
"lockscreen.locked": true,
|
||||
"lockscreen.lock-immediately": true,
|
||||
"tethering.usb.enabled": false,
|
||||
"tethering.wifi.enabled": false,
|
||||
"ums.enabled": false
|
||||
},
|
||||
|
||||
// List of preferences to set to a specific value
|
||||
prefs: {
|
||||
"b2g.killswitch.test": true
|
||||
},
|
||||
|
||||
// List of Android properties to set to a specific value
|
||||
properties: {
|
||||
"persist.sys.usb.config": "none" // will change sys.usb.config and sys.usb.state
|
||||
},
|
||||
|
||||
// List of Android services to control
|
||||
services: {
|
||||
"adbd": "stop"
|
||||
}
|
||||
},
|
||||
|
||||
init: function() {
|
||||
DEBUG && debug("init");
|
||||
if (libcutils) {
|
||||
this._libcutils = libcutils;
|
||||
}
|
||||
|
||||
kMessages.forEach(m => {
|
||||
ppmm.addMessageListener(m, this);
|
||||
});
|
||||
|
||||
Services.obs.addObserver(this, kXpcomShutdownObserverTopic, false);
|
||||
|
||||
this.readStateProperty();
|
||||
},
|
||||
|
||||
uninit: function() {
|
||||
kMessages.forEach(m => {
|
||||
ppmm.removeMessageListener(m, this);
|
||||
});
|
||||
|
||||
Services.obs.removeObserver(this, kXpcomShutdownObserverTopic);
|
||||
},
|
||||
|
||||
checkLibcUtils: function() {
|
||||
DEBUG && debug("checkLibcUtils");
|
||||
if (!this._libcutils) {
|
||||
debug("No proper libcutils binding, aborting.");
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
readStateProperty: function() {
|
||||
DEBUG && debug("readStateProperty");
|
||||
try {
|
||||
this.checkLibcUtils();
|
||||
} catch (ex) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._ksState =
|
||||
this._libcutils.property_get(kProperty, "false") === "true";
|
||||
},
|
||||
|
||||
writeStateProperty: function() {
|
||||
DEBUG && debug("writeStateProperty");
|
||||
try {
|
||||
this.checkLibcUtils();
|
||||
} catch (ex) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._libcutils.property_set(kProperty, this._ksState.toString());
|
||||
},
|
||||
|
||||
getPref(name, value) {
|
||||
let rv = undefined;
|
||||
|
||||
try {
|
||||
switch (typeof value) {
|
||||
case "boolean":
|
||||
rv = Services.prefs.getBoolPref(name, value);
|
||||
break;
|
||||
|
||||
case "number":
|
||||
rv = Services.prefs.getIntPref(name, value);
|
||||
break;
|
||||
|
||||
case "string":
|
||||
rv = Services.prefs.getCharPref(name, value);
|
||||
break;
|
||||
|
||||
default:
|
||||
debug("Unexpected pref type " + value);
|
||||
break;
|
||||
}
|
||||
} catch (ex) {
|
||||
}
|
||||
|
||||
return rv;
|
||||
},
|
||||
|
||||
setPref(name, value) {
|
||||
switch (typeof value) {
|
||||
case "boolean":
|
||||
Services.prefs.setBoolPref(name, value);
|
||||
break;
|
||||
|
||||
case "number":
|
||||
Services.prefs.setIntPref(name, value);
|
||||
break;
|
||||
|
||||
case "string":
|
||||
Services.prefs.setCharPref(name, value);
|
||||
break;
|
||||
|
||||
default:
|
||||
debug("Unexpected pref type " + value);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
doEnable: function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Make sure that the API cannot do a new |enable()| call once the
|
||||
// feature has been enabled, otherwise we will overwrite the user values.
|
||||
if (this._ksState) {
|
||||
reject(true);
|
||||
return;
|
||||
}
|
||||
|
||||
this.saveUserValues().then(() => {
|
||||
DEBUG && debug("Toggling settings: " +
|
||||
JSON.stringify(this._enabledValues.settings));
|
||||
|
||||
let lock = settings.createLock();
|
||||
for (let key of Object.keys(this._enabledValues.settings)) {
|
||||
lock.set(key, this._enabledValues.settings[key], this);
|
||||
}
|
||||
|
||||
DEBUG && debug("Toggling prefs: " +
|
||||
JSON.stringify(this._enabledValues.prefs));
|
||||
|
||||
for (let key of Object.keys(this._enabledValues.prefs)) {
|
||||
this.setPref(key, this._enabledValues.prefs[key]);
|
||||
}
|
||||
|
||||
DEBUG && debug("Toggling properties: " +
|
||||
JSON.stringify(this._enabledValues.properties));
|
||||
|
||||
for (let key of Object.keys(this._enabledValues.properties)) {
|
||||
this._libcutils.property_set(key, this._enabledValues.properties[key]);
|
||||
}
|
||||
|
||||
DEBUG && debug("Toggling services: " +
|
||||
JSON.stringify(this._enabledValues.services));
|
||||
|
||||
for (let key of Object.keys(this._enabledValues.services)) {
|
||||
let value = this._enabledValues.services[key];
|
||||
if (value !== "start" && value !== "stop") {
|
||||
debug("Unexpected service " + key + " value:" + value);
|
||||
}
|
||||
|
||||
this._libcutils.property_set("ctl." + value, key);
|
||||
}
|
||||
|
||||
this._ksState = true;
|
||||
this.writeStateProperty();
|
||||
|
||||
resolve(true);
|
||||
}).catch(err => {
|
||||
DEBUG && debug("doEnable: " + err);
|
||||
|
||||
reject(false);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
saveUserValues: function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
this.checkLibcUtils();
|
||||
} catch (ex) {
|
||||
reject("nolibcutils");
|
||||
}
|
||||
|
||||
let _userValues = {
|
||||
settings: { },
|
||||
prefs: { },
|
||||
properties: { }
|
||||
};
|
||||
|
||||
// Those will be sync calls
|
||||
for (let key of Object.keys(this._enabledValues.prefs)) {
|
||||
_userValues.prefs[key] =
|
||||
this.getPref(key, this._enabledValues.prefs[key]);
|
||||
}
|
||||
|
||||
for (let key of Object.keys(this._enabledValues.properties)) {
|
||||
_userValues.properties[key] = this._libcutils.property_get(key);
|
||||
}
|
||||
|
||||
let self = this;
|
||||
let getCallback = {
|
||||
handleAbort: function(m) {
|
||||
DEBUG && debug("getCallback: handleAbort: m=" + m);
|
||||
reject(m);
|
||||
},
|
||||
|
||||
handleError: function(m) {
|
||||
DEBUG && debug("getCallback: handleError: m=" + m);
|
||||
reject(m);
|
||||
},
|
||||
|
||||
handle: function(n, v) {
|
||||
DEBUG && debug("getCallback: handle: n=" + n + " ; v=" + v);
|
||||
|
||||
if (self._pendingSettingsGet) {
|
||||
// We have received a settings callback value for saving user data
|
||||
let pending = self._pendingSettingsGet.indexOf(n);
|
||||
if (pending !== -1) {
|
||||
_userValues.settings[n] = v;
|
||||
self._pendingSettingsGet.splice(pending, 1);
|
||||
}
|
||||
|
||||
if (self._pendingSettingsGet.length === 0) {
|
||||
delete self._pendingSettingsGet;
|
||||
let payload = JSON.stringify(_userValues);
|
||||
DEBUG && debug("Dumping to " + kUserValues + ": " + payload);
|
||||
OS.File.writeAtomic(kUserValues, payload).then(
|
||||
function writeOk() {
|
||||
resolve(true);
|
||||
},
|
||||
function writeNok(err) {
|
||||
reject("write error");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// For settings we have to wait all the callbacks to come back before
|
||||
// we can resolve or reject
|
||||
this._pendingSettingsGet = [];
|
||||
let lock = settings.createLock();
|
||||
for (let key of Object.keys(this._enabledValues.settings)) {
|
||||
this._pendingSettingsGet.push(key);
|
||||
lock.get(key, getCallback);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
doDisable: function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.restoreUserValues().then(() => {
|
||||
this._ksState = false;
|
||||
this.writeStateProperty();
|
||||
|
||||
resolve(true);
|
||||
}).catch(err => {
|
||||
DEBUG && debug("doDisable: " + err);
|
||||
|
||||
reject(false);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
restoreUserValues: function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
this.checkLibcUtils();
|
||||
} catch (ex) {
|
||||
reject("nolibcutils");
|
||||
}
|
||||
|
||||
OS.File.read(kUserValues, { encoding: "utf-8" }).then(content => {
|
||||
let values = JSON.parse(content);
|
||||
|
||||
for (let key of Object.keys(values.prefs)) {
|
||||
this.setPref(key, values.prefs[key]);
|
||||
}
|
||||
|
||||
for (let key of Object.keys(values.properties)) {
|
||||
this._libcutils.property_set(key, values.properties[key]);
|
||||
}
|
||||
|
||||
let self = this;
|
||||
let saveCallback = {
|
||||
handleAbort: function(m) {
|
||||
DEBUG && debug("saveCallback: handleAbort: m=" + m);
|
||||
reject(m);
|
||||
},
|
||||
|
||||
handleError: function(m) {
|
||||
DEBUG && debug("saveCallback: handleError: m=" + m);
|
||||
reject(m);
|
||||
},
|
||||
|
||||
handle: function(n, v) {
|
||||
DEBUG && debug("saveCallback: handle: n=" + n + " ; v=" + v);
|
||||
|
||||
if (self._pendingSettingsSet) {
|
||||
// We have received a settings callback value for setting user data
|
||||
let pending = self._pendingSettingsSet.indexOf(n);
|
||||
if (pending !== -1) {
|
||||
self._pendingSettingsSet.splice(pending, 1);
|
||||
}
|
||||
|
||||
if (self._pendingSettingsSet.length === 0) {
|
||||
delete self._pendingSettingsSet;
|
||||
DEBUG && debug("Restored from " + kUserValues + ": " + JSON.stringify(values));
|
||||
resolve(values);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// For settings we have to wait all the callbacks to come back before
|
||||
// we can resolve or reject
|
||||
this._pendingSettingsSet = [];
|
||||
let lock = settings.createLock();
|
||||
for (let key of Object.keys(values.settings)) {
|
||||
this._pendingSettingsSet.push(key);
|
||||
lock.set(key, values.settings[key], saveCallback);
|
||||
}
|
||||
}).catch(err => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// Settings Callbacks
|
||||
handle: function(aName, aValue) {
|
||||
DEBUG && debug("handle: aName=" + aName + " ; aValue=" + aValue);
|
||||
// We don't have to do anything for now.
|
||||
},
|
||||
|
||||
handleAbort: function(aMessage) {
|
||||
debug("handleAbort: " + JSON.stringify(aMessage));
|
||||
throw Cr.NS_ERROR_ABORT;
|
||||
},
|
||||
|
||||
handleError: function(aMessage) {
|
||||
debug("handleError: " + JSON.stringify(aMessage));
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
},
|
||||
|
||||
// addObserver
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case kXpcomShutdownObserverTopic:
|
||||
this.uninit();
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG && debug("Wrong observer topic: " + aTopic);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
// addMessageListener
|
||||
receiveMessage: function(aMessage) {
|
||||
let hasPermission = aMessage.target.assertPermission("killswitch");
|
||||
DEBUG && debug("hasPermission: " + hasPermission);
|
||||
|
||||
if (!hasPermission) {
|
||||
debug("Message " + aMessage.name + " from a process with no killswitch perm.");
|
||||
aMessage.target.killChild();
|
||||
throw Cr.NS_ERROR_NOT_AVAILABLE;
|
||||
return;
|
||||
}
|
||||
|
||||
function returnMessage(name, data) {
|
||||
if (aMessage.target) {
|
||||
data.requestID = aMessage.data.requestID;
|
||||
try {
|
||||
aMessage.target.sendAsyncMessage(name, data);
|
||||
} catch (e) {
|
||||
if (DEBUG) debug("Return message failed, " + name + ": " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (aMessage.name) {
|
||||
case kEnableKillSwitch:
|
||||
this.doEnable().then(
|
||||
() => {
|
||||
returnMessage(kEnableKillSwitchOK, {});
|
||||
},
|
||||
err => {
|
||||
debug("doEnable failed: " + err);
|
||||
returnMessage(kEnableKillSwitchKO, {});
|
||||
}
|
||||
);
|
||||
break;
|
||||
case kDisableKillSwitch:
|
||||
this.doDisable().then(
|
||||
() => {
|
||||
returnMessage(kDisableKillSwitchOK, {});
|
||||
},
|
||||
err => {
|
||||
debug("doDisable failed: " + err);
|
||||
returnMessage(kDisableKillSwitchKO, {});
|
||||
}
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
debug("Unsupported message: " + aMessage.name);
|
||||
aMessage.target && aMessage.target.killChild();
|
||||
throw Cr.NS_ERROR_ILLEGAL_VALUE;
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// This code should ALWAYS be living only on the parent side.
|
||||
if (!inParent) {
|
||||
debug("KillSwitchMain should only be living on parent side.");
|
||||
throw Cr.NS_ERROR_ABORT;
|
||||
} else {
|
||||
this.KillSwitchMain.init();
|
||||
}
|
|
@ -18,6 +18,7 @@ EXTRA_COMPONENTS += [
|
|||
'FxAccountsUIGlue.js',
|
||||
'HelperAppDialog.js',
|
||||
'InterAppCommUIGlue.js',
|
||||
'KillSwitch.js',
|
||||
'MailtoProtocolHandler.js',
|
||||
'MobileIdentityUIGlue.js',
|
||||
'OMAContentHandler.js',
|
||||
|
@ -74,6 +75,10 @@ EXTRA_JS_MODULES += [
|
|||
'WebappsUpdater.jsm',
|
||||
]
|
||||
|
||||
EXTRA_PP_JS_MODULES += [
|
||||
'KillSwitchMain.jsm'
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
|
||||
EXTRA_JS_MODULES += [
|
||||
'GlobalSimulatorScreen.jsm'
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
let Ci = Components.interfaces;
|
||||
let Cc = Components.classes;
|
||||
let Cu = Components.utils;
|
||||
|
||||
// Stolen from SpecialPowers, since at this point we don't know we're in a test.
|
||||
let isMainProcess = function() {
|
||||
try {
|
||||
return Cc["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Ci.nsIXULRuntime)
|
||||
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
||||
} catch (e) { }
|
||||
return true;
|
||||
};
|
||||
|
||||
var fakeLibcUtils = {
|
||||
_props_: {},
|
||||
property_set: function(name, value) {
|
||||
dump("property_set('" + name + "', '" + value+ "' [" + (typeof value) + "]);\n");
|
||||
this._props_[name] = value;
|
||||
},
|
||||
property_get: function(name, defaultValue) {
|
||||
dump("property_get('" + name + "', '" + defaultValue+ "');\n");
|
||||
if (Object.keys(this._props_).indexOf(name) !== -1) {
|
||||
return this._props_[name];
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var kUserValues;
|
||||
|
||||
function installUserValues(next) {
|
||||
var fakeValues = {
|
||||
settings: {
|
||||
"lockscreen.locked": false,
|
||||
"lockscreen.lock-immediately": false
|
||||
},
|
||||
prefs: {
|
||||
"b2g.killswitch.test": false
|
||||
},
|
||||
properties: {
|
||||
"dalvik.vm.heapmaxfree": "32m",
|
||||
"dalvik.vm.isa.arm.features": "fdiv",
|
||||
"dalvik.vm.lockprof.threshold": "5000",
|
||||
"net.bt.name": "BTAndroid",
|
||||
"dalvik.vm.stack-trace-file": "/data/anr/stack-traces.txt"
|
||||
}
|
||||
};
|
||||
|
||||
OS.File.writeAtomic(kUserValues,
|
||||
JSON.stringify(fakeValues)).then(() => {
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
if (isMainProcess()) {
|
||||
Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
Cu.import("resource://gre/modules/KillSwitchMain.jsm");
|
||||
|
||||
kUserValues = OS.Path.join(OS.Constants.Path.profileDir, "killswitch.json");
|
||||
|
||||
installUserValues(() => {
|
||||
KillSwitchMain._libcutils = fakeLibcUtils;
|
||||
});
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
function setupSettings(target) {
|
||||
ok((Object.keys(initialSettingsValues).length > 0), "Has at least one setting");
|
||||
|
||||
Object.keys(initialSettingsValues).forEach(k => {
|
||||
ok(Object.keys(target).indexOf(k) !== -1, "Same settings set");
|
||||
});
|
||||
|
||||
var lock = navigator.mozSettings.createLock();
|
||||
lock.set(initialSettingsValues);
|
||||
}
|
||||
|
||||
function testSettingsInitial(next) {
|
||||
var promises = [];
|
||||
for (var setting in initialSettingsValues) {
|
||||
promises.push(navigator.mozSettings.createLock().get(setting));
|
||||
}
|
||||
|
||||
Promise.all(promises).then(values => {
|
||||
values.forEach(set => {
|
||||
var key = Object.keys(set)[0];
|
||||
var value = set[key];
|
||||
is(value, initialSettingsValues[key], "Value of " + key + " is initial one");
|
||||
});
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
function testSettingsExpected(target, next) {
|
||||
var promises = [];
|
||||
for (var setting in initialSettingsValues) {
|
||||
promises.push(navigator.mozSettings.createLock().get(setting));
|
||||
}
|
||||
|
||||
Promise.all(promises).then(values => {
|
||||
values.forEach(set => {
|
||||
var key = Object.keys(set)[0];
|
||||
var value = set[key];
|
||||
is(value, target[key], "Value of " + key + " is expected one");
|
||||
});
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
function testSetPrefValue(prefName, prefValue) {
|
||||
switch (typeof prefValue) {
|
||||
case "boolean":
|
||||
SpecialPowers.setBoolPref(prefName, prefValue);
|
||||
break;
|
||||
|
||||
case "number":
|
||||
SpecialPowers.setIntPref(prefName, prefValue);
|
||||
break;
|
||||
|
||||
case "string":
|
||||
SpecialPowers.setCharPref(prefName, prefValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
is(false, "Unexpected pref type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function testGetPrefValue(prefName, prefValue) {
|
||||
var rv = undefined;
|
||||
|
||||
switch (typeof prefValue) {
|
||||
case "boolean":
|
||||
rv = SpecialPowers.getBoolPref(prefName);
|
||||
break;
|
||||
|
||||
case "number":
|
||||
rv = SpecialPowers.getIntPref(prefName);
|
||||
break;
|
||||
|
||||
case "string":
|
||||
rv = SpecialPowers.getCharPref(prefName);
|
||||
break;
|
||||
|
||||
default:
|
||||
is(false, "Unexpected pref type");
|
||||
break;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
function setupPrefs(target) {
|
||||
ok((Object.keys(initialPrefsValues).length > 0), "Has at least one pref");
|
||||
|
||||
Object.keys(initialPrefsValues).forEach(k => {
|
||||
ok(Object.keys(target).indexOf(k) !== -1, "Same pref set");
|
||||
});
|
||||
|
||||
Object.keys(initialPrefsValues).forEach(key => {
|
||||
testSetPrefValue(key, initialPrefsValues[key]);
|
||||
});
|
||||
}
|
||||
|
||||
function testPrefsInitial() {
|
||||
Object.keys(initialPrefsValues).forEach(key => {
|
||||
var value = testGetPrefValue(key, initialPrefsValues[key]);
|
||||
is(value, initialPrefsValues[key], "Value of " + key + " is initial one");
|
||||
});
|
||||
}
|
||||
|
||||
function testPrefsExpected(target) {
|
||||
Object.keys(target).forEach(key => {
|
||||
var value = testGetPrefValue(key, target[key]);
|
||||
is(value, target[key], "Value of " + key + " is initial one");
|
||||
});
|
||||
}
|
||||
|
||||
function finish() {
|
||||
SpecialPowers.removePermission("killswitch", document);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function addPermissions() {
|
||||
if (SpecialPowers.hasPermission("killswitch", document)) {
|
||||
startTests();
|
||||
} else {
|
||||
var allow = SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
[ "killswitch", "settings-api-read", "settings-api-write",
|
||||
"settings-read", "settings-write", "settings-clear"
|
||||
].forEach(perm => {
|
||||
SpecialPowers.addPermission(perm, allow, document);
|
||||
});
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
function loadSettings() {
|
||||
var url = SimpleTest.getTestFileURL("file_loadserver.js");
|
||||
var script = SpecialPowers.loadChromeScript(url);
|
||||
}
|
||||
|
||||
function addPrefs() {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.ignore_webidl_scope_checks", true],
|
||||
["dom.mozKillSwitch.enabled", true],
|
||||
]}, addPermissions);
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
[DEFAULT]
|
||||
skip-if = toolkit != "gonk"
|
||||
support-files =
|
||||
permission_handler_chrome.js
|
||||
SandboxPromptTest.html
|
||||
|
@ -8,14 +7,27 @@ support-files =
|
|||
systemapp_helper.js
|
||||
presentation_prompt_handler_chrome.js
|
||||
presentation_ui_glue_handler_chrome.js
|
||||
file_loadserver.js
|
||||
killswitch.js
|
||||
|
||||
[test_filepicker_path.html]
|
||||
skip-if = toolkit != "gonk"
|
||||
[test_permission_deny.html]
|
||||
skip-if = toolkit != "gonk"
|
||||
[test_permission_gum_remember.html]
|
||||
skip-if = true # Bug 1019572 - frequent timeouts
|
||||
[test_sandbox_permission.html]
|
||||
skip-if = toolkit != "gonk"
|
||||
[test_screenshot.html]
|
||||
skip-if = toolkit != "gonk"
|
||||
[test_systemapp.html]
|
||||
skip-if = toolkit != "gonk"
|
||||
[test_presentation_device_prompt.html]
|
||||
skip-if = toolkit != "gonk"
|
||||
[test_permission_visibilitychange.html]
|
||||
skip-if = toolkit != "gonk"
|
||||
[test_presentation_request_ui_glue.html]
|
||||
skip-if = toolkit != "gonk"
|
||||
[test_killswitch_basics.html]
|
||||
[test_killswitch_disable.html]
|
||||
[test_killswitch_enable.html]
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Enabling of killswitch feature</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
"use strict";
|
||||
|
||||
function testNotExposed(check) {
|
||||
ok(!("mozKillSwitch" in navigator),
|
||||
"mozKillSwitch not exposed in navigator: " + check);
|
||||
}
|
||||
|
||||
function testIsExposed() {
|
||||
ok(("mozKillSwitch" in navigator), "mozKillSwitch is exposed in navigator");
|
||||
ok(("enable" in navigator.mozKillSwitch), "mozKillSwitch has |enable|");
|
||||
ok(("disable" in navigator.mozKillSwitch), "mozKillSwitch has |disable|");
|
||||
}
|
||||
|
||||
function continueTests() {
|
||||
// Now we should have it!
|
||||
testIsExposed();
|
||||
finish();
|
||||
}
|
||||
|
||||
function finish() {
|
||||
SpecialPowers.removePermission("killswitch", document);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function alreadyHasPermission() {
|
||||
return SpecialPowers.hasPermission("killswitch", document);
|
||||
}
|
||||
|
||||
function addPermission() {
|
||||
var allow = SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
SpecialPowers.addPermission("killswitch", allow, document);
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
function addPrefIgnoreWebIDL(next) {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.ignore_webidl_scope_checks", true],
|
||||
]}, next);
|
||||
}
|
||||
|
||||
function addPrefKillSwitch(next) {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.mozKillSwitch.enabled", true],
|
||||
]}, next);
|
||||
}
|
||||
|
||||
function startTests() {
|
||||
if (alreadyHasPermission()) {
|
||||
continueTests();
|
||||
} else {
|
||||
// Make sure it's not exposed
|
||||
testNotExposed("webidl, pref, perm");
|
||||
|
||||
// Expose certified APIs
|
||||
addPrefIgnoreWebIDL(() => {
|
||||
// Still not exposed because not perm and pref
|
||||
testNotExposed("pref, perm");
|
||||
|
||||
// Add the kill switch pref
|
||||
addPrefKillSwitch(() => {
|
||||
// Still not exposed because not perm
|
||||
testNotExposed("perm");
|
||||
|
||||
// Will reload the page
|
||||
addPermission();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
startTests();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,65 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Disabling of killswitch feature</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
|
||||
</script>
|
||||
<script type="application/javascript" src="killswitch.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
"use strict";
|
||||
|
||||
var initialSettingsValues = {
|
||||
"lockscreen.locked": true,
|
||||
"lockscreen.lock-immediately": true
|
||||
};
|
||||
|
||||
var initialPrefsValues = {
|
||||
"b2g.killswitch.test": true
|
||||
};
|
||||
|
||||
var disabledSettingsExpected = {
|
||||
"lockscreen.locked": false,
|
||||
"lockscreen.lock-immediately": false
|
||||
};
|
||||
|
||||
var disabledPrefsExpected = {
|
||||
"b2g.killswitch.test": false
|
||||
};
|
||||
|
||||
function testDoAction() {
|
||||
return navigator.mozKillSwitch.disable();
|
||||
}
|
||||
|
||||
function startTests() {
|
||||
setupSettings(disabledSettingsExpected);
|
||||
setupPrefs(initialPrefsValues);
|
||||
testSettingsInitial(() => {
|
||||
testPrefsInitial();
|
||||
testDoAction().then(() => {
|
||||
testSettingsExpected(disabledSettingsExpected, () => {
|
||||
testPrefsExpected(disabledPrefsExpected);
|
||||
finish();
|
||||
});
|
||||
}).catch(() => {
|
||||
ok(false, "KillSwitch promise failed");
|
||||
finish();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
loadSettings();
|
||||
addPrefs();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,65 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Enabling of killswitch feature</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
|
||||
</script>
|
||||
<script type="application/javascript" src="killswitch.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
"use strict";
|
||||
|
||||
var initialSettingsValues = {
|
||||
"lockscreen.locked": false,
|
||||
"lockscreen.lock-immediately": false
|
||||
};
|
||||
|
||||
var initialPrefsValues = {
|
||||
"b2g.killswitch.test": false
|
||||
};
|
||||
|
||||
var enabledSettingsExpected = {
|
||||
"lockscreen.locked": true,
|
||||
"lockscreen.lock-immediately": true
|
||||
};
|
||||
|
||||
var enabledPrefsExpected = {
|
||||
"b2g.killswitch.test": true
|
||||
};
|
||||
|
||||
function testDoAction() {
|
||||
return navigator.mozKillSwitch.enable();
|
||||
}
|
||||
|
||||
function startTests() {
|
||||
setupSettings(enabledSettingsExpected);
|
||||
setupPrefs(initialPrefsValues);
|
||||
testSettingsInitial(() => {
|
||||
testPrefsInitial();
|
||||
testDoAction().then(() => {
|
||||
testSettingsExpected(enabledSettingsExpected, () => {
|
||||
testPrefsExpected(enabledPrefsExpected);
|
||||
finish();
|
||||
});
|
||||
}).catch(() => {
|
||||
ok(false, "KillSwitch promise failed");
|
||||
finish();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
loadSettings();
|
||||
addPrefs();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,425 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
|
||||
|
||||
let kUserValues;
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
Cu.import("resource://gre/modules/KillSwitchMain.jsm");
|
||||
|
||||
check_enabledValues();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function check_enabledValues() {
|
||||
let expected = {
|
||||
settings: {
|
||||
"debugger.remote-mode": "disabled",
|
||||
"developer.menu.enabled": false,
|
||||
"devtools.unrestricted": false,
|
||||
"lockscreen.enabled": true,
|
||||
"lockscreen.locked": true,
|
||||
"lockscreen.lock-immediately": true,
|
||||
"tethering.usb.enabled": false,
|
||||
"tethering.wifi.enabled": false,
|
||||
"ums.enabled": false
|
||||
},
|
||||
prefs: {
|
||||
"b2g.killswitch.test": true
|
||||
},
|
||||
properties: {
|
||||
"persist.sys.usb.config": "none"
|
||||
},
|
||||
services: {
|
||||
"adbd": "stop"
|
||||
}
|
||||
};
|
||||
|
||||
for (let key of Object.keys(KillSwitchMain._enabledValues.settings)) {
|
||||
strictEqual(expected.settings[key],
|
||||
KillSwitchMain._enabledValues.settings[key],
|
||||
"setting " + key);
|
||||
}
|
||||
|
||||
for (let key of Object.keys(KillSwitchMain._enabledValues.prefs)) {
|
||||
strictEqual(expected.prefs[key],
|
||||
KillSwitchMain._enabledValues.prefs[key],
|
||||
"pref " + key);
|
||||
}
|
||||
|
||||
for (let key of Object.keys(KillSwitchMain._enabledValues.properties)) {
|
||||
strictEqual(expected.properties[key],
|
||||
KillSwitchMain._enabledValues.properties[key],
|
||||
"proprety " + key);
|
||||
}
|
||||
|
||||
for (let key of Object.keys(KillSwitchMain._enabledValues.services)) {
|
||||
strictEqual(expected.services[key],
|
||||
KillSwitchMain._enabledValues.services[key],
|
||||
"service " + key);
|
||||
}
|
||||
}
|
||||
|
||||
add_test(function test_prepareTestValues() {
|
||||
if (("adbd" in KillSwitchMain._enabledValues.services)) {
|
||||
strictEqual(KillSwitchMain._enabledValues.services["adbd"], "stop");
|
||||
|
||||
// We replace those for the test because on Gonk we will loose the control
|
||||
KillSwitchMain._enabledValues.settings = {
|
||||
"lockscreen.locked": true,
|
||||
"lockscreen.lock-immediately": true
|
||||
};
|
||||
KillSwitchMain._enabledValues.services = {};
|
||||
KillSwitchMain._enabledValues.properties = {
|
||||
"dalvik.vm.heapmaxfree": "8m",
|
||||
"dalvik.vm.isa.arm.features": "div",
|
||||
"dalvik.vm.lockprof.threshold": "500",
|
||||
"net.bt.name": "Android",
|
||||
"dalvik.vm.stack-trace-file": "/data/anr/traces.txt"
|
||||
}
|
||||
}
|
||||
|
||||
kUserValues = OS.Path.join(OS.Constants.Path.profileDir, "killswitch.json");
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
function reset_status() {
|
||||
KillSwitchMain._ksState = undefined;
|
||||
KillSwitchMain._libcutils.property_set("persist.moz.killswitch", "undefined");
|
||||
}
|
||||
|
||||
function install_common_tests() {
|
||||
add_test(function test_readStateProperty() {
|
||||
KillSwitchMain._libcutils.property_set("persist.moz.killswitch", "false");
|
||||
KillSwitchMain.readStateProperty();
|
||||
strictEqual(KillSwitchMain._ksState, false);
|
||||
|
||||
KillSwitchMain._libcutils.property_set("persist.moz.killswitch", "true");
|
||||
KillSwitchMain.readStateProperty();
|
||||
strictEqual(KillSwitchMain._ksState, true);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_writeStateProperty() {
|
||||
KillSwitchMain._ksState = false;
|
||||
KillSwitchMain.writeStateProperty();
|
||||
let state = KillSwitchMain._libcutils.property_get("persist.moz.killswitch");
|
||||
strictEqual(state, "false");
|
||||
|
||||
KillSwitchMain._ksState = true;
|
||||
KillSwitchMain.writeStateProperty();
|
||||
state = KillSwitchMain._libcutils.property_get("persist.moz.killswitch");
|
||||
strictEqual(state, "true");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_doEnable() {
|
||||
reset_status();
|
||||
|
||||
let enable = KillSwitchMain.doEnable();
|
||||
ok(enable, "should have a Promise");
|
||||
|
||||
enable.then(() => {
|
||||
strictEqual(KillSwitchMain._ksState, true);
|
||||
let state = KillSwitchMain._libcutils.property_get("persist.moz.killswitch");
|
||||
strictEqual(state, "true");
|
||||
|
||||
run_next_test();
|
||||
}).catch(err => {
|
||||
ok(false, "should have succeeded");
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_enableMessage() {
|
||||
reset_status();
|
||||
|
||||
let listener = {
|
||||
assertPermission: function() {
|
||||
return true;
|
||||
},
|
||||
sendAsyncMessage: function(name, data) {
|
||||
strictEqual(name, "KillSwitch:Enable:OK");
|
||||
strictEqual(data.requestID, 1);
|
||||
|
||||
let state = KillSwitchMain._libcutils.property_get("persist.moz.killswitch");
|
||||
strictEqual(state, "true");
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
};
|
||||
|
||||
KillSwitchMain.receiveMessage({
|
||||
name: "KillSwitch:Enable",
|
||||
target: listener,
|
||||
data: {
|
||||
requestID: 1
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_saveUserValues_prepare() {
|
||||
reset_status();
|
||||
|
||||
OS.File.exists(kUserValues).then(e => {
|
||||
if (e) {
|
||||
OS.File.remove(kUserValues).then(() => {
|
||||
run_next_test();
|
||||
}).catch(err => {
|
||||
ok(false, "should have succeeded");
|
||||
run_next_test();
|
||||
});
|
||||
} else {
|
||||
run_next_test();
|
||||
}
|
||||
}).catch(err => {
|
||||
ok(false, "should have succeeded");
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_saveUserValues() {
|
||||
reset_status();
|
||||
|
||||
let expectedValues = Object.assign({}, KillSwitchMain._enabledValues);
|
||||
|
||||
// Reset _enabledValues so we check properly that the dumped state
|
||||
// is the current device state
|
||||
KillSwitchMain._enabledValues = {
|
||||
settings: {
|
||||
"lockscreen.locked": false,
|
||||
"lockscreen.lock-immediately": false
|
||||
},
|
||||
prefs: {
|
||||
"b2g.killswitch.test": false
|
||||
},
|
||||
properties: {
|
||||
"dalvik.vm.heapmaxfree": "32m",
|
||||
"dalvik.vm.isa.arm.features": "fdiv",
|
||||
"dalvik.vm.lockprof.threshold": "5000",
|
||||
"net.bt.name": "BTAndroid",
|
||||
"dalvik.vm.stack-trace-file": "/data/anr/stack-traces.txt"
|
||||
},
|
||||
services: {}
|
||||
};
|
||||
|
||||
KillSwitchMain.saveUserValues().then(e => {
|
||||
ok(e, "should have succeeded");
|
||||
|
||||
OS.File.read(kUserValues, { encoding: "utf-8" }).then(content => {
|
||||
let obj = JSON.parse(content);
|
||||
|
||||
deepEqual(obj.settings, expectedValues.settings);
|
||||
notDeepEqual(obj.settings, KillSwitchMain._enabledValues.settings);
|
||||
|
||||
deepEqual(obj.prefs, expectedValues.prefs);
|
||||
notDeepEqual(obj.prefs, KillSwitchMain._enabledValues.prefs);
|
||||
|
||||
deepEqual(obj.properties, expectedValues.properties);
|
||||
notDeepEqual(obj.properties, KillSwitchMain._enabledValues.properties);
|
||||
|
||||
run_next_test();
|
||||
}).catch(err => {
|
||||
ok(false, "should have succeeded");
|
||||
run_next_test();
|
||||
});
|
||||
}).catch(err => {
|
||||
ok(false, "should have succeeded");
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_saveUserValues_cleaup() {
|
||||
reset_status();
|
||||
|
||||
OS.File.exists(kUserValues).then(e => {
|
||||
if (e) {
|
||||
OS.File.remove(kUserValues).then(() => {
|
||||
ok(true, "should have had a file");
|
||||
run_next_test();
|
||||
}).catch(err => {
|
||||
ok(false, "should have succeeded");
|
||||
run_next_test();
|
||||
});
|
||||
} else {
|
||||
ok(false, "should have had a file");
|
||||
run_next_test();
|
||||
}
|
||||
}).catch(err => {
|
||||
ok(false, "should have succeeded");
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_restoreUserValues_prepare() {
|
||||
reset_status();
|
||||
|
||||
let fakeValues = {
|
||||
settings: {
|
||||
"lockscreen.locked": false,
|
||||
"lockscreen.lock-immediately": false
|
||||
},
|
||||
prefs: {
|
||||
"b2g.killswitch.test": false
|
||||
},
|
||||
properties: {
|
||||
"dalvik.vm.heapmaxfree": "32m",
|
||||
"dalvik.vm.isa.arm.features": "fdiv",
|
||||
"dalvik.vm.lockprof.threshold": "5000",
|
||||
"net.bt.name": "BTAndroid",
|
||||
"dalvik.vm.stack-trace-file": "/data/anr/stack-traces.txt"
|
||||
}
|
||||
};
|
||||
|
||||
OS.File.exists(kUserValues).then(e => {
|
||||
if (!e) {
|
||||
OS.File.writeAtomic(kUserValues,
|
||||
JSON.stringify(fakeValues)).then(() => {
|
||||
ok(true, "success writing file");
|
||||
run_next_test();
|
||||
}, err => {
|
||||
ok(false, "error writing file");
|
||||
run_next_test();
|
||||
});
|
||||
} else {
|
||||
ok(false, "file should not have been there");
|
||||
run_next_test();
|
||||
}
|
||||
}).catch(err => {
|
||||
ok(false, "should have succeeded");
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_restoreUserValues() {
|
||||
reset_status();
|
||||
|
||||
KillSwitchMain.restoreUserValues().then(e => {
|
||||
ok(e, "should have succeeded");
|
||||
|
||||
strictEqual(e.settings["lockscreen.locked"], false);
|
||||
strictEqual(e.settings["lockscreen.lock-immediately"], false);
|
||||
|
||||
strictEqual(e.prefs["b2g.killswitch.test"], false);
|
||||
|
||||
strictEqual(
|
||||
e.properties["dalvik.vm.heapmaxfree"],
|
||||
"32m");
|
||||
strictEqual(
|
||||
e.properties["dalvik.vm.isa.arm.features"],
|
||||
"fdiv");
|
||||
strictEqual(
|
||||
e.properties["dalvik.vm.lockprof.threshold"],
|
||||
"5000");
|
||||
strictEqual(
|
||||
e.properties["net.bt.name"],
|
||||
"BTAndroid");
|
||||
strictEqual(
|
||||
e.properties["dalvik.vm.stack-trace-file"],
|
||||
"/data/anr/stack-traces.txt");
|
||||
|
||||
strictEqual(
|
||||
KillSwitchMain._libcutils.property_get("dalvik.vm.heapmaxfree"),
|
||||
"32m");
|
||||
strictEqual(
|
||||
KillSwitchMain._libcutils.property_get("dalvik.vm.isa.arm.features"),
|
||||
"fdiv");
|
||||
strictEqual(
|
||||
KillSwitchMain._libcutils.property_get("dalvik.vm.lockprof.threshold"),
|
||||
"5000");
|
||||
strictEqual(
|
||||
KillSwitchMain._libcutils.property_get("net.bt.name"),
|
||||
"BTAndroid");
|
||||
strictEqual(
|
||||
KillSwitchMain._libcutils.property_get("dalvik.vm.stack-trace-file"),
|
||||
"/data/anr/stack-traces.txt");
|
||||
|
||||
run_next_test();
|
||||
}).catch(err => {
|
||||
ok(false, "should not have had an error");
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_doDisable() {
|
||||
reset_status();
|
||||
|
||||
let disable = KillSwitchMain.doDisable()
|
||||
ok(disable, "should have a Promise");
|
||||
|
||||
disable.then(() => {
|
||||
strictEqual(KillSwitchMain._ksState, false);
|
||||
let state = KillSwitchMain._libcutils.property_get("persist.moz.killswitch");
|
||||
strictEqual(state, "false");
|
||||
|
||||
run_next_test();
|
||||
}).catch(err => {
|
||||
ok(false, "should have succeeded");
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_disableMessage() {
|
||||
reset_status();
|
||||
|
||||
let listener = {
|
||||
assertPermission: function() {
|
||||
return true;
|
||||
},
|
||||
sendAsyncMessage: function(name, data) {
|
||||
strictEqual(name, "KillSwitch:Disable:OK");
|
||||
strictEqual(data.requestID, 2);
|
||||
|
||||
let state = KillSwitchMain._libcutils.property_get("persist.moz.killswitch");
|
||||
strictEqual(state, "false");
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
};
|
||||
|
||||
KillSwitchMain.receiveMessage({
|
||||
name: "KillSwitch:Disable",
|
||||
target: listener,
|
||||
data: {
|
||||
requestID: 2
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_doEnable_only_once() {
|
||||
reset_status();
|
||||
|
||||
let firstEnable = KillSwitchMain.doEnable();
|
||||
ok(firstEnable, "should have a first Promise");
|
||||
|
||||
firstEnable.then(() => {
|
||||
let secondEnable = KillSwitchMain.doEnable();
|
||||
ok(secondEnable, "should have a second Promise");
|
||||
|
||||
secondEnable.then(() => {
|
||||
ok(false, "second enable should have not succeeded");
|
||||
run_next_test();
|
||||
}).catch(err => {
|
||||
strictEqual(err, true, "second enable should reject(true);");
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
}).catch(err => {
|
||||
ok(false, "first enable should have succeeded");
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {results: Cr} = Components;
|
||||
|
||||
// Trivial test just to make sure we have no syntax error
|
||||
add_test(function test_ksm_ok() {
|
||||
ok(KillSwitchMain, "KillSwitchMain object exists");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
let aMessageNoPerm = {
|
||||
name: "KillSwitch:Enable",
|
||||
target: {
|
||||
assertPermission: function() {
|
||||
return false;
|
||||
},
|
||||
killChild: function() { }
|
||||
}
|
||||
};
|
||||
|
||||
let aMessageWithPerm = {
|
||||
name: "KillSwitch:Enable",
|
||||
target: {
|
||||
assertPermission: function() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
data: {
|
||||
requestID: 0
|
||||
}
|
||||
};
|
||||
|
||||
add_test(function test_sendMessageWithoutPerm() {
|
||||
try {
|
||||
KillSwitchMain.receiveMessage(aMessageNoPerm);
|
||||
ok(false, "Should have failed");
|
||||
} catch (ex) {
|
||||
// strictEqual(ex, Cr.NS_ERROR_NOT_AVAILABLE);
|
||||
}
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_sendMessageWithPerm() {
|
||||
let rv = KillSwitchMain.receiveMessage(aMessageWithPerm);
|
||||
strictEqual(rv, undefined);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
let uMessage = {
|
||||
name: "KillSwitch:WTF",
|
||||
target: {
|
||||
assertPermission: function() {
|
||||
return true;
|
||||
},
|
||||
killChild: function() { }
|
||||
}
|
||||
};
|
||||
|
||||
add_test(function test_sendUnknownMessage() {
|
||||
try {
|
||||
KillSwitchMain.receiveMessage(uMessage);
|
||||
ok(false, "Should have failed");
|
||||
} catch (ex) {
|
||||
strictEqual(ex, Cr.NS_ERROR_ILLEGAL_VALUE);
|
||||
}
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
let fakeLibcUtils = {
|
||||
_props_: {},
|
||||
property_set: function(name, value) {
|
||||
dump("property_set('" + name + "', '" + value+ "' [" + (typeof value) + "]);\n");
|
||||
this._props_[name] = value;
|
||||
},
|
||||
property_get: function(name, defaultValue) {
|
||||
dump("property_get('" + name + "', '" + defaultValue+ "');\n");
|
||||
if (Object.keys(this._props_).indexOf(name) !== -1) {
|
||||
return this._props_[name];
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
add_test(function test_nolibcutils() {
|
||||
KillSwitchMain._libcutils = null;
|
||||
try {
|
||||
KillSwitchMain.checkLibcUtils();
|
||||
ok(false, "Should have failed");
|
||||
} catch (ex) {
|
||||
strictEqual(ex, Cr.NS_ERROR_NO_INTERFACE);
|
||||
}
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_install_fakelibcutils() {
|
||||
KillSwitchMain._libcutils = fakeLibcUtils;
|
||||
let rv = KillSwitchMain.checkLibcUtils();
|
||||
strictEqual(rv, true);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
install_common_tests();
|
|
@ -0,0 +1,42 @@
|
|||
/* 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/. */
|
||||
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "libcutils", function () {
|
||||
Cu.import("resource://gre/modules/systemlibs.js");
|
||||
return libcutils;
|
||||
});
|
||||
|
||||
// Trivial test just to make sure we have no syntax error
|
||||
add_test(function test_ksm_ok() {
|
||||
ok(KillSwitchMain, "KillSwitchMain object exists");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_has_libcutils() {
|
||||
let rv = KillSwitchMain.checkLibcUtils();
|
||||
strictEqual(rv, true);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_libcutils_works() {
|
||||
KillSwitchMain._libcutils.property_set("ro.moz.ks_test", "wesh");
|
||||
let rv_ks_get = KillSwitchMain._libcutils.property_get("ro.moz.ks_test");
|
||||
strictEqual(rv_ks_get, "wesh")
|
||||
let rv_sys_get = libcutils.property_get("ro.moz.ks_test")
|
||||
strictEqual(rv_sys_get, "wesh")
|
||||
|
||||
KillSwitchMain._libcutils.property_set("ro.moz.ks_test2", "123456789");
|
||||
rv_ks_get = KillSwitchMain._libcutils.property_get("ro.moz.ks_test2");
|
||||
strictEqual(rv_ks_get, "123456789")
|
||||
rv_sys_get = libcutils.property_get("ro.moz.ks_test2")
|
||||
strictEqual(rv_sys_get, "123456789")
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
install_common_tests();
|
|
@ -41,3 +41,12 @@ head = head_logshake_gonk.js
|
|||
skip-if = (toolkit != "gonk")
|
||||
|
||||
[test_aboutserviceworkers.js]
|
||||
|
||||
[test_killswitch.js]
|
||||
head = file_killswitch.js
|
||||
skip-if = (toolkit == "gonk")
|
||||
|
||||
[test_killswitch_gonk.js]
|
||||
head = file_killswitch.js
|
||||
# Bug 1193677: disable on B2G ICS Emulator for intermittent failures with IndexedDB
|
||||
skip-if = ((toolkit != "gonk") || (toolkit == "gonk" && debug))
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6641107c83e718d9896f90a9529ad0c252ddc271"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
|
||||
|
@ -73,7 +73,7 @@
|
|||
<project name="platform/external/libselinux" path="external/libselinux" revision="1e2cf2c4a2d15a9b1ca2d353b99fb6884413ffe1"/>
|
||||
<project name="platform/external/libsepol" path="external/libsepol" revision="edc447a138ec77236f1cbfd36c1211a38ba21418"/>
|
||||
<project name="platform/external/libvpx" path="external/libvpx" revision="ca9281af0bfe816f1ae2fc3e8771524164a0a03c"/>
|
||||
<project name="platform/external/mdnsresponder" path="external/mdnsresponder" revision="c46f53f5e072f23051c4eedef730386f7634dc11"/>
|
||||
<project name="platform/external/mdnsresponder" path="external/mdnsresponder" remote="caf" revision="dd17df3f6775c4366a5c1d21865370d60a3b1295"/>
|
||||
<project name="platform/external/mksh" path="external/mksh" revision="f8c396c4d446a038358106a301b329607a04633d"/>
|
||||
<project name="platform/external/netcat" path="external/netcat" revision="444644cfa9a2f3002863caa168fb2d6b34dfd1e8"/>
|
||||
<project name="platform/external/openssl" path="external/openssl" revision="bb8428f762b3632f493572c4f73957e1281ade79"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6641107c83e718d9896f90a9529ad0c252ddc271"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
|
||||
|
@ -74,7 +74,7 @@
|
|||
<project name="platform/external/libselinux" path="external/libselinux" revision="1e2cf2c4a2d15a9b1ca2d353b99fb6884413ffe1"/>
|
||||
<project name="platform/external/libsepol" path="external/libsepol" revision="8fd7c65a336d45d5225f32363a9f26c1e3e60c3c"/>
|
||||
<project name="platform/external/libvpx" path="external/libvpx" revision="5e563eddf3e143a4b670766b49f676ce39023322"/>
|
||||
<project name="platform/external/mdnsresponder" path="external/mdnsresponder" revision="c46f53f5e072f23051c4eedef730386f7634dc11"/>
|
||||
<project name="platform/external/mdnsresponder" path="external/mdnsresponder" remote="caf" revision="dd17df3f6775c4366a5c1d21865370d60a3b1295"/>
|
||||
<project name="platform/external/mksh" path="external/mksh" revision="f8c396c4d446a038358106a301b329607a04633d"/>
|
||||
<project name="platform/external/netcat" path="external/netcat" revision="444644cfa9a2f3002863caa168fb2d6b34dfd1e8"/>
|
||||
<project name="platform/external/openssl" path="external/openssl" revision="bb8428f762b3632f493572c4f73957e1281ade79"/>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6641107c83e718d9896f90a9529ad0c252ddc271"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6641107c83e718d9896f90a9529ad0c252ddc271"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
|
||||
|
@ -74,7 +74,7 @@
|
|||
<project name="platform/external/libselinux" path="external/libselinux" revision="f2a93748f1974a76f1676f66049b3a29f1b4e532"/>
|
||||
<project name="platform/external/libsepol" path="external/libsepol" revision="cf9b75ee1949969c6620fcbec854e67a305dbbc7"/>
|
||||
<project name="platform/external/libvpx" path="external/libvpx" revision="11e4fb71a745e7d0f76099f8861d7e6083c104fa"/>
|
||||
<project name="platform/external/mdnsresponder" path="external/mdnsresponder" revision="dcea77d81cd32b7874b1e26a6474e34917326472"/>
|
||||
<project name="platform/external/mdnsresponder" path="external/mdnsresponder" remote="caf" revision="dd17df3f6775c4366a5c1d21865370d60a3b1295"/>
|
||||
<project name="platform/external/mksh" path="external/mksh" revision="221fb0e62a39d4cedd6469a048cadb28fbf01a96"/>
|
||||
<project name="platform/external/netcat" path="external/netcat" revision="0c2bf20f00ca9d74080a75eda76d0a5550702eaa"/>
|
||||
<project name="platform/external/openssl" path="external/openssl" revision="aa09f63881e72abb398d301c8c19c56583790c84"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="05a36844c1046a1eb07d5b1325f85ed741f961ea">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6641107c83e718d9896f90a9529ad0c252ddc271"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
|
||||
<project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="337e0ef5e40f02a1ae59b90db0548976c70a7226"/>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6641107c83e718d9896f90a9529ad0c252ddc271"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
|
||||
|
@ -72,7 +72,7 @@
|
|||
<project name="platform/external/libselinux" path="external/libselinux" revision="1e2cf2c4a2d15a9b1ca2d353b99fb6884413ffe1"/>
|
||||
<project name="platform/external/libsepol" path="external/libsepol" revision="edc447a138ec77236f1cbfd36c1211a38ba21418"/>
|
||||
<project name="platform/external/libvpx" path="external/libvpx" revision="ca9281af0bfe816f1ae2fc3e8771524164a0a03c"/>
|
||||
<project name="platform/external/mdnsresponder" path="external/mdnsresponder" revision="c46f53f5e072f23051c4eedef730386f7634dc11"/>
|
||||
<project name="platform/external/mdnsresponder" path="external/mdnsresponder" remote="caf" revision="dd17df3f6775c4366a5c1d21865370d60a3b1295"/>
|
||||
<project name="platform/external/mksh" path="external/mksh" revision="f8c396c4d446a038358106a301b329607a04633d"/>
|
||||
<project name="platform/external/netcat" path="external/netcat" revision="444644cfa9a2f3002863caa168fb2d6b34dfd1e8"/>
|
||||
<project name="platform/external/openssl" path="external/openssl" revision="bb8428f762b3632f493572c4f73957e1281ade79"/>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"git": {
|
||||
"git_revision": "d784c81961d82cbe9e111405468c590a8345856c",
|
||||
"git_revision": "b69c16798ddd7154207f56d983721a327522f5d1",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "34464a3c3dc438c500b48f2b7ff54025f46ce1fd",
|
||||
"revision": "27d2127a81f03614541bfd148daa3002a9010e57",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6641107c83e718d9896f90a9529ad0c252ddc271"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="05a36844c1046a1eb07d5b1325f85ed741f961ea">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6641107c83e718d9896f90a9529ad0c252ddc271"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
|
||||
<project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="337e0ef5e40f02a1ae59b90db0548976c70a7226"/>
|
||||
|
|
|
@ -85,6 +85,13 @@ endif
|
|||
DEFINES += -DBINPATH=$(BINPATH)
|
||||
DEFINES += -DRESPATH=$(RESPATH)
|
||||
|
||||
LPROJ_ROOT = $(firstword $(subst -, ,$(AB_CD)))
|
||||
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
|
||||
ifeq (zh-TW,$(AB_CD))
|
||||
LPROJ_ROOT := $(subst -,_,$(AB_CD))
|
||||
endif
|
||||
endif
|
||||
DEFINES += -DLPROJ_ROOT=$(LPROJ_ROOT)
|
||||
|
||||
ifneq (,$(filter WINNT Darwin Android,$(OS_TARGET)))
|
||||
DEFINES += -DMOZ_SHARED_MOZGLUE=1
|
||||
|
|
|
@ -32,7 +32,8 @@
|
|||
@APPNAME@/Contents/Info.plist
|
||||
@APPNAME@/Contents/PkgInfo
|
||||
@APPNAME@/Contents/Plug-Ins/
|
||||
@RESPATH@
|
||||
@RESPATH@/b2g.icns
|
||||
@RESPATH@/@LPROJ_ROOT@.lproj/*
|
||||
#endif
|
||||
|
||||
[@AB_CD@]
|
||||
|
@ -961,6 +962,7 @@ bin/libfreebl_32int64_3.so
|
|||
@RESPATH@/components/B2GAppMigrator.js
|
||||
@RESPATH@/components/B2GPresentationDevicePrompt.js
|
||||
@RESPATH@/components/PresentationRequestUIGlue.js
|
||||
@RESPATH@/components/KillSwitch.js
|
||||
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
@RESPATH@/components/SimulatorScreen.js
|
||||
|
|
|
@ -382,7 +382,7 @@
|
|||
label="&viewPageSourceCmd.label;"
|
||||
accesskey="&viewPageSourceCmd.accesskey;"
|
||||
oncommand="BrowserViewSource(gContextMenu.browser);"
|
||||
observes="isImage"/>
|
||||
observes="canViewSource"/>
|
||||
<menuitem id="context-viewinfo"
|
||||
label="&viewPageInfoCmd.label;"
|
||||
accesskey="&viewPageInfoCmd.accesskey;"
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
<commandset id="editMenuCommands"/>
|
||||
|
||||
<command id="View:PageSource" oncommand="BrowserViewSource(window.gBrowser.selectedBrowser);" observes="isImage"/>
|
||||
<command id="View:PageSource" oncommand="BrowserViewSource(window.gBrowser.selectedBrowser);" observes="canViewSource"/>
|
||||
<command id="View:PageInfo" oncommand="BrowserPageInfo();"/>
|
||||
<command id="View:FullScreen" oncommand="BrowserFullScreen();"/>
|
||||
<command id="View:ReaderView" oncommand="ReaderParent.toggleReaderMode(event);"/>
|
||||
|
@ -174,6 +174,7 @@
|
|||
oncommand="gPopupBlockerObserver.dontShowMessage();"/>
|
||||
<broadcaster id="blockedPopupsSeparator"/>
|
||||
<broadcaster id="isImage"/>
|
||||
<broadcaster id="canViewSource"/>
|
||||
<broadcaster id="isFrameImage"/>
|
||||
<broadcaster id="singleFeedMenuitemState" disabled="true"/>
|
||||
<broadcaster id="multipleFeedsMenuState" hidden="true"/>
|
||||
|
@ -231,7 +232,9 @@
|
|||
<broadcaster id="devtoolsMenuBroadcaster_PageSource"
|
||||
label="&pageSourceCmd.label;"
|
||||
key="key_viewSource"
|
||||
command="View:PageSource"/>
|
||||
command="View:PageSource">
|
||||
<observes element="canViewSource" attribute="disabled"/>
|
||||
</broadcaster>
|
||||
<broadcaster id="devtoolsMenuBroadcaster_ErrorConsole"
|
||||
label="&errorConsoleCmd.label;"
|
||||
command="Tools:ErrorConsole"/>
|
||||
|
|
|
@ -4049,6 +4049,10 @@ var XULBrowserWindow = {
|
|||
delete this.isImage;
|
||||
return this.isImage = document.getElementById("isImage");
|
||||
},
|
||||
get canViewSource () {
|
||||
delete this.canViewSource;
|
||||
return this.canViewSource = document.getElementById("canViewSource");
|
||||
},
|
||||
|
||||
init: function () {
|
||||
// Initialize the security button's state and tooltip text.
|
||||
|
@ -4206,6 +4210,7 @@ var XULBrowserWindow = {
|
|||
if (aRequest) {
|
||||
let msg = "";
|
||||
let location;
|
||||
let canViewSource = true;
|
||||
// Get the URI either from a channel or a pseudo-object
|
||||
if (aRequest instanceof nsIChannel || "URI" in aRequest) {
|
||||
location = aRequest.URI;
|
||||
|
@ -4214,6 +4219,9 @@ var XULBrowserWindow = {
|
|||
if (location.scheme == "keyword" && aWebProgress.isTopLevel)
|
||||
gBrowser.userTypedValue = null;
|
||||
|
||||
canViewSource = !Services.prefs.getBoolPref("view_source.tab") ||
|
||||
location.scheme != "view-source";
|
||||
|
||||
if (location.spec != "about:blank") {
|
||||
switch (aStatus) {
|
||||
case Components.results.NS_ERROR_NET_TIMEOUT:
|
||||
|
@ -4227,10 +4235,18 @@ var XULBrowserWindow = {
|
|||
this.setDefaultStatus(msg);
|
||||
|
||||
// Disable menu entries for images, enable otherwise
|
||||
if (browser.documentContentType && BrowserUtils.mimeTypeIsTextBased(browser.documentContentType))
|
||||
if (browser.documentContentType && BrowserUtils.mimeTypeIsTextBased(browser.documentContentType)) {
|
||||
this.isImage.removeAttribute('disabled');
|
||||
else
|
||||
} else {
|
||||
canViewSource = false;
|
||||
this.isImage.setAttribute('disabled', 'true');
|
||||
}
|
||||
|
||||
if (canViewSource) {
|
||||
this.canViewSource.removeAttribute('disabled');
|
||||
} else {
|
||||
this.canViewSource.setAttribute('disabled', 'true');
|
||||
}
|
||||
}
|
||||
|
||||
this.isBusy = false;
|
||||
|
|
|
@ -474,6 +474,7 @@ skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test un
|
|||
[browser_urlbar_search_healthreport.js]
|
||||
[browser_urlbar_searchsettings.js]
|
||||
[browser_utilityOverlay.js]
|
||||
[browser_viewSourceInTabOnViewSource.js]
|
||||
[browser_visibleFindSelection.js]
|
||||
[browser_visibleLabel.js]
|
||||
[browser_visibleTabs.js]
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
function wait_while_tab_is_busy() {
|
||||
return new Promise(resolve => {
|
||||
let progressListener = {
|
||||
onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
|
||||
gBrowser.removeProgressListener(this);
|
||||
setTimeout(resolve, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
gBrowser.addProgressListener(progressListener);
|
||||
});
|
||||
}
|
||||
|
||||
// This function waits for the tab to stop being busy instead of waiting for it
|
||||
// to load, since the canViewSource change happens at that time.
|
||||
let with_new_tab_opened = Task.async(function* (options, taskFn) {
|
||||
let busyPromise = wait_while_tab_is_busy();
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(options.gBrowser, options.url, false);
|
||||
yield busyPromise;
|
||||
yield taskFn(tab.linkedBrowser);
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
yield new Promise((resolve) => {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["view_source.tab", true],
|
||||
]}, resolve);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* test_regular_page() {
|
||||
function* test_expect_view_source_enabled(browser) {
|
||||
ok(!XULBrowserWindow.canViewSource.hasAttribute("disabled"),
|
||||
"View Source should be enabled");
|
||||
}
|
||||
|
||||
yield with_new_tab_opened({
|
||||
gBrowser,
|
||||
url: "http://example.com",
|
||||
}, test_expect_view_source_enabled);
|
||||
});
|
||||
|
||||
add_task(function* test_view_source_page() {
|
||||
function* test_expect_view_source_disabled(browser) {
|
||||
ok(XULBrowserWindow.canViewSource.hasAttribute("disabled"),
|
||||
"View Source should be disabled");
|
||||
}
|
||||
|
||||
yield with_new_tab_opened({
|
||||
gBrowser,
|
||||
url: "view-source:http://example.com",
|
||||
}, test_expect_view_source_disabled);
|
||||
});
|
|
@ -37,12 +37,22 @@ AppValidator.prototype._getPackagedManifestFile = function () {
|
|||
this.error(strings.GetStringFromName("validator.expectProjectFolder"));
|
||||
return null;
|
||||
}
|
||||
manifestFile.append("manifest.webapp");
|
||||
if (!manifestFile.exists() || !manifestFile.isFile()) {
|
||||
|
||||
let appManifestFile = manifestFile.clone();
|
||||
appManifestFile.append("manifest.webapp");
|
||||
|
||||
let jsonManifestFile = manifestFile.clone();
|
||||
jsonManifestFile.append("manifest.json");
|
||||
|
||||
let hasAppManifest = appManifestFile.exists() && appManifestFile.isFile();
|
||||
let hasJsonManifest = jsonManifestFile.exists() && jsonManifestFile.isFile();
|
||||
|
||||
if (!hasAppManifest && !hasJsonManifest) {
|
||||
this.error(strings.GetStringFromName("validator.wrongManifestFileName"));
|
||||
return null;
|
||||
}
|
||||
return manifestFile;
|
||||
|
||||
return hasAppManifest ? appManifestFile : jsonManifestFile;
|
||||
};
|
||||
|
||||
AppValidator.prototype._getPackagedManifestURL = function () {
|
||||
|
@ -191,10 +201,6 @@ AppValidator.prototype._getOriginURL = function () {
|
|||
};
|
||||
|
||||
AppValidator.prototype.validateLaunchPath = function (manifest) {
|
||||
// Addons don't use index page (yet?)
|
||||
if (manifest.role && manifest.role === "addon") {
|
||||
return promise.resolve();
|
||||
}
|
||||
let deferred = promise.defer();
|
||||
// The launch_path field has to start with a `/`
|
||||
if (manifest.launch_path && manifest.launch_path[0] !== "/") {
|
||||
|
@ -267,14 +273,20 @@ AppValidator.prototype.validate = function () {
|
|||
this.errors = [];
|
||||
this.warnings = [];
|
||||
return this._getManifest().
|
||||
then((function (manifest) {
|
||||
then((manifest) => {
|
||||
if (manifest) {
|
||||
this.manifest = manifest;
|
||||
|
||||
// Skip validations for add-ons
|
||||
if (manifest.role === "addon" || manifest.manifest_version) {
|
||||
return promise.resolve();
|
||||
}
|
||||
|
||||
this.validateManifest(manifest);
|
||||
this.validateType(manifest);
|
||||
return this.validateLaunchPath(manifest);
|
||||
}
|
||||
}).bind(this));
|
||||
});
|
||||
};
|
||||
|
||||
exports.AppValidator = AppValidator;
|
||||
|
|
|
@ -659,7 +659,7 @@ let AppManager = exports.AppManager = {
|
|||
|
||||
// Addons don't have any document to load (yet?)
|
||||
// So that there is no need to run them, installing is enough
|
||||
if (project.manifest.role && project.manifest.role === "addon") {
|
||||
if (project.manifest.manifest_version || project.manifest.role === "addon") {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ project.installing=Installing…
|
|||
project.installed=Installed!
|
||||
validator.nonExistingFolder=The project folder doesn't exists
|
||||
validator.expectProjectFolder=The project folder ends up being a file
|
||||
validator.wrongManifestFileName=Packaged apps require a manifest file that can only be named 'manifest.webapp' at project root folder
|
||||
validator.wrongManifestFileName=A manifest file is required at project root folder, named either 'manifest.webapp' for packaged apps or 'manifest.json' for addons.
|
||||
validator.invalidManifestURL=Invalid manifest URL '%S'
|
||||
# LOCALIZATION NOTE (validator.invalidManifestJSON, validator.noAccessManifestURL):
|
||||
# %1$S is the error message, %2$S is the URI of the manifest.
|
||||
|
|
|
@ -287,8 +287,8 @@ class RemoteAutomation(Automation):
|
|||
self.procName = app
|
||||
|
||||
# Setting timeout at 1 hour since on a remote device this takes much longer.
|
||||
# Temporarily increased to 75 minutes because no more chunks can be created.
|
||||
self.timeout = 4500
|
||||
# Temporarily increased to 90 minutes because no more chunks can be created.
|
||||
self.timeout = 5400
|
||||
# The benefit of the following sleep is unclear; it was formerly 15 seconds
|
||||
time.sleep(1)
|
||||
|
||||
|
|
|
@ -497,6 +497,12 @@ this.PermissionsTable = { geolocation: {
|
|||
trusted: DENY_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"killswitch": {
|
||||
app: DENY_ACTION,
|
||||
trusted: DENY_ACTION,
|
||||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ this.EXPORTED_SYMBOLS = ["UserCustomizations"];
|
|||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Extension.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ValueExtractor",
|
||||
|
@ -47,7 +48,7 @@ this.UserCustomizations = {
|
|||
debug("Starting customization registration for " + aApp.manifestURL + "\n");
|
||||
|
||||
let extension = new Extension({
|
||||
id: aApp.manifestURL,
|
||||
id: AppsUtils.computeHash(aApp.manifestURL),
|
||||
resourceURI: Services.io.newURI(aApp.origin + "/", null, null)
|
||||
});
|
||||
|
||||
|
@ -150,6 +151,9 @@ this.UserCustomizations = {
|
|||
},
|
||||
|
||||
init: function() {
|
||||
// XXX : For testing purposes. Will not commit.
|
||||
AppsUtils.allowUnsignedAddons = true;
|
||||
|
||||
this._enabled = false;
|
||||
try {
|
||||
this._enabled = Services.prefs.getBoolPref("dom.apps.customization.enabled");
|
||||
|
|
|
@ -861,9 +861,13 @@ this.DOMApplicationRegistry = {
|
|||
root = aManifest.entry_points[aEntryPoint];
|
||||
}
|
||||
|
||||
if (!root.messages || !Array.isArray(root.messages) ||
|
||||
root.messages.length == 0) {
|
||||
dump("Could not register invalid system message entry\n");
|
||||
if (!root.messages) {
|
||||
// This application just doesn't use system messages.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Array.isArray(root.messages) || root.messages.length == 0) {
|
||||
dump("Could not register invalid system message entry for " + aApp.manifestURL + "\n");
|
||||
try {
|
||||
dump(JSON.stringify(root.messages) + "\n");
|
||||
} catch(e) {}
|
||||
|
@ -877,7 +881,7 @@ this.DOMApplicationRegistry = {
|
|||
let handlerPageURI = launchPathURI;
|
||||
let messageName;
|
||||
if (typeof(aMessage) !== "object" || Object.keys(aMessage).length !== 1) {
|
||||
dump("Could not register invalid system message entry\n");
|
||||
dump("Could not register invalid system message entry for " + aApp.manifestURL + "\n");
|
||||
try {
|
||||
dump(JSON.stringify(aMessage) + "\n");
|
||||
} catch(e) {}
|
||||
|
|
|
@ -2468,24 +2468,6 @@ Navigator::HasUserMediaSupport(JSContext* /* unused */,
|
|||
}
|
||||
#endif // MOZ_MEDIA_NAVIGATOR
|
||||
|
||||
/* static */
|
||||
bool
|
||||
Navigator::HasInputMethodSupport(JSContext* /* unused */,
|
||||
JSObject* aGlobal)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
|
||||
if (!win || !Preferences::GetBool("dom.mozInputMethod.enabled", false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Preferences::GetBool("dom.mozInputMethod.testing", false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return CheckPermission(win, "input") ||
|
||||
CheckPermission(win, "input-manage");
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
Navigator::HasDataStoreSupport(nsIPrincipal* aPrincipal)
|
||||
|
|
|
@ -323,8 +323,6 @@ public:
|
|||
JSObject* /* unused */);
|
||||
#endif // MOZ_MEDIA_NAVIGATOR
|
||||
|
||||
static bool HasInputMethodSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||
|
||||
static bool HasDataStoreSupport(nsIPrincipal* aPrincipal);
|
||||
|
||||
static bool HasDataStoreSupport(JSContext* cx, JSObject* aGlobal);
|
||||
|
|
|
@ -113,8 +113,11 @@ PostMessageEvent::Run()
|
|||
false /*cancelable */, messageData, mCallerOrigin,
|
||||
EmptyString(), mSource);
|
||||
|
||||
nsTArray<nsRefPtr<MessagePortBase>> ports;
|
||||
TakeTransferredPorts(ports);
|
||||
|
||||
event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
|
||||
GetTransferredPorts()));
|
||||
ports));
|
||||
|
||||
// We can't simply call dispatchEvent on the window because doing so ends
|
||||
// up flipping the trusted bit on the event, and we don't want that to
|
||||
|
|
|
@ -14,11 +14,24 @@
|
|||
#include "mozilla/dom/FileListBinding.h"
|
||||
#include "mozilla/dom/ImageBitmap.h"
|
||||
#include "mozilla/dom/ImageBitmapBinding.h"
|
||||
#include "mozilla/dom/ImageData.h"
|
||||
#include "mozilla/dom/ImageDataBinding.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/dom/StructuredClone.h"
|
||||
#include "mozilla/dom/MessagePort.h"
|
||||
#include "mozilla/dom/MessagePortBinding.h"
|
||||
#include "mozilla/dom/PMessagePort.h"
|
||||
#include "mozilla/dom/StructuredCloneTags.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozilla/dom/WebCryptoCommon.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "MultipartBlobImpl.h"
|
||||
#include "nsFormData.h"
|
||||
#include "nsIRemoteBlob.h"
|
||||
#include "nsQueryObject.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -142,11 +155,7 @@ bool
|
|||
StructuredCloneHelperInternal::Write(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
MOZ_ASSERT(!mBuffer, "Double Write is not allowed");
|
||||
MOZ_ASSERT(!mShutdownCalled, "This method cannot be called after Shutdown.");
|
||||
|
||||
mBuffer = new JSAutoStructuredCloneBuffer(&gCallbacks, this);
|
||||
return mBuffer->write(aCx, aValue, &gCallbacks, this);
|
||||
return Write(aCx, aValue, JS::UndefinedHandleValue);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -217,24 +226,37 @@ StructuredCloneHelper::StructuredCloneHelper(CloningSupport aSupportsCloning,
|
|||
StructuredCloneHelper::~StructuredCloneHelper()
|
||||
{
|
||||
Shutdown();
|
||||
MOZ_ASSERT(mTransferredPorts.IsEmpty());
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneHelper::Write(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue,
|
||||
bool aMaybeToDifferentThread,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
Write(aCx, aValue, JS::UndefinedHandleValue, aRv);
|
||||
Write(aCx, aValue, JS::UndefinedHandleValue, aMaybeToDifferentThread, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneHelper::Write(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue,
|
||||
JS::Handle<JS::Value> aTransfer,
|
||||
bool aMaybeToDifferentThread,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (!StructuredCloneHelperInternal::Write(aCx, aValue, aTransfer)) {
|
||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aMaybeToDifferentThread) {
|
||||
for (uint32_t i = 0, len = mBlobImplArray.Length(); i < len; ++i) {
|
||||
if (!mBlobImplArray[i]->MayBeClonedToOtherThreads()) {
|
||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -324,6 +346,346 @@ StructuredCloneHelper::FreeBuffer(uint64_t* aBuffer,
|
|||
JS_ClearStructuredClone(aBuffer, aBufferLength, &gCallbacks, this, false);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Recursive!
|
||||
already_AddRefed<BlobImpl>
|
||||
EnsureBlobForBackgroundManager(BlobImpl* aBlobImpl,
|
||||
PBackgroundChild* aManager = nullptr)
|
||||
{
|
||||
MOZ_ASSERT(aBlobImpl);
|
||||
|
||||
if (!aManager) {
|
||||
aManager = BackgroundChild::GetForCurrentThread();
|
||||
MOZ_ASSERT(aManager);
|
||||
}
|
||||
|
||||
nsRefPtr<BlobImpl> blobImpl = aBlobImpl;
|
||||
|
||||
const nsTArray<nsRefPtr<BlobImpl>>* subBlobImpls =
|
||||
aBlobImpl->GetSubBlobImpls();
|
||||
|
||||
if (!subBlobImpls || !subBlobImpls->Length()) {
|
||||
if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryObject(blobImpl)) {
|
||||
// Always make sure we have a blob from an actor we can use on this
|
||||
// thread.
|
||||
BlobChild* blobChild = BlobChild::GetOrCreate(aManager, blobImpl);
|
||||
MOZ_ASSERT(blobChild);
|
||||
|
||||
blobImpl = blobChild->GetBlobImpl();
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
DebugOnly<bool> isMutable;
|
||||
MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)));
|
||||
MOZ_ASSERT(!isMutable);
|
||||
} else {
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blobImpl->SetMutable(false)));
|
||||
}
|
||||
|
||||
return blobImpl.forget();
|
||||
}
|
||||
|
||||
const uint32_t subBlobCount = subBlobImpls->Length();
|
||||
MOZ_ASSERT(subBlobCount);
|
||||
|
||||
nsTArray<nsRefPtr<BlobImpl>> newSubBlobImpls;
|
||||
newSubBlobImpls.SetLength(subBlobCount);
|
||||
|
||||
bool newBlobImplNeeded = false;
|
||||
|
||||
for (uint32_t index = 0; index < subBlobCount; index++) {
|
||||
const nsRefPtr<BlobImpl>& subBlobImpl = subBlobImpls->ElementAt(index);
|
||||
MOZ_ASSERT(subBlobImpl);
|
||||
|
||||
nsRefPtr<BlobImpl>& newSubBlobImpl = newSubBlobImpls[index];
|
||||
|
||||
newSubBlobImpl = EnsureBlobForBackgroundManager(subBlobImpl, aManager);
|
||||
MOZ_ASSERT(newSubBlobImpl);
|
||||
|
||||
if (subBlobImpl != newSubBlobImpl) {
|
||||
newBlobImplNeeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (newBlobImplNeeded) {
|
||||
nsString contentType;
|
||||
blobImpl->GetType(contentType);
|
||||
|
||||
if (blobImpl->IsFile()) {
|
||||
nsString name;
|
||||
blobImpl->GetName(name);
|
||||
|
||||
blobImpl = new MultipartBlobImpl(newSubBlobImpls, name, contentType);
|
||||
} else {
|
||||
blobImpl = new MultipartBlobImpl(newSubBlobImpls, contentType);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blobImpl->SetMutable(false)));
|
||||
}
|
||||
|
||||
return blobImpl.forget();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
ReadBlob(JSContext* aCx,
|
||||
uint32_t aIndex,
|
||||
StructuredCloneHelper* aHelper)
|
||||
{
|
||||
MOZ_ASSERT(aHelper);
|
||||
MOZ_ASSERT(aIndex < aHelper->BlobImpls().Length());
|
||||
nsRefPtr<BlobImpl> blobImpl = aHelper->BlobImpls()[aIndex];
|
||||
|
||||
blobImpl = EnsureBlobForBackgroundManager(blobImpl);
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
// nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
|
||||
// called because the static analysis thinks dereferencing XPCOM objects
|
||||
// can GC (because in some cases it can!), and a return statement with a
|
||||
// JSObject* type means that JSObject* is on the stack as a raw pointer
|
||||
// while destructors are running.
|
||||
JS::Rooted<JS::Value> val(aCx);
|
||||
{
|
||||
nsRefPtr<Blob> blob = Blob::Create(aHelper->ParentDuringRead(), blobImpl);
|
||||
if (!ToJSValue(aCx, blob, &val)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return &val.toObject();
|
||||
}
|
||||
|
||||
bool
|
||||
WriteBlob(JSStructuredCloneWriter* aWriter,
|
||||
Blob* aBlob,
|
||||
StructuredCloneHelper* aHelper)
|
||||
{
|
||||
MOZ_ASSERT(aWriter);
|
||||
MOZ_ASSERT(aBlob);
|
||||
MOZ_ASSERT(aHelper);
|
||||
|
||||
nsRefPtr<BlobImpl> blobImpl = EnsureBlobForBackgroundManager(aBlob->Impl());
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
// We store the position of the blobImpl in the array as index.
|
||||
if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
|
||||
aHelper->BlobImpls().Length())) {
|
||||
aHelper->BlobImpls().AppendElement(blobImpl);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the WriteFileList for the format.
|
||||
JSObject*
|
||||
ReadFileList(JSContext* aCx,
|
||||
JSStructuredCloneReader* aReader,
|
||||
uint32_t aCount,
|
||||
StructuredCloneHelper* aHelper)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(aReader);
|
||||
|
||||
JS::Rooted<JS::Value> val(aCx);
|
||||
{
|
||||
nsRefPtr<FileList> fileList = new FileList(aHelper->ParentDuringRead());
|
||||
|
||||
uint32_t tag, offset;
|
||||
// Offset is the index of the blobImpl from which we can find the blobImpl
|
||||
// for this FileList.
|
||||
if (!JS_ReadUint32Pair(aReader, &tag, &offset)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(tag == 0);
|
||||
|
||||
// |aCount| is the number of BlobImpls to use from the |offset|.
|
||||
for (uint32_t i = 0; i < aCount; ++i) {
|
||||
uint32_t index = offset + i;
|
||||
MOZ_ASSERT(index < aHelper->BlobImpls().Length());
|
||||
|
||||
nsRefPtr<BlobImpl> blobImpl = aHelper->BlobImpls()[index];
|
||||
MOZ_ASSERT(blobImpl->IsFile());
|
||||
|
||||
nsRefPtr<File> file = File::Create(aHelper->ParentDuringRead(), blobImpl);
|
||||
if (!fileList->Append(file)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ToJSValue(aCx, fileList, &val)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return &val.toObject();
|
||||
}
|
||||
|
||||
// The format of the FileList serialization is:
|
||||
// - pair of ints: SCTAG_DOM_FILELIST, Length of the FileList
|
||||
// - pair of ints: 0, The offset of the BlobImpl array
|
||||
bool
|
||||
WriteFileList(JSStructuredCloneWriter* aWriter,
|
||||
FileList* aFileList,
|
||||
StructuredCloneHelper* aHelper)
|
||||
{
|
||||
MOZ_ASSERT(aWriter);
|
||||
MOZ_ASSERT(aFileList);
|
||||
MOZ_ASSERT(aHelper);
|
||||
|
||||
// A FileList is serialized writing the X number of elements and the offset
|
||||
// from mBlobImplArray. The Read will take X elements from mBlobImplArray
|
||||
// starting from the offset.
|
||||
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST,
|
||||
aFileList->Length()) ||
|
||||
!JS_WriteUint32Pair(aWriter, 0,
|
||||
aHelper->BlobImpls().Length())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < aFileList->Length(); ++i) {
|
||||
aHelper->BlobImpls().AppendElement(aFileList->Item(i)->Impl());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read the WriteFormData for the format.
|
||||
JSObject*
|
||||
ReadFormData(JSContext* aCx,
|
||||
JSStructuredCloneReader* aReader,
|
||||
uint32_t aCount,
|
||||
StructuredCloneHelper* aHelper)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(aReader);
|
||||
MOZ_ASSERT(aHelper);
|
||||
|
||||
// See the serialization of the FormData for the format.
|
||||
JS::Rooted<JS::Value> val(aCx);
|
||||
{
|
||||
nsRefPtr<nsFormData> formData =
|
||||
new nsFormData(aHelper->ParentDuringRead());
|
||||
|
||||
Optional<nsAString> thirdArg;
|
||||
for (uint32_t i = 0; i < aCount; ++i) {
|
||||
nsAutoString name;
|
||||
if (!ReadString(aReader, name)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t tag, indexOrLengthOfString;
|
||||
if (!JS_ReadUint32Pair(aReader, &tag, &indexOrLengthOfString)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (tag == SCTAG_DOM_BLOB) {
|
||||
MOZ_ASSERT(indexOrLengthOfString < aHelper->BlobImpls().Length());
|
||||
|
||||
nsRefPtr<BlobImpl> blobImpl =
|
||||
aHelper->BlobImpls()[indexOrLengthOfString];
|
||||
MOZ_ASSERT(blobImpl->IsFile());
|
||||
|
||||
nsRefPtr<File> file =
|
||||
File::Create(aHelper->ParentDuringRead(), blobImpl);
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
formData->Append(name, *file, thirdArg);
|
||||
} else {
|
||||
MOZ_ASSERT(tag == 0);
|
||||
|
||||
nsAutoString value;
|
||||
value.SetLength(indexOrLengthOfString);
|
||||
size_t charSize = sizeof(nsString::char_type);
|
||||
if (!JS_ReadBytes(aReader, (void*) value.BeginWriting(),
|
||||
indexOrLengthOfString * charSize)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
formData->Append(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ToJSValue(aCx, formData, &val)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return &val.toObject();
|
||||
}
|
||||
|
||||
// The format of the FormData serialization is:
|
||||
// - pair of ints: SCTAG_DOM_FORMDATA, Length of the FormData elements
|
||||
// - for each Element element:
|
||||
// - name string
|
||||
// - if it's a blob:
|
||||
// - pair of ints: SCTAG_DOM_BLOB, index of the BlobImpl in the array
|
||||
// mBlobImplArray.
|
||||
// - else:
|
||||
// - pair of ints: 0, string length
|
||||
// - value string
|
||||
bool
|
||||
WriteFormData(JSStructuredCloneWriter* aWriter,
|
||||
nsFormData* aFormData,
|
||||
StructuredCloneHelper* aHelper)
|
||||
{
|
||||
MOZ_ASSERT(aWriter);
|
||||
MOZ_ASSERT(aFormData);
|
||||
MOZ_ASSERT(aHelper);
|
||||
|
||||
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FORMDATA,
|
||||
aFormData->Length())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS Closure final
|
||||
{
|
||||
JSStructuredCloneWriter* mWriter;
|
||||
StructuredCloneHelper* mHelper;
|
||||
|
||||
public:
|
||||
Closure(JSStructuredCloneWriter* aWriter,
|
||||
StructuredCloneHelper* aHelper)
|
||||
: mWriter(aWriter),
|
||||
mHelper(aHelper)
|
||||
{ }
|
||||
|
||||
static bool
|
||||
Write(const nsString& aName, bool isFile, const nsString& aValue,
|
||||
File* aFile, void* aClosure)
|
||||
{
|
||||
Closure* closure = static_cast<Closure*>(aClosure);
|
||||
if (!WriteString(closure->mWriter, aName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isFile) {
|
||||
BlobImpl* blobImpl = aFile->Impl();
|
||||
if (!JS_WriteUint32Pair(closure->mWriter, SCTAG_DOM_BLOB,
|
||||
closure->mHelper->BlobImpls().Length())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
closure->mHelper->BlobImpls().AppendElement(blobImpl);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t charSize = sizeof(nsString::char_type);
|
||||
if (!JS_WriteUint32Pair(closure->mWriter, 0, aValue.Length()) ||
|
||||
!JS_WriteBytes(closure->mWriter, aValue.get(),
|
||||
aValue.Length() * charSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
Closure closure(aWriter, aHelper);
|
||||
return aFormData->ForEach(Closure::Write, &closure);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
JSObject*
|
||||
StructuredCloneHelper::ReadCallback(JSContext* aCx,
|
||||
JSStructuredCloneReader* aReader,
|
||||
|
@ -333,56 +695,19 @@ StructuredCloneHelper::ReadCallback(JSContext* aCx,
|
|||
MOZ_ASSERT(mSupportsCloning);
|
||||
|
||||
if (aTag == SCTAG_DOM_BLOB) {
|
||||
MOZ_ASSERT(aIndex < mBlobImplArray.Length());
|
||||
nsRefPtr<BlobImpl> blobImpl = mBlobImplArray[aIndex];
|
||||
|
||||
// nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
|
||||
// called because the static analysis thinks dereferencing XPCOM objects
|
||||
// can GC (because in some cases it can!), and a return statement with a
|
||||
// JSObject* type means that JSObject* is on the stack as a raw pointer
|
||||
// while destructors are running.
|
||||
JS::Rooted<JS::Value> val(aCx);
|
||||
{
|
||||
nsRefPtr<Blob> blob = Blob::Create(mParent, blobImpl);
|
||||
if (!ToJSValue(aCx, blob, &val)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return &val.toObject();
|
||||
return ReadBlob(aCx, aIndex, this);
|
||||
}
|
||||
|
||||
if (aTag == SCTAG_DOM_FILELIST) {
|
||||
JS::Rooted<JS::Value> val(aCx);
|
||||
{
|
||||
nsRefPtr<FileList> fileList = new FileList(mParent);
|
||||
return ReadFileList(aCx, aReader, aIndex, this);
|
||||
}
|
||||
|
||||
// |aIndex| is the number of BlobImpls to use from |offset|.
|
||||
uint32_t tag, offset;
|
||||
if (!JS_ReadUint32Pair(aReader, &tag, &offset)) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(tag == 0);
|
||||
if (aTag == SCTAG_DOM_IMAGEDATA) {
|
||||
return ReadStructuredCloneImageData(aCx, aReader);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < aIndex; ++i) {
|
||||
uint32_t index = offset + i;
|
||||
MOZ_ASSERT(index < mBlobImplArray.Length());
|
||||
|
||||
nsRefPtr<BlobImpl> blobImpl = mBlobImplArray[index];
|
||||
MOZ_ASSERT(blobImpl->IsFile());
|
||||
|
||||
nsRefPtr<File> file = File::Create(mParent, blobImpl);
|
||||
if (!fileList->Append(file)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ToJSValue(aCx, fileList, &val)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return &val.toObject();
|
||||
if (aTag == SCTAG_DOM_FORMDATA) {
|
||||
return ReadFormData(aCx, aReader, aIndex, this);
|
||||
}
|
||||
|
||||
if (aTag == SCTAG_DOM_IMAGEBITMAP) {
|
||||
|
@ -410,35 +735,31 @@ StructuredCloneHelper::WriteCallback(JSContext* aCx,
|
|||
{
|
||||
Blob* blob = nullptr;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
|
||||
BlobImpl* blobImpl = blob->Impl();
|
||||
if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
|
||||
mBlobImplArray.Length())) {
|
||||
mBlobImplArray.AppendElement(blobImpl);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return WriteBlob(aWriter, blob, this);
|
||||
}
|
||||
}
|
||||
|
||||
// See if this is a FileList object.
|
||||
{
|
||||
FileList* fileList = nullptr;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) {
|
||||
// A FileList is serialized writing the X number of elements and the offset
|
||||
// from mBlobImplArray. The Read will take X elements from mBlobImplArray
|
||||
// starting from the offset.
|
||||
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST,
|
||||
fileList->Length()) ||
|
||||
!JS_WriteUint32Pair(aWriter, 0,
|
||||
mBlobImplArray.Length())) {
|
||||
return false;
|
||||
}
|
||||
return WriteFileList(aWriter, fileList, this);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < fileList->Length(); ++i) {
|
||||
mBlobImplArray.AppendElement(fileList->Item(i)->Impl());
|
||||
}
|
||||
// See if this is a ImageData object.
|
||||
{
|
||||
ImageData* imageData = nullptr;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageData, aObj, imageData))) {
|
||||
return WriteStructuredCloneImageData(aCx, aWriter, imageData);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
// See if this is a FormData object.
|
||||
{
|
||||
nsFormData* formData = nullptr;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(FormData, aObj, formData))) {
|
||||
return WriteFormData(aWriter, formData, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -81,6 +81,11 @@ public:
|
|||
bool Read(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aValue);
|
||||
|
||||
bool HasBeenWritten() const
|
||||
{
|
||||
return !!mBuffer;
|
||||
}
|
||||
|
||||
uint64_t* BufferData() const
|
||||
{
|
||||
MOZ_ASSERT(mBuffer, "Write() has never been called.");
|
||||
|
@ -132,11 +137,13 @@ public:
|
|||
|
||||
void Write(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue,
|
||||
bool aMaybeToDifferentThread,
|
||||
ErrorResult &aRv);
|
||||
|
||||
void Write(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue,
|
||||
JS::Handle<JS::Value> aTransfer,
|
||||
bool aMaybeToDifferentThread,
|
||||
ErrorResult &aRv);
|
||||
|
||||
void Read(nsISupports* aParent,
|
||||
|
@ -184,10 +191,19 @@ public:
|
|||
return mBlobImplArray;
|
||||
}
|
||||
|
||||
const nsTArray<nsRefPtr<MessagePortBase>>& GetTransferredPorts() const
|
||||
nsISupports* ParentDuringRead() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
// This must be called if the transferring has ports generated by Read().
|
||||
// MessagePorts are not thread-safe and they must be retrieved in the thread
|
||||
// where they are created.
|
||||
void TakeTransferredPorts(nsTArray<nsRefPtr<MessagePortBase>>& aPorts)
|
||||
{
|
||||
MOZ_ASSERT(mSupportsTransferring);
|
||||
return mTransferredPorts;
|
||||
MOZ_ASSERT(aPorts.IsEmpty());
|
||||
aPorts.SwapElements(mTransferredPorts);
|
||||
}
|
||||
|
||||
nsTArray<MessagePortIdentifier>& PortIdentifiers()
|
||||
|
|
|
@ -46,6 +46,8 @@ enum StructuredCloneTags {
|
|||
|
||||
SCTAG_DOM_RTC_CERTIFICATE,
|
||||
|
||||
SCTAG_DOM_FORMDATA,
|
||||
|
||||
SCTAG_DOM_MAX
|
||||
};
|
||||
|
||||
|
|
|
@ -3205,6 +3205,93 @@ nsDOMWindowUtils::RemoteFrameFullscreenReverted()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS FullscreenChangePrepare
|
||||
{
|
||||
public:
|
||||
FullscreenChangePrepare(nsIPresShell* aPresShell,
|
||||
const nsSize& aSize, nsSize* aOldSize = nullptr)
|
||||
: mPresShell(aPresShell)
|
||||
{
|
||||
if (mPresShell) {
|
||||
mPresShell->SetIsInFullscreenChange(true);
|
||||
}
|
||||
if (aSize.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (nsViewManager* viewManager = mPresShell->GetViewManager()) {
|
||||
if (aOldSize) {
|
||||
viewManager->GetWindowDimensions(&aOldSize->width, &aOldSize->height);
|
||||
}
|
||||
viewManager->SetWindowDimensions(aSize.width, aSize.height);
|
||||
}
|
||||
}
|
||||
|
||||
~FullscreenChangePrepare()
|
||||
{
|
||||
if (mPresShell) {
|
||||
mPresShell->SetIsInFullscreenChange(false);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIPresShell> mPresShell;
|
||||
};
|
||||
|
||||
class OldWindowSize : public LinkedListElement<OldWindowSize>
|
||||
{
|
||||
public:
|
||||
static void Set(nsPIDOMWindow* aWindow, const nsSize& aSize)
|
||||
{
|
||||
OldWindowSize* item = GetItem(aWindow);
|
||||
if (item) {
|
||||
item->mSize = aSize;
|
||||
} else if (aWindow) {
|
||||
item = new OldWindowSize(do_GetWeakReference(aWindow), aSize);
|
||||
sList.insertBack(item);
|
||||
}
|
||||
}
|
||||
|
||||
static nsSize GetAndRemove(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
nsSize result;
|
||||
if (OldWindowSize* item = GetItem(aWindow)) {
|
||||
result = item->mSize;
|
||||
delete item;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit OldWindowSize(already_AddRefed<nsIWeakReference>&& aWindow,
|
||||
const nsSize& aSize)
|
||||
: mWindow(Move(aWindow)), mSize(aSize) { }
|
||||
~OldWindowSize() { };
|
||||
|
||||
static OldWindowSize* GetItem(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
OldWindowSize* item = sList.getFirst();
|
||||
while (item) {
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(item->mWindow);
|
||||
if (!window) {
|
||||
OldWindowSize* thisItem = item;
|
||||
item = thisItem->getNext();
|
||||
delete thisItem;
|
||||
continue;
|
||||
}
|
||||
if (window == aWindow) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
static LinkedList<OldWindowSize> sList;
|
||||
nsWeakPtr mWindow;
|
||||
nsSize mSize;
|
||||
};
|
||||
|
||||
LinkedList<OldWindowSize> OldWindowSize::sList;
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::HandleFullscreenRequests(bool* aRetVal)
|
||||
{
|
||||
|
@ -3213,6 +3300,18 @@ nsDOMWindowUtils::HandleFullscreenRequests(bool* aRetVal)
|
|||
nsCOMPtr<nsIDocument> doc = GetDocument();
|
||||
NS_ENSURE_STATE(doc);
|
||||
|
||||
// Notify the pres shell that we are starting fullscreen change, and
|
||||
// set the window dimensions in advance. Since the resize message
|
||||
// comes after the fullscreen change call, doing so could avoid an
|
||||
// extra resize reflow after this point.
|
||||
nsRect screenRect;
|
||||
if (nsPresContext* presContext = GetPresContext()) {
|
||||
presContext->DeviceContext()->GetRect(screenRect);
|
||||
}
|
||||
nsSize oldSize;
|
||||
FullscreenChangePrepare prepare(GetPresShell(), screenRect.Size(), &oldSize);
|
||||
OldWindowSize::Set(doc->GetWindow(), oldSize);
|
||||
|
||||
*aRetVal = nsIDocument::HandlePendingFullscreenRequests(doc);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -3224,6 +3323,16 @@ nsDOMWindowUtils::ExitFullscreen()
|
|||
|
||||
nsCOMPtr<nsIDocument> doc = GetDocument();
|
||||
NS_ENSURE_STATE(doc);
|
||||
if (!doc->IsFullScreenDoc()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Notify the pres shell that we are starting fullscreen change, and
|
||||
// set the window dimensions in advance. Since the resize message
|
||||
// comes after the fullscreen change call, doing so could avoid an
|
||||
// extra resize reflow after this point.
|
||||
FullscreenChangePrepare prepare(
|
||||
GetPresShell(), OldWindowSize::GetAndRemove(doc->GetWindow()));
|
||||
|
||||
nsIDocument::ExitFullscreenInDocTree(doc);
|
||||
return NS_OK;
|
||||
|
|
|
@ -1763,12 +1763,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
|
|||
cb.NoteNativeChild(timeout, NS_CYCLE_COLLECTION_PARTICIPANT(nsTimeout));
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHistory)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplicationCache)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedDoc)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWakeLock)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingStorageEvents)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers)
|
||||
|
||||
|
@ -1827,15 +1833,20 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
|
|||
tmp->mListenerManager->Disconnect();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mHistory)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage)
|
||||
if (tmp->mApplicationCache) {
|
||||
static_cast<nsDOMOfflineResourceList*>(tmp->mApplicationCache.get())->Disconnect();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplicationCache)
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedDoc)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWakeLock)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingStorageEvents)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers)
|
||||
|
||||
|
@ -6385,7 +6396,8 @@ FullscreenTransitionTask::Run()
|
|||
mWindow->mFullScreen = mFullscreen;
|
||||
}
|
||||
// Toggle the fullscreen state on the widget
|
||||
mWidget->MakeFullScreen(mFullscreen, mScreen);
|
||||
mWindow->SetWidgetFullscreen(nsPIDOMWindow::eForFullscreenAPI,
|
||||
mFullscreen, mWidget, mScreen);
|
||||
// Set observer for the next content paint.
|
||||
nsCOMPtr<nsIObserver> observer = new Observer(this);
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
|
@ -6464,13 +6476,7 @@ MakeWidgetFullscreen(nsGlobalWindow* aWindow, gfx::VRHMDInfo* aHMD,
|
|||
}
|
||||
nsCOMPtr<nsIScreen> screen = aHMD ? aHMD->GetScreen() : nullptr;
|
||||
if (!performTransition) {
|
||||
if (aReason == nsPIDOMWindow::eForFullscreenMode) {
|
||||
// If we enter fullscreen for fullscreen mode, we want
|
||||
// the native system behavior.
|
||||
widget->MakeFullScreenWithNativeTransition(aFullscreen, screen);
|
||||
} else {
|
||||
widget->MakeFullScreen(aFullscreen, screen);
|
||||
}
|
||||
aWindow->SetWidgetFullscreen(aReason, aFullscreen, widget, screen);
|
||||
} else {
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
new FullscreenTransitionTask(duration, aWindow, aFullscreen,
|
||||
|
@ -6574,6 +6580,27 @@ nsGlobalWindow::SetFullscreenInternal(FullscreenReason aReason,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::SetWidgetFullscreen(FullscreenReason aReason, bool aIsFullscreen,
|
||||
nsIWidget* aWidget, nsIScreen* aScreen)
|
||||
{
|
||||
MOZ_ASSERT(IsOuterWindow());
|
||||
MOZ_ASSERT(this == GetTop(), "Only topmost window should call this");
|
||||
MOZ_ASSERT(!GetFrameElementInternal(), "Content window should not call this");
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||
|
||||
if (nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell()) {
|
||||
presShell->SetIsInFullscreenChange(true);
|
||||
}
|
||||
if (aReason == nsPIDOMWindow::eForFullscreenMode) {
|
||||
// If we enter fullscreen for fullscreen mode, we want
|
||||
// the native system behavior.
|
||||
aWidget->MakeFullScreenWithNativeTransition(aIsFullscreen, aScreen);
|
||||
} else {
|
||||
aWidget->MakeFullScreen(aIsFullscreen, aScreen);
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
nsGlobalWindow::FinishFullscreenChange(bool aIsFullscreen)
|
||||
{
|
||||
|
@ -6606,6 +6633,11 @@ nsGlobalWindow::FinishFullscreenChange(bool aIsFullscreen)
|
|||
// respond visually if we are kicked into full screen mode
|
||||
DispatchCustomEvent(NS_LITERAL_STRING("fullscreen"));
|
||||
|
||||
if (nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell()) {
|
||||
MOZ_ASSERT(presShell->IsInFullscreenChange());
|
||||
presShell->SetIsInFullscreenChange(false);
|
||||
}
|
||||
|
||||
if (!mWakeLock && mFullScreen) {
|
||||
nsRefPtr<power::PowerManagerService> pmService =
|
||||
power::PowerManagerService::GetInstance();
|
||||
|
@ -8614,7 +8646,7 @@ nsGlobalWindow::PostMessageMozOuter(JSContext* aCx, JS::Handle<JS::Value> aMessa
|
|||
JS::Rooted<JS::Value> message(aCx, aMessage);
|
||||
JS::Rooted<JS::Value> transfer(aCx, aTransfer);
|
||||
|
||||
event->Write(aCx, message, transfer, aError);
|
||||
event->Write(aCx, message, transfer, false, aError);
|
||||
if (NS_WARN_IF(aError.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -498,6 +498,8 @@ public:
|
|||
FullscreenReason aReason, bool aIsFullscreen,
|
||||
mozilla::gfx::VRHMDInfo *aHMD = nullptr) override final;
|
||||
virtual void FinishFullscreenChange(bool aIsFullscreen) override final;
|
||||
void SetWidgetFullscreen(FullscreenReason aReason, bool aIsFullscreen,
|
||||
nsIWidget* aWidget, nsIScreen* aScreen);
|
||||
bool FullScreen() const;
|
||||
|
||||
// Inner windows only.
|
||||
|
@ -1631,13 +1633,6 @@ private:
|
|||
void DisconnectEventTargetObjects();
|
||||
|
||||
protected:
|
||||
// When adding new member variables, be careful not to create cycles
|
||||
// through JavaScript. If there is any chance that a member variable
|
||||
// could own objects that are implemented in JavaScript, then those
|
||||
// objects will keep the global object (this object) alive. To prevent
|
||||
// these cycles, ownership of such members must be released in
|
||||
// |CleanUp| and |DetachFromDocShell|.
|
||||
|
||||
// This member is also used on both inner and outer windows, but
|
||||
// for slightly different purposes. On inner windows it means the
|
||||
// inner window is held onto by session history and should not
|
||||
|
|
|
@ -52,7 +52,7 @@ nsStructuredCloneContainer::InitFromJSVal(JS::Handle<JS::Value> aData,
|
|||
}
|
||||
|
||||
ErrorResult rv;
|
||||
Write(aCx, aData, rv);
|
||||
Write(aCx, aData, true, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
|
|
@ -2875,26 +2875,22 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody)
|
|||
NS_ASSERTION(listener != this,
|
||||
"Using an object as a listener that can't be exposed to JS");
|
||||
|
||||
// Bypass the network cache in cases where it makes no sense:
|
||||
// POST responses are always unique, and we provide no API that would
|
||||
// allow our consumers to specify a "cache key" to access old POST
|
||||
// responses, so they are not worth caching.
|
||||
if (method.EqualsLiteral("POST")) {
|
||||
AddLoadFlags(mChannel,
|
||||
nsIRequest::LOAD_BYPASS_CACHE | nsIRequest::INHIBIT_CACHING);
|
||||
} else {
|
||||
// When we are sync loading, we need to bypass the local cache when it would
|
||||
// otherwise block us waiting for exclusive access to the cache. If we don't
|
||||
// do this, then we could dead lock in some cases (see bug 309424).
|
||||
//
|
||||
// Also don't block on the cache entry on async if it is busy - favoring parallelism
|
||||
// over cache hit rate for xhr. This does not disable the cache everywhere -
|
||||
// only in cases where more than one channel for the same URI is accessed
|
||||
// simultanously.
|
||||
// When we are sync loading, we need to bypass the local cache when it would
|
||||
// otherwise block us waiting for exclusive access to the cache. If we don't
|
||||
// do this, then we could dead lock in some cases (see bug 309424).
|
||||
//
|
||||
// Also don't block on the cache entry on async if it is busy - favoring parallelism
|
||||
// over cache hit rate for xhr. This does not disable the cache everywhere -
|
||||
// only in cases where more than one channel for the same URI is accessed
|
||||
// simultanously.
|
||||
|
||||
AddLoadFlags(mChannel,
|
||||
nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY);
|
||||
}
|
||||
AddLoadFlags(mChannel,
|
||||
nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY);
|
||||
|
||||
// While it would be optimal to bypass the cache in case of POST requests
|
||||
// since they are never cached, our ServiceWorker interception implementation
|
||||
// on single-process systems is implemented via the HTTP cache, so DO NOT
|
||||
// bypass the cache based on method!
|
||||
|
||||
// Since we expect XML data, set the type hint accordingly
|
||||
// if the channel doesn't know any content type.
|
||||
|
|
|
@ -836,4 +836,5 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g'
|
|||
[test_window_element_enumeration.html]
|
||||
[test_referrer_redirect.html]
|
||||
[test_postMessages.html]
|
||||
support-files = worker_postMessages.js
|
||||
[test_window_proto.html]
|
||||
|
|
|
@ -278,6 +278,51 @@ function test_windowToIframeURL(url) {
|
|||
document.body.appendChild(ifr);
|
||||
}
|
||||
|
||||
// PostMessage for Workers
|
||||
function test_workers() {
|
||||
info("Testing Workers");
|
||||
|
||||
var resolve;
|
||||
|
||||
var w = new Worker('worker_postMessages.js');
|
||||
w.postMessage('workers');
|
||||
w.onmessage = function(e) {
|
||||
is(e.data, 'ok', "Worker ready!");
|
||||
|
||||
w.onmessage = function(e) {
|
||||
if (!resolve) {
|
||||
ok(false, "Unexpected message!");
|
||||
return;
|
||||
}
|
||||
|
||||
let tmp = resolve;
|
||||
resolve = null;
|
||||
tmp({ data: e.data, ports: e.ports });
|
||||
}
|
||||
|
||||
runTests({
|
||||
clonableObjects: true,
|
||||
transferableObjects: true,
|
||||
send: function(what, ports) {
|
||||
return new Promise(function(r, rr) {
|
||||
resolve = r;
|
||||
try {
|
||||
w.postMessage(what, ports);
|
||||
} catch(e) {
|
||||
resolve = null;
|
||||
rr();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
finished: function() {
|
||||
onmessage = null;
|
||||
next();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// PostMessage for BroadcastChannel
|
||||
function test_broadcastChannel() {
|
||||
info("Testing broadcastChannel");
|
||||
|
@ -320,6 +365,52 @@ function test_broadcastChannel() {
|
|||
});
|
||||
}
|
||||
|
||||
// PostMessage for BroadcastChannel in workers
|
||||
function test_broadcastChannel_inWorkers() {
|
||||
info("Testing broadcastChannel in Workers");
|
||||
|
||||
var bc = new BroadcastChannel('postMessagesTest_inWorkers');
|
||||
var resolve;
|
||||
|
||||
var w = new Worker('worker_postMessages.js');
|
||||
w.postMessage('broadcastChannel');
|
||||
w.onmessage = function(e) {
|
||||
is(e.data, 'ok', "Worker ready!");
|
||||
|
||||
w.onmessage = function(e) {
|
||||
if (!resolve) {
|
||||
ok(false, "Unexpected message!");
|
||||
return;
|
||||
}
|
||||
|
||||
let tmp = resolve;
|
||||
resolve = null;
|
||||
tmp({ data: e.data, ports: e.ports });
|
||||
}
|
||||
|
||||
runTests({
|
||||
clonableObjects: true,
|
||||
transferableObjects: false,
|
||||
send: function(what, ports) {
|
||||
return new Promise(function(r, rr) {
|
||||
if (ports.length) {
|
||||
rr();
|
||||
return;
|
||||
}
|
||||
|
||||
resolve = r;
|
||||
bc.postMessage(what);
|
||||
});
|
||||
},
|
||||
|
||||
finished: function() {
|
||||
onmessage = null;
|
||||
next();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// PostMessage for MessagePort
|
||||
function test_messagePort() {
|
||||
info("Testing messagePort");
|
||||
|
@ -360,6 +451,52 @@ function test_messagePort() {
|
|||
});
|
||||
}
|
||||
|
||||
// PostMessage for MessagePort in Workers
|
||||
function test_messagePort_inWorkers() {
|
||||
info("Testing messagePort in workers");
|
||||
|
||||
var mc = new MessageChannel();
|
||||
var resolve;
|
||||
|
||||
var w = new Worker('worker_postMessages.js');
|
||||
w.postMessage('messagePort', [ mc.port2 ]);
|
||||
w.onmessage = function(e) {
|
||||
is(e.data, 'ok', "Worker ready!");
|
||||
|
||||
w.onmessage = function(e) {
|
||||
if (!resolve) {
|
||||
ok(false, "Unexpected message!");
|
||||
return;
|
||||
}
|
||||
|
||||
let tmp = resolve;
|
||||
resolve = null;
|
||||
tmp({ data: e.data, ports: e.ports });
|
||||
}
|
||||
|
||||
runTests({
|
||||
clonableObjects: true,
|
||||
transferableObjects: true,
|
||||
send: function(what, ports) {
|
||||
return new Promise(function(r, rr) {
|
||||
resolve = r;
|
||||
try {
|
||||
mc.port1.postMessage(what, ports);
|
||||
} catch(e) {
|
||||
resolve = null;
|
||||
rr();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
finished: function() {
|
||||
onmessage = null;
|
||||
next();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var tests = [
|
||||
create_fileList,
|
||||
|
||||
|
@ -367,11 +504,13 @@ var tests = [
|
|||
test_windowToIframe,
|
||||
test_windowToCrossOriginIframe,
|
||||
|
||||
test_workers,
|
||||
|
||||
test_broadcastChannel,
|
||||
// TODO BroadcastChannel in worker
|
||||
test_broadcastChannel_inWorkers,
|
||||
|
||||
test_messagePort,
|
||||
// TODO MessagePort in worker
|
||||
test_messagePort_inWorkers,
|
||||
];
|
||||
|
||||
function next() {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
function test_workers() {
|
||||
onmessage = function(e) {
|
||||
postMessage(e.data, e.ports);
|
||||
}
|
||||
}
|
||||
|
||||
function test_broadcastChannel() {
|
||||
var bc = new BroadcastChannel('postMessagesTest_inWorkers');
|
||||
bc.onmessage = function(e) {
|
||||
postMessage(e.data);
|
||||
}
|
||||
}
|
||||
|
||||
function test_messagePort(port) {
|
||||
port.onmessage = function(e) {
|
||||
postMessage(e.data, e.ports);
|
||||
}
|
||||
}
|
||||
|
||||
onmessage = function(e) {
|
||||
if (e.data == 'workers') {
|
||||
test_workers();
|
||||
postMessage('ok');
|
||||
} else if (e.data == 'broadcastChannel') {
|
||||
test_broadcastChannel();
|
||||
postMessage('ok');
|
||||
} else if (e.data == 'messagePort') {
|
||||
test_messagePort(e.ports[0]);
|
||||
postMessage('ok');
|
||||
} else {
|
||||
postMessage('ko');
|
||||
}
|
||||
}
|
|
@ -454,19 +454,11 @@ BroadcastChannel::PostMessageInternal(JSContext* aCx,
|
|||
{
|
||||
nsRefPtr<BroadcastChannelMessage> data = new BroadcastChannelMessage();
|
||||
|
||||
data->Write(aCx, aMessage, aRv);
|
||||
data->Write(aCx, aMessage, true, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = data->BlobImpls();
|
||||
for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) {
|
||||
if (!blobImpls[i]->MayBeClonedToOtherThreads()) {
|
||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PostMessageData(data);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,13 +17,11 @@ function setup() {
|
|||
}
|
||||
|
||||
SpecialPowers.setBoolPref("dom.mozInputMethod.enabled", true);
|
||||
SpecialPowers.setBoolPref("dom.mozInputMethod.testing", true);
|
||||
SpecialPowers.addPermission('input-manage', true, document);
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
SpecialPowers.setBoolPref("dom.mozInputMethod.enabled", false);
|
||||
SpecialPowers.setBoolPref("dom.mozInputMethod.testing", false);
|
||||
SpecialPowers.removePermission('input-manage', document);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ skip-if = toolkit == 'android' || (toolkit == 'gonk' && !debug) #TIMED_OUT, bug
|
|||
skip-if = (toolkit == 'gonk') # Disabled on b2g due to bug 1097419
|
||||
[test_browserElement_oop_SendEvent.html]
|
||||
[test_browserElement_oop_SetInputMethodActive.html]
|
||||
skip-if = (os == "android")
|
||||
skip-if = (os == "android") || (toolkit == 'gonk') # Disabled on B2G Emulator bug 1198163
|
||||
[test_browserElement_oop_SetVisible.html]
|
||||
[test_browserElement_oop_SetVisibleFrames.html]
|
||||
[test_browserElement_oop_SetVisibleFrames2.html]
|
||||
|
|
|
@ -209,7 +209,7 @@ skip-if = (toolkit == 'gonk') # Disabled on b2g due to bug 1097419
|
|||
[test_browserElement_inproc_SendEvent.html]
|
||||
# The setInputMethodActive() tests will timed out on Android
|
||||
[test_browserElement_inproc_SetInputMethodActive.html]
|
||||
skip-if = (os == "android")
|
||||
skip-if = (os == "android") || (toolkit == 'gonk') # Disabled on B2G Emulator bug 1198163
|
||||
[test_browserElement_inproc_SetVisible.html]
|
||||
[test_browserElement_inproc_SetVisibleFrames.html]
|
||||
[test_browserElement_inproc_SetVisibleFrames2.html]
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
#include "mozilla/dom/ImageBitmap.h"
|
||||
#include "mozilla/dom/ImageBitmapBinding.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/StructuredCloneTags.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/dom/WorkerRunnable.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "imgTools.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "libyuv.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
||||
|
|
|
@ -36,15 +36,6 @@ let Utils = {
|
|||
return mm;
|
||||
},
|
||||
checkPermissionForMM: function u_checkPermissionForMM(mm, permName) {
|
||||
let testing = false;
|
||||
try {
|
||||
testing = Services.prefs.getBoolPref("dom.mozInputMethod.testing");
|
||||
} catch (e) { }
|
||||
|
||||
if (testing) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return mm.assertPermission(permName);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -213,14 +213,8 @@ MozInputMethod.prototype = {
|
|||
this._isSystem = true;
|
||||
}
|
||||
|
||||
// Check if we can use keyboard related APIs.
|
||||
let testing = false;
|
||||
try {
|
||||
testing = Services.prefs.getBoolPref("dom.mozInputMethod.testing");
|
||||
} catch (e) {
|
||||
}
|
||||
perm = Services.perms.testExactPermissionFromPrincipal(principal, "input");
|
||||
if (!testing && perm !== Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
if (perm !== Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
this._isKeyboard = false;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ function inputmethod_setup(callback) {
|
|||
}
|
||||
|
||||
let permissions = [];
|
||||
['input-manage', 'browser'].forEach(function(name) {
|
||||
['input', 'input-manage', 'browser'].forEach(function(name) {
|
||||
permissions.push({
|
||||
type: name,
|
||||
allow: true,
|
||||
|
@ -20,9 +20,7 @@ function inputmethod_setup(callback) {
|
|||
let prefs = [
|
||||
['dom.mozBrowserFramesEnabled', true],
|
||||
// Enable navigator.mozInputMethod.
|
||||
['dom.mozInputMethod.enabled', true],
|
||||
// Bypass the permission check for mozInputMethod API.
|
||||
['dom.mozInputMethod.testing', true]
|
||||
['dom.mozInputMethod.enabled', true]
|
||||
];
|
||||
SpecialPowers.pushPrefEnv({set: prefs}, function() {
|
||||
SimpleTest.waitForFocus(callback);
|
||||
|
|
|
@ -89,7 +89,11 @@ function runTest() {
|
|||
SpecialPowers.pushPermissions([{
|
||||
type: 'input',
|
||||
allow: true,
|
||||
context: imeUrl
|
||||
context: {
|
||||
url: imeUrl,
|
||||
appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
|
||||
isInBrowserElement: true
|
||||
}
|
||||
}], function() {
|
||||
keyboardA.src = imeUrl;
|
||||
keyboardB.src = imeUrl;
|
||||
|
|
|
@ -76,7 +76,11 @@ function runTest() {
|
|||
SpecialPowers.pushPermissions([{
|
||||
type: 'input',
|
||||
allow: true,
|
||||
context: imeUrl
|
||||
context: {
|
||||
url: imeUrl,
|
||||
appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
|
||||
isInBrowserElement: true
|
||||
}
|
||||
}], function() {
|
||||
// STEP 2c: Tell Gecko to use this iframe as its keyboard app
|
||||
let req = keyboard.setInputMethodActive(true);
|
||||
|
|
|
@ -66,6 +66,9 @@
|
|||
#include "nsIWidget.h"
|
||||
#include "nsIWindowMediator.h"
|
||||
#include "nsIWindowWatcher.h"
|
||||
#ifndef XP_WIN
|
||||
#include "nsJARProtocolHandler.h"
|
||||
#endif
|
||||
#include "nsOpenURIInFrameParams.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsPIWindowWatcher.h"
|
||||
|
@ -898,9 +901,21 @@ TabParent::LoadURL(nsIURI* aURI)
|
|||
rv = packageFile->GetPath(path);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
nsRefPtr<OpenFileAndSendFDRunnable> openFileRunnable =
|
||||
new OpenFileAndSendFDRunnable(path, this);
|
||||
openFileRunnable->Dispatch();
|
||||
#ifndef XP_WIN
|
||||
PRFileDesc* cachedFd = nullptr;
|
||||
gJarHandler->JarCache()->GetFd(packageFile, &cachedFd);
|
||||
|
||||
if (cachedFd) {
|
||||
FileDescriptor::PlatformHandleType handle =
|
||||
FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(cachedFd));
|
||||
unused << SendCacheFileDescriptor(path, FileDescriptor(handle));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
nsRefPtr<OpenFileAndSendFDRunnable> openFileRunnable =
|
||||
new OpenFileAndSendFDRunnable(path, this);
|
||||
openFileRunnable->Dispatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,6 +161,11 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
|
|||
'/security/sandbox/chromium-shim',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] != 'WINNT':
|
||||
LOCAL_INCLUDES += [
|
||||
'/modules/libjar',
|
||||
]
|
||||
|
||||
DEFINES['BIN_SUFFIX'] = '"%s"' % CONFIG['BIN_SUFFIX']
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gonk', 'qt'):
|
||||
|
|
|
@ -10,10 +10,6 @@
|
|||
#include "nsMimeTypes.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#ifdef MOZ_ANDROID_OMX
|
||||
#include "AndroidMediaPluginHost.h"
|
||||
#endif
|
||||
|
||||
#include "OggDecoder.h"
|
||||
#include "OggReader.h"
|
||||
#ifdef MOZ_WAVE
|
||||
|
@ -34,7 +30,6 @@
|
|||
#include "GStreamerReader.h"
|
||||
#endif
|
||||
#ifdef MOZ_ANDROID_OMX
|
||||
#include "AndroidMediaPluginHost.h"
|
||||
#include "AndroidMediaDecoder.h"
|
||||
#include "AndroidMediaReader.h"
|
||||
#include "AndroidMediaPluginHost.h"
|
||||
|
|
|
@ -2353,12 +2353,12 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
|||
// Play the remaining media. We want to run AdvanceFrame() at least
|
||||
// once to ensure the current playback position is advanced to the
|
||||
// end of the media, and so that we update the readyState.
|
||||
MaybeStartPlayback();
|
||||
if (VideoQueue().GetSize() > 1 ||
|
||||
(HasAudio() && !mAudioCompleted) ||
|
||||
(mAudioCaptured && !mDecodedStream->IsFinished()))
|
||||
{
|
||||
// Start playback if necessary to play the remaining media.
|
||||
MaybeStartPlayback();
|
||||
UpdateRenderedVideoFrames();
|
||||
NS_ASSERTION(!IsPlaying() ||
|
||||
mLogicallySeeking ||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "AndroidMediaPluginHost.h"
|
||||
#include "nsXPCOMStrings.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "AndroidMediaReader.h"
|
||||
#include "nsIGfxInfo.h"
|
||||
#include "gfxCrashReporterUtils.h"
|
||||
#include "prmem.h"
|
||||
|
@ -288,7 +287,6 @@ MPAPI::Decoder *AndroidMediaPluginHost::CreateDecoder(MediaResource *aResource,
|
|||
|
||||
decoder->mResource = strdup(url.get());
|
||||
if (plugin->CreateDecoder(&sPluginHost, decoder, chars, len)) {
|
||||
aResource->AddRef();
|
||||
return decoder.forget();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -461,7 +461,7 @@ AndroidMediaResourceServer::AddResource(mozilla::MediaResource* aResource, nsCSt
|
|||
MutexAutoLock lock(mMutex);
|
||||
|
||||
// Adding a resource URL that already exists is considered an error.
|
||||
if (mResources.find(aUrl) != mResources.end()) return NS_ERROR_FAILURE;
|
||||
if (mResources.find(url) != mResources.end()) return NS_ERROR_FAILURE;
|
||||
mResources[url] = aResource;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ support-files =
|
|||
[test_BufferedSeek_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_BufferingWait.html]
|
||||
skip-if = true # bug 1190776
|
||||
[test_BufferingWait_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac") || (os == "win" && os_version == "6.1")) # Only supported on osx and vista+, disabling on win7 bug 1191138
|
||||
[test_EndOfStream.html]
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "mozilla/SharedThreadPool.h"
|
||||
|
||||
#include "MediaInfo.h"
|
||||
#include "FuzzingWrapper.h"
|
||||
#include "H264Converter.h"
|
||||
|
||||
#include "OpusDecoder.h"
|
||||
|
@ -50,6 +51,9 @@ bool PlatformDecoderModule::sGonkDecoderEnabled = false;
|
|||
bool PlatformDecoderModule::sAndroidMCDecoderEnabled = false;
|
||||
bool PlatformDecoderModule::sAndroidMCDecoderPreferred = false;
|
||||
bool PlatformDecoderModule::sGMPDecoderEnabled = false;
|
||||
bool PlatformDecoderModule::sEnableFuzzingWrapper = false;
|
||||
uint32_t PlatformDecoderModule::sVideoOutputMinimumInterval_ms = 0;
|
||||
bool PlatformDecoderModule::sDontDelayInputExhausted = false;
|
||||
|
||||
/* static */
|
||||
void
|
||||
|
@ -81,6 +85,13 @@ PlatformDecoderModule::Init()
|
|||
Preferences::AddBoolVarCache(&sGMPDecoderEnabled,
|
||||
"media.fragmented-mp4.gmp.enabled", false);
|
||||
|
||||
Preferences::AddBoolVarCache(&sEnableFuzzingWrapper,
|
||||
"media.decoder.fuzzing.enabled", false);
|
||||
Preferences::AddUintVarCache(&sVideoOutputMinimumInterval_ms,
|
||||
"media.decoder.fuzzing.video-output-minimum-interval-ms", 0);
|
||||
Preferences::AddBoolVarCache(&sDontDelayInputExhausted,
|
||||
"media.decoder.fuzzing.dont-delay-inputexhausted", false);
|
||||
|
||||
#ifdef XP_WIN
|
||||
WMFDecoderModule::Init();
|
||||
#endif
|
||||
|
@ -212,25 +223,40 @@ PlatformDecoderModule::CreateDecoder(const TrackInfo& aConfig,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
MediaDataDecoderCallback* callback = aCallback;
|
||||
nsRefPtr<DecoderCallbackFuzzingWrapper> callbackWrapper;
|
||||
if (sEnableFuzzingWrapper) {
|
||||
callbackWrapper = new DecoderCallbackFuzzingWrapper(aCallback);
|
||||
callbackWrapper->SetVideoOutputMinimumInterval(
|
||||
TimeDuration::FromMilliseconds(sVideoOutputMinimumInterval_ms));
|
||||
callbackWrapper->SetDontDelayInputExhausted(sDontDelayInputExhausted);
|
||||
callback = callbackWrapper.get();
|
||||
}
|
||||
|
||||
if (H264Converter::IsH264(aConfig)) {
|
||||
m = new H264Converter(this,
|
||||
*aConfig.GetAsVideoInfo(),
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aTaskQueue,
|
||||
aCallback);
|
||||
callback);
|
||||
} else if (!hasPlatformDecoder && VPXDecoder::IsVPX(aConfig.mMimeType)) {
|
||||
m = new VPXDecoder(*aConfig.GetAsVideoInfo(),
|
||||
aImageContainer,
|
||||
aTaskQueue,
|
||||
aCallback);
|
||||
callback);
|
||||
} else {
|
||||
m = CreateVideoDecoder(*aConfig.GetAsVideoInfo(),
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aTaskQueue,
|
||||
aCallback);
|
||||
callback);
|
||||
}
|
||||
|
||||
if (callbackWrapper && m) {
|
||||
m = new DecoderFuzzingWrapper(m.forget(), callbackWrapper.forget());
|
||||
}
|
||||
|
||||
return m.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -159,6 +159,9 @@ protected:
|
|||
static bool sAndroidMCDecoderPreferred;
|
||||
static bool sAndroidMCDecoderEnabled;
|
||||
static bool sGMPDecoderEnabled;
|
||||
static bool sEnableFuzzingWrapper;
|
||||
static uint32_t sVideoOutputMinimumInterval_ms;
|
||||
static bool sDontDelayInputExhausted;
|
||||
};
|
||||
|
||||
// A callback used by MediaDataDecoder to return output/errors to the
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "GonkNativeWindowClient.h"
|
||||
#include "mozilla/layers/GrallocTextureClient.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include <cutils/properties.h>
|
||||
|
||||
#define READ_OUTPUT_BUFFER_TIMEOUT_US 3000
|
||||
|
||||
|
@ -78,6 +79,19 @@ GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
|||
{
|
||||
nsIntSize displaySize(mDisplayWidth, mDisplayHeight);
|
||||
nsIntRect pictureRect(0, 0, mVideoWidth, mVideoHeight);
|
||||
|
||||
uint32_t maxWidth, maxHeight;
|
||||
char propValue[PROPERTY_VALUE_MAX];
|
||||
property_get("ro.moz.omx.hw.max_width", propValue, "-1");
|
||||
maxWidth = -1 == atoi(propValue) ? MAX_VIDEO_WIDTH : atoi(propValue);
|
||||
property_get("ro.moz.omx.hw.max_height", propValue, "-1");
|
||||
maxHeight = -1 == atoi(propValue) ? MAX_VIDEO_HEIGHT : atoi(propValue) ;
|
||||
|
||||
if (mVideoWidth * mVideoHeight > maxWidth * maxHeight) {
|
||||
GVDM_LOG("Video resolution exceeds hw codec capability");
|
||||
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
|
||||
}
|
||||
|
||||
// Validate the container-reported frame and pictureRect sizes. This ensures
|
||||
// that our video frame creation code doesn't overflow.
|
||||
nsIntSize frameSize(mVideoWidth, mVideoHeight);
|
||||
|
@ -355,6 +369,10 @@ GonkVideoDecoderManager::SetVideoFormat()
|
|||
nsresult
|
||||
GonkVideoDecoderManager::Flush()
|
||||
{
|
||||
if (mDecoder == nullptr) {
|
||||
GVDM_LOG("Decoder is not inited");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mQueueSample.Clear();
|
||||
|
|
|
@ -10,6 +10,7 @@ EXPORTS += [
|
|||
'agnostic/VPXDecoder.h',
|
||||
'PlatformDecoderModule.h',
|
||||
'SharedDecoderManager.h',
|
||||
'wrappers/FuzzingWrapper.h',
|
||||
'wrappers/H264Converter.h'
|
||||
]
|
||||
|
||||
|
@ -20,6 +21,7 @@ UNIFIED_SOURCES += [
|
|||
'agnostic/VPXDecoder.cpp',
|
||||
'PlatformDecoderModule.cpp',
|
||||
'SharedDecoderManager.cpp',
|
||||
'wrappers/FuzzingWrapper.cpp',
|
||||
'wrappers/H264Converter.cpp'
|
||||
]
|
||||
|
||||
|
|
|
@ -0,0 +1,324 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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 "FuzzingWrapper.h"
|
||||
|
||||
PRLogModuleInfo* GetFuzzingWrapperLog() {
|
||||
static PRLogModuleInfo* log = nullptr;
|
||||
if (!log) {
|
||||
log = PR_NewLogModule("MediaFuzzingWrapper");
|
||||
}
|
||||
return log;
|
||||
}
|
||||
#define DFW_LOGD(arg, ...) MOZ_LOG(GetFuzzingWrapperLog(), mozilla::LogLevel::Debug, ("DecoderFuzzingWrapper(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
#define DFW_LOGV(arg, ...) MOZ_LOG(GetFuzzingWrapperLog(), mozilla::LogLevel::Verbose, ("DecoderFuzzingWrapper(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
#define CFW_LOGD(arg, ...) MOZ_LOG(GetFuzzingWrapperLog(), mozilla::LogLevel::Debug, ("DecoderCallbackFuzzingWrapper(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
#define CFW_LOGV(arg, ...) MOZ_LOG(GetFuzzingWrapperLog(), mozilla::LogLevel::Verbose, ("DecoderCallbackFuzzingWrapper(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
DecoderFuzzingWrapper::DecoderFuzzingWrapper(
|
||||
already_AddRefed<MediaDataDecoder> aDecoder,
|
||||
already_AddRefed<DecoderCallbackFuzzingWrapper> aCallbackWrapper)
|
||||
: mDecoder(aDecoder)
|
||||
, mCallbackWrapper(aCallbackWrapper)
|
||||
{
|
||||
DFW_LOGV("aDecoder=%p aCallbackWrapper=%p", mDecoder.get(), mCallbackWrapper.get());
|
||||
}
|
||||
|
||||
DecoderFuzzingWrapper::~DecoderFuzzingWrapper()
|
||||
{
|
||||
DFW_LOGV("");
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder::InitPromise>
|
||||
DecoderFuzzingWrapper::Init()
|
||||
{
|
||||
DFW_LOGV("");
|
||||
MOZ_ASSERT(mDecoder);
|
||||
return mDecoder->Init();
|
||||
}
|
||||
|
||||
nsresult
|
||||
DecoderFuzzingWrapper::Input(MediaRawData* aData)
|
||||
{
|
||||
DFW_LOGV("aData.mTime=%lld", aData->mTime);
|
||||
MOZ_ASSERT(mDecoder);
|
||||
return mDecoder->Input(aData);
|
||||
}
|
||||
|
||||
nsresult
|
||||
DecoderFuzzingWrapper::Flush()
|
||||
{
|
||||
DFW_LOGV("");
|
||||
MOZ_ASSERT(mDecoder);
|
||||
// Flush may output some frames (though unlikely).
|
||||
// Flush may block a bit, it's ok if we output some frames in the meantime.
|
||||
nsresult result = mDecoder->Flush();
|
||||
// Clear any delayed output we may have.
|
||||
mCallbackWrapper->ClearDelayedOutput();
|
||||
return result;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DecoderFuzzingWrapper::Drain()
|
||||
{
|
||||
DFW_LOGV("");
|
||||
MOZ_ASSERT(mDecoder);
|
||||
// Note: The decoder should callback DrainComplete(), we'll drain the
|
||||
// delayed output (if any) then.
|
||||
return mDecoder->Drain();
|
||||
}
|
||||
|
||||
nsresult
|
||||
DecoderFuzzingWrapper::Shutdown()
|
||||
{
|
||||
DFW_LOGV("");
|
||||
MOZ_ASSERT(mDecoder);
|
||||
// Both shutdowns below may block a bit.
|
||||
nsresult result = mDecoder->Shutdown();
|
||||
mCallbackWrapper->Shutdown();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
DecoderFuzzingWrapper::IsHardwareAccelerated(nsACString& aFailureReason) const
|
||||
{
|
||||
DFW_LOGV("");
|
||||
MOZ_ASSERT(mDecoder);
|
||||
return mDecoder->IsHardwareAccelerated(aFailureReason);
|
||||
}
|
||||
|
||||
nsresult
|
||||
DecoderFuzzingWrapper::ConfigurationChanged(const TrackInfo& aConfig)
|
||||
{
|
||||
DFW_LOGV("");
|
||||
MOZ_ASSERT(mDecoder);
|
||||
return mDecoder->ConfigurationChanged(aConfig);
|
||||
}
|
||||
|
||||
|
||||
DecoderCallbackFuzzingWrapper::DecoderCallbackFuzzingWrapper(MediaDataDecoderCallback* aCallback)
|
||||
: mCallback(aCallback)
|
||||
, mDontDelayInputExhausted(false)
|
||||
, mDraining(false)
|
||||
, mTaskQueue(new TaskQueue(SharedThreadPool::Get(NS_LITERAL_CSTRING("MediaFuzzingWrapper"), 1)))
|
||||
{
|
||||
CFW_LOGV("aCallback=%p", aCallback);
|
||||
}
|
||||
|
||||
DecoderCallbackFuzzingWrapper::~DecoderCallbackFuzzingWrapper()
|
||||
{
|
||||
CFW_LOGV("");
|
||||
}
|
||||
|
||||
void
|
||||
DecoderCallbackFuzzingWrapper::SetVideoOutputMinimumInterval(
|
||||
TimeDuration aFrameOutputMinimumInterval)
|
||||
{
|
||||
CFW_LOGD("aFrameOutputMinimumInterval=%fms",
|
||||
aFrameOutputMinimumInterval.ToMilliseconds());
|
||||
mFrameOutputMinimumInterval = aFrameOutputMinimumInterval;
|
||||
}
|
||||
|
||||
void
|
||||
DecoderCallbackFuzzingWrapper::SetDontDelayInputExhausted(
|
||||
bool aDontDelayInputExhausted)
|
||||
{
|
||||
CFW_LOGD("aDontDelayInputExhausted=%d",
|
||||
aDontDelayInputExhausted);
|
||||
mDontDelayInputExhausted = aDontDelayInputExhausted;
|
||||
}
|
||||
|
||||
void
|
||||
DecoderCallbackFuzzingWrapper::Output(MediaData* aData)
|
||||
{
|
||||
if (!mTaskQueue->IsCurrentThreadIn()) {
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethodWithArg<StorensRefPtrPassByPtr<MediaData>>(
|
||||
this, &DecoderCallbackFuzzingWrapper::Output, aData);
|
||||
mTaskQueue->Dispatch(task.forget());
|
||||
return;
|
||||
}
|
||||
CFW_LOGV("aData.mTime=%lld", aData->mTime);
|
||||
MOZ_ASSERT(mCallback);
|
||||
if (mFrameOutputMinimumInterval) {
|
||||
if (!mPreviousOutput.IsNull()) {
|
||||
if (!mDelayedOutput.empty()) {
|
||||
// We already have some delayed frames, just add this one to the queue.
|
||||
mDelayedOutput.push_back(MakePair<nsRefPtr<MediaData>, bool>(aData, false));
|
||||
CFW_LOGD("delaying output of sample@%lld, total queued:%d",
|
||||
aData->mTime, int(mDelayedOutput.size()));
|
||||
return;
|
||||
}
|
||||
if (TimeStamp::Now() < mPreviousOutput + mFrameOutputMinimumInterval) {
|
||||
// Frame arriving too soon after the previous one, start queuing.
|
||||
mDelayedOutput.push_back(MakePair<nsRefPtr<MediaData>, bool>(aData, false));
|
||||
CFW_LOGD("delaying output of sample@%lld, first queued", aData->mTime);
|
||||
if (!mDelayedOutputTimer) {
|
||||
mDelayedOutputTimer = new MediaTimer();
|
||||
}
|
||||
ScheduleOutputDelayedFrame();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// If we're here, we're going to actually output a frame -> Record time.
|
||||
mPreviousOutput = TimeStamp::Now();
|
||||
}
|
||||
|
||||
// Passing the data straight through, no need to dispatch to another queue,
|
||||
// callback should deal with that.
|
||||
mCallback->Output(aData);
|
||||
}
|
||||
|
||||
void
|
||||
DecoderCallbackFuzzingWrapper::Error()
|
||||
{
|
||||
if (!mTaskQueue->IsCurrentThreadIn()) {
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::Error);
|
||||
mTaskQueue->Dispatch(task.forget());
|
||||
return;
|
||||
}
|
||||
CFW_LOGV("");
|
||||
MOZ_ASSERT(mCallback);
|
||||
ClearDelayedOutput();
|
||||
mCallback->Error();
|
||||
}
|
||||
|
||||
void
|
||||
DecoderCallbackFuzzingWrapper::InputExhausted()
|
||||
{
|
||||
if (!mTaskQueue->IsCurrentThreadIn()) {
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::InputExhausted);
|
||||
mTaskQueue->Dispatch(task.forget());
|
||||
return;
|
||||
}
|
||||
if (!mDontDelayInputExhausted && !mDelayedOutput.empty()) {
|
||||
MediaDataAndInputExhausted& last = mDelayedOutput.back();
|
||||
CFW_LOGD("InputExhausted delayed until after output of sample@%lld",
|
||||
last.first()->mTime);
|
||||
last.second() = true;
|
||||
return;
|
||||
}
|
||||
CFW_LOGV("");
|
||||
MOZ_ASSERT(mCallback);
|
||||
mCallback->InputExhausted();
|
||||
}
|
||||
|
||||
void
|
||||
DecoderCallbackFuzzingWrapper::DrainComplete()
|
||||
{
|
||||
if (!mTaskQueue->IsCurrentThreadIn()) {
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::DrainComplete);
|
||||
mTaskQueue->Dispatch(task.forget());
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mCallback);
|
||||
if (mDelayedOutput.empty()) {
|
||||
// No queued output -> Draining is complete now.
|
||||
CFW_LOGV("No delayed output -> DrainComplete now");
|
||||
mCallback->DrainComplete();
|
||||
} else {
|
||||
// Queued output waiting -> Make sure we call DrainComplete when it's empty.
|
||||
CFW_LOGD("Delayed output -> DrainComplete later");
|
||||
mDraining = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DecoderCallbackFuzzingWrapper::ReleaseMediaResources()
|
||||
{
|
||||
if (!mTaskQueue->IsCurrentThreadIn()) {
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::ReleaseMediaResources);
|
||||
mTaskQueue->Dispatch(task.forget());
|
||||
return;
|
||||
}
|
||||
CFW_LOGV("");
|
||||
MOZ_ASSERT(mCallback);
|
||||
mCallback->ReleaseMediaResources();
|
||||
}
|
||||
|
||||
bool
|
||||
DecoderCallbackFuzzingWrapper::OnReaderTaskQueue()
|
||||
{
|
||||
CFW_LOGV("");
|
||||
MOZ_ASSERT(mCallback);
|
||||
return mCallback->OnReaderTaskQueue();
|
||||
}
|
||||
|
||||
void
|
||||
DecoderCallbackFuzzingWrapper::ScheduleOutputDelayedFrame()
|
||||
{
|
||||
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
|
||||
nsRefPtr<DecoderCallbackFuzzingWrapper> self = this;
|
||||
mDelayedOutputTimer->WaitUntil(
|
||||
mPreviousOutput + mFrameOutputMinimumInterval,
|
||||
__func__)
|
||||
->Then(mTaskQueue, __func__,
|
||||
[self] () -> void { self->OutputDelayedFrame(); },
|
||||
[self] () -> void { self->OutputDelayedFrame(); });
|
||||
}
|
||||
|
||||
void
|
||||
DecoderCallbackFuzzingWrapper::OutputDelayedFrame()
|
||||
{
|
||||
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
|
||||
if (mDelayedOutput.empty()) {
|
||||
if (mDraining) {
|
||||
// No more output, and we were draining -> Send DrainComplete.
|
||||
mDraining = false;
|
||||
mCallback->DrainComplete();
|
||||
}
|
||||
return;
|
||||
}
|
||||
MediaDataAndInputExhausted& data = mDelayedOutput.front();
|
||||
CFW_LOGD("Outputting delayed sample@%lld, remaining:%d",
|
||||
data.first()->mTime, int(mDelayedOutput.size() - 1));
|
||||
mPreviousOutput = TimeStamp::Now();
|
||||
mCallback->Output(data.first());
|
||||
if (data.second()) {
|
||||
CFW_LOGD("InputExhausted after delayed sample@%lld", data.first()->mTime);
|
||||
mCallback->InputExhausted();
|
||||
}
|
||||
mDelayedOutput.pop_front();
|
||||
if (!mDelayedOutput.empty()) {
|
||||
// More output -> Send it later.
|
||||
ScheduleOutputDelayedFrame();
|
||||
} else if (mDraining) {
|
||||
// No more output, and we were draining -> Send DrainComplete.
|
||||
CFW_LOGD("DrainComplete");
|
||||
mDraining = false;
|
||||
mCallback->DrainComplete();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DecoderCallbackFuzzingWrapper::ClearDelayedOutput()
|
||||
{
|
||||
if (!mTaskQueue->IsCurrentThreadIn()) {
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::ClearDelayedOutput);
|
||||
mTaskQueue->Dispatch(task.forget());
|
||||
return;
|
||||
}
|
||||
mDelayedOutputTimer = nullptr;
|
||||
mDelayedOutput.clear();
|
||||
}
|
||||
|
||||
void
|
||||
DecoderCallbackFuzzingWrapper::Shutdown()
|
||||
{
|
||||
DFW_LOGV("Shutting down mTaskQueue");
|
||||
mTaskQueue->BeginShutdown();
|
||||
mTaskQueue->AwaitIdle();
|
||||
DFW_LOGV("mTaskQueue shut down");
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,120 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
|
||||
#if !defined(FuzzingWrapper_h_)
|
||||
#define FuzzingWrapper_h_
|
||||
|
||||
#include "mozilla/Pair.h"
|
||||
#include "PlatformDecoderModule.h"
|
||||
|
||||
#include <deque>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Fuzzing wrapper for media decoders.
|
||||
//
|
||||
// DecoderFuzzingWrapper owns the DecoderCallbackFuzzingWrapper, and inserts
|
||||
// itself between the reader and the decoder.
|
||||
// DecoderCallbackFuzzingWrapper inserts itself between a decoder and its
|
||||
// callback.
|
||||
// Together they are used to introduce some fuzzing, (e.g. delay output).
|
||||
//
|
||||
// Normally:
|
||||
// ====================================>
|
||||
// reader decoder
|
||||
// <------------------------------------
|
||||
//
|
||||
// With fuzzing:
|
||||
// ======> DecoderFuzzingWrapper ======>
|
||||
// reader v decoder
|
||||
// <-- DecoderCallbackFuzzingWrapper <--
|
||||
//
|
||||
// Creation order should be:
|
||||
// 1. Create DecoderCallbackFuzzingWrapper, give the expected callback target.
|
||||
// 2. Create actual decoder, give DecoderCallbackFuzzingWrapper as callback.
|
||||
// 3. Create DecoderFuzzingWrapper, give decoder and DecoderCallbackFuzzingWrapper.
|
||||
// DecoderFuzzingWrapper is what the reader sees as decoder, it owns the
|
||||
// real decoder and the DecoderCallbackFuzzingWrapper.
|
||||
|
||||
class DecoderCallbackFuzzingWrapper : public MediaDataDecoderCallback
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecoderCallbackFuzzingWrapper)
|
||||
|
||||
explicit DecoderCallbackFuzzingWrapper(MediaDataDecoderCallback* aCallback);
|
||||
|
||||
// Enforce a minimum interval between output frames (i.e., limit frame rate).
|
||||
// Of course, if the decoder is even slower, this won't have any effect.
|
||||
void SetVideoOutputMinimumInterval(TimeDuration aFrameOutputMinimumInterval);
|
||||
// If false (default), if frames are delayed, any InputExhausted is delayed to
|
||||
// be later sent after the corresponding delayed frame.
|
||||
// If true, InputExhausted are passed through immediately; This could result
|
||||
// in lots of frames being decoded and queued for delayed output!
|
||||
void SetDontDelayInputExhausted(bool aDontDelayInputExhausted);
|
||||
|
||||
private:
|
||||
virtual ~DecoderCallbackFuzzingWrapper();
|
||||
|
||||
// MediaDataDecoderCallback implementation.
|
||||
void Output(MediaData* aData) override;
|
||||
void Error() override;
|
||||
void InputExhausted() override;
|
||||
void DrainComplete() override;
|
||||
void ReleaseMediaResources() override;
|
||||
bool OnReaderTaskQueue() override;
|
||||
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
|
||||
// Settings for minimum frame output interval & InputExhausted,
|
||||
// should be set during init and then only read on mTaskQueue.
|
||||
TimeDuration mFrameOutputMinimumInterval;
|
||||
bool mDontDelayInputExhausted;
|
||||
// Members for minimum frame output interval & InputExhausted,
|
||||
// should only be accessed on mTaskQueue.
|
||||
TimeStamp mPreviousOutput;
|
||||
// First member is the frame to be delayed.
|
||||
// Second member is true if an 'InputExhausted' arrived after that frame; in
|
||||
// which case an InputExhausted will be sent after finally outputting the frame.
|
||||
typedef Pair<nsRefPtr<MediaData>, bool> MediaDataAndInputExhausted;
|
||||
std::deque<MediaDataAndInputExhausted> mDelayedOutput;
|
||||
nsRefPtr<MediaTimer> mDelayedOutputTimer;
|
||||
// If draining, a 'DrainComplete' will be sent after all delayed frames have
|
||||
// been output.
|
||||
bool mDraining;
|
||||
// All callbacks are redirected through this task queue, both to avoid locking
|
||||
// and to have a consistent sequencing of callbacks.
|
||||
nsRefPtr<TaskQueue> mTaskQueue;
|
||||
void ScheduleOutputDelayedFrame();
|
||||
void OutputDelayedFrame();
|
||||
public: // public for the benefit of DecoderFuzzingWrapper.
|
||||
void ClearDelayedOutput();
|
||||
void Shutdown();
|
||||
};
|
||||
|
||||
class DecoderFuzzingWrapper : public MediaDataDecoder
|
||||
{
|
||||
public:
|
||||
DecoderFuzzingWrapper(already_AddRefed<MediaDataDecoder> aDecoder,
|
||||
already_AddRefed<DecoderCallbackFuzzingWrapper> aCallbackWrapper);
|
||||
virtual ~DecoderFuzzingWrapper();
|
||||
|
||||
private:
|
||||
// MediaDataDecoder implementation.
|
||||
nsRefPtr<InitPromise> Init() override;
|
||||
nsresult Input(MediaRawData* aSample) override;
|
||||
nsresult Flush() override;
|
||||
nsresult Drain() override;
|
||||
nsresult Shutdown() override;
|
||||
bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
|
||||
nsresult ConfigurationChanged(const TrackInfo& aConfig) override;
|
||||
|
||||
nsRefPtr<MediaDataDecoder> mDecoder;
|
||||
nsRefPtr<DecoderCallbackFuzzingWrapper> mCallbackWrapper;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -1,7 +1,7 @@
|
|||
[DEFAULT]
|
||||
# strictContentSandbox - bug 1042735, Android 2.3 - bug 981881
|
||||
tags = msg webrtc
|
||||
skip-if = (os == 'win' && strictContentSandbox) || android_version == '10' || android_version == '18' || (buildapp == 'mulet') || (toolkit == 'gonk' && debug) # b2g(Either bug 1171118 or bug 1169838, take your pick)
|
||||
skip-if = (os == 'win' && strictContentSandbox) || android_version == '10' || (buildapp == 'mulet') || (toolkit == 'gonk' && debug) # b2g(Either bug 1171118 or bug 1169838, take your pick)
|
||||
support-files =
|
||||
head.js
|
||||
dataChannel.js
|
||||
|
@ -17,21 +17,21 @@ support-files =
|
|||
[test_dataChannel_basicAudio.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # Bug 962984 for debug, bug 963244 for opt
|
||||
[test_dataChannel_basicAudioVideo.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_dataChannel_basicAudioVideoNoBundle.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) FAILS WHEN RUN MANUALLY ON AWS, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_dataChannel_basicAudioVideoCombined.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_dataChannel_basicDataOnly.html]
|
||||
[test_dataChannel_basicVideo.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_dataChannel_bug1013809.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g emulator seems to be too slow (Bug 1016498 and 1008080)
|
||||
[test_dataChannel_noOffer.html]
|
||||
[test_enumerateDevices.html]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[test_getUserMedia_audioCapture.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g emulator seems to be too slow (Bug 1016498 and 1008080)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g emulator seems to be too slow (Bug 1016498 and 1008080), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_getUserMedia_basicAudio.html]
|
||||
skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # debug-only failure
|
||||
[test_getUserMedia_basicVideo.html]
|
||||
|
@ -46,7 +46,7 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # no
|
|||
skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # debug-only failure, turned an intermittent (bug 962579) into a permanant orange
|
||||
[test_getUserMedia_constraints.html]
|
||||
[test_getUserMedia_callbacks.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' || buildapp == 'mulet' # Bug 1063290, intermittent timeout # TC: Bug 1144079 - Re-enable Mulet mochitests and reftests taskcluster-specific disables.
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || buildapp == 'mulet' # Bug 1063290, intermittent timeout # TC: Bug 1144079 - Re-enable Mulet mochitests and reftests taskcluster-specific disables.
|
||||
[test_getUserMedia_gumWithinGum.html]
|
||||
[test_getUserMedia_playAudioTwice.html]
|
||||
[test_getUserMedia_playVideoAudioTwice.html]
|
||||
|
@ -63,11 +63,11 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 1021776, too --ing
|
|||
[test_peerConnection_basicAudio.html]
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
|
||||
[test_peerConnection_basicAudioVideo.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_basicAudioVideoCombined.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_basicAudioVideoNoBundle.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_basicVideo.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_basicScreenshare.html]
|
||||
|
@ -92,7 +92,7 @@ skip-if = buildapp == 'b2g' || buildapp == 'mulet' || os == 'android' # bug 1043
|
|||
[test_peerConnection_bug1064223.html]
|
||||
[test_peerConnection_capturedVideo.html]
|
||||
tags=capturestream
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_captureStream_canvas_2d.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_captureStream_canvas_webgl.html]
|
||||
|
@ -103,9 +103,9 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video suppo
|
|||
[test_peerConnection_closeDuringIce.html]
|
||||
[test_peerConnection_errorCallbacks.html]
|
||||
[test_peerConnection_iceFailure.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || os == 'linux' || os == 'mac' || os == 'win' # Disabling because of test failures on B2G emulator (Bug 1180388 for win, mac and linux)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || os == 'linux' || os == 'mac' || os == 'win' || android_version == '18' # Disabling because of test failures on B2G emulator (Bug 1180388 for win, mac and linux), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_forwarding_basicAudioVideoCombined.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_noTrickleAnswer.html]
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
|
||||
[test_peerConnection_noTrickleOffer.html]
|
||||
|
@ -116,17 +116,17 @@ skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio
|
|||
[test_peerConnection_offerRequiresReceiveVideo.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_offerRequiresReceiveVideoAudio.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_promiseSendOnly.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_relayOnly.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_callbacks.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_replaceTrack.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_syncSetDescription.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_setLocalAnswerInHaveLocalOffer.html]
|
||||
[test_peerConnection_setLocalAnswerInStable.html]
|
||||
[test_peerConnection_setLocalOfferInHaveRemoteOffer.html]
|
||||
|
@ -138,51 +138,51 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video suppo
|
|||
[test_peerConnection_toJSON.html]
|
||||
|
||||
[test_peerConnection_twoAudioStreams.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g (Bug 1059867), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_twoAudioTracksInOneStream.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g (Bug 1059867), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_twoAudioVideoStreams.html]
|
||||
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s)
|
||||
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s) || android_version == '18'
|
||||
[test_peerConnection_twoAudioVideoStreamsCombined.html]
|
||||
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s)
|
||||
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s) || android_version == '18'
|
||||
[test_peerConnection_twoVideoStreams.html]
|
||||
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s)
|
||||
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s) || android_version == '18'
|
||||
[test_peerConnection_twoVideoTracksInOneStream.html]
|
||||
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s)
|
||||
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
|
||||
[test_peerConnection_addSecondAudioStream.html]
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
[test_peerConnection_answererAddSecondAudioStream.html]
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
[test_peerConnection_removeAudioTrack.html]
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_removeThenAddAudioTrack.html]
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_addSecondVideoStream.html]
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s)
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
|
||||
[test_peerConnection_removeVideoTrack.html]
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s)
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
|
||||
[test_peerConnection_removeThenAddVideoTrack.html]
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s)
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
|
||||
[test_peerConnection_replaceVideoThenRenegotiate.html]
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s)
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
|
||||
[test_peerConnection_addSecondAudioStreamNoBundle.html]
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_removeThenAddAudioTrackNoBundle.html]
|
||||
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
|
||||
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_addSecondVideoStreamNoBundle.html]
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s)
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || android_version == '18'
|
||||
[test_peerConnection_removeThenAddVideoTrackNoBundle.html]
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s)
|
||||
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || android_version == '18'
|
||||
[test_peerConnection_addDataChannel.html]
|
||||
skip-if = toolkit == 'gonk' # B2G emulator seems to be so slow that DTLS cannot establish properly
|
||||
[test_peerConnection_addDataChannelNoBundle.html]
|
||||
|
@ -195,7 +195,7 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
|||
[test_peerConnection_localReofferRollback.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_remoteRollback.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g (Bug 1059867), android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_remoteReofferRollback.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
|
||||
|
|
|
@ -140,9 +140,12 @@ public:
|
|||
event->SetTrusted(true);
|
||||
event->SetSource(mPort);
|
||||
|
||||
nsTArray<nsRefPtr<MessagePortBase>> ports;
|
||||
mData->TakeTransferredPorts(ports);
|
||||
|
||||
nsRefPtr<MessagePortList> portList =
|
||||
new MessagePortList(static_cast<dom::Event*>(event.get()),
|
||||
mData->GetTransferredPorts());
|
||||
ports);
|
||||
event->SetPorts(portList);
|
||||
|
||||
bool dummy;
|
||||
|
|
|
@ -46,19 +46,11 @@ SharedMessagePortMessage::Write(JSContext* aCx,
|
|||
JS::Handle<JS::Value> aTransfer,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
StructuredCloneHelper::Write(aCx, aValue, aTransfer, aRv);
|
||||
StructuredCloneHelper::Write(aCx, aValue, aTransfer, true, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = BlobImpls();
|
||||
for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) {
|
||||
if (!blobImpls[i]->MayBeClonedToOtherThreads()) {
|
||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FallibleTArray<uint8_t> cloneData;
|
||||
|
||||
MoveBufferDataToArray(cloneData, aRv);
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
[JSImplementation="@mozilla.org/b2g-inputmethod;1",
|
||||
NavigatorProperty="mozInputMethod",
|
||||
Func="Navigator::HasInputMethodSupport"]
|
||||
Pref="dom.mozInputMethod.enabled",
|
||||
CheckAnyPermissions="input input-manage"]
|
||||
interface MozInputMethod : EventTarget {
|
||||
// Input Method Manager contain a few global methods expose to apps
|
||||
readonly attribute MozInputMethodManager mgmt;
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This API is intended to lock the device in a way that it has no value
|
||||
* anymore for a thief. A side effect is also protecting user's data. This
|
||||
* means that we expect the device to be:
|
||||
* - locked so that only the legitimate user can unlock it
|
||||
* - unable to communitate via ADB, Devtools, MTP and/or UMS, ...
|
||||
* - unable to go into recovery or fastboot mode to avoid flashing anything
|
||||
*/
|
||||
|
||||
[JSImplementation="@mozilla.org/moz-kill-switch;1",
|
||||
NavigatorProperty="mozKillSwitch",
|
||||
AvailableIn="CertifiedApps",
|
||||
CheckAnyPermissions="killswitch",
|
||||
Pref="dom.mozKillSwitch.enabled"]
|
||||
interface KillSwitch {
|
||||
Promise<any> enable();
|
||||
Promise<any> disable();
|
||||
};
|
|
@ -276,6 +276,7 @@ WEBIDL_FILES = [
|
|||
'KeyboardEvent.webidl',
|
||||
'KeyEvent.webidl',
|
||||
'KeyframeEffect.webidl',
|
||||
'KillSwitch.webidl',
|
||||
'LegacyQueryInterface.webidl',
|
||||
'LinkStyle.webidl',
|
||||
'ListBoxObject.webidl',
|
||||
|
|
|
@ -233,7 +233,7 @@ public:
|
|||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
// This needs to be structured cloned while it's still on the worker thread.
|
||||
Write(aCx, aObj, mRv);
|
||||
Write(aCx, aObj, true, mRv);
|
||||
NS_WARN_IF(mRv.Failed());
|
||||
}
|
||||
|
||||
|
@ -294,7 +294,7 @@ public:
|
|||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
// This needs to be structured cloned while it's still on the worker thread.
|
||||
Write(aCx, aObj, mRv);
|
||||
Write(aCx, aObj, true, mRv);
|
||||
NS_WARN_IF(mRv.Failed());
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "nsGlobalWindow.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerStructuredClone.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -73,24 +72,17 @@ ServiceWorkerClient::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProt
|
|||
|
||||
namespace {
|
||||
|
||||
class ServiceWorkerClientPostMessageRunnable final : public nsRunnable
|
||||
class ServiceWorkerClientPostMessageRunnable final
|
||||
: public nsRunnable
|
||||
, public StructuredCloneHelper
|
||||
{
|
||||
uint64_t mWindowId;
|
||||
JSAutoStructuredCloneBuffer mBuffer;
|
||||
WorkerStructuredCloneClosure mClosure;
|
||||
|
||||
public:
|
||||
ServiceWorkerClientPostMessageRunnable(uint64_t aWindowId,
|
||||
JSAutoStructuredCloneBuffer&& aData,
|
||||
WorkerStructuredCloneClosure& aClosure)
|
||||
: mWindowId(aWindowId),
|
||||
mBuffer(Move(aData))
|
||||
{
|
||||
mClosure.mClonedObjects.SwapElements(aClosure.mClonedObjects);
|
||||
mClosure.mClonedImages.SwapElements(aClosure.mClonedImages);
|
||||
MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty());
|
||||
mClosure.mMessagePortIdentifiers.SwapElements(aClosure.mMessagePortIdentifiers);
|
||||
}
|
||||
explicit ServiceWorkerClientPostMessageRunnable(uint64_t aWindowId)
|
||||
: StructuredCloneHelper(CloningSupported, TransferringSupported)
|
||||
, mWindowId(aWindowId)
|
||||
{}
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
|
@ -123,40 +115,40 @@ private:
|
|||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
// Release reference to objects that were AddRef'd for
|
||||
// cloning into worker when array goes out of scope.
|
||||
WorkerStructuredCloneClosure closure;
|
||||
closure.mClonedObjects.SwapElements(mClosure.mClonedObjects);
|
||||
closure.mClonedImages.SwapElements(mClosure.mClonedImages);
|
||||
MOZ_ASSERT(mClosure.mMessagePorts.IsEmpty());
|
||||
closure.mMessagePortIdentifiers.SwapElements(mClosure.mMessagePortIdentifiers);
|
||||
closure.mParentWindow = do_QueryInterface(aTargetContainer->GetParentObject());
|
||||
|
||||
JS::Rooted<JS::Value> messageData(aCx);
|
||||
if (!mBuffer.read(aCx, &messageData,
|
||||
WorkerStructuredCloneCallbacks(), &closure)) {
|
||||
xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
ErrorResult rv;
|
||||
Read(aTargetContainer->GetParentObject(), aCx, &messageData, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
xpc::Throw(aCx, rv.StealNSResult());
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMMessageEvent> event = new MessageEvent(aTargetContainer,
|
||||
nullptr, nullptr);
|
||||
nsresult rv =
|
||||
event->InitMessageEvent(NS_LITERAL_STRING("message"),
|
||||
false /* non-bubbling */,
|
||||
false /* not cancelable */,
|
||||
messageData,
|
||||
EmptyString(),
|
||||
EmptyString(),
|
||||
nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(aCx, rv);
|
||||
nsRefPtr<MessageEvent> event = new MessageEvent(aTargetContainer,
|
||||
nullptr, nullptr);
|
||||
rv = event->InitMessageEvent(NS_LITERAL_STRING("message"),
|
||||
false /* non-bubbling */,
|
||||
false /* not cancelable */,
|
||||
messageData,
|
||||
EmptyString(),
|
||||
EmptyString(),
|
||||
nullptr);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
xpc::Throw(aCx, rv.StealNSResult());
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsTArray<nsRefPtr<MessagePortBase>> ports;
|
||||
TakeTransferredPorts(ports);
|
||||
|
||||
nsRefPtr<MessagePortList> portList =
|
||||
new MessagePortList(static_cast<dom::Event*>(event.get()),
|
||||
ports);
|
||||
event->SetPorts(portList);
|
||||
|
||||
event->SetTrusted(true);
|
||||
bool status = false;
|
||||
aTargetContainer->DispatchEvent(event, &status);
|
||||
aTargetContainer->DispatchEvent(static_cast<dom::Event*>(event.get()),
|
||||
&status);
|
||||
|
||||
if (!status) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -194,22 +186,17 @@ ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
|||
transferable.setObject(*array);
|
||||
}
|
||||
|
||||
const JSStructuredCloneCallbacks* callbacks = WorkerStructuredCloneCallbacks();
|
||||
nsRefPtr<ServiceWorkerClientPostMessageRunnable> runnable =
|
||||
new ServiceWorkerClientPostMessageRunnable(mWindowId);
|
||||
|
||||
WorkerStructuredCloneClosure closure;
|
||||
|
||||
JSAutoStructuredCloneBuffer buffer;
|
||||
if (!buffer.write(aCx, aMessage, transferable, callbacks, &closure)) {
|
||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
runnable->Write(aCx, aMessage, transferable, true, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<ServiceWorkerClientPostMessageRunnable> runnable =
|
||||
new ServiceWorkerClientPostMessageRunnable(mWindowId, Move(buffer),
|
||||
closure);
|
||||
nsresult rv = NS_DispatchToMainThread(runnable);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
aRv = NS_DispatchToMainThread(runnable);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,15 +45,10 @@
|
|||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/LoadContext.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/BlobBinding.h"
|
||||
#include "mozilla/dom/ErrorEvent.h"
|
||||
#include "mozilla/dom/ErrorEventBinding.h"
|
||||
#include "mozilla/dom/Exceptions.h"
|
||||
#include "mozilla/dom/FunctionBinding.h"
|
||||
#include "mozilla/dom/ImageBitmap.h"
|
||||
#include "mozilla/dom/ImageBitmapBinding.h"
|
||||
#include "mozilla/dom/ImageData.h"
|
||||
#include "mozilla/dom/ImageDataBinding.h"
|
||||
#include "mozilla/dom/MessageEvent.h"
|
||||
#include "mozilla/dom/MessageEventBinding.h"
|
||||
#include "mozilla/dom/MessagePort.h"
|
||||
|
@ -62,26 +57,18 @@
|
|||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseDebugging.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/StructuredClone.h"
|
||||
#include "mozilla/dom/StructuredCloneHelper.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/dom/WebCryptoCommon.h"
|
||||
#include "mozilla/dom/WorkerBinding.h"
|
||||
#include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
|
||||
#include "mozilla/dom/WorkerGlobalScopeBinding.h"
|
||||
#include "mozilla/dom/indexedDB/IDBFactory.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/dom/ipc/nsIRemoteBlob.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "MultipartBlobImpl.h"
|
||||
#include "nsAlgorithm.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCycleCollector.h"
|
||||
#include "nsError.h"
|
||||
#include "nsDOMJSUtils.h"
|
||||
#include "nsFormData.h"
|
||||
#include "nsHostObjectProtocolHandler.h"
|
||||
#include "nsJSEnvironment.h"
|
||||
#include "nsJSUtils.h"
|
||||
|
@ -113,7 +100,6 @@
|
|||
#include "WorkerFeature.h"
|
||||
#include "WorkerRunnable.h"
|
||||
#include "WorkerScope.h"
|
||||
#include "WorkerStructuredClone.h"
|
||||
#include "WorkerThread.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
@ -327,481 +313,6 @@ LogErrorToConsole(const nsAString& aMessage,
|
|||
fflush(stderr);
|
||||
}
|
||||
|
||||
// Recursive!
|
||||
already_AddRefed<BlobImpl>
|
||||
EnsureBlobForBackgroundManager(BlobImpl* aBlobImpl,
|
||||
PBackgroundChild* aManager = nullptr)
|
||||
{
|
||||
MOZ_ASSERT(aBlobImpl);
|
||||
|
||||
if (!aManager) {
|
||||
aManager = BackgroundChild::GetForCurrentThread();
|
||||
MOZ_ASSERT(aManager);
|
||||
}
|
||||
|
||||
nsRefPtr<BlobImpl> blobImpl = aBlobImpl;
|
||||
|
||||
const nsTArray<nsRefPtr<BlobImpl>>* subBlobImpls =
|
||||
aBlobImpl->GetSubBlobImpls();
|
||||
|
||||
if (!subBlobImpls) {
|
||||
if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryObject(blobImpl)) {
|
||||
// Always make sure we have a blob from an actor we can use on this
|
||||
// thread.
|
||||
BlobChild* blobChild = BlobChild::GetOrCreate(aManager, blobImpl);
|
||||
MOZ_ASSERT(blobChild);
|
||||
|
||||
blobImpl = blobChild->GetBlobImpl();
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
DebugOnly<bool> isMutable;
|
||||
MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)));
|
||||
MOZ_ASSERT(!isMutable);
|
||||
} else {
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blobImpl->SetMutable(false)));
|
||||
}
|
||||
|
||||
return blobImpl.forget();
|
||||
}
|
||||
|
||||
const uint32_t subBlobCount = subBlobImpls->Length();
|
||||
MOZ_ASSERT(subBlobCount);
|
||||
|
||||
nsTArray<nsRefPtr<BlobImpl>> newSubBlobImpls;
|
||||
newSubBlobImpls.SetLength(subBlobCount);
|
||||
|
||||
bool newBlobImplNeeded = false;
|
||||
|
||||
for (uint32_t index = 0; index < subBlobCount; index++) {
|
||||
const nsRefPtr<BlobImpl>& subBlobImpl = subBlobImpls->ElementAt(index);
|
||||
MOZ_ASSERT(subBlobImpl);
|
||||
|
||||
nsRefPtr<BlobImpl>& newSubBlobImpl = newSubBlobImpls[index];
|
||||
|
||||
newSubBlobImpl = EnsureBlobForBackgroundManager(subBlobImpl, aManager);
|
||||
MOZ_ASSERT(newSubBlobImpl);
|
||||
|
||||
if (subBlobImpl != newSubBlobImpl) {
|
||||
newBlobImplNeeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (newBlobImplNeeded) {
|
||||
nsString contentType;
|
||||
blobImpl->GetType(contentType);
|
||||
|
||||
if (blobImpl->IsFile()) {
|
||||
nsString name;
|
||||
blobImpl->GetName(name);
|
||||
|
||||
blobImpl = new MultipartBlobImpl(newSubBlobImpls, name, contentType);
|
||||
} else {
|
||||
blobImpl = new MultipartBlobImpl(newSubBlobImpls, contentType);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blobImpl->SetMutable(false)));
|
||||
}
|
||||
|
||||
return blobImpl.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Blob>
|
||||
ReadBlobOrFileNoWrap(JSContext* aCx,
|
||||
JSStructuredCloneReader* aReader)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(aReader);
|
||||
|
||||
nsRefPtr<BlobImpl> blobImpl;
|
||||
{
|
||||
BlobImpl* rawBlobImpl;
|
||||
MOZ_ALWAYS_TRUE(JS_ReadBytes(aReader, &rawBlobImpl, sizeof(rawBlobImpl)));
|
||||
|
||||
MOZ_ASSERT(rawBlobImpl);
|
||||
|
||||
blobImpl = rawBlobImpl;
|
||||
}
|
||||
|
||||
blobImpl = EnsureBlobForBackgroundManager(blobImpl);
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
nsCOMPtr<nsISupports> parent;
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIScriptGlobalObject> scriptGlobal =
|
||||
nsJSUtils::GetStaticScriptGlobal(JS::CurrentGlobalOrNull(aCx));
|
||||
parent = do_QueryInterface(scriptGlobal);
|
||||
} else {
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
WorkerGlobalScope* globalScope = workerPrivate->GlobalScope();
|
||||
MOZ_ASSERT(globalScope);
|
||||
|
||||
parent = do_QueryObject(globalScope);
|
||||
}
|
||||
|
||||
nsRefPtr<Blob> blob = Blob::Create(parent, blobImpl);
|
||||
return blob.forget();
|
||||
}
|
||||
|
||||
void
|
||||
ReadBlobOrFile(JSContext* aCx,
|
||||
JSStructuredCloneReader* aReader,
|
||||
JS::MutableHandle<JSObject*> aBlobOrFile)
|
||||
{
|
||||
nsRefPtr<Blob> blob = ReadBlobOrFileNoWrap(aCx, aReader);
|
||||
aBlobOrFile.set(blob->WrapObject(aCx, nullptr));
|
||||
}
|
||||
|
||||
// See WriteFormData for serialization format.
|
||||
void
|
||||
ReadFormData(JSContext* aCx,
|
||||
JSStructuredCloneReader* aReader,
|
||||
uint32_t aCount,
|
||||
JS::MutableHandle<JSObject*> aFormData)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(aReader);
|
||||
MOZ_ASSERT(!aFormData);
|
||||
|
||||
nsCOMPtr<nsISupports> parent;
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIScriptGlobalObject> scriptGlobal =
|
||||
nsJSUtils::GetStaticScriptGlobal(JS::CurrentGlobalOrNull(aCx));
|
||||
parent = do_QueryInterface(scriptGlobal);
|
||||
} else {
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
workerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
WorkerGlobalScope* globalScope = workerPrivate->GlobalScope();
|
||||
MOZ_ASSERT(globalScope);
|
||||
|
||||
parent = do_QueryObject(globalScope);
|
||||
}
|
||||
|
||||
nsRefPtr<nsFormData> formData = new nsFormData(parent);
|
||||
MOZ_ASSERT(formData);
|
||||
|
||||
Optional<nsAString> thirdArg;
|
||||
|
||||
uint32_t isFile;
|
||||
uint32_t dummy;
|
||||
for (uint32_t i = 0; i < aCount; ++i) {
|
||||
MOZ_ALWAYS_TRUE(JS_ReadUint32Pair(aReader, &isFile, &dummy));
|
||||
|
||||
nsAutoString name;
|
||||
MOZ_ALWAYS_TRUE(ReadString(aReader, name));
|
||||
|
||||
if (isFile) {
|
||||
// Read out the tag since the blob reader isn't expecting it.
|
||||
MOZ_ALWAYS_TRUE(JS_ReadUint32Pair(aReader, &dummy, &dummy));
|
||||
nsRefPtr<Blob> blob = ReadBlobOrFileNoWrap(aCx, aReader);
|
||||
MOZ_ASSERT(blob);
|
||||
formData->Append(name, *blob, thirdArg);
|
||||
} else {
|
||||
nsAutoString value;
|
||||
MOZ_ALWAYS_TRUE(ReadString(aReader, value));
|
||||
formData->Append(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
aFormData.set(formData->WrapObject(aCx, nullptr));
|
||||
}
|
||||
|
||||
bool
|
||||
WriteBlobOrFile(JSStructuredCloneWriter* aWriter,
|
||||
BlobImpl* aBlobImpl,
|
||||
WorkerStructuredCloneClosure& aClosure)
|
||||
{
|
||||
MOZ_ASSERT(aWriter);
|
||||
MOZ_ASSERT(aBlobImpl);
|
||||
|
||||
if (!aBlobImpl->MayBeClonedToOtherThreads()) {
|
||||
NS_WARNING("Not all the blob implementations can be sent between threads.");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<BlobImpl> blobImpl = EnsureBlobForBackgroundManager(aBlobImpl);
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
aBlobImpl = blobImpl;
|
||||
|
||||
if (NS_WARN_IF(!JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_BLOB, 0)) ||
|
||||
NS_WARN_IF(!JS_WriteBytes(aWriter, &aBlobImpl, sizeof(aBlobImpl)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aClosure.mClonedObjects.AppendElement(aBlobImpl);
|
||||
return true;
|
||||
}
|
||||
|
||||
// A FormData is serialized as:
|
||||
// - A pair of ints (tag identifying it as a FormData, number of elements in
|
||||
// the FormData)
|
||||
// - for each (key, value) pair:
|
||||
// - pair of ints (is value a file?, 0). If not a file, value is a string.
|
||||
// - string name
|
||||
// - if value is a file:
|
||||
// - write the file/blob
|
||||
// - else:
|
||||
// - string value
|
||||
bool
|
||||
WriteFormData(JSStructuredCloneWriter* aWriter,
|
||||
nsFormData* aFormData,
|
||||
WorkerStructuredCloneClosure& aClosure)
|
||||
{
|
||||
MOZ_ASSERT(aWriter);
|
||||
MOZ_ASSERT(aFormData);
|
||||
|
||||
if (NS_WARN_IF(!JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_FORMDATA, aFormData->Length()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS Closure final
|
||||
{
|
||||
JSStructuredCloneWriter* mWriter;
|
||||
WorkerStructuredCloneClosure& mClones;
|
||||
|
||||
public:
|
||||
Closure(JSStructuredCloneWriter* aWriter,
|
||||
WorkerStructuredCloneClosure& aClones)
|
||||
: mWriter(aWriter), mClones(aClones)
|
||||
{ }
|
||||
|
||||
static bool
|
||||
Write(const nsString& aName, bool isFile, const nsString& aValue,
|
||||
File* aFile, void* aClosure)
|
||||
{
|
||||
Closure* closure = static_cast<Closure*>(aClosure);
|
||||
if (!JS_WriteUint32Pair(closure->mWriter, /* a file? */ (uint32_t) isFile, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!WriteString(closure->mWriter, aName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isFile) {
|
||||
if (!WriteBlobOrFile(closure->mWriter, aFile->Impl(),
|
||||
closure->mClones)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!WriteString(closure->mWriter, aValue)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
Closure closure(aWriter, aClosure);
|
||||
return aFormData->ForEach(Closure::Write, &closure);
|
||||
}
|
||||
|
||||
struct WorkerStructuredCloneCallbacks
|
||||
{
|
||||
static JSObject*
|
||||
Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
|
||||
uint32_t aData, void* aClosure)
|
||||
{
|
||||
// See if object is a nsIDOMBlob pointer.
|
||||
if (aTag == DOMWORKER_SCTAG_BLOB) {
|
||||
MOZ_ASSERT(!aData);
|
||||
|
||||
JS::Rooted<JSObject*> blobOrFile(aCx);
|
||||
ReadBlobOrFile(aCx, aReader, &blobOrFile);
|
||||
|
||||
return blobOrFile;
|
||||
}
|
||||
|
||||
// See if the object is an ImageData.
|
||||
if (aTag == SCTAG_DOM_IMAGEDATA) {
|
||||
MOZ_ASSERT(!aData);
|
||||
return ReadStructuredCloneImageData(aCx, aReader);
|
||||
}
|
||||
|
||||
// See if the object is a FormData.
|
||||
if (aTag == DOMWORKER_SCTAG_FORMDATA) {
|
||||
JS::Rooted<JSObject*> formData(aCx);
|
||||
// aData is the entry count.
|
||||
ReadFormData(aCx, aReader, aData, &formData);
|
||||
return formData;
|
||||
}
|
||||
|
||||
// See if the object is an ImageBitmap.
|
||||
if (aTag == SCTAG_DOM_IMAGEBITMAP) {
|
||||
NS_ASSERTION(aClosure, "Null pointer!");
|
||||
|
||||
// Get the current global object.
|
||||
auto* closure = static_cast<WorkerStructuredCloneClosure*>(aClosure);
|
||||
nsCOMPtr<nsIGlobalObject> parent = do_QueryInterface(closure->mParentWindow);
|
||||
// aData is the index of the cloned image.
|
||||
return ImageBitmap::ReadStructuredClone(aCx, aReader, parent,
|
||||
closure->mClonedImages, aData);
|
||||
}
|
||||
|
||||
return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr);
|
||||
}
|
||||
|
||||
static bool
|
||||
Write(JSContext* aCx, JSStructuredCloneWriter* aWriter,
|
||||
JS::Handle<JSObject*> aObj, void* aClosure)
|
||||
{
|
||||
NS_ASSERTION(aClosure, "Null pointer!");
|
||||
|
||||
auto* closure = static_cast<WorkerStructuredCloneClosure*>(aClosure);
|
||||
|
||||
// See if this is a Blob/File object.
|
||||
{
|
||||
nsRefPtr<Blob> blob;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
|
||||
BlobImpl* blobImpl = blob->Impl();
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
if (WriteBlobOrFile(aWriter, blobImpl, *closure)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// See if this is an ImageData object.
|
||||
{
|
||||
ImageData* imageData = nullptr;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageData, aObj, imageData))) {
|
||||
return WriteStructuredCloneImageData(aCx, aWriter, imageData);
|
||||
}
|
||||
}
|
||||
|
||||
// See if this is a FormData object.
|
||||
{
|
||||
nsFormData* formData = nullptr;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(FormData, aObj, formData))) {
|
||||
if (WriteFormData(aWriter, formData, *closure)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// See if this is an ImageBitmap object.
|
||||
{
|
||||
ImageBitmap* imageBitmap = nullptr;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageBitmap, aObj, imageBitmap))) {
|
||||
return ImageBitmap::WriteStructuredClone(aWriter,
|
||||
closure->mClonedImages,
|
||||
imageBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr);
|
||||
}
|
||||
|
||||
static void
|
||||
Error(JSContext* aCx, uint32_t /* aErrorId */)
|
||||
{
|
||||
Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
}
|
||||
|
||||
static bool
|
||||
ReadTransfer(JSContext* aCx, JSStructuredCloneReader* aReader,
|
||||
uint32_t aTag, void* aContent, uint64_t aExtraData,
|
||||
void* aClosure, JS::MutableHandle<JSObject*> aReturnObject)
|
||||
{
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
auto* closure = static_cast<WorkerStructuredCloneClosure*>(aClosure);
|
||||
|
||||
if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
|
||||
MOZ_ASSERT(!aContent);
|
||||
MOZ_ASSERT(aExtraData < closure->mMessagePortIdentifiers.Length());
|
||||
|
||||
ErrorResult rv;
|
||||
nsRefPtr<MessagePortBase> port =
|
||||
dom::MessagePort::Create(closure->mParentWindow,
|
||||
closure->mMessagePortIdentifiers[aExtraData],
|
||||
rv);
|
||||
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
closure->mMessagePorts.AppendElement(port);
|
||||
|
||||
JS::Rooted<JS::Value> value(aCx);
|
||||
if (!GetOrCreateDOMReflector(aCx, port, &value)) {
|
||||
JS_ClearPendingException(aCx);
|
||||
return false;
|
||||
}
|
||||
|
||||
aReturnObject.set(&value.toObject());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
Transfer(JSContext* aCx, JS::Handle<JSObject*> aObj, void* aClosure,
|
||||
uint32_t* aTag, JS::TransferableOwnership* aOwnership,
|
||||
void** aContent, uint64_t *aExtraData)
|
||||
{
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
auto* closure = static_cast<WorkerStructuredCloneClosure*>(aClosure);
|
||||
|
||||
MessagePortBase* port;
|
||||
nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (NS_WARN_IF(closure->mTransferredPorts.Contains(port))) {
|
||||
// No duplicates.
|
||||
return false;
|
||||
}
|
||||
|
||||
MessagePortIdentifier identifier;
|
||||
if (!port->CloneAndDisentangle(identifier)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
closure->mMessagePortIdentifiers.AppendElement(identifier);
|
||||
closure->mTransferredPorts.AppendElement(port);
|
||||
|
||||
*aTag = SCTAG_DOM_MAP_MESSAGEPORT;
|
||||
*aOwnership = JS::SCTAG_TMO_CUSTOM;
|
||||
*aContent = nullptr;
|
||||
*aExtraData = closure->mMessagePortIdentifiers.Length() - 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
FreeTransfer(uint32_t aTag, JS::TransferableOwnership aOwnership,
|
||||
void *aContent, uint64_t aExtraData, void* aClosure)
|
||||
{
|
||||
if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
|
||||
MOZ_ASSERT(aClosure);
|
||||
MOZ_ASSERT(!aContent);
|
||||
auto* closure = static_cast<WorkerStructuredCloneClosure*>(aClosure);
|
||||
|
||||
MOZ_ASSERT(aExtraData < closure->mMessagePortIdentifiers.Length());
|
||||
dom::MessagePort::ForceClose(closure->mMessagePortIdentifiers[aExtraData]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const JSStructuredCloneCallbacks gWorkerStructuredCloneCallbacks = {
|
||||
WorkerStructuredCloneCallbacks::Read,
|
||||
WorkerStructuredCloneCallbacks::Write,
|
||||
WorkerStructuredCloneCallbacks::Error,
|
||||
WorkerStructuredCloneCallbacks::ReadTransfer,
|
||||
WorkerStructuredCloneCallbacks::Transfer,
|
||||
WorkerStructuredCloneCallbacks::FreeTransfer
|
||||
};
|
||||
|
||||
class MainThreadReleaseRunnable final : public nsRunnable
|
||||
{
|
||||
nsTArray<nsCOMPtr<nsISupports>> mDoomed;
|
||||
|
@ -1081,9 +592,8 @@ private:
|
|||
};
|
||||
|
||||
class MessageEventRunnable final : public WorkerRunnable
|
||||
, public StructuredCloneHelper
|
||||
{
|
||||
JSAutoStructuredCloneBuffer mBuffer;
|
||||
WorkerStructuredCloneClosure mClosure;
|
||||
uint64_t mMessagePortSerial;
|
||||
bool mToMessagePort;
|
||||
|
||||
|
@ -1095,24 +605,12 @@ public:
|
|||
TargetAndBusyBehavior aBehavior,
|
||||
bool aToMessagePort, uint64_t aMessagePortSerial)
|
||||
: WorkerRunnable(aWorkerPrivate, aBehavior)
|
||||
, StructuredCloneHelper(CloningSupported, TransferringSupported)
|
||||
, mMessagePortSerial(aMessagePortSerial)
|
||||
, mToMessagePort(aToMessagePort)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
||||
JS::Handle<JS::Value> aTransferredValue,
|
||||
const JSStructuredCloneCallbacks *aCallbacks)
|
||||
{
|
||||
bool ok = mBuffer.write(aCx, aValue, aTransferredValue, aCallbacks,
|
||||
&mClosure);
|
||||
// This hashtable has to be empty because it could contain MessagePort
|
||||
// objects that cannot be freed on a different thread.
|
||||
mClosure.mTransferredPorts.Clear();
|
||||
return ok;
|
||||
}
|
||||
|
||||
void
|
||||
SetMessageSource(ServiceWorkerClientInfo* aSource)
|
||||
{
|
||||
|
@ -1123,49 +621,44 @@ public:
|
|||
DispatchDOMEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
DOMEventTargetHelper* aTarget, bool aIsMainThread)
|
||||
{
|
||||
// Release reference to objects that were AddRef'd for
|
||||
// cloning into worker when array goes out of scope.
|
||||
WorkerStructuredCloneClosure closure;
|
||||
closure.mClonedObjects.SwapElements(mClosure.mClonedObjects);
|
||||
closure.mClonedImages.SwapElements(mClosure.mClonedImages);
|
||||
MOZ_ASSERT(mClosure.mMessagePorts.IsEmpty());
|
||||
closure.mMessagePortIdentifiers.SwapElements(mClosure.mMessagePortIdentifiers);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> parent;
|
||||
if (aIsMainThread) {
|
||||
closure.mParentWindow = do_QueryInterface(aTarget->GetParentObject());
|
||||
parent = do_QueryInterface(aTarget->GetParentObject());
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> messageData(aCx);
|
||||
if (!mBuffer.read(aCx, &messageData,
|
||||
workers::WorkerStructuredCloneCallbacks(),
|
||||
&closure)) {
|
||||
xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
ErrorResult rv;
|
||||
Read(parent, aCx, &messageData, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
xpc::Throw(aCx, rv.StealNSResult());
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<MessageEvent> event = new MessageEvent(aTarget, nullptr, nullptr);
|
||||
nsresult rv =
|
||||
event->InitMessageEvent(NS_LITERAL_STRING("message"),
|
||||
false /* non-bubbling */,
|
||||
false /* non-cancelable */,
|
||||
messageData,
|
||||
EmptyString(),
|
||||
EmptyString(),
|
||||
nullptr);
|
||||
rv = event->InitMessageEvent(NS_LITERAL_STRING("message"),
|
||||
false /* non-bubbling */,
|
||||
false /* cancelable */,
|
||||
messageData,
|
||||
EmptyString(),
|
||||
EmptyString(),
|
||||
nullptr);
|
||||
if (mEventSource) {
|
||||
nsRefPtr<ServiceWorkerClient> client =
|
||||
new ServiceWorkerWindowClient(aTarget, *mEventSource);
|
||||
event->SetSource(client);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(aCx, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
xpc::Throw(aCx, rv.StealNSResult());
|
||||
return false;
|
||||
}
|
||||
|
||||
nsTArray<nsRefPtr<MessagePortBase>> ports;
|
||||
TakeTransferredPorts(ports);
|
||||
|
||||
event->SetTrusted(true);
|
||||
event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
|
||||
closure.mMessagePorts));
|
||||
ports));
|
||||
nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
|
||||
|
||||
nsEventStatus dummy = nsEventStatus_eIgnore;
|
||||
|
@ -1190,8 +683,7 @@ private:
|
|||
return
|
||||
aWorkerPrivate->DispatchMessageEventToMessagePort(aCx,
|
||||
mMessagePortSerial,
|
||||
Move(mBuffer),
|
||||
mClosure);
|
||||
*this);
|
||||
}
|
||||
|
||||
if (aWorkerPrivate->IsFrozen()) {
|
||||
|
@ -3307,9 +2799,8 @@ WorkerPrivateParent<Derived>::PostMessageInternal(
|
|||
WorkerRunnable::WorkerThreadModifyBusyCount,
|
||||
aToMessagePort, aMessagePortSerial);
|
||||
|
||||
if (!runnable->Write(aCx, aMessage, transferable,
|
||||
&gWorkerStructuredCloneCallbacks)) {
|
||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
runnable->Write(aCx, aMessage, transferable, true, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3352,45 +2843,10 @@ template <class Derived>
|
|||
bool
|
||||
WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
|
||||
JSContext* aCx, uint64_t aMessagePortSerial,
|
||||
JSAutoStructuredCloneBuffer&& aBuffer,
|
||||
WorkerStructuredCloneClosure& aClosure)
|
||||
StructuredCloneHelper& aHelper)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
JSAutoStructuredCloneBuffer buffer(Move(aBuffer));
|
||||
|
||||
class MOZ_STACK_CLASS AutoCloneBufferCleaner final
|
||||
{
|
||||
public:
|
||||
AutoCloneBufferCleaner(JSAutoStructuredCloneBuffer& aBuffer,
|
||||
const JSStructuredCloneCallbacks* aCallbacks,
|
||||
WorkerStructuredCloneClosure& aClosure)
|
||||
: mBuffer(aBuffer)
|
||||
, mCallbacks(aCallbacks)
|
||||
, mClosure(aClosure)
|
||||
{}
|
||||
|
||||
~AutoCloneBufferCleaner()
|
||||
{
|
||||
mBuffer.clear(mCallbacks, &mClosure);
|
||||
}
|
||||
|
||||
private:
|
||||
JSAutoStructuredCloneBuffer& mBuffer;
|
||||
const JSStructuredCloneCallbacks* mCallbacks;
|
||||
WorkerStructuredCloneClosure& mClosure;
|
||||
};
|
||||
|
||||
WorkerStructuredCloneClosure closure;
|
||||
closure.mClonedObjects.SwapElements(aClosure.mClonedObjects);
|
||||
closure.mClonedImages.SwapElements(aClosure.mClonedImages);
|
||||
MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty());
|
||||
closure.mMessagePortIdentifiers.SwapElements(aClosure.mMessagePortIdentifiers);
|
||||
|
||||
AutoCloneBufferCleaner bufferCleaner(buffer,
|
||||
&gWorkerStructuredCloneCallbacks,
|
||||
closure);
|
||||
|
||||
SharedWorker* sharedWorker;
|
||||
if (!mSharedWorkers.Get(aMessagePortSerial, &sharedWorker)) {
|
||||
// SharedWorker has already been unregistered?
|
||||
|
@ -3404,7 +2860,7 @@ WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
|
|||
return true;
|
||||
}
|
||||
|
||||
closure.mParentWindow = do_QueryInterface(port->GetParentObject());
|
||||
nsCOMPtr<nsISupports> parent = do_QueryInterface(port->GetParentObject());
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(port->GetParentObject()))) {
|
||||
|
@ -3412,24 +2868,27 @@ WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
|
|||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
ErrorResult rv;
|
||||
JS::Rooted<JS::Value> data(cx);
|
||||
if (!buffer.read(cx, &data, &gWorkerStructuredCloneCallbacks,
|
||||
&closure)) {
|
||||
aHelper.Read(parent, cx, &data, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
xpc::Throw(cx, rv.StealNSResult());
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<MessageEvent> event = new MessageEvent(port, nullptr, nullptr);
|
||||
nsresult rv =
|
||||
event->InitMessageEvent(NS_LITERAL_STRING("message"), false, false, data,
|
||||
EmptyString(), EmptyString(), nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, rv);
|
||||
rv = event->InitMessageEvent(NS_LITERAL_STRING("message"), false, false, data,
|
||||
EmptyString(), EmptyString(), nullptr);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
xpc::Throw(cx, rv.StealNSResult());
|
||||
return false;
|
||||
}
|
||||
|
||||
event->SetTrusted(true);
|
||||
nsTArray<nsRefPtr<MessagePortBase>> ports;
|
||||
aHelper.TakeTransferredPorts(ports);
|
||||
|
||||
event->SetPorts(new MessagePortList(port, closure.mMessagePorts));
|
||||
event->SetTrusted(true);
|
||||
event->SetPorts(new MessagePortList(port, ports));
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> domEvent;
|
||||
CallQueryInterface(event.get(), getter_AddRefs(domEvent));
|
||||
|
@ -3437,8 +2896,8 @@ WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
|
|||
|
||||
bool ignored;
|
||||
rv = port->DispatchEvent(domEvent, &ignored);
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
xpc::Throw(cx, rv.StealNSResult());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -6091,9 +5550,8 @@ WorkerPrivate::PostMessageToParentInternal(
|
|||
WorkerRunnable::ParentThreadUnchangedBusyCount,
|
||||
aToMessagePort, aMessagePortSerial);
|
||||
|
||||
if (!runnable->Write(aCx, aMessage, transferable,
|
||||
&gWorkerStructuredCloneCallbacks)) {
|
||||
aRv = NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
runnable->Write(aCx, aMessage, transferable, true, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -7244,30 +6702,7 @@ GetWorkerCrossThreadDispatcher(JSContext* aCx, JS::Value aWorker)
|
|||
return w->GetCrossThreadDispatcher();
|
||||
}
|
||||
|
||||
const JSStructuredCloneCallbacks*
|
||||
WorkerStructuredCloneCallbacks()
|
||||
{
|
||||
return &gWorkerStructuredCloneCallbacks;
|
||||
}
|
||||
|
||||
// Force instantiation.
|
||||
template class WorkerPrivateParent<WorkerPrivate>;
|
||||
|
||||
WorkerStructuredCloneClosure::WorkerStructuredCloneClosure()
|
||||
{}
|
||||
|
||||
WorkerStructuredCloneClosure::~WorkerStructuredCloneClosure()
|
||||
{}
|
||||
|
||||
void
|
||||
WorkerStructuredCloneClosure::Clear()
|
||||
{
|
||||
mParentWindow = nullptr;
|
||||
mClonedObjects.Clear();
|
||||
mClonedImages.Clear();
|
||||
mMessagePorts.Clear();
|
||||
mMessagePortIdentifiers.Clear();
|
||||
mTransferredPorts.Clear();
|
||||
}
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
|
|
@ -28,12 +28,10 @@
|
|||
#include "nsTArray.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsTObserverArray.h"
|
||||
#include "mozilla/dom/StructuredCloneTags.h"
|
||||
|
||||
#include "Queue.h"
|
||||
#include "WorkerFeature.h"
|
||||
|
||||
class JSAutoStructuredCloneBuffer;
|
||||
class nsIChannel;
|
||||
class nsIDocument;
|
||||
class nsIEventTarget;
|
||||
|
@ -52,6 +50,7 @@ struct RuntimeStats;
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Function;
|
||||
class StructuredCloneHelper;
|
||||
} // namespace dom
|
||||
namespace ipc {
|
||||
class PrincipalInfo;
|
||||
|
@ -74,7 +73,6 @@ class WorkerDebuggerGlobalScope;
|
|||
class WorkerGlobalScope;
|
||||
class WorkerPrivate;
|
||||
class WorkerRunnable;
|
||||
class WorkerStructuredCloneClosure;
|
||||
class WorkerThread;
|
||||
|
||||
// SharedMutex is a small wrapper around an (internal) reference-counted Mutex
|
||||
|
@ -350,8 +348,7 @@ public:
|
|||
DispatchMessageEventToMessagePort(
|
||||
JSContext* aCx,
|
||||
uint64_t aMessagePortSerial,
|
||||
JSAutoStructuredCloneBuffer&& aBuffer,
|
||||
WorkerStructuredCloneClosure& aClosure);
|
||||
StructuredCloneHelper& aHelper);
|
||||
|
||||
void
|
||||
UpdateRuntimeOptions(JSContext* aCx,
|
||||
|
@ -1509,17 +1506,6 @@ IsCurrentThreadRunningChromeWorker();
|
|||
JSContext*
|
||||
GetCurrentThreadJSContext();
|
||||
|
||||
enum WorkerStructuredDataType
|
||||
{
|
||||
DOMWORKER_SCTAG_BLOB = SCTAG_DOM_MAX,
|
||||
DOMWORKER_SCTAG_FORMDATA = SCTAG_DOM_MAX + 1,
|
||||
|
||||
DOMWORKER_SCTAG_END
|
||||
};
|
||||
|
||||
const JSStructuredCloneCallbacks*
|
||||
WorkerStructuredCloneCallbacks();
|
||||
|
||||
class AutoSyncLoopHolder
|
||||
{
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* 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_workers_WorkerStructuredClone_h
|
||||
#define mozilla_dom_workers_WorkerStructuredClone_h
|
||||
|
||||
#include "Workers.h"
|
||||
#include "mozilla/dom/PMessagePort.h"
|
||||
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
class Image;
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
|
||||
class MessagePortBase;
|
||||
|
||||
namespace workers {
|
||||
|
||||
// This class is implemented in WorkerPrivate.cpp
|
||||
class WorkerStructuredCloneClosure final
|
||||
{
|
||||
private:
|
||||
WorkerStructuredCloneClosure(const WorkerStructuredCloneClosure&) = delete;
|
||||
WorkerStructuredCloneClosure & operator=(const WorkerStructuredCloneClosure&) = delete;
|
||||
|
||||
public:
|
||||
WorkerStructuredCloneClosure();
|
||||
~WorkerStructuredCloneClosure();
|
||||
|
||||
void Clear();
|
||||
|
||||
// This can be null if the MessagePort is created in a worker.
|
||||
nsCOMPtr<nsPIDOMWindow> mParentWindow;
|
||||
|
||||
nsTArray<nsCOMPtr<nsISupports>> mClonedObjects;
|
||||
|
||||
// This is used for sharing the backend of ImageBitmaps.
|
||||
// The layers::Image object must be thread-safely reference-counted.
|
||||
// The layers::Image object will not be written ever via any ImageBitmap
|
||||
// instance, so no race condition will occur.
|
||||
nsTArray<nsRefPtr<layers::Image>> mClonedImages;
|
||||
|
||||
// The transferred ports.
|
||||
nsTArray<nsRefPtr<MessagePortBase>> mMessagePorts;
|
||||
|
||||
// Information for the transferring.
|
||||
nsTArray<MessagePortIdentifier> mMessagePortIdentifiers;
|
||||
|
||||
// To avoid duplicates in the transferred ports.
|
||||
nsTArray<nsRefPtr<MessagePortBase>> mTransferredPorts;
|
||||
};
|
||||
|
||||
} // namespace workers
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_workers_WorkerStructuredClone_h
|
|
@ -18,6 +18,7 @@
|
|||
#include "mozilla/dom/Exceptions.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/ProgressEvent.h"
|
||||
#include "mozilla/dom/StructuredCloneHelper.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsFormData.h"
|
||||
|
@ -27,7 +28,6 @@
|
|||
#include "RuntimeService.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerRunnable.h"
|
||||
#include "WorkerStructuredClone.h"
|
||||
#include "XMLHttpRequestUpload.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -175,6 +175,116 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
class WorkerThreadProxySyncRunnable : public nsRunnable
|
||||
{
|
||||
protected:
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
nsRefPtr<Proxy> mProxy;
|
||||
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
|
||||
|
||||
private:
|
||||
class ResponseRunnable final: public MainThreadStopSyncLoopRunnable
|
||||
{
|
||||
nsRefPtr<Proxy> mProxy;
|
||||
nsresult mErrorCode;
|
||||
|
||||
public:
|
||||
ResponseRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
|
||||
nsresult aErrorCode)
|
||||
: MainThreadStopSyncLoopRunnable(aWorkerPrivate, aProxy->GetEventTarget(),
|
||||
NS_SUCCEEDED(aErrorCode)),
|
||||
mProxy(aProxy), mErrorCode(aErrorCode)
|
||||
{
|
||||
MOZ_ASSERT(aProxy);
|
||||
}
|
||||
|
||||
private:
|
||||
~ResponseRunnable()
|
||||
{ }
|
||||
|
||||
virtual void
|
||||
MaybeSetException(JSContext* aCx) override
|
||||
{
|
||||
MOZ_ASSERT(NS_FAILED(mErrorCode));
|
||||
|
||||
Throw(aCx, mErrorCode);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
WorkerThreadProxySyncRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy)
|
||||
: mWorkerPrivate(aWorkerPrivate), mProxy(aProxy)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
MOZ_ASSERT(aProxy);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
bool
|
||||
Dispatch(JSContext* aCx)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
AutoSyncLoopHolder syncLoop(mWorkerPrivate);
|
||||
mSyncLoopTarget = syncLoop.EventTarget();
|
||||
|
||||
if (NS_FAILED(NS_DispatchToMainThread(this))) {
|
||||
JS_ReportError(aCx, "Failed to dispatch to main thread!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return syncLoop.Run();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~WorkerThreadProxySyncRunnable()
|
||||
{ }
|
||||
|
||||
virtual nsresult
|
||||
MainThreadRun() = 0;
|
||||
|
||||
private:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
};
|
||||
|
||||
class SendRunnable final
|
||||
: public WorkerThreadProxySyncRunnable
|
||||
, public StructuredCloneHelper
|
||||
{
|
||||
nsString mStringBody;
|
||||
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
|
||||
bool mHasUploadListeners;
|
||||
|
||||
public:
|
||||
SendRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
|
||||
const nsAString& aStringBody)
|
||||
: WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
|
||||
, StructuredCloneHelper(CloningSupported, TransferringNotSupported)
|
||||
, mStringBody(aStringBody)
|
||||
, mHasUploadListeners(false)
|
||||
{
|
||||
}
|
||||
|
||||
void SetHaveUploadListeners(bool aHasUploadListeners)
|
||||
{
|
||||
mHasUploadListeners = aHasUploadListeners;
|
||||
}
|
||||
|
||||
void SetSyncLoopTarget(nsIEventTarget* aSyncLoopTarget)
|
||||
{
|
||||
mSyncLoopTarget = aSyncLoopTarget;
|
||||
}
|
||||
|
||||
private:
|
||||
~SendRunnable()
|
||||
{ }
|
||||
|
||||
virtual nsresult
|
||||
MainThreadRun() override;
|
||||
};
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
@ -410,11 +520,10 @@ private:
|
|||
};
|
||||
|
||||
class EventRunnable final : public MainThreadProxyRunnable
|
||||
, public StructuredCloneHelper
|
||||
{
|
||||
nsString mType;
|
||||
nsString mResponseType;
|
||||
JSAutoStructuredCloneBuffer mResponseBuffer;
|
||||
WorkerStructuredCloneClosure mResponseClosure;
|
||||
JS::Heap<JS::Value> mResponse;
|
||||
nsString mResponseText;
|
||||
nsString mResponseURL;
|
||||
|
@ -456,17 +565,19 @@ public:
|
|||
|
||||
EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType,
|
||||
bool aLengthComputable, uint64_t aLoaded, uint64_t aTotal)
|
||||
: MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy), mType(aType),
|
||||
mResponse(JS::UndefinedValue()), mLoaded(aLoaded), mTotal(aTotal),
|
||||
mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0), mReadyState(0),
|
||||
mUploadEvent(aUploadEvent), mProgressEvent(true),
|
||||
: MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy),
|
||||
StructuredCloneHelper(CloningSupported, TransferringNotSupported),
|
||||
mType(aType), mResponse(JS::UndefinedValue()), mLoaded(aLoaded),
|
||||
mTotal(aTotal), mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0),
|
||||
mReadyState(0), mUploadEvent(aUploadEvent), mProgressEvent(true),
|
||||
mLengthComputable(aLengthComputable), mUseCachedArrayBufferResponse(false),
|
||||
mResponseTextResult(NS_OK), mStatusResult(NS_OK), mResponseResult(NS_OK)
|
||||
{ }
|
||||
|
||||
EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType)
|
||||
: MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy), mType(aType),
|
||||
mResponse(JS::UndefinedValue()), mLoaded(0), mTotal(0),
|
||||
: MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy),
|
||||
StructuredCloneHelper(CloningSupported, TransferringNotSupported),
|
||||
mType(aType), mResponse(JS::UndefinedValue()), mLoaded(0), mTotal(0),
|
||||
mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0), mReadyState(0),
|
||||
mUploadEvent(aUploadEvent), mProgressEvent(false), mLengthComputable(0),
|
||||
mUseCachedArrayBufferResponse(false), mResponseTextResult(NS_OK),
|
||||
|
@ -484,80 +595,6 @@ private:
|
|||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
|
||||
};
|
||||
|
||||
class WorkerThreadProxySyncRunnable : public nsRunnable
|
||||
{
|
||||
protected:
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
nsRefPtr<Proxy> mProxy;
|
||||
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
|
||||
|
||||
private:
|
||||
class ResponseRunnable final: public MainThreadStopSyncLoopRunnable
|
||||
{
|
||||
nsRefPtr<Proxy> mProxy;
|
||||
nsresult mErrorCode;
|
||||
|
||||
public:
|
||||
ResponseRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
|
||||
nsresult aErrorCode)
|
||||
: MainThreadStopSyncLoopRunnable(aWorkerPrivate, aProxy->GetEventTarget(),
|
||||
NS_SUCCEEDED(aErrorCode)),
|
||||
mProxy(aProxy), mErrorCode(aErrorCode)
|
||||
{
|
||||
MOZ_ASSERT(aProxy);
|
||||
}
|
||||
|
||||
private:
|
||||
~ResponseRunnable()
|
||||
{ }
|
||||
|
||||
virtual void
|
||||
MaybeSetException(JSContext* aCx) override
|
||||
{
|
||||
MOZ_ASSERT(NS_FAILED(mErrorCode));
|
||||
|
||||
Throw(aCx, mErrorCode);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
WorkerThreadProxySyncRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy)
|
||||
: mWorkerPrivate(aWorkerPrivate), mProxy(aProxy)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
MOZ_ASSERT(aProxy);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
bool
|
||||
Dispatch(JSContext* aCx)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
AutoSyncLoopHolder syncLoop(mWorkerPrivate);
|
||||
mSyncLoopTarget = syncLoop.EventTarget();
|
||||
|
||||
if (NS_FAILED(NS_DispatchToMainThread(this))) {
|
||||
JS_ReportError(aCx, "Failed to dispatch to main thread!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return syncLoop.Run();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~WorkerThreadProxySyncRunnable()
|
||||
{ }
|
||||
|
||||
virtual nsresult
|
||||
MainThreadRun() = 0;
|
||||
|
||||
private:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
};
|
||||
|
||||
class SyncTeardownRunnable final : public WorkerThreadProxySyncRunnable
|
||||
{
|
||||
public:
|
||||
|
@ -791,39 +828,6 @@ private:
|
|||
MainThreadRunInternal();
|
||||
};
|
||||
|
||||
class SendRunnable final : public WorkerThreadProxySyncRunnable
|
||||
{
|
||||
nsString mStringBody;
|
||||
JSAutoStructuredCloneBuffer mBody;
|
||||
WorkerStructuredCloneClosure mClosure;
|
||||
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
|
||||
bool mHasUploadListeners;
|
||||
|
||||
public:
|
||||
SendRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
|
||||
const nsAString& aStringBody, JSAutoStructuredCloneBuffer&& aBody,
|
||||
WorkerStructuredCloneClosure& aClosure,
|
||||
nsIEventTarget* aSyncLoopTarget, bool aHasUploadListeners)
|
||||
: WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
|
||||
, mStringBody(aStringBody)
|
||||
, mBody(Move(aBody))
|
||||
, mSyncLoopTarget(aSyncLoopTarget)
|
||||
, mHasUploadListeners(aHasUploadListeners)
|
||||
{
|
||||
mClosure.mClonedObjects.SwapElements(aClosure.mClonedObjects);
|
||||
mClosure.mClonedImages.SwapElements(aClosure.mClonedImages);
|
||||
MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty());
|
||||
MOZ_ASSERT(aClosure.mMessagePortIdentifiers.IsEmpty());
|
||||
}
|
||||
|
||||
private:
|
||||
~SendRunnable()
|
||||
{ }
|
||||
|
||||
virtual nsresult
|
||||
MainThreadRun() override;
|
||||
};
|
||||
|
||||
class SetRequestHeaderRunnable final : public WorkerThreadProxySyncRunnable
|
||||
{
|
||||
nsCString mHeader;
|
||||
|
@ -1227,21 +1231,11 @@ EventRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
|||
}
|
||||
|
||||
if (doClone) {
|
||||
// Anything subject to GC must be cloned.
|
||||
const JSStructuredCloneCallbacks* callbacks =
|
||||
workers::WorkerStructuredCloneCallbacks();
|
||||
|
||||
WorkerStructuredCloneClosure closure;
|
||||
|
||||
if (mResponseBuffer.write(aCx, response, transferable, callbacks,
|
||||
&closure)) {
|
||||
mResponseClosure.mClonedObjects.SwapElements(closure.mClonedObjects);
|
||||
mResponseClosure.mClonedImages.SwapElements(closure.mClonedImages);
|
||||
MOZ_ASSERT(mResponseClosure.mMessagePorts.IsEmpty());
|
||||
MOZ_ASSERT(mResponseClosure.mMessagePortIdentifiers.IsEmpty());
|
||||
} else {
|
||||
ErrorResult rv;
|
||||
Write(aCx, response, transferable, false, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
NS_WARNING("Failed to clone response!");
|
||||
mResponseResult = NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
mResponseResult = rv.StealNSResult();
|
||||
mProxy->mArrayBufferResponseWasTransferred = false;
|
||||
}
|
||||
}
|
||||
|
@ -1336,22 +1330,14 @@ EventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
|||
state->mResponseResult = mResponseResult;
|
||||
|
||||
if (NS_SUCCEEDED(mResponseResult)) {
|
||||
if (mResponseBuffer.data()) {
|
||||
if (HasBeenWritten()) {
|
||||
MOZ_ASSERT(mResponse.isUndefined());
|
||||
|
||||
JSAutoStructuredCloneBuffer responseBuffer(Move(mResponseBuffer));
|
||||
|
||||
const JSStructuredCloneCallbacks* callbacks =
|
||||
workers::WorkerStructuredCloneCallbacks();
|
||||
|
||||
WorkerStructuredCloneClosure closure;
|
||||
closure.mClonedObjects.SwapElements(mResponseClosure.mClonedObjects);
|
||||
closure.mClonedImages.SwapElements(mResponseClosure.mClonedImages);
|
||||
MOZ_ASSERT(mResponseClosure.mMessagePorts.IsEmpty());
|
||||
MOZ_ASSERT(mResponseClosure.mMessagePortIdentifiers.IsEmpty());
|
||||
|
||||
ErrorResult rv;
|
||||
JS::Rooted<JS::Value> response(aCx);
|
||||
if (!responseBuffer.read(aCx, &response, callbacks, &closure)) {
|
||||
Read(nullptr, aCx, &response, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1517,32 +1503,25 @@ SendRunnable::MainThreadRun()
|
|||
{
|
||||
nsCOMPtr<nsIVariant> variant;
|
||||
|
||||
if (mBody.data()) {
|
||||
if (HasBeenWritten()) {
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
nsIXPConnect* xpc = nsContentUtils::XPConnect();
|
||||
MOZ_ASSERT(xpc);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
const JSStructuredCloneCallbacks* callbacks =
|
||||
workers::WorkerStructuredCloneCallbacks();
|
||||
ErrorResult rv;
|
||||
|
||||
JS::Rooted<JS::Value> body(cx);
|
||||
if (mBody.read(cx, &body, callbacks, &mClosure)) {
|
||||
if (NS_FAILED(xpc->JSValToVariant(cx, body, getter_AddRefs(variant)))) {
|
||||
rv = NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
rv = NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
Read(nullptr, cx, &body, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
mBody.clear();
|
||||
mClosure.Clear();
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = xpc->JSValToVariant(cx, body, getter_AddRefs(variant));
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIWritableVariant> wvariant =
|
||||
|
@ -1845,11 +1824,10 @@ XMLHttpRequest::Unpin()
|
|||
}
|
||||
|
||||
void
|
||||
XMLHttpRequest::SendInternal(const nsAString& aStringBody,
|
||||
JSAutoStructuredCloneBuffer&& aBody,
|
||||
WorkerStructuredCloneClosure& aClosure,
|
||||
XMLHttpRequest::SendInternal(SendRunnable* aRunnable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(aRunnable);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
// No send() calls when open is running.
|
||||
|
@ -1879,10 +1857,10 @@ XMLHttpRequest::SendInternal(const nsAString& aStringBody,
|
|||
|
||||
JSContext* cx = mWorkerPrivate->GetJSContext();
|
||||
|
||||
nsRefPtr<SendRunnable> runnable =
|
||||
new SendRunnable(mWorkerPrivate, mProxy, aStringBody, Move(aBody),
|
||||
aClosure, syncLoopTarget, hasUploadListeners);
|
||||
if (!runnable->Dispatch(cx)) {
|
||||
aRunnable->SetSyncLoopTarget(syncLoopTarget);
|
||||
aRunnable->SetHaveUploadListeners(hasUploadListeners);
|
||||
|
||||
if (!aRunnable->Dispatch(cx)) {
|
||||
// Dispatch() may have spun the event loop and we may have already unrooted.
|
||||
// If so we don't want autoUnpin to try again.
|
||||
if (!mRooted) {
|
||||
|
@ -2109,11 +2087,11 @@ XMLHttpRequest::Send(ErrorResult& aRv)
|
|||
return;
|
||||
}
|
||||
|
||||
// Nothing to clone.
|
||||
JSAutoStructuredCloneBuffer buffer;
|
||||
WorkerStructuredCloneClosure closure;
|
||||
nsRefPtr<SendRunnable> sendRunnable =
|
||||
new SendRunnable(mWorkerPrivate, mProxy, NullString());
|
||||
|
||||
SendInternal(NullString(), Move(buffer), closure, aRv);
|
||||
// Nothing to clone.
|
||||
SendInternal(sendRunnable, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2131,11 +2109,11 @@ XMLHttpRequest::Send(const nsAString& aBody, ErrorResult& aRv)
|
|||
return;
|
||||
}
|
||||
|
||||
// Nothing to clone.
|
||||
JSAutoStructuredCloneBuffer buffer;
|
||||
WorkerStructuredCloneClosure closure;
|
||||
nsRefPtr<SendRunnable> sendRunnable =
|
||||
new SendRunnable(mWorkerPrivate, mProxy, aBody);
|
||||
|
||||
SendInternal(aBody, Move(buffer), closure, aRv);
|
||||
// Nothing to clone.
|
||||
SendInternal(sendRunnable, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2171,18 +2149,15 @@ XMLHttpRequest::Send(JS::Handle<JSObject*> aBody, ErrorResult& aRv)
|
|||
valToClone.setString(bodyStr);
|
||||
}
|
||||
|
||||
const JSStructuredCloneCallbacks* callbacks =
|
||||
WorkerStructuredCloneCallbacks();
|
||||
nsRefPtr<SendRunnable> sendRunnable =
|
||||
new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
|
||||
|
||||
WorkerStructuredCloneClosure closure;
|
||||
|
||||
JSAutoStructuredCloneBuffer buffer;
|
||||
if (!buffer.write(cx, valToClone, callbacks, &closure)) {
|
||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
sendRunnable->Write(cx, valToClone, false, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
SendInternal(EmptyString(), Move(buffer), closure, aRv);
|
||||
SendInternal(sendRunnable, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2215,18 +2190,15 @@ XMLHttpRequest::Send(Blob& aBody, ErrorResult& aRv)
|
|||
return;
|
||||
}
|
||||
|
||||
const JSStructuredCloneCallbacks* callbacks =
|
||||
WorkerStructuredCloneCallbacks();
|
||||
nsRefPtr<SendRunnable> sendRunnable =
|
||||
new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
|
||||
|
||||
WorkerStructuredCloneClosure closure;
|
||||
|
||||
JSAutoStructuredCloneBuffer buffer;
|
||||
if (!buffer.write(cx, value, callbacks, &closure)) {
|
||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
sendRunnable->Write(cx, value, false, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
SendInternal(EmptyString(), Move(buffer), closure, aRv);
|
||||
SendInternal(sendRunnable, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2251,17 +2223,15 @@ XMLHttpRequest::Send(nsFormData& aBody, ErrorResult& aRv)
|
|||
return;
|
||||
}
|
||||
|
||||
const JSStructuredCloneCallbacks* callbacks =
|
||||
WorkerStructuredCloneCallbacks();
|
||||
nsRefPtr<SendRunnable> sendRunnable =
|
||||
new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
|
||||
|
||||
JSAutoStructuredCloneBuffer buffer;
|
||||
WorkerStructuredCloneClosure closure;
|
||||
if (!buffer.write(cx, value, callbacks, &closure)) {
|
||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
sendRunnable->Write(cx, value, false, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
SendInternal(EmptyString(), Move(buffer), closure, aRv);
|
||||
SendInternal(sendRunnable, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
|
||||
#include "js/StructuredClone.h"
|
||||
#include "nsXMLHttpRequest.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -26,9 +25,9 @@ class Blob;
|
|||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class Proxy;
|
||||
class SendRunnable;
|
||||
class XMLHttpRequestUpload;
|
||||
class WorkerPrivate;
|
||||
class WorkerStructuredCloneClosure;
|
||||
|
||||
class XMLHttpRequest final: public nsXHREventTarget,
|
||||
public WorkerFeature
|
||||
|
@ -291,9 +290,7 @@ private:
|
|||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
SendInternal(const nsAString& aStringBody,
|
||||
JSAutoStructuredCloneBuffer&& aBody,
|
||||
WorkerStructuredCloneClosure& aClosure,
|
||||
SendInternal(SendRunnable* aRunnable,
|
||||
ErrorResult& aRv);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
function fetchXHR(name, onload, onerror, headers) {
|
||||
function fetchXHRWithMethod(name, method, onload, onerror, headers) {
|
||||
expectAsyncResult();
|
||||
|
||||
onload = onload || function() {
|
||||
|
@ -11,7 +11,7 @@ function fetchXHR(name, onload, onerror, headers) {
|
|||
};
|
||||
|
||||
var x = new XMLHttpRequest();
|
||||
x.open('GET', name, true);
|
||||
x.open(method, name, true);
|
||||
x.onload = function() { onload(x) };
|
||||
x.onerror = function() { onerror(x) };
|
||||
headers = headers || [];
|
||||
|
@ -21,6 +21,10 @@ function fetchXHR(name, onload, onerror, headers) {
|
|||
x.send();
|
||||
}
|
||||
|
||||
function fetchXHR(name, onload, onerror, headers) {
|
||||
return fetchXHRWithMethod(name, 'GET', onload, onerror, headers);
|
||||
}
|
||||
|
||||
fetchXHR('bare-synthesized.txt', function(xhr) {
|
||||
my_ok(xhr.status == 200, "load should be successful");
|
||||
my_ok(xhr.responseText == "synthesized response body", "load should have synthesized response");
|
||||
|
@ -297,3 +301,11 @@ fetch(new Request('body-blob', {method: 'POST', body: new Blob(new String('my bo
|
|||
my_ok(body == 'my bodymy body', "the Blob body of the intercepted fetch should be visible in the SW");
|
||||
finish();
|
||||
});
|
||||
|
||||
['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'].forEach(function(method) {
|
||||
fetchXHRWithMethod('xhr-method-test.txt', method, function(xhr) {
|
||||
my_ok(xhr.status == 200, method + " load should be successful");
|
||||
my_ok(xhr.responseText == ("intercepted " + method), method + " load should have synthesized response");
|
||||
finish();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -268,4 +268,8 @@ onfetch = function(ev) {
|
|||
var url = 'http://example.com/tests/dom/security/test/cors/file_CrossSiteXHR_server.sjs?status=200';
|
||||
ev.respondWith(fetch(url, { mode: 'no-cors' }));
|
||||
}
|
||||
|
||||
else if (ev.request.url.includes('xhr-method-test.txt')) {
|
||||
ev.respondWith(new Response('intercepted ' + ev.request.method));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -509,7 +509,7 @@ ClientLayerManager::MakeSnapshotIfRequired()
|
|||
gfx::Matrix rotate = ComputeTransformForUnRotation(outerBounds, mTargetRotation);
|
||||
|
||||
gfx::Matrix oldMatrix = dt->GetTransform();
|
||||
dt->SetTransform(oldMatrix * rotate);
|
||||
dt->SetTransform(rotate * oldMatrix);
|
||||
dt->DrawSurface(surf, dstRect, srcRect,
|
||||
DrawSurfaceOptions(),
|
||||
DrawOptions(1.0f, CompositionOp::OP_OVER));
|
||||
|
|
|
@ -20,16 +20,9 @@ ImageContainerParent::~ImageContainerParent()
|
|||
}
|
||||
}
|
||||
|
||||
static void SendDeleteAndIgnoreResult(ImageContainerParent* self)
|
||||
{
|
||||
unused << PImageContainerParent::Send__delete__(self);
|
||||
}
|
||||
|
||||
bool ImageContainerParent::RecvAsyncDelete()
|
||||
{
|
||||
MessageLoop::current()->PostTask(
|
||||
FROM_HERE, NewRunnableFunction(&SendDeleteAndIgnoreResult, this));
|
||||
|
||||
unused << PImageContainerParent::Send__delete__(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -201,7 +201,7 @@ class BaseStackFrame {
|
|||
|
||||
// Get a unique identifier for this StackFrame. The identifier is not valid
|
||||
// across garbage collections.
|
||||
virtual uintptr_t identifier() const { return reinterpret_cast<uintptr_t>(ptr); }
|
||||
virtual uint64_t identifier() const { return reinterpret_cast<uint64_t>(ptr); }
|
||||
|
||||
// Get this frame's parent frame.
|
||||
virtual StackFrame parent() const = 0;
|
||||
|
@ -376,7 +376,7 @@ class StackFrame : public JS::Traceable {
|
|||
// Methods that forward to virtual calls through BaseStackFrame.
|
||||
|
||||
void trace(JSTracer* trc) { base()->trace(trc); }
|
||||
uintptr_t identifier() const { return base()->identifier(); }
|
||||
uint64_t identifier() const { return base()->identifier(); }
|
||||
uint32_t line() const { return base()->line(); }
|
||||
uint32_t column() const { return base()->column(); }
|
||||
AtomOrTwoByteChars source() const { return base()->source(); }
|
||||
|
@ -415,7 +415,7 @@ class ConcreteStackFrame<void> : public BaseStackFrame {
|
|||
public:
|
||||
static void construct(void* storage, void*) { new (storage) ConcreteStackFrame(nullptr); }
|
||||
|
||||
uintptr_t identifier() const override { return 0; }
|
||||
uint64_t identifier() const override { return 0; }
|
||||
void trace(JSTracer* trc) override { }
|
||||
bool constructSavedFrameStack(JSContext* cx, MutableHandleObject out) const override {
|
||||
out.set(nullptr);
|
||||
|
@ -470,14 +470,14 @@ class Base {
|
|||
//
|
||||
// This is probably suitable for use in serializations, as it is an integral
|
||||
// type. It may also help save memory when constructing HashSets of
|
||||
// ubi::Nodes: since a uintptr_t will always be smaller than a ubi::Node, a
|
||||
// HashSet<ubi::Node::Id> will use less space per element than a
|
||||
// HashSet<ubi::Node>.
|
||||
// ubi::Nodes: since a uint64_t will always be smaller-or-equal-to the size
|
||||
// of a ubi::Node, a HashSet<ubi::Node::Id> may use less space per element
|
||||
// than a HashSet<ubi::Node>.
|
||||
//
|
||||
// (Note that 'unique' only means 'up to equality on ubi::Node'; see the
|
||||
// caveats about multiple objects allocated at the same address for
|
||||
// 'ubi::Node::operator=='.)
|
||||
typedef uintptr_t Id;
|
||||
using Id = uint64_t;
|
||||
virtual Id identifier() const { return reinterpret_cast<Id>(ptr); }
|
||||
|
||||
// Returns true if this node is pointing to something on the live heap, as
|
||||
|
@ -495,8 +495,9 @@ class Base {
|
|||
// Return the size of this node, in bytes. Include any structures that this
|
||||
// node owns exclusively that are not exposed as their own ubi::Nodes.
|
||||
// |mallocSizeOf| should be a malloc block sizing function; see
|
||||
// |mfbt/MemoryReporting.h.
|
||||
virtual size_t size(mozilla::MallocSizeOf mallocSizeof) const { return 0; }
|
||||
// |mfbt/MemoryReporting.h|.
|
||||
using Size = uint64_t;
|
||||
virtual Size size(mozilla::MallocSizeOf mallocSizeof) const { return 1; }
|
||||
|
||||
// Return an EdgeRange that initially contains all the referent's outgoing
|
||||
// edges. The caller takes ownership of the EdgeRange.
|
||||
|
@ -688,7 +689,8 @@ class Node {
|
|||
return base()->jsObjectConstructorName(cx, outName);
|
||||
}
|
||||
|
||||
size_t size(mozilla::MallocSizeOf mallocSizeof) const {
|
||||
using Size = Base::Size;
|
||||
Size size(mozilla::MallocSizeOf mallocSizeof) const {
|
||||
return base()->size(mallocSizeof);
|
||||
}
|
||||
|
||||
|
@ -701,7 +703,7 @@ class Node {
|
|||
return base()->allocationStack();
|
||||
}
|
||||
|
||||
typedef Base::Id Id;
|
||||
using Id = Base::Id;
|
||||
Id identifier() const { return base()->identifier(); }
|
||||
|
||||
// A hash policy for ubi::Nodes.
|
||||
|
@ -969,7 +971,7 @@ class Concrete<JSObject> : public TracerConcreteWithCompartment<JSObject> {
|
|||
const char* jsObjectClassName() const override;
|
||||
bool jsObjectConstructorName(JSContext* cx,
|
||||
UniquePtr<char16_t[], JS::FreePolicy>& outName) const override;
|
||||
size_t size(mozilla::MallocSizeOf mallocSizeOf) const override;
|
||||
Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
|
||||
|
||||
bool hasAllocationStack() const override;
|
||||
StackFrame allocationStack() const override;
|
||||
|
@ -985,7 +987,7 @@ class Concrete<JSObject> : public TracerConcreteWithCompartment<JSObject> {
|
|||
|
||||
// For JSString, we extend the generic template with a 'size' implementation.
|
||||
template<> struct Concrete<JSString> : TracerConcrete<JSString> {
|
||||
size_t size(mozilla::MallocSizeOf mallocSizeOf) const override;
|
||||
Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
|
||||
|
||||
protected:
|
||||
explicit Concrete(JSString *ptr) : TracerConcrete<JSString>(ptr) { }
|
||||
|
@ -998,7 +1000,7 @@ template<> struct Concrete<JSString> : TracerConcrete<JSString> {
|
|||
template<>
|
||||
class Concrete<void> : public Base {
|
||||
const char16_t* typeName() const override;
|
||||
size_t size(mozilla::MallocSizeOf mallocSizeOf) const override;
|
||||
Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
|
||||
UniquePtr<EdgeRange> edges(JSContext* cx, bool wantNames) const override;
|
||||
JS::Zone* zone() const override;
|
||||
JSCompartment* compartment() const override;
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
setJitCompilerOption("ion.warmup.trigger", 30);
|
||||
var spaces = [
|
||||
"\u0009", "\u000b", "\u000c", "\u0020", "\u00a0", "\u1680",
|
||||
"\u180e", "\u2000", "\u2001", "\u2002", "\u2003", "\u2004",
|
||||
"\u2005", "\u2006", "\u2007", "\u2008", "\u2009", "\u200a",
|
||||
];
|
||||
var line_terminators = [ "\u2028", "\u2029", "\u000a", "\u000d" ];
|
||||
var space_chars = [].concat(spaces, line_terminators);
|
||||
var non_space_chars = [ "\u200b", "\u200c", "\u200d" ];
|
||||
var chars = [].concat(space_chars, non_space_chars);
|
||||
var is_space = [].concat(space_chars.map(function(ch) { return true; }),
|
||||
non_space_chars.map(function() { return false; }));
|
||||
chars.map(function(ch) {}).join(',');
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
const numRows = 600;
|
||||
const numCols = 600;
|
||||
function computeEscapeSpeed(c) {
|
||||
const scaler = 5;
|
||||
const threshold = (colors.length - 1) * scaler + 1;
|
||||
for (var i = 1; i < threshold; ++i) {}
|
||||
}
|
||||
const colorStrings = [ "deeppink", ];
|
||||
var colors = [];
|
||||
function createMandelSet(realRange, imagRange) {
|
||||
for each (var color in colorStrings) {
|
||||
var [r, g, b] = [0, 0, 0];
|
||||
colors.push([r, g, b, 0xff]);
|
||||
}
|
||||
var realStep = (realRange.max - realRange.min)/numCols;
|
||||
var imagStep = (imagRange.min - imagRange.max)/(function (colors) {} ) ;
|
||||
for (var i = 0, curReal = realRange.min; i < numCols; ++i, curReal += realStep) {
|
||||
for (var j = 0, curImag = imagRange.max; j < numRows; ++j, curImag += imagStep) {
|
||||
var c = { r: curReal, i: curImag }
|
||||
var n = computeEscapeSpeed(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
var realRange = { min: -2.1, max: 2 };
|
||||
var imagRange = { min: -2, max: 2 };
|
||||
createMandelSet(realRange, imagRange);
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
function printStatus (msg) {
|
||||
var lines = msg.split ("\n");
|
||||
for (var i=0; i<lines.length; i++)
|
||||
lines[i];
|
||||
}
|
||||
Object.prototype.length = function(){};
|
||||
var summary = 'Do not assert: !OBJ_GET_PROTO(cx, ctor)';
|
||||
printStatus (summary);
|
|
@ -0,0 +1,183 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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 "jit/InstructionReordering.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
static void
|
||||
MoveBefore(MBasicBlock* block, MInstruction* at, MInstruction* ins)
|
||||
{
|
||||
if (at == ins)
|
||||
return;
|
||||
|
||||
// Update instruction numbers.
|
||||
for (MInstructionIterator iter(block->begin(at)); *iter != ins; iter++) {
|
||||
MOZ_ASSERT(iter->id() < ins->id());
|
||||
iter->setId(iter->id() + 1);
|
||||
}
|
||||
ins->setId(at->id() - 1);
|
||||
block->moveBefore(at, ins);
|
||||
}
|
||||
|
||||
static bool
|
||||
IsLastUse(MDefinition* ins, MDefinition* input, MBasicBlock* loopHeader)
|
||||
{
|
||||
// If we are in a loop, this cannot be the last use of any definitions from
|
||||
// outside the loop, as those definitions can be used in future iterations.
|
||||
if (loopHeader && input->block()->id() < loopHeader->id())
|
||||
return false;
|
||||
for (MUseDefIterator iter(input); iter; iter++) {
|
||||
// Watch for uses defined in blocks which ReorderInstructions hasn't
|
||||
// processed yet. These nodes have not had their ids set yet.
|
||||
if (iter.def()->block()->id() > ins->block()->id())
|
||||
return false;
|
||||
if (iter.def()->id() > ins->id())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
jit::ReorderInstructions(MIRGenerator* mir, MIRGraph& graph)
|
||||
{
|
||||
// Renumber all instructions in the graph as we go.
|
||||
size_t nextId = 0;
|
||||
|
||||
// List of the headers of any loops we are in.
|
||||
Vector<MBasicBlock*, 4, SystemAllocPolicy> loopHeaders;
|
||||
|
||||
for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
|
||||
// Don't reorder instructions within entry blocks, which have special requirements.
|
||||
if (*block == graph.entryBlock() || *block == graph.osrBlock())
|
||||
continue;
|
||||
|
||||
if (block->isLoopHeader()) {
|
||||
if (!loopHeaders.append(*block))
|
||||
return false;
|
||||
}
|
||||
|
||||
MBasicBlock* innerLoop = loopHeaders.empty() ? nullptr : loopHeaders.back();
|
||||
|
||||
for (MPhiIterator iter(block->phisBegin()); iter != block->phisEnd(); iter++)
|
||||
iter->setId(nextId++);
|
||||
|
||||
for (MInstructionIterator iter(block->begin()); iter != block->end(); iter++)
|
||||
iter->setId(nextId++);
|
||||
|
||||
for (MInstructionIterator iter(block->begin()); iter != block->end(); ) {
|
||||
MInstruction* ins = *iter;
|
||||
|
||||
// Filter out some instructions which are never reordered.
|
||||
if (ins->isEffectful() ||
|
||||
!ins->isMovable() ||
|
||||
ins->resumePoint() ||
|
||||
ins == block->lastIns())
|
||||
{
|
||||
iter++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Move constants with a single use in the current block to the
|
||||
// start of the block. Constants won't be reordered by the logic
|
||||
// below, as they have no inputs. Moving them up as high as
|
||||
// possible can allow their use to be moved up further, though,
|
||||
// and has no cost if the constant is emitted at its use.
|
||||
if (ins->isConstant() &&
|
||||
ins->hasOneUse() &&
|
||||
ins->usesBegin()->consumer()->block() == *block &&
|
||||
!IsFloatingPointType(ins->type()))
|
||||
{
|
||||
iter++;
|
||||
MInstructionIterator targetIter = block->begin();
|
||||
if (targetIter->isInterruptCheck())
|
||||
targetIter++;
|
||||
MoveBefore(*block, *targetIter, ins);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look for inputs where this instruction is the last use of that
|
||||
// input. If we move this instruction up, the input's lifetime will
|
||||
// be shortened, modulo resume point uses (which don't need to be
|
||||
// stored in a register, and can be handled by the register
|
||||
// allocator by just spilling at some point with no reload).
|
||||
Vector<MDefinition*, 4, SystemAllocPolicy> lastUsedInputs;
|
||||
for (size_t i = 0; i < ins->numOperands(); i++) {
|
||||
MDefinition* input = ins->getOperand(i);
|
||||
if (!input->isConstant() && IsLastUse(ins, input, innerLoop)) {
|
||||
if (!lastUsedInputs.append(input))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't try to move instructions which aren't the last use of any
|
||||
// of their inputs (we really ought to move these down instead).
|
||||
if (lastUsedInputs.length() < 2) {
|
||||
iter++;
|
||||
continue;
|
||||
}
|
||||
|
||||
MInstruction* target = ins;
|
||||
for (MInstructionReverseIterator riter = ++block->rbegin(ins); riter != block->rend(); riter++) {
|
||||
MInstruction* prev = *riter;
|
||||
if (prev->isInterruptCheck())
|
||||
break;
|
||||
|
||||
// The instruction can't be moved before any of its uses.
|
||||
bool isUse = false;
|
||||
for (size_t i = 0; i < ins->numOperands(); i++) {
|
||||
if (ins->getOperand(i) == prev) {
|
||||
isUse = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isUse)
|
||||
break;
|
||||
|
||||
// The instruction can't be moved before an instruction that
|
||||
// stores to a location read by the instruction.
|
||||
if (prev->isEffectful() &&
|
||||
(ins->getAliasSet().flags() & prev->getAliasSet().flags()) &&
|
||||
ins->mightAlias(prev))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Make sure the instruction will still be the last use of one
|
||||
// of its inputs when moved up this far.
|
||||
for (size_t i = 0; i < lastUsedInputs.length(); ) {
|
||||
bool found = false;
|
||||
for (size_t j = 0; j < prev->numOperands(); j++) {
|
||||
if (prev->getOperand(j) == lastUsedInputs[i]) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
lastUsedInputs[i] = lastUsedInputs.back();
|
||||
lastUsedInputs.popBack();
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (lastUsedInputs.length() < 2)
|
||||
break;
|
||||
|
||||
// We can move the instruction before this one.
|
||||
target = prev;
|
||||
}
|
||||
|
||||
iter++;
|
||||
MoveBefore(*block, target, ins);
|
||||
}
|
||||
|
||||
if (block->isLoopBackedge())
|
||||
loopHeaders.popBack();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче