Merge m-c to fx-team a=merge

This commit is contained in:
Wes Kocher 2015-01-13 17:47:46 -08:00
commit 805b38ff92
340 changed files with 11404 additions and 17639 deletions

View File

@ -730,22 +730,30 @@ pref("hal.processPriorityManager.gonk.BACKGROUND.KillUnderKB", 20480);
pref("hal.processPriorityManager.gonk.BACKGROUND.cgroup", "apps/bg_non_interactive");
// Control group definitions (i.e., CPU priority groups) for B2G processes.
//
// memory_swappiness - 0 - The kernel will swap only to avoid an out of memory condition
// memory_swappiness - 60 - The default value.
// memory_swappiness - 100 - The kernel will swap aggressively.
// Foreground apps
pref("hal.processPriorityManager.gonk.cgroups.apps.cpu_shares", 1024);
pref("hal.processPriorityManager.gonk.cgroups.apps.cpu_notify_on_migrate", 1);
pref("hal.processPriorityManager.gonk.cgroups.apps.memory_swappiness", 10);
// Foreground apps with high priority, 16x more CPU than foreground ones
pref("hal.processPriorityManager.gonk.cgroups.apps/critical.cpu_shares", 16384);
pref("hal.processPriorityManager.gonk.cgroups.apps/critical.cpu_notify_on_migrate", 1);
pref("hal.processPriorityManager.gonk.cgroups.apps/critical.memory_swappiness", 0);
// Background perceivable apps, ~10x less CPU than foreground ones
pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.cpu_shares", 103);
pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.cpu_notify_on_migrate", 0);
pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.memory_swappiness", 60);
// Background apps, ~20x less CPU than foreground ones and ~2x less than perceivable ones
pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.cpu_shares", 52);
pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.cpu_notify_on_migrate", 0);
pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.memory_swappiness", 100);
// By default the compositor thread on gonk runs without real-time priority. RT
// priority can be enabled by setting this pref to a value between 1 and 99.
@ -1080,3 +1088,6 @@ pref("dom.mozSettings.SettingsService.verbose.enabled", false);
// IndexedDB transactions to be opened as readonly or keep everything as
// readwrite.
pref("dom.mozSettings.allowForceReadOnly", false);
// RequestSync API is enabled by default on B2G.
pref("dom.requestSync.enabled", true);

View File

@ -15,6 +15,7 @@ Cu.import('resource://gre/modules/UserAgentOverrides.jsm');
Cu.import('resource://gre/modules/Keyboard.jsm');
Cu.import('resource://gre/modules/ErrorPage.jsm');
Cu.import('resource://gre/modules/AlertsHelper.jsm');
Cu.import('resource://gre/modules/RequestSyncService.jsm');
#ifdef MOZ_WIDGET_GONK
Cu.import('resource://gre/modules/NetworkStatsService.jsm');
Cu.import('resource://gre/modules/ResourceStatsService.jsm');
@ -27,6 +28,7 @@ SignInToWebsiteController.init();
Cu.import('resource://gre/modules/FxAccountsMgmtService.jsm');
Cu.import('resource://gre/modules/DownloadsAPI.jsm');
Cu.import('resource://gre/modules/MobileIdentityManager.jsm');
Cu.import('resource://gre/modules/PresentationDeviceInfoManager.jsm');
XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
"resource://gre/modules/SystemAppProxy.jsm");

View File

@ -106,3 +106,7 @@ contract @mozilla.org/services/mobileid-ui-glue;1 {83dbe26a-81f3-4a75-9541-3d0b7
component {7211ece0-b458-4635-9afc-f8d7f376ee95} B2GAppMigrator.js
contract @mozilla.org/app-migrator;1 {7211ece0-b458-4635-9afc-f8d7f376ee95}
# B2GPresentationDevicePrompt.js
component {4a300c26-e99b-4018-ab9b-c48cf9bc4de1} B2GPresentationDevicePrompt.js
contract @mozilla.org/presentation-device/prompt;1 {4a300c26-e99b-4018-ab9b-c48cf9bc4de1}

View File

@ -0,0 +1,87 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 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/. */
"use strict";
function debug(aMsg) {
//dump("-*- B2GPresentationDevicePrompt: " + aMsg + "\n");
}
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
const kB2GPRESENTATIONDEVICEPROMPT_CONTRACTID = "@mozilla.org/presentation-device/prompt;1";
const kB2GPRESENTATIONDEVICEPROMPT_CID = Components.ID("{4a300c26-e99b-4018-ab9b-c48cf9bc4de1}");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
"resource://gre/modules/SystemAppProxy.jsm");
function B2GPresentationDevicePrompt() {}
B2GPresentationDevicePrompt.prototype = {
classID: kB2GPRESENTATIONDEVICEPROMPT_CID,
contractID: kB2GPRESENTATIONDEVICEPROMPT_CONTRACTID,
classDescription: "B2G Presentation Device Prompt",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevicePrompt]),
// nsIPresentationDevicePrompt
promptDeviceSelection: function(aRequest) {
let self = this;
let requestId = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator).generateUUID().toString();
SystemAppProxy.addEventListener("mozContentEvent", function contentEvent(aEvent) {
let detail = aEvent.detail;
if (detail.id !== requestId) {
return;
}
SystemAppProxy.removeEventListener("mozContentEvent", contentEvent);
switch (detail.type) {
case "presentation-select-result":
debug("device " + detail.deviceId + " is selected by user");
let device = self._getDeviceById(detail.deviceId);
if (!device) {
debug("cancel request because device is not found");
aRequest.cancel();
}
aRequest.select(device);
break;
case "presentation-select-deny":
debug("request canceled by user");
aRequest.cancel();
break;
}
});
let detail = {
type: "presentation-select-device",
origin: aRequest.origin,
requestURL: aRequest.requestURL,
id: requestId,
};
SystemAppProxy.dispatchEvent(detail);
},
_getDeviceById: function(aDeviceId) {
let deviceManager = Cc["@mozilla.org/presentation-device/manager;1"]
.getService(Ci.nsIPresentationDeviceManager);
let devices = deviceManager.getAvailableDevices().QueryInterface(Ci.nsIArray);
for (let i = 0; i < devices.length; i++) {
let device = devices.queryElementAt(i, Ci.nsIPresentationDevice);
if (device.id === aDeviceId) {
return device;
}
}
return null;
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([B2GPresentationDevicePrompt]);

View File

@ -11,6 +11,7 @@ EXTRA_COMPONENTS += [
'AlertsService.js',
'B2GAboutRedirector.js',
'B2GAppMigrator.js',
'B2GPresentationDevicePrompt.js',
'ContentPermissionPrompt.js',
'FilePicker.js',
'FxAccountsUIGlue.js',

View File

@ -5,6 +5,7 @@ support-files =
SandboxPromptTest.html
filepicker_path_handler_chrome.js
systemapp_helper.js
presentation_prompt_handler_chrome.js
[test_filepicker_path.html]
[test_permission_deny.html]
@ -12,3 +13,4 @@ support-files =
skip-if = true # Bug 1019572 - frequent timeouts
[test_sandbox_permission.html]
[test_systemapp.html]
[test_presentation_device_prompt.html]

View File

@ -0,0 +1,94 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
function debug(str) {
dump('presentation_prompt_handler_chrome: ' + str + '\n');
}
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
const { XPCOMUtils } = Cu.import('resource://gre/modules/XPCOMUtils.jsm');
const { SystemAppProxy } = Cu.import('resource://gre/modules/SystemAppProxy.jsm');
const manager = Cc["@mozilla.org/presentation-device/manager;1"]
.getService(Ci.nsIPresentationDeviceManager);
const prompt = Cc['@mozilla.org/presentation-device/prompt;1']
.getService(Ci.nsIPresentationDevicePrompt);
function TestPresentationDevice(options) {
this.id = options.id;
this.name = options.name;
this.type = options.type;
}
TestPresentationDevice.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
establishSessionTransport: function() {
return null;
},
};
function TestPresentationRequest(options) {
this.origin = options.origin;
this.requestURL = options.requestURL;
}
TestPresentationRequest.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceRequest]),
select: function(device) {
let result = {
type: 'select',
device: {
id: device.id,
name: device.name,
type: device.type,
},
};
sendAsyncMessage('presentation-select-result', result);
},
cancel: function() {
let result = {
type: 'cancel',
};
sendAsyncMessage('presentation-select-result', result);
},
};
var testDevice = null;
addMessageListener('setup', function(device_options) {
testDevice = new TestPresentationDevice(device_options);
manager.QueryInterface(Ci.nsIPresentationDeviceListener).addDevice(testDevice);
sendAsyncMessage('setup-complete');
});
let eventHandler = function(evt) {
if (!evt.detail || evt.detail.type !== 'presentation-select-device') {
return;
}
sendAsyncMessage('presentation-select-device', evt.detail);
};
SystemAppProxy.addEventListener('mozChromeEvent', eventHandler);
// need to remove ChromeEvent listener after test finished.
addMessageListener('teardown', function() {
if (testDevice) {
manager.removeDevice(testDevice);
}
SystemAppProxy.removeEventListener('mozChromeEvent', eventHandler);
});
addMessageListener('trigger-device-prompt', function(request_options) {
let request = new TestPresentationRequest(request_options);
prompt.promptDeviceSelection(request);
});
addMessageListener('presentation-select-response', function(detail) {
SystemAppProxy._sendCustomEvent('mozContentEvent', detail);
});

View File

@ -0,0 +1,145 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for Presentation Device Selection</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Test for Presentation Device Selection</a>
<script type="application/javascript;version=1.8">
'use strict';
SimpleTest.waitForExplicitFinish();
var contentEventHandler = null;
var gUrl = SimpleTest.getTestFileURL('presentation_prompt_handler_chrome.js');
var gScript = SpecialPowers.loadChromeScript(gUrl);
function testSetup() {
info('setup for device selection');
return new Promise(function(resolve, reject) {
let device = {
id: 'test-id',
name: 'test-name',
type: 'test-type',
};
gScript.addMessageListener('setup-complete', function() {
resolve(device);
});
gScript.sendAsyncMessage('setup', device);
});
}
function testSelected(device) {
info('test device selected by user');
return new Promise(function(resolve, reject) {
let request = {
origin: 'test-origin',
requestURL: 'test-requestURL',
};
gScript.addMessageListener('presentation-select-device', function contentEventHandler(detail) {
gScript.removeMessageListener('presentation-select-device', contentEventHandler);
ok(true, 'receive user prompt for device selection');
is(detail.origin, request.origin, 'expected origin');
is(detail.requestURL, request.requestURL, 'expected requestURL');
let response = {
id: detail.id,
type: 'presentation-select-result',
deviceId: device.id,
};
gScript.sendAsyncMessage('presentation-select-response', response);
gScript.addMessageListener('presentation-select-result', function resultHandler(result) {
gScript.removeMessageListener('presentation-select-result', resultHandler);
is(result.type, 'select', 'expect device selected');
is(result.device.id, device.id, 'expected device id');
is(result.device.name, device.name, 'expected device name');
is(result.device.type, device.type, 'expected devcie type');
resolve();
});
});
gScript.sendAsyncMessage('trigger-device-prompt', request);
});
}
function testSelectedNotExisted() {
info('test selected device doesn\'t exist');
return new Promise(function(resolve, reject) {
gScript.addMessageListener('presentation-select-device', function contentEventHandler(detail) {
gScript.removeMessageListener('presentation-select-device', contentEventHandler);
ok(true, 'receive user prompt for device selection');
let response = {
id: detail.id,
type: 'presentation-select-deny',
deviceId: undefined, // simulate device Id that doesn't exist
};
gScript.sendAsyncMessage('presentation-select-response', response);
gScript.addMessageListener('presentation-select-result', function resultHandler(result) {
gScript.removeMessageListener('presentation-select-result', resultHandler);
is(result.type, 'cancel', 'expect user cancel');
resolve();
});
});
let request = {
origin: 'test-origin',
requestURL: 'test-requestURL',
};
gScript.sendAsyncMessage('trigger-device-prompt', request);
});
}
function testDenied() {
info('test denial of device selection');
return new Promise(function(resolve, reject) {
gScript.addMessageListener('presentation-select-device', function contentEventHandler(detail) {
gScript.removeMessageListener('presentation-select-device', contentEventHandler);
ok(true, 'receive user prompt for device selection');
let response = {
id: detail.id,
type: 'presentation-select-deny',
};
gScript.sendAsyncMessage('presentation-select-response', response);
gScript.addMessageListener('presentation-select-result', function resultHandler(result) {
gScript.removeMessageListener('presentation-select-result', resultHandler);
is(result.type, 'cancel', 'expect user cancel');
resolve();
});
});
let request = {
origin: 'test-origin',
requestURL: 'test-requestURL',
};
gScript.sendAsyncMessage('trigger-device-prompt', request);
});
}
function runTests() {
testSetup()
.then(testSelected)
.then(testSelectedNotExisted)
.then(testDenied)
.then(function() {
info('test finished, teardown');
gScript.sendAsyncMessage('teardown');
gScript.destroy();
SimpleTest.finish();
});
}
window.addEventListener('load', runTests);
</script>
</pre>
</body>
</html>

View File

@ -27,7 +27,8 @@
],
"env": {
"VARIANT": "user",
"MOZILLA_OFFICIAL": "1"
"MOZILLA_OFFICIAL": "1",
"B2G_UPDATE_CHANNEL": "nightly"
},
"b2g_manifest": "dolphin.xml",
"b2g_manifest_intree": true,

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9946a490a9264b42e65385d703b28fa055ab2d42"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e2a0f7c311119d4a8e160bdfb9e28a0e61a180fc"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
@ -116,7 +116,7 @@
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="f7d9bf71cf6693474f3f2a81a4ba62c0fc5646aa"/>
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="cfcef469537869947abb9aa1d656774cc2678d4c"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="288db53ad77084bd44791add5e3a4c266a6e9c60"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="aa3adea9c18ae00d36e597d5890cf14cb7dfb105"/>
<project name="platform/system/extras" path="system/extras" revision="10e78a05252b3de785f88c2d0b9ea8a428009c50"/>
<project name="platform/system/media" path="system/media" revision="7ff72c2ea2496fa50b5e8a915e56e901c3ccd240"/>
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="fe95bc6f83af5c18a73aa86c96e7fa7f79b91477"/>

View File

@ -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="9946a490a9264b42e65385d703b28fa055ab2d42"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e2a0f7c311119d4a8e160bdfb9e28a0e61a180fc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9946a490a9264b42e65385d703b28fa055ab2d42"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e2a0f7c311119d4a8e160bdfb9e28a0e61a180fc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
@ -118,7 +118,7 @@
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="842e33e43a55ea44833b9e23e4d180fa17c843af"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5db24726f0f42124304195a6bdea129039eeeaeb"/>
<project name="platform/system/bluetooth" path="system/bluetooth" revision="930ae098543881f47eac054677726ee4b998b2f8"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="288db53ad77084bd44791add5e3a4c266a6e9c60"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="aa3adea9c18ae00d36e597d5890cf14cb7dfb105"/>
<project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
<project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="fe95bc6f83af5c18a73aa86c96e7fa7f79b91477"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9946a490a9264b42e65385d703b28fa055ab2d42"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e2a0f7c311119d4a8e160bdfb9e28a0e61a180fc"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
@ -116,7 +116,7 @@
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="f7d9bf71cf6693474f3f2a81a4ba62c0fc5646aa"/>
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="b562b01c93de9578d5db537b6a602a38e1aaa0ce"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="387f03e815f57d536dd922706db1622bddba8d81"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="288db53ad77084bd44791add5e3a4c266a6e9c60"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="aa3adea9c18ae00d36e597d5890cf14cb7dfb105"/>
<project name="platform/system/extras" path="system/extras" revision="5356165f67f4a81c2ef28671c13697f1657590df"/>
<project name="platform/system/media" path="system/media" revision="be0e2fe59a8043fa5200f75697df9220a99abe9d"/>
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="fe95bc6f83af5c18a73aa86c96e7fa7f79b91477"/>

View File

@ -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="9946a490a9264b42e65385d703b28fa055ab2d42"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e2a0f7c311119d4a8e160bdfb9e28a0e61a180fc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9946a490a9264b42e65385d703b28fa055ab2d42"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e2a0f7c311119d4a8e160bdfb9e28a0e61a180fc"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
@ -116,7 +116,7 @@
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="f7d9bf71cf6693474f3f2a81a4ba62c0fc5646aa"/>
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="69d524e80cdf3981006627c65ac85f3a871238a3"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="288db53ad77084bd44791add5e3a4c266a6e9c60"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="aa3adea9c18ae00d36e597d5890cf14cb7dfb105"/>
<project name="platform/system/extras" path="system/extras" revision="576f57b6510de59c08568b53c0fb60588be8689e"/>
<project name="platform/system/media" path="system/media" revision="20c2fb4c896aa59f2e8379d755f439dc59a5cf9b"/>
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="fe95bc6f83af5c18a73aa86c96e7fa7f79b91477"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9946a490a9264b42e65385d703b28fa055ab2d42"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e2a0f7c311119d4a8e160bdfb9e28a0e61a180fc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "fe8bc669500de4e81dc5e1e0ef4e044222bdbeaa",
"revision": "6d459c49070f4c80bf97795e86369ab2eb765c36",
"repo_path": "integration/gaia-central"
}

View File

@ -17,7 +17,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="9946a490a9264b42e65385d703b28fa055ab2d42"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e2a0f7c311119d4a8e160bdfb9e28a0e61a180fc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>

View File

@ -15,7 +15,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="9946a490a9264b42e65385d703b28fa055ab2d42"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e2a0f7c311119d4a8e160bdfb9e28a0e61a180fc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9946a490a9264b42e65385d703b28fa055ab2d42"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e2a0f7c311119d4a8e160bdfb9e28a0e61a180fc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
@ -118,7 +118,7 @@
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="842e33e43a55ea44833b9e23e4d180fa17c843af"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5db24726f0f42124304195a6bdea129039eeeaeb"/>
<project name="platform/system/bluetooth" path="system/bluetooth" revision="930ae098543881f47eac054677726ee4b998b2f8"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="288db53ad77084bd44791add5e3a4c266a6e9c60"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="aa3adea9c18ae00d36e597d5890cf14cb7dfb105"/>
<project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
<project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="fe95bc6f83af5c18a73aa86c96e7fa7f79b91477"/>

View File

@ -17,7 +17,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="9946a490a9264b42e65385d703b28fa055ab2d42"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e2a0f7c311119d4a8e160bdfb9e28a0e61a180fc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -210,6 +210,7 @@
@BINPATH@/components/dom_xul.xpt
@BINPATH@/components/dom_time.xpt
@BINPATH@/components/dom_engineeringmode.xpt
@BINPATH@/components/dom_presentation.xpt
@BINPATH@/components/downloads.xpt
@BINPATH@/components/editor.xpt
@BINPATH@/components/embed_base.xpt
@ -342,6 +343,9 @@
@BINPATH@/components/zipwriter.xpt
; JavaScript components
@BINPATH@/components/RequestSync.manifest
@BINPATH@/components/RequestSyncManager.js
@BINPATH@/components/RequestSyncScheduler.js
@BINPATH@/components/ChromeNotifications.js
@BINPATH@/components/ChromeNotifications.manifest
@BINPATH@/components/ConsoleAPI.manifest
@ -400,6 +404,8 @@
@BINPATH@/components/nsAsyncShutdown.js
@BINPATH@/components/htmlMenuBuilder.js
@BINPATH@/components/htmlMenuBuilder.manifest
@BINPATH@/components/PresentationDeviceInfoManager.manifest
@BINPATH@/components/PresentationDeviceInfoManager.js
; WiFi, NetworkManager, NetworkStats
#ifdef MOZ_WIDGET_GONK
@ -859,6 +865,7 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@
@BINPATH@/components/InterAppCommUIGlue.js
@BINPATH@/components/SystemMessageGlue.js
@BINPATH@/components/B2GAppMigrator.js
@BINPATH@/components/B2GPresentationDevicePrompt.js
#ifndef MOZ_WIDGET_GONK
@BINPATH@/components/SimulatorScreen.js

View File

@ -249,7 +249,8 @@ Sanitizer.prototype = {
try {
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
os.notifyObservers(null, "browser:purge-session-history", "");
let clearStartingTime = this.range ? String(this.range[0]) : "";
os.notifyObservers(null, "browser:purge-session-history", clearStartingTime);
}
catch (e) { }

View File

@ -826,12 +826,12 @@ this.PlacesUIUtils = {
* web panel.
* see also openUILinkIn
*/
openNodeIn: function PUIU_openNodeIn(aNode, aWhere, aView) {
openNodeIn: function PUIU_openNodeIn(aNode, aWhere, aView, aPrivate) {
let window = aView.ownerWindow;
this._openNodeIn(aNode, aWhere, window);
this._openNodeIn(aNode, aWhere, window, aPrivate);
},
_openNodeIn: function PUIU_openNodeIn(aNode, aWhere, aWindow) {
_openNodeIn: function PUIU_openNodeIn(aNode, aWhere, aWindow, aPrivate=false) {
if (aNode && PlacesUtils.nodeIsURI(aNode) &&
this.checkURLSecurity(aNode, aWindow)) {
let isBookmark = PlacesUtils.nodeIsBookmark(aNode);
@ -855,8 +855,10 @@ this.PlacesUIUtils = {
}
}
}
aWindow.openUILinkIn(aNode.uri, aWhere, {
inBackground: Services.prefs.getBoolPref("browser.tabs.loadBookmarksInBackground")
inBackground: Services.prefs.getBoolPref("browser.tabs.loadBookmarksInBackground"),
private: aPrivate,
});
}
},

View File

@ -7,6 +7,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "ForgetAboutSite",
"resource://gre/modules/ForgetAboutSite.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
// XXXmano: we should move most/all of these constants to PlacesUtils
const ORGANIZER_ROOT_BOOKMARKS = "place:folder=BOOKMARKS_MENU&excludeItems=1&queryType=1";
@ -178,6 +180,7 @@ PlacesController.prototype = {
return false;
case "placesCmd_open":
case "placesCmd_open:window":
case "placesCmd_open:privatewindow":
case "placesCmd_open:tab":
var selectedNode = this._view.selectedNode;
return selectedNode && PlacesUtils.nodeIsURI(selectedNode);
@ -263,6 +266,9 @@ PlacesController.prototype = {
case "placesCmd_open:window":
PlacesUIUtils.openNodeIn(this._view.selectedNode, "window", this._view);
break;
case "placesCmd_open:privatewindow":
PlacesUIUtils.openNodeIn(this._view.selectedNode, "window", this._view, true);
break;
case "placesCmd_open:tab":
PlacesUIUtils.openNodeIn(this._view.selectedNode, "tab", this._view);
break;
@ -601,7 +607,10 @@ PlacesController.prototype = {
// We allow pasting into tag containers, so special case that.
var hideIfNoIP = item.getAttribute("hideifnoinsertionpoint") == "true" &&
noIp && !(ip && ip.isTag && item.id == "placesContext_paste");
var shouldHideItem = hideIfNoIP || !this._shouldShowMenuItem(item, metadata);
var hideIfPrivate = item.getAttribute("hideifprivatebrowsing") == "true" &&
PrivateBrowsingUtils.isWindowPrivate(window);
var shouldHideItem = hideIfNoIP || hideIfPrivate ||
!this._shouldShowMenuItem(item, metadata);
item.hidden = item.disabled = shouldHideItem;
if (!item.hidden) {
@ -1690,6 +1699,7 @@ function goUpdatePlacesCommands() {
updatePlacesCommand("placesCmd_open");
updatePlacesCommand("placesCmd_open:window");
updatePlacesCommand("placesCmd_open:privatewindow");
updatePlacesCommand("placesCmd_open:tab");
updatePlacesCommand("placesCmd_new:folder");
updatePlacesCommand("placesCmd_new:bookmark");

View File

@ -54,6 +54,8 @@
oncommand="goDoPlacesCommand('placesCmd_open');"/>
<command id="placesCmd_open:window"
oncommand="goDoPlacesCommand('placesCmd_open:window');"/>
<command id="placesCmd_open:privatewindow"
oncommand="goDoPlacesCommand('placesCmd_open:privatewindow');"/>
<command id="placesCmd_open:tab"
oncommand="goDoPlacesCommand('placesCmd_open:tab');"/>
@ -129,6 +131,13 @@
accesskey="&cmd.open_window.accesskey;"
selectiontype="single"
selection="link"/>
<menuitem id="placesContext_open:newprivatewindow"
command="placesCmd_open:privatewindow"
label="&cmd.open_private_window.label;"
accesskey="&cmd.open_private_window.accesskey;"
selectiontype="single"
selection="link"
hideifprivatebrowsing="true"/>
<menuseparator id="placesContext_openSeparator"/>
<menuitem id="placesContext_new:bookmark"
command="placesCmd_new:bookmark"

View File

@ -237,6 +237,7 @@
@RESPATH@/components/dom_gamepad.xpt
#endif
@RESPATH@/components/dom_payment.xpt
@RESPATH@/components/dom_presentation.xpt
@RESPATH@/components/downloads.xpt
@RESPATH@/components/editor.xpt
@RESPATH@/components/embed_base.xpt
@ -540,6 +541,10 @@
@RESPATH@/components/htmlMenuBuilder.js
@RESPATH@/components/htmlMenuBuilder.manifest
@RESPATH@/components/RequestSync.manifest
@RESPATH@/components/RequestSyncManager.js
@RESPATH@/components/RequestSyncScheduler.js
@RESPATH@/components/PermissionSettings.js
@RESPATH@/components/PermissionSettings.manifest
@RESPATH@/components/ContactManager.js
@ -602,6 +607,9 @@
@RESPATH@/components/nsAsyncShutdown.manifest
@RESPATH@/components/nsAsyncShutdown.js
@RESPATH@/components/PresentationDeviceInfoManager.manifest
@RESPATH@/components/PresentationDeviceInfoManager.js
; InputMethod API
@RESPATH@/components/MozKeyboard.js
@RESPATH@/components/InputMethod.manifest

View File

@ -52,6 +52,8 @@
<!ENTITY cmd.open.accesskey "O">
<!ENTITY cmd.open_window.label "Open in a New Window">
<!ENTITY cmd.open_window.accesskey "N">
<!ENTITY cmd.open_private_window.label "Open in a New Private Window">
<!ENTITY cmd.open_private_window.accesskey "P">
<!ENTITY cmd.open_tab.label "Open in a New Tab">
<!ENTITY cmd.open_tab.accesskey "w">
<!ENTITY cmd.open_all_in_tabs.label "Open All in Tabs">

View File

@ -533,6 +533,7 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
list-style-image: url("moz-icon://stock/gtk-info?size=menu");
}
#placesContext_open\:newprivatewindow,
#privateBrowsingItem {
list-style-image: url("chrome://browser/skin/Privacy-16.png");
}

View File

@ -200,6 +200,11 @@ menuitem[command="placesCmd_open:window"] {
-moz-image-region: rect(0px 80px 16px 64px);
}
#placesContext_open\:newprivatewindow,
menuitem[command="placesCmd_open:privatewindow"] {
list-style-image: url("chrome://browser/skin/Privacy-16.png");
}
#placesContext_open\:newtab,
menuitem[command="placesCmd_open:tab"] {
list-style-image: url("chrome://browser/skin/Toolbar-small.png");

View File

@ -526,6 +526,12 @@ this.PermissionsTable = { geolocation: {
trusted: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
"presentation-device-manage": {
app: DENY_ACTION,
trusted: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
}
};

View File

@ -129,10 +129,11 @@ AnonymousContent::GetElementById(const nsAString& aElementId)
return nullptr;
}
JSObject*
AnonymousContent::WrapObject(JSContext* aCx)
bool
AnonymousContent::WrapObject(JSContext* aCx,
JS::MutableHandle<JSObject*> aReflector)
{
return AnonymousContentBinding::Wrap(aCx, this);
return AnonymousContentBinding::Wrap(aCx, this, aReflector);
}
} // dom namespace

View File

@ -27,7 +27,7 @@ public:
explicit AnonymousContent(Element* aContentNode);
nsCOMPtr<Element> GetContentNode();
void SetContentNode(Element* aContentNode);
JSObject* WrapObject(JSContext* aCx);
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
// WebIDL methods
void SetTextContentForElement(const nsAString& aElementId,

View File

@ -23,6 +23,11 @@ namespace dom {
static const double radPerDegree = 2.0 * M_PI / 360.0;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMMatrixReadOnly, mParent)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMMatrixReadOnly, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMMatrixReadOnly, Release)
already_AddRefed<DOMMatrix>
DOMMatrixReadOnly::Translate(double aTx,
double aTy,
@ -303,11 +308,6 @@ DOMMatrixReadOnly::Stringify(nsAString& aResult)
aResult = matrixStr;
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMMatrix, mParent)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMMatrix, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMMatrix, Release)
already_AddRefed<DOMMatrix>
DOMMatrix::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
{

View File

@ -40,6 +40,9 @@ public:
}
}
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMMatrixReadOnly)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMMatrixReadOnly)
#define GetMatrixMember(entry2D, entry3D, default) \
{ \
if (mMatrix3D) { \
@ -130,9 +133,8 @@ protected:
nsAutoPtr<gfx::Matrix> mMatrix2D;
nsAutoPtr<gfx::Matrix4x4> mMatrix3D;
~DOMMatrixReadOnly()
{
}
virtual ~DOMMatrixReadOnly() {}
private:
DOMMatrixReadOnly() = delete;
DOMMatrixReadOnly(const DOMMatrixReadOnly&) = delete;
@ -150,9 +152,6 @@ public:
: DOMMatrixReadOnly(aParent, other)
{}
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMMatrix)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMMatrix)
static already_AddRefed<DOMMatrix>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
static already_AddRefed<DOMMatrix>
@ -246,8 +245,6 @@ public:
DOMMatrix* SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv);
private:
void Ensure3DMatrix();
~DOMMatrix() {}
};
}

View File

@ -12,10 +12,10 @@
using namespace mozilla;
using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMPoint, mParent)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMPointReadOnly, mParent)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMPoint, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMPoint, Release)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMPointReadOnly, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMPointReadOnly, Release)
already_AddRefed<DOMPoint>
DOMPoint::Constructor(const GlobalObject& aGlobal, const DOMPointInit& aParams,

View File

@ -33,29 +33,29 @@ public:
{
}
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMPointReadOnly)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMPointReadOnly)
double X() const { return mX; }
double Y() const { return mY; }
double Z() const { return mZ; }
double W() const { return mW; }
protected:
virtual ~DOMPointReadOnly() {}
nsCOMPtr<nsISupports> mParent;
double mX, mY, mZ, mW;
};
class DOMPoint MOZ_FINAL : public DOMPointReadOnly
{
~DOMPoint() {}
public:
explicit DOMPoint(nsISupports* aParent, double aX = 0.0, double aY = 0.0,
double aZ = 0.0, double aW = 1.0)
: DOMPointReadOnly(aParent, aX, aY, aZ, aW)
{}
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMPoint)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMPoint)
static already_AddRefed<DOMPoint>
Constructor(const GlobalObject& aGlobal, const DOMPointInit& aParams,
ErrorResult& aRV);

View File

@ -1847,6 +1847,33 @@ Navigator::MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv)
return result;
}
void
Navigator::MozSetMessageHandlerPromise(Promise& aPromise,
ErrorResult& aRv)
{
// The WebIDL binding is responsible for the pref check here.
aRv = EnsureMessagesManager();
if (NS_WARN_IF(aRv.Failed())) {
return;
}
bool result = false;
aRv = mMessagesManager->MozIsHandlingMessage(&result);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
if (!result) {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return;
}
aRv = mMessagesManager->MozSetMessageHandlerPromise(&aPromise);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
}
void
Navigator::MozSetMessageHandler(const nsAString& aType,
systemMessageCallback* aCallback,

View File

@ -235,6 +235,8 @@ public:
systemMessageCallback* aCallback,
ErrorResult& aRv);
bool MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv);
void MozSetMessageHandlerPromise(Promise& aPromise, ErrorResult& aRv);
#ifdef MOZ_B2G
already_AddRefed<Promise> GetMobileIdAssertion(const MobileIdOptions& options,
ErrorResult& aRv);

View File

@ -288,10 +288,10 @@ void NodeIterator::ContentRemoved(nsIDocument *aDocument,
mWorkingPointer.AdjustAfterRemoval(mRoot, container, aChild, aPreviousSibling);
}
JSObject*
NodeIterator::WrapObject(JSContext *cx)
bool
NodeIterator::WrapObject(JSContext *cx, JS::MutableHandle<JSObject*> aReflector)
{
return NodeIteratorBinding::Wrap(cx, this);
return NodeIteratorBinding::Wrap(cx, this, aReflector);
}
} // namespace dom

View File

@ -69,7 +69,7 @@ public:
}
// The XPCOM Detach() is fine for our purposes
JSObject* WrapObject(JSContext *cx);
bool WrapObject(JSContext *cx, JS::MutableHandle<JSObject*> aReflector);
private:
virtual ~NodeIterator();

View File

@ -450,10 +450,10 @@ TreeWalker::NextSiblingInternal(bool aReversed, ErrorResult& aResult)
}
}
JSObject*
TreeWalker::WrapObject(JSContext *cx)
bool
TreeWalker::WrapObject(JSContext *aCx, JS::MutableHandle<JSObject*> aReflector)
{
return TreeWalkerBinding::Wrap(cx, this);
return TreeWalkerBinding::Wrap(aCx, this, aReflector);
}
} // namespace dom

View File

@ -65,7 +65,7 @@ public:
already_AddRefed<nsINode> PreviousNode(ErrorResult& aResult);
already_AddRefed<nsINode> NextNode(ErrorResult& aResult);
JSObject* WrapObject(JSContext *cx);
bool WrapObject(JSContext *aCx, JS::MutableHandle<JSObject*> aReflector);
private:
nsCOMPtr<nsINode> mCurrentNode;

View File

@ -46,10 +46,10 @@ URL::URL(nsIURI* aURI)
{
}
JSObject*
URL::WrapObject(JSContext* aCx)
bool
URL::WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector)
{
return URLBinding::Wrap(aCx, this);
return URLBinding::Wrap(aCx, this, aReflector);
}
/* static */ already_AddRefed<URL>

View File

@ -43,8 +43,8 @@ public:
explicit URL(nsIURI* aURI);
// WebIDL methods
JSObject*
WrapObject(JSContext* aCx);
bool
WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
static already_AddRefed<URL>
Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,

View File

@ -646,13 +646,14 @@ WebSocketImpl::DoOnMessageAvailable(const nsACString& aMsg, bool isBinary)
if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch the message event");
}
} else {
// CLOSING should be the only other state where it's possible to get msgs
// from channel: Spec says to drop them.
MOZ_ASSERT(readyState == WebSocket::CLOSING,
"Received message while CONNECTING or CLOSED");
return NS_OK;
}
// CLOSING should be the only other state where it's possible to get msgs
// from channel: Spec says to drop them.
MOZ_ASSERT(readyState == WebSocket::CLOSING,
"Received message while CONNECTING or CLOSED");
return NS_OK;
}
@ -718,14 +719,17 @@ WebSocketImpl::OnStart(nsISupports* aContext)
mWebSocket->SetReadyState(WebSocket::OPEN);
// Let's keep the object alive because the webSocket can be CCed in the
// onopen callback.
nsRefPtr<WebSocket> webSocket = mWebSocket;
// Call 'onopen'
rv = mWebSocket->CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("open"));
rv = webSocket->CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("open"));
if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch the open event");
}
mWebSocket->UpdateMustKeepAlive();
webSocket->UpdateMustKeepAlive();
return NS_OK;
}
@ -1596,23 +1600,27 @@ WebSocketImpl::DispatchConnectionCloseEvents()
mWebSocket->SetReadyState(WebSocket::CLOSED);
// Let's keep the object alive because the webSocket can be CCed in the
// onerror or in the onclose callback.
nsRefPtr<WebSocket> webSocket = mWebSocket;
// Call 'onerror' if needed
if (mFailed) {
nsresult rv =
mWebSocket->CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error"));
webSocket->CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error"));
if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch the error event");
}
}
nsresult rv = mWebSocket->CreateAndDispatchCloseEvent(mCloseEventWasClean,
mCloseEventCode,
mCloseEventReason);
nsresult rv = webSocket->CreateAndDispatchCloseEvent(mCloseEventWasClean,
mCloseEventCode,
mCloseEventReason);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch the close event");
}
mWebSocket->UpdateMustKeepAlive();
webSocket->UpdateMustKeepAlive();
Disconnect();
}

View File

@ -5300,8 +5300,8 @@ nsIDocument::RemoveAnonymousContent(AnonymousContent& aContent,
return;
}
// Iterate over know customContents to get and remove the right one
for (int32_t i = mAnonymousContents.Length() - 1; i >= 0; --i) {
// Iterate over mAnonymousContents to find and remove the given node.
for (size_t i = 0, len = mAnonymousContents.Length(); i < len; ++i) {
if (mAnonymousContents[i] == &aContent) {
// Get the node from the customContent
nsCOMPtr<Element> node = aContent.GetContentNode();

View File

@ -2305,7 +2305,7 @@ nsFrameLoader::CreateStaticClone(nsIFrameLoader* aDest)
bool
nsFrameLoader::DoLoadFrameScript(const nsAString& aURL, bool aRunInGlobalScope)
{
auto* tabParent = static_cast<TabParent*>(GetRemoteBrowser());
mozilla::dom::PBrowserParent* tabParent = GetRemoteBrowser();
if (tabParent) {
return tabParent->SendLoadRemoteScript(nsString(aURL), aRunInGlobalScope);
}

View File

@ -2299,9 +2299,9 @@ CreateNativeGlobalForInner(JSContext* aCx,
uint32_t flags = needComponents ? 0 : nsIXPConnect::OMIT_COMPONENTS_OBJECT;
flags |= nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK;
aGlobal.set(WindowBinding::Wrap(aCx, aNewInner, aNewInner, options,
nsJSPrincipals::get(aPrincipal), false));
if (!aGlobal || !xpc::InitGlobalObject(aCx, aGlobal, flags)) {
if (!WindowBinding::Wrap(aCx, aNewInner, aNewInner, options,
nsJSPrincipals::get(aPrincipal), false, aGlobal) ||
!xpc::InitGlobalObject(aCx, aGlobal, flags)) {
return NS_ERROR_FAILURE;
}

View File

@ -667,47 +667,70 @@ DefineWebIDLBindingPropertiesOnXPCObject(JSContext* cx,
JS::Handle<JSObject*> obj,
const NativeProperties* properties);
#define HAS_MEMBER_TYPEDEFS \
private: \
typedef char yes[1]; \
typedef char no[2]
#ifdef _MSC_VER
#define HAS_MEMBER_CHECK(_name) \
template<typename V> static yes& Check(char (*)[(&V::_name == 0) + 1])
template<typename V> static yes& Check##_name(char (*)[(&V::_name == 0) + 1])
#else
#define HAS_MEMBER_CHECK(_name) \
template<typename V> static yes& Check(char (*)[sizeof(&V::_name) + 1])
template<typename V> static yes& Check##_name(char (*)[sizeof(&V::_name) + 1])
#endif
#define HAS_MEMBER(_name) \
template<typename T> \
class Has##_name##Member { \
typedef char yes[1]; \
typedef char no[2]; \
HAS_MEMBER_CHECK(_name); \
template<typename V> static no& Check(...); \
#define HAS_MEMBER(_memberName, _valueName) \
private: \
HAS_MEMBER_CHECK(_memberName); \
template<typename V> static no& Check##_memberName(...); \
\
public: \
static bool const Value = sizeof(Check<T>(nullptr)) == sizeof(yes); \
static bool const _valueName = \
sizeof(Check##_memberName<T>(nullptr)) == sizeof(yes)
template<class T>
struct NativeHasMember
{
HAS_MEMBER_TYPEDEFS;
HAS_MEMBER(GetParentObject, GetParentObject);
HAS_MEMBER(JSBindingFinalized, JSBindingFinalized);
HAS_MEMBER(WrapObject, WrapObject);
};
HAS_MEMBER(WrapObject)
// HasWrapObject<T>::Value will be true if T has a WrapObject member but it's
// not nsWrapperCache::WrapObject.
template<typename T>
struct HasWrapObject
template<class T>
struct IsSmartPtr
{
private:
typedef char yes[1];
typedef char no[2];
typedef JSObject* (nsWrapperCache::*WrapObject)(JSContext*,
JS::Handle<JSObject*>);
template<typename U, U> struct SFINAE;
template <typename V> static no& Check(SFINAE<WrapObject, &V::WrapObject>*);
template <typename V> static yes& Check(...);
HAS_MEMBER_TYPEDEFS;
HAS_MEMBER(get, value);
};
template<class T>
struct IsRefcounted
{
HAS_MEMBER_TYPEDEFS;
HAS_MEMBER(AddRef, HasAddref);
HAS_MEMBER(Release, HasRelease);
public:
static bool const Value = HasWrapObjectMember<T>::Value &&
sizeof(Check<T>(nullptr)) == sizeof(yes);
static bool const value = HasAddref && HasRelease;
private:
// This struct only works if T is fully declared (not just forward declared).
// The IsBaseOf check will ensure that, we don't really need it for any other
// reason (the static assert will of course always be true).
static_assert(!IsBaseOf<nsISupports, T>::value || IsRefcounted::value,
"Classes derived from nsISupports are refcounted!");
};
#undef HAS_MEMBER
#undef HAS_MEMBER_CHECK
#undef HAS_MEMBER_TYPEDEFS
#ifdef DEBUG
template <class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
struct
@ -976,6 +999,7 @@ WrapNewBindingNonWrapperCachedObject(JSContext* cx,
T* value,
JS::MutableHandle<JS::Value> rval)
{
static_assert(IsRefcounted<T>::value, "Don't pass owned classes in here.");
MOZ_ASSERT(value);
// We try to wrap in the compartment of the underlying object of "scope"
JS::Rooted<JSObject*> obj(cx);
@ -995,11 +1019,9 @@ WrapNewBindingNonWrapperCachedObject(JSContext* cx,
}
MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
obj = value->WrapObject(cx);
}
if (!obj) {
return false;
if (!value->WrapObject(cx, &obj)) {
return false;
}
}
// We can end up here in all sorts of compartments, per above. Make
@ -1014,11 +1036,12 @@ WrapNewBindingNonWrapperCachedObject(JSContext* cx,
// is true if the JSObject took ownership
template <class T>
inline bool
WrapNewBindingNonWrapperCachedOwnedObject(JSContext* cx,
JS::Handle<JSObject*> scopeArg,
nsAutoPtr<T>& value,
JS::MutableHandle<JS::Value> rval)
WrapNewBindingNonWrapperCachedObject(JSContext* cx,
JS::Handle<JSObject*> scopeArg,
nsAutoPtr<T>& value,
JS::MutableHandle<JS::Value> rval)
{
static_assert(!IsRefcounted<T>::value, "Only pass owned classes in here.");
// We do a runtime check on value, because otherwise we might in
// fact end up wrapping a null and invoking methods on it later.
if (!value) {
@ -1041,17 +1064,12 @@ WrapNewBindingNonWrapperCachedOwnedObject(JSContext* cx,
ac.emplace(cx, scope);
}
bool tookOwnership = false;
MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
obj = value->WrapObject(cx, &tookOwnership);
MOZ_ASSERT_IF(obj, tookOwnership);
if (tookOwnership) {
value.forget();
if (!value->WrapObject(cx, &obj)) {
return false;
}
}
if (!obj) {
return false;
value.forget();
}
// We can end up here in all sorts of compartments, per above. Make
@ -1060,8 +1078,9 @@ WrapNewBindingNonWrapperCachedOwnedObject(JSContext* cx,
return JS_WrapValue(cx, rval);
}
// Helper for smart pointers (nsAutoPtr/nsRefPtr/nsCOMPtr).
template <template <typename> class SmartPtr, typename T>
// Helper for smart pointers (nsRefPtr/nsCOMPtr).
template <template <typename> class SmartPtr, typename T,
typename U=typename EnableIf<IsRefcounted<T>::value, T>::Type>
inline bool
WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
const SmartPtr<T>& value,
@ -1100,9 +1119,8 @@ HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
// Helper for calling HandleNewBindingWrappingFailure with smart pointers
// (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
HAS_MEMBER(get)
template <class T, bool isSmartPtr=HasgetMember<T>::Value>
template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
struct HandleNewBindingWrappingFailureHelper
{
static inline bool Wrap(JSContext* cx, JS::Handle<JSObject*> scope,
@ -1467,7 +1485,7 @@ struct WrapNativeParentFallback<T, true >
// Wrapping of our native parent, for cases when it's a WebIDL object (though
// possibly preffed off).
template<typename T, bool hasWrapObject=HasWrapObject<T>::Value >
template<typename T, bool hasWrapObject=NativeHasMember<T>::WrapObject>
struct WrapNativeParentHelper
{
static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
@ -1493,7 +1511,7 @@ struct WrapNativeParentHelper
// Wrapping of our native parent, for cases when it's not a WebIDL object. In
// this case it must be nsISupports.
template<typename T>
struct WrapNativeParentHelper<T, false >
struct WrapNativeParentHelper<T, false>
{
static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
{
@ -1551,9 +1569,7 @@ WrapNativeParent(JSContext* cx, const T& p)
return WrapNativeParent(cx, GetParentPointer(p), GetWrapperCache(p), GetUseXBLScope(p));
}
HAS_MEMBER(GetParentObject)
template<typename T, bool WrapperCached=HasGetParentObjectMember<T>::Value>
template<typename T, bool WrapperCached=NativeHasMember<T>::GetParentObject>
struct GetParentObject
{
static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
@ -1632,7 +1648,7 @@ WrapCallThisObject<JS::Rooted<JSObject*>>(JSContext* cx,
// Helper for calling GetOrCreateDOMReflector with smart pointers
// (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
template <class T, bool isSmartPtr=HasgetMember<T>::Value>
template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
struct GetOrCreateDOMReflectorHelper
{
static inline bool GetOrCreate(JSContext* cx, const T& value,
@ -1648,6 +1664,7 @@ struct GetOrCreateDOMReflectorHelper<T, false>
static inline bool GetOrCreate(JSContext* cx, T& value,
JS::MutableHandle<JS::Value> rval)
{
static_assert(IsRefcounted<T>::value, "Don't pass owned classes in here.");
return GetOrCreateDOMReflector(cx, &value, rval);
}
};
@ -1673,7 +1690,7 @@ GetOrCreateDOMReflector(JSContext* cx, JS::Handle<JSObject*> scope, T& value,
// Helper for calling GetOrCreateDOMReflectorNoWrap with smart pointers
// (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
template <class T, bool isSmartPtr=HasgetMember<T>::Value>
template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
struct GetOrCreateDOMReflectorNoWrapHelper
{
static inline bool GetOrCreate(JSContext* cx, const T& value,
@ -1712,7 +1729,7 @@ GetCallbackFromCallbackObject(T* aObj)
// Helper for getting the callback JSObject* of a smart ptr around a
// CallbackObject or a reference to a CallbackObject or something like
// that.
template <class T, bool isSmartPtr=HasgetMember<T>::Value>
template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
struct GetCallbackFromCallbackObjectHelper
{
static inline JSObject* Get(const T& aObj)
@ -2503,30 +2520,7 @@ HasConstructor(JSObject* obj)
}
#endif
// Transfer reference in ptr to smartPtr.
template<class T>
inline void
Take(nsRefPtr<T>& smartPtr, T* ptr)
{
smartPtr = dont_AddRef(ptr);
}
// Transfer ownership of ptr to smartPtr.
template<class T>
inline void
Take(nsAutoPtr<T>& smartPtr, T* ptr)
{
smartPtr = ptr;
}
inline void
MustInheritFromNonRefcountedDOMObject(NonRefcountedDOMObject*)
{
}
HAS_MEMBER(JSBindingFinalized)
template<class T, bool hasCallback=HasJSBindingFinalizedMember<T>::Value>
template<class T, bool hasCallback=NativeHasMember<T>::JSBindingFinalized>
struct JSBindingFinalized
{
static void Finalized(T* self)
@ -2753,11 +2747,119 @@ ToSupportsIsOnPrimaryInheritanceChain(T* aObject, nsWrapperCache* aCache)
aCache);
}
template<class T, template <typename> class SmartPtr,
// The BindingJSObjectCreator class is supposed to be used by a caller that
// wants to create and initialise a binding JSObject. After initialisation has
// been successfully completed it should call ForgetObject().
// The BindingJSObjectCreator object will root the JSObject until ForgetObject()
// is called on it. If the native object for the binding is refcounted it will
// also hold a strong reference to it, that reference is transferred to the
// JSObject (which holds the native in a slot) when ForgetObject() is called. If
// the BindingJSObjectCreator object is destroyed and ForgetObject() was never
// called on it then the JSObject's slot holding the native will be set to
// undefined, and for a refcounted native the strong reference will be released.
template<class T>
class MOZ_STACK_CLASS BindingJSObjectCreator
{
public:
explicit BindingJSObjectCreator(JSContext* aCx)
: mReflector(aCx)
{
}
~BindingJSObjectCreator()
{
if (mReflector) {
js::SetReservedOrProxyPrivateSlot(mReflector, DOM_OBJECT_SLOT,
JS::UndefinedValue());
}
}
void
CreateProxyObject(JSContext* aCx, const js::Class* aClass,
const DOMProxyHandler* aHandler,
JS::Handle<JSObject*> aProto,
JS::Handle<JSObject*> aParent, T* aNative,
JS::MutableHandle<JSObject*> aReflector)
{
js::ProxyOptions options;
options.setClass(aClass);
JS::Rooted<JS::Value> proxyPrivateVal(aCx, JS::PrivateValue(aNative));
aReflector.set(js::NewProxyObject(aCx, aHandler, proxyPrivateVal, aProto,
aParent, options));
if (aReflector) {
mNative = aNative;
mReflector = aReflector;
}
}
void
CreateObject(JSContext* aCx, const JSClass* aClass,
JS::Handle<JSObject*> aProto, JS::Handle<JSObject*> aParent,
T* aNative, JS::MutableHandle<JSObject*> aReflector)
{
aReflector.set(JS_NewObject(aCx, aClass, aProto, aParent));
if (aReflector) {
js::SetReservedSlot(aReflector, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
mNative = aNative;
mReflector = aReflector;
}
}
void
InitializationSucceeded()
{
void* dummy;
mNative.forget(&dummy);
mReflector = nullptr;
}
private:
struct OwnedNative
{
// Make sure the native objects inherit from NonRefcountedDOMObject so
// that we log their ctor and dtor.
static_assert(IsBaseOf<NonRefcountedDOMObject, T>::value,
"Non-refcounted objects with DOM bindings should inherit "
"from NonRefcountedDOMObject.");
OwnedNative&
operator=(T* aNative)
{
return *this;
}
// This signature sucks, but it's the only one that will make a nsRefPtr
// just forget about its pointer without warning.
void
forget(void**)
{
}
};
JS::Rooted<JSObject*> mReflector;
typename Conditional<IsRefcounted<T>::value, nsRefPtr<T>, OwnedNative>::Type mNative;
};
template<class T,
bool isISupports=IsBaseOf<nsISupports, T>::value>
class DeferredFinalizer
{
typedef nsTArray<SmartPtr<T> > SmartPtrArray;
typedef typename Conditional<IsRefcounted<T>::value,
nsRefPtr<T>, nsAutoPtr<T>>::Type SmartPtr;
typedef nsTArray<SmartPtr> SmartPtrArray;
template<class U>
static inline void
AppendAndTake(nsTArray<nsRefPtr<U>>& smartPtrArray, U* ptr)
{
smartPtrArray.AppendElement(dont_AddRef(ptr));
}
template<class U>
static inline void
AppendAndTake(nsTArray<nsAutoPtr<U>>& smartPtrArray, U* ptr)
{
smartPtrArray.AppendElement(ptr);
}
static void*
AppendDeferredFinalizePointer(void* aData, void* aObject)
@ -2766,11 +2868,7 @@ class DeferredFinalizer
if (!pointers) {
pointers = new SmartPtrArray();
}
T* self = static_cast<T*>(aObject);
SmartPtr<T>* defer = pointers->AppendElement();
Take(*defer, self);
AppendAndTake(*pointers, static_cast<T*>(aObject));
return pointers;
}
static bool
@ -2800,8 +2898,8 @@ public:
}
};
template<class T, template <typename> class SmartPtr>
class DeferredFinalizer<T, SmartPtr, true>
template<class T>
class DeferredFinalizer<T, true>
{
public:
static void
@ -2811,11 +2909,11 @@ public:
}
};
template<class T, template <typename> class SmartPtr>
template<class T>
static void
AddForDeferredFinalization(T* aObject)
{
DeferredFinalizer<T, SmartPtr>::AddForDeferredFinalization(aObject);
DeferredFinalizer<T>::AddForDeferredFinalization(aObject);
}
// This returns T's CC participant if it participates in CC or null if it
@ -3109,17 +3207,26 @@ StrongOrRawPtr(already_AddRefed<S>&& aPtr)
return aPtr.template downcast<T>();
}
template<class T>
inline T*
template<class T,
class ReturnType=typename Conditional<IsRefcounted<T>::value, T*,
nsAutoPtr<T>>::Type>
inline ReturnType
StrongOrRawPtr(T* aPtr)
{
return aPtr;
return ReturnType(aPtr);
}
template<class T, template<typename> class SmartPtr, class S>
inline void
StrongOrRawPtr(SmartPtr<S>&& aPtr) = delete;
template<class T>
struct StrongPtrForMember
{
typedef typename Conditional<IsRefcounted<T>::value,
nsRefPtr<T>, nsAutoPtr<T>>::Type Type;
};
inline
JSObject*
GetErrorPrototype(JSContext* aCx, JS::Handle<JSObject*> aForObj)

View File

@ -44,22 +44,6 @@
# Always true for worker descriptors for non-callback
# interfaces. Defaults to true for non-worker non-callback
# descriptors.
# * nativeOwnership: Describes how the native object is held. 3 possible
# types: worker object ('worker'), non-refcounted object
# ('owned'), refcounted object ('refcounted').
# Non-refcounted objects need to inherit from
# mozilla::dom::NonRefcountedDOMObject and preferably use
# MOZ_COUNT_CTOR/MOZ_COUNT_DTOR in their
# constructor/destructor so they participate in leak
# logging.
# This mostly determines how the finalizer releases the
# binding's hold on the native object. For a worker object
# it'll call Release, for a non-refcounted object it'll
# call delete through XPConnect's deferred finalization
# mechanism, for a refcounted object it'll call Release
# through XPConnect's deferred finalization mechanism.
# 'worker' opts into old style worker models. Defaults to
# 'refcounted'.
#
# The following fields are either a string, an array (defaults to an empty
# array) or a dictionary with three possible keys (all, getterOnly and
@ -1227,15 +1211,15 @@ DOMInterfaces = {
},
'TextDecoder': {
'nativeOwnership': 'owned',
'wrapperCache': False
},
'TextEncoder': {
'nativeOwnership': 'owned',
'wrapperCache': False
},
'TextMetrics': {
'nativeOwnership': 'owned',
'wrapperCache': False
},
'TimeRanges': {
@ -1271,8 +1255,13 @@ DOMInterfaces = {
'wrapperCache': False,
}],
'VRFieldOfView': {
'wrapperCache': False,
},
'VRFieldOfViewReadOnly': {
'concrete': False
'concrete': False,
'wrapperCache': False,
},
'VRDevice': {
@ -1589,7 +1578,6 @@ DOMInterfaces = {
'XPathExpression': {
'wrapperCache': False,
'nativeOwnership': 'owned',
},
'XSLTProcessor': {

View File

@ -1565,14 +1565,6 @@ class CGAddPropertyHook(CGAbstractClassHook):
""")
def DeferredFinalizeSmartPtr(descriptor):
if descriptor.nativeOwnership == 'owned':
smartPtr = 'nsAutoPtr'
else:
smartPtr = 'nsRefPtr'
return smartPtr
def finalizeHook(descriptor, hookName, freeOp):
finalize = "JSBindingFinalized<%s>::Finalized(self);\n" % descriptor.nativeType
if descriptor.wrapperCache:
@ -1581,8 +1573,8 @@ def finalizeHook(descriptor, hookName, freeOp):
finalize += "self->mExpandoAndGeneration.expando = JS::UndefinedValue();\n"
if descriptor.isGlobal():
finalize += "mozilla::dom::FinalizeGlobal(CastToJSFreeOp(%s), obj);\n" % freeOp
finalize += ("AddForDeferredFinalization<%s, %s >(self);\n" %
(descriptor.nativeType, DeferredFinalizeSmartPtr(descriptor)))
finalize += ("AddForDeferredFinalization<%s>(self);\n" %
descriptor.nativeType)
return CGIfWrapper(CGGeneric(finalize), "self")
@ -3065,50 +3057,35 @@ class CGConstructorEnabled(CGAbstractMethod):
def CreateBindingJSObject(descriptor, properties):
objDecl = "BindingJSObjectCreator<%s> creator(aCx);\n" % descriptor.nativeType
# We don't always need to root obj, but there are a variety
# of cases where we do, so for simplicity, just always root it.
objDecl = "JS::Rooted<JSObject*> obj(aCx);\n"
if descriptor.proxy:
create = dedent(
"""
JS::Rooted<JS::Value> proxyPrivateVal(aCx, JS::PrivateValue(aObject));
js::ProxyOptions options;
options.setClass(&Class.mBase);
obj = NewProxyObject(aCx, DOMProxyHandler::getInstance(),
proxyPrivateVal, proto, global, options);
if (!obj) {
return nullptr;
creator.CreateProxyObject(aCx, &Class.mBase, DOMProxyHandler::getInstance(),
proto, global, aObject, aReflector);
if (!aReflector) {
return false;
}
""")
if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
create += dedent("""
js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO,
js::SetProxyExtra(aReflector, JSPROXYSLOT_EXPANDO,
JS::PrivateValue(&aObject->mExpandoAndGeneration));
""")
else:
create = dedent(
"""
obj = JS_NewObject(aCx, Class.ToJSClass(), proto, global);
if (!obj) {
return nullptr;
creator.CreateObject(aCx, Class.ToJSClass(), proto, global, aObject, aReflector);
if (!aReflector) {
return false;
}
js::SetReservedSlot(obj, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
""")
create = objDecl + create
if descriptor.nativeOwnership == 'refcounted':
create += "NS_ADDREF(aObject);\n"
else:
create += dedent("""
// Make sure the native objects inherit from NonRefcountedDOMObject so that we
// log their ctor and dtor.
MustInheritFromNonRefcountedDOMObject(aObject);
*aTookOwnership = true;
""")
return create
return objDecl + create
def InitUnforgeablePropertiesOnObject(descriptor, obj, properties, failureReturnValue=""):
@ -3181,7 +3158,7 @@ def InitUnforgeableProperties(descriptor, properties):
"// by the interface prototype object.\n")
else:
unforgeableProperties = CGWrapper(
InitUnforgeablePropertiesOnObject(descriptor, "obj", properties, "nullptr"),
InitUnforgeablePropertiesOnObject(descriptor, "aReflector", properties, "false"),
pre=(
"// Important: do unforgeable property setup after we have handed\n"
"// over ownership of the C++ object to obj as needed, so that if\n"
@ -3219,9 +3196,9 @@ def InitMemberSlots(descriptor, wrapperCache):
clearWrapper = " aCache->ClearWrapper();\n"
else:
clearWrapper = ""
return ("if (!UpdateMemberSlots(aCx, obj, aObject)) {\n"
return ("if (!UpdateMemberSlots(aCx, aReflector, aObject)) {\n"
"%s"
" return nullptr;\n"
" return false;\n"
"}\n" % clearWrapper)
@ -3235,8 +3212,9 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
assert descriptor.interface.hasInterfacePrototypeObject()
args = [Argument('JSContext*', 'aCx'),
Argument(descriptor.nativeType + '*', 'aObject'),
Argument('nsWrapperCache*', 'aCache')]
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
Argument('nsWrapperCache*', 'aCache'),
Argument('JS::MutableHandle<JSObject*>', 'aReflector')]
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'bool', args)
self.properties = properties
def definition_body(self):
@ -3249,33 +3227,31 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
JS::Rooted<JSObject*> parent(aCx, WrapNativeParent(aCx, aObject->GetParentObject()));
if (!parent) {
return nullptr;
return false;
}
// That might have ended up wrapping us already, due to the wonders
// of XBL. Check for that, and bail out as needed. Scope so we don't
// collide with the "obj" we declare in CreateBindingJSObject.
{
JSObject* obj = aCache->GetWrapper();
if (obj) {
return obj;
}
// of XBL. Check for that, and bail out as needed.
aReflector.set(aCache->GetWrapper());
if (aReflector) {
return true;
}
JSAutoCompartment ac(aCx, parent);
JS::Rooted<JSObject*> global(aCx, js::GetGlobalForObjectCrossCompartment(parent));
JS::Handle<JSObject*> proto = GetProtoObjectHandle(aCx, global);
if (!proto) {
return nullptr;
return false;
}
$*{createObject}
$*{unforgeable}
aCache->SetWrapper(obj);
aCache->SetWrapper(aReflector);
$*{slots}
return obj;
creator.InitializationSucceeded();
return true;
""",
assertion=AssertInheritanceChain(self.descriptor),
createObject=CreateBindingJSObject(self.descriptor, self.properties),
@ -3293,7 +3269,10 @@ class CGWrapMethod(CGAbstractMethod):
inline=True, templateArgs=["class T"])
def definition_body(self):
return "return Wrap(aCx, aObject, aObject);\n"
return dedent("""
JS::Rooted<JSObject*> reflector(aCx);
return Wrap(aCx, aObject, aObject, &reflector) ? reflector.get() : nullptr;
""")
class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
@ -3307,10 +3286,9 @@ class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
# XXX can we wrap if we don't have an interface prototype object?
assert descriptor.interface.hasInterfacePrototypeObject()
args = [Argument('JSContext*', 'aCx'),
Argument(descriptor.nativeType + '*', 'aObject')]
if descriptor.nativeOwnership == 'owned':
args.append(Argument('bool*', 'aTookOwnership'))
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
Argument(descriptor.nativeType + '*', 'aObject'),
Argument('JS::MutableHandle<JSObject*>', 'aReflector')]
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'bool', args)
self.properties = properties
def definition_body(self):
@ -3321,7 +3299,7 @@ class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
JS::Handle<JSObject*> proto = GetProtoObjectHandle(aCx, global);
if (!proto) {
return nullptr;
return false;
}
$*{createObject}
@ -3329,7 +3307,8 @@ class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
$*{unforgeable}
$*{slots}
return obj;
creator.InitializationSucceeded();
return true;
""",
assertions=AssertInheritanceChain(self.descriptor),
createObject=CreateBindingJSObject(self.descriptor, self.properties),
@ -3351,8 +3330,9 @@ class CGWrapGlobalMethod(CGAbstractMethod):
Argument('nsWrapperCache*', 'aCache'),
Argument('JS::CompartmentOptions&', 'aOptions'),
Argument('JSPrincipals*', 'aPrincipal'),
Argument('bool', 'aInitStandardClasses')]
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
Argument('bool', 'aInitStandardClasses'),
Argument('JS::MutableHandle<JSObject*>', 'aReflector')]
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'bool', args)
self.descriptor = descriptor
self.properties = properties
@ -3368,7 +3348,7 @@ class CGWrapGlobalMethod(CGAbstractMethod):
if self.descriptor.workers:
fireOnNewGlobal = """// XXXkhuey can't do this yet until workers can lazy resolve.
// JS_FireOnNewGlobalObject(aCx, obj);
// JS_FireOnNewGlobalObject(aCx, aReflector);
"""
else:
fireOnNewGlobal = ""
@ -3379,7 +3359,6 @@ class CGWrapGlobalMethod(CGAbstractMethod):
MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
"nsISupports must be on our primary inheritance chain");
JS::Rooted<JSObject*> obj(aCx);
CreateGlobal<${nativeType}, GetProtoObjectHandle>(aCx,
aObject,
aCache,
@ -3387,24 +3366,24 @@ class CGWrapGlobalMethod(CGAbstractMethod):
aOptions,
aPrincipal,
aInitStandardClasses,
&obj);
if (!obj) {
return nullptr;
aReflector);
if (!aReflector) {
return false;
}
// obj is a new global, so has a new compartment. Enter it
// aReflector is a new global, so has a new compartment. Enter it
// before doing anything with it.
JSAutoCompartment ac(aCx, obj);
JSAutoCompartment ac(aCx, aReflector);
if (!DefineProperties(aCx, obj, ${properties}, ${chromeProperties})) {
return nullptr;
if (!DefineProperties(aCx, aReflector, ${properties}, ${chromeProperties})) {
return false;
}
$*{unforgeable}
$*{slots}
$*{fireOnNewGlobal}
return obj;
return true;
""",
assertions=AssertInheritanceChain(self.descriptor),
nativeType=self.descriptor.nativeType,
@ -4704,12 +4683,6 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
isMember or
isCallbackReturnValue)
if forceOwningType and descriptor.nativeOwnership == 'owned':
raise TypeError("Interface %s has 'owned' nativeOwnership, so we "
"don't know how to keep it alive in %s" %
(descriptor.interface.identifier.name,
sourceDescription))
typeName = descriptor.nativeType
typePtr = typeName + "*"
@ -4733,6 +4706,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
declType = "NonNull<" + typeName + ">"
templateBody = ""
if forceOwningType:
templateBody += 'static_assert(IsRefcounted<%s>::value, "We can only store refcounted classes.");' % typeName
if not descriptor.skipGen and not descriptor.interface.isConsequential() and not descriptor.interface.isExternal():
if failureCode is not None:
templateBody += str(CastableObjectUnwrapper(
@ -5769,15 +5744,11 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
if not descriptor.interface.isExternal() and not descriptor.skipGen:
if descriptor.wrapperCache:
assert descriptor.nativeOwnership != 'owned'
wrapMethod = "GetOrCreateDOMReflector"
else:
if not returnsNewObject:
raise MethodNotNewObjectError(descriptor.interface.identifier.name)
if descriptor.nativeOwnership == 'owned':
wrapMethod = "WrapNewBindingNonWrapperCachedOwnedObject"
else:
wrapMethod = "WrapNewBindingNonWrapperCachedObject"
wrapMethod = "WrapNewBindingNonWrapperCachedObject"
wrap = "%s(cx, ${obj}, %s, ${jsvalHandle})" % (wrapMethod, result)
if not descriptor.hasXPConnectImpls:
# Can only fail to wrap as a new-binding object
@ -6098,11 +6069,8 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
result = CGGeneric(descriptorProvider.getDescriptor(
returnType.unroll().inner.identifier.name).nativeType)
conversion = None
if descriptorProvider.getDescriptor(
returnType.unroll().inner.identifier.name).nativeOwnership == 'owned':
result = CGTemplatedType("nsAutoPtr", result)
elif isMember:
result = CGTemplatedType("nsRefPtr", result)
if isMember:
result = CGGeneric("StrongPtrForMember<%s>::Type" % result.define())
else:
conversion = CGGeneric("StrongOrRawPtr<%s>" % result.define())
result = CGGeneric("auto")
@ -6693,8 +6661,7 @@ class CGPerSignatureCall(CGThing):
returnsNewObject = memberReturnsNewObject(self.idlNode)
if (returnsNewObject and
self.returnType.isGeckoInterface() and
not self.descriptor.getDescriptor(self.returnType.unroll().inner.identifier.name).nativeOwnership == 'owned'):
self.returnType.isGeckoInterface()):
wrapCode += dedent(
"""
static_assert(!IsPointer<decltype(result)>::value,
@ -10994,16 +10961,17 @@ class CGDescriptor(CGThing):
assert not descriptor.concrete or descriptor.interface.hasInterfacePrototypeObject()
if descriptor.nativeOwnership == 'owned' and (
descriptor.interface.hasChildInterfaces() or
descriptor.interface.parent):
raise TypeError("Owned interface cannot have a parent or children")
self._deps = descriptor.interface.getDeps()
cgThings = []
cgThings.append(CGGeneric(declare="typedef %s NativeType;\n" %
descriptor.nativeType))
parent = descriptor.interface.parent
if parent:
cgThings.append(CGGeneric("static_assert(IsRefcounted<NativeType>::value == IsRefcounted<%s::NativeType>::value,\n"
" \"Can't inherit from an interface with a different ownership model.\");\n" %
toBindingNamespace(descriptor.parentPrototypeName)))
# These are set to true if at least one non-static
# method/getter/setter or jsonifier exist on the interface.
(hasMethod, hasGetter, hasLenientGetter, hasSetter, hasLenientSetter,
@ -12213,7 +12181,10 @@ class CGBindingRoot(CGThing):
declare or define to generate header or cpp code (respectively).
"""
def __init__(self, config, prefix, webIDLFile):
bindingHeaders = {}
bindingHeaders = dict.fromkeys((
'mozilla/dom/NonRefcountedDOMObject.h',
),
True)
bindingDeclareHeaders = dict.fromkeys((
'mozilla/dom/BindingDeclarations.h',
'mozilla/dom/Nullable.h',
@ -12255,8 +12226,6 @@ class CGBindingRoot(CGThing):
bindingHeaders["mozilla/Preferences.h"] = any(
descriptorRequiresPreferences(d) for d in descriptors)
bindingHeaders["mozilla/dom/NonRefcountedDOMObject.h"] = any(
d.nativeOwnership == 'owned' for d in descriptors)
bindingHeaders["mozilla/dom/DOMJSProxyHandler.h"] = any(
d.concrete and d.proxy for d in descriptors)
@ -13066,40 +13035,30 @@ class CGExampleClass(CGBindingImplClass):
CGExampleMethod, CGExampleGetter, CGExampleSetter,
wantGetParent=descriptor.wrapperCache)
self.refcounted = descriptor.nativeOwnership == "refcounted"
self.parentIface = descriptor.interface.parent
if self.parentIface:
self.parentDesc = descriptor.getDescriptor(
self.parentIface.identifier.name)
bases = [ClassBase(self.nativeLeafName(self.parentDesc))]
else:
bases = []
if self.refcounted:
bases.append(ClassBase("nsISupports /* Change nativeOwnership in the binding configuration if you don't want this */"))
if descriptor.wrapperCache:
bases.append(ClassBase("nsWrapperCache /* Change wrapperCache in the binding configuration if you don't want this */"))
else:
bases.append(ClassBase("NonRefcountedDOMObject"))
bases = [ ClassBase("nsISupports /* or NonRefcountedDOMObject if this is a non-refcounted object */") ]
if descriptor.wrapperCache:
bases.append(ClassBase("nsWrapperCache /* Change wrapperCache in the binding configuration if you don't want this */"))
if self.refcounted:
destructorVisibility = "protected"
if self.parentIface:
extradeclarations = (
"public:\n"
" NS_DECL_ISUPPORTS_INHERITED\n"
" NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(%s, %s)\n"
"\n" % (self.nativeLeafName(descriptor),
self.nativeLeafName(self.parentDesc)))
else:
extradeclarations = (
"public:\n"
" NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n"
" NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(%s)\n"
"\n" % self.nativeLeafName(descriptor))
destructorVisibility = "protected"
if self.parentIface:
extradeclarations = (
"public:\n"
" NS_DECL_ISUPPORTS_INHERITED\n"
" NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(%s, %s)\n"
"\n" % (self.nativeLeafName(descriptor),
self.nativeLeafName(self.parentDesc)))
else:
destructorVisibility = "public"
extradeclarations = ""
extradeclarations = (
"public:\n"
" NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n"
" NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(%s)\n"
"\n" % self.nativeLeafName(descriptor))
if descriptor.interface.hasChildInterfaces():
decorators = ""
@ -13117,55 +13076,43 @@ class CGExampleClass(CGBindingImplClass):
def define(self):
# Just override CGClass and do our own thing
if self.refcounted:
ctordtor = dedent("""
${nativeType}::${nativeType}()
{
}
ctordtor = dedent("""
${nativeType}::${nativeType}()
{
// Add |MOZ_COUNT_CTOR(${nativeType});| for a non-refcounted object.
}
${nativeType}::~${nativeType}()
{
// Add |MOZ_COUNT_DTOR(${nativeType});| for a non-refcounted object.
}
""")
if self.parentIface:
ccImpl = dedent("""
// Only needed for refcounted objects.
NS_IMPL_CYCLE_COLLECTION_INHERITED_0(${nativeType}, ${parentType})
NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
NS_INTERFACE_MAP_END_INHERITING(${parentType})
${nativeType}::~${nativeType}()
{
}
""")
else:
ctordtor = dedent("""
${nativeType}::${nativeType}()
{
MOZ_COUNT_CTOR(${nativeType});
}
ccImpl = dedent("""
// Only needed for refcounted objects.
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(${nativeType})
NS_IMPL_CYCLE_COLLECTING_ADDREF(${nativeType})
NS_IMPL_CYCLE_COLLECTING_RELEASE(${nativeType})
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
${nativeType}::~${nativeType}()
{
MOZ_COUNT_DTOR(${nativeType});
}
""")
if self.refcounted:
if self.parentIface:
ccImpl = dedent("""
NS_IMPL_CYCLE_COLLECTION_INHERITED_0(${nativeType}, ${parentType})
NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
NS_INTERFACE_MAP_END_INHERITING(${parentType})
""")
else:
ccImpl = dedent("""
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(${nativeType})
NS_IMPL_CYCLE_COLLECTING_ADDREF(${nativeType})
NS_IMPL_CYCLE_COLLECTING_RELEASE(${nativeType})
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
""")
else:
ccImpl = ""
classImpl = ccImpl + ctordtor + "\n" + dedent("""
JSObject*
${nativeType}::WrapObject(JSContext* aCx)

View File

@ -468,16 +468,10 @@ class Descriptor(DescriptorProvider):
iface.setUserData('hasProxyDescendant', True)
iface = iface.parent
self.nativeOwnership = desc.get('nativeOwnership', 'refcounted')
if not self.nativeOwnership in ('owned', 'refcounted'):
raise TypeError("Descriptor for %s has unrecognized value (%s) "
"for nativeOwnership" %
(self.interface.identifier.name, self.nativeOwnership))
if desc.get('wantsQI', None) != None:
self._wantsQI = desc.get('wantsQI', None)
self.wrapperCache = (not self.interface.isCallback() and
(self.nativeOwnership != 'owned' and
desc.get('wrapperCache', True)))
desc.get('wrapperCache', True))
def make_name(name):
return name + "_workers" if self.workers else name

View File

@ -12,12 +12,12 @@
namespace mozilla {
namespace dom {
// Natives for DOM classes with 'owned' as the value for nativeOwnership in
// Bindings.conf need to inherit from this class.
// Natives for DOM classes that aren't refcounted need to inherit from this
// class.
// If you're seeing objects of this class leak then natives for one of the DOM
// classes with 'owned' as the value for nativeOwnership in Bindings.conf is
// leaking. If the native for that class has MOZ_COUNT_CTOR/DTOR in its
// constructor/destructor then it should show up in the leak log too.
// classes inheriting from it is leaking. If the native for that class has
// MOZ_COUNT_CTOR/DTOR in its constructor/destructor then it should show up in
// the leak log too.
class NonRefcountedDOMObject
{
protected:

View File

@ -32,7 +32,9 @@ ReadStructuredCloneImageData(JSContext* aCx, JSStructuredCloneReader* aReader)
nsRefPtr<ImageData> imageData = new ImageData(width, height,
dataArray.toObject());
// Wrap it in a JS::Value.
result = imageData->WrapObject(aCx);
if (!imageData->WrapObject(aCx, &result)) {
return nullptr;
}
}
return result;
}

View File

@ -90,7 +90,7 @@ class TestNonWrapperCacheInterface : public nsISupports
public:
NS_DECL_ISUPPORTS
virtual JSObject* WrapObject(JSContext* cx);
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
};
class OnlyForUseInConstructor : public nsISupports,

View File

@ -108,10 +108,10 @@ ImageData::DropData()
}
}
JSObject*
ImageData::WrapObject(JSContext* cx)
bool
ImageData::WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector)
{
return ImageDataBinding::Wrap(cx, this);
return ImageDataBinding::Wrap(aCx, this, aReflector);
}
} // namespace dom

View File

@ -73,7 +73,7 @@ public:
return mData;
}
JSObject* WrapObject(JSContext* cx);
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
private:
void HoldData();

View File

@ -30,9 +30,9 @@ public:
return width;
}
JSObject* WrapObject(JSContext* aCx, bool* aTookOwnership)
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector)
{
return TextMetricsBinding::Wrap(aCx, this, aTookOwnership);
return TextMetricsBinding::Wrap(aCx, this, aReflector);
}
private:

View File

@ -11,10 +11,11 @@
namespace mozilla {
JSObject*
WebGLActiveInfo::WrapObject(JSContext* cx)
bool
WebGLActiveInfo::WrapObject(JSContext* aCx,
JS::MutableHandle<JSObject*> aReflector)
{
return dom::WebGLActiveInfoBinding::Wrap(cx, this);
return dom::WebGLActiveInfoBinding::Wrap(aCx, this, aReflector);
}
} // namespace mozilla

View File

@ -35,7 +35,7 @@ public:
retval = mName;
}
JSObject* WrapObject(JSContext* cx);
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
NS_INLINE_DECL_REFCOUNTING(WebGLActiveInfo)

View File

@ -10,10 +10,11 @@
namespace mozilla {
JSObject*
WebGLShaderPrecisionFormat::WrapObject(JSContext* cx)
bool
WebGLShaderPrecisionFormat::WrapObject(JSContext* aCx,
JS::MutableHandle<JSObject*> aReflector)
{
return dom::WebGLShaderPrecisionFormatBinding::Wrap(cx, this);
return dom::WebGLShaderPrecisionFormatBinding::Wrap(aCx, this, aReflector);
}
} // namespace mozilla

View File

@ -24,7 +24,7 @@ public:
, mPrecision(precision)
{ }
JSObject* WrapObject(JSContext* cx);
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
// WebIDL WebGLShaderPrecisionFormat API
GLint RangeMin() const {

View File

@ -12,10 +12,11 @@
namespace mozilla {
JSObject*
WebGLUniformLocation::WrapObject(JSContext* cx)
bool
WebGLUniformLocation::WrapObject(JSContext* aCx,
JS::MutableHandle<JSObject*> aReflector)
{
return dom::WebGLUniformLocationBinding::Wrap(cx, this);
return dom::WebGLUniformLocationBinding::Wrap(aCx, this, aReflector);
}
WebGLUniformLocation::WebGLUniformLocation(WebGLContext* context,

View File

@ -31,7 +31,7 @@ public:
uint32_t ProgramGeneration() const { return mProgramGeneration; }
int ElementSize() const { return mElementSize; }
JSObject* WrapObject(JSContext* cx);
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLUniformLocation)
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(WebGLUniformLocation)

View File

@ -29,10 +29,11 @@ DataStoreCursor::Constructor(GlobalObject& aGlobal, ErrorResult& aRv)
return cursor.forget();
}
JSObject*
DataStoreCursor::WrapObject(JSContext* aCx)
bool
DataStoreCursor::WrapObject(JSContext* aCx,
JS::MutableHandle<JSObject*> aReflector)
{
return DataStoreCursorBinding::Wrap(aCx, this);
return DataStoreCursorBinding::Wrap(aCx, this, aReflector);
}
already_AddRefed<DataStore>
@ -72,4 +73,4 @@ DataStoreCursor::SetDataStoreCursorImpl(DataStoreCursorImpl& aCursor)
}
} //namespace dom
} //namespace mozilla
} //namespace mozilla

View File

@ -33,7 +33,7 @@ public:
static already_AddRefed<DataStoreCursor> Constructor(GlobalObject& aGlobal,
ErrorResult& aRv);
JSObject* WrapObject(JSContext *aCx);
bool WrapObject(JSContext *aCx, JS::MutableHandle<JSObject*> aReflector);
// WebIDL (public APIs)
@ -56,4 +56,4 @@ private:
} //namespace dom
} //namespace mozilla
#endif
#endif

View File

@ -49,9 +49,9 @@ public:
MOZ_COUNT_DTOR(TextDecoder);
}
JSObject* WrapObject(JSContext* aCx, bool* aTookOwnership)
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector)
{
return TextDecoderBinding::Wrap(aCx, this, aTookOwnership);
return TextDecoderBinding::Wrap(aCx, this, aReflector);
}
/**

View File

@ -42,9 +42,9 @@ public:
~TextEncoder()
{}
JSObject* WrapObject(JSContext* aCx, bool* aTookOwnership)
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector)
{
return TextEncoderBinding::Wrap(aCx, this, aTookOwnership);
return TextEncoderBinding::Wrap(aCx, this, aReflector);
}
protected:

File diff suppressed because it is too large Load Diff

View File

@ -6,13 +6,20 @@
#ifndef mozilla_dom_Fetch_h
#define mozilla_dom_Fetch_h
#include "nsIInputStreamPump.h"
#include "nsIStreamLoader.h"
#include "nsCOMPtr.h"
#include "nsError.h"
#include "nsProxyRelease.h"
#include "nsString.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/RequestBinding.h"
#include "mozilla/dom/workers/bindings/WorkerFeature.h"
class nsIInputStream;
class nsIOutputStream;
class nsIGlobalObject;
namespace mozilla {
@ -53,6 +60,41 @@ ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrUSVStringOrU
nsIInputStream** aStream,
nsCString& aContentType);
template <class Derived> class FetchBodyFeature;
/*
* FetchBody's body consumption uses nsIInputStreamPump to read from the
* underlying stream to a block of memory, which is then adopted by
* ContinueConsumeBody() and converted to the right type based on the JS
* function called.
*
* Use of the nsIInputStreamPump complicates things on the worker thread.
* The solution used here is similar to WebSockets.
* The difference is that we are only interested in completion and not data
* events, and nsIInputStreamPump can only deliver completion on the main thread.
*
* Before starting the pump on the main thread, we addref the FetchBody to keep
* it alive. Then we add a feature, to track the status of the worker.
*
* ContinueConsumeBody() is the function that cleans things up in both success
* and error conditions and so all callers call it with the appropriate status.
*
* Once the read is initiated on the main thread there are two possibilities.
*
* 1) Pump finishes before worker has finished Running.
* In this case we adopt the data and dispatch a runnable to the worker,
* which derefs FetchBody and removes the feature and resolves the Promise.
*
* 2) Pump still working while worker has stopped Running.
* The feature is Notify()ed and ContinueConsumeBody() is called with
* NS_BINDING_ABORTED. We first Cancel() the pump using a sync runnable to
* ensure that mFetchBody remains alive (since mConsumeBodyPump is strongly
* held by it) until pump->Cancel() is called. OnStreamComplete() will not
* do anything if the error code is NS_BINDING_ABORTED, so we don't have to
* worry about keeping anything alive.
*
* The pump is always released on the main thread.
*/
template <class Derived>
class FetchBody {
public:
@ -83,9 +125,27 @@ public:
return ConsumeBody(CONSUME_TEXT, aRv);
}
// Utility public methods accessed by various runnables.
void
BeginConsumeBodyMainThread();
void
ContinueConsumeBody(nsresult aStatus, uint32_t aLength, uint8_t* aResult);
void
CancelPump();
// Always set whenever the FetchBody is created on the worker thread.
workers::WorkerPrivate* mWorkerPrivate;
// Set when consuming the body is attempted on a worker.
// Unset when consumption is done/aborted.
nsAutoPtr<workers::WorkerFeature> mFeature;
protected:
FetchBody()
: mBodyUsed(false)
FetchBody();
virtual ~FetchBody()
{
}
@ -97,7 +157,6 @@ protected:
void
SetMimeType(ErrorResult& aRv);
private:
enum ConsumeType
{
@ -114,11 +173,46 @@ private:
return static_cast<Derived*>(const_cast<FetchBody*>(this));
}
nsresult
BeginConsumeBody();
already_AddRefed<Promise>
ConsumeBody(ConsumeType aType, ErrorResult& aRv);
bool
AddRefObject();
void
ReleaseObject();
bool
RegisterFeature();
void
UnregisterFeature();
bool
IsOnTargetThread()
{
return NS_IsMainThread() == !mWorkerPrivate;
}
void
AssertIsOnTargetThread()
{
MOZ_ASSERT(IsOnTargetThread());
}
// Only ever set once, always on target thread.
bool mBodyUsed;
nsCString mMimeType;
// Only touched on target thread.
ConsumeType mConsumeType;
nsRefPtr<Promise> mConsumePromise;
DebugOnly<bool> mReadDone;
nsMainThreadPtrHandle<nsIInputStreamPump> mConsumeBodyPump;
};
} // namespace dom

View File

@ -5,12 +5,19 @@
#include "mozilla/dom/FetchDriver.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsIHttpChannel.h"
#include "nsIHttpHeaderVisitor.h"
#include "nsIScriptSecurityManager.h"
#include "nsIThreadRetargetableRequest.h"
#include "nsIUploadChannel2.h"
#include "nsContentPolicyUtils.h"
#include "nsDataHandler.h"
#include "nsHostObjectProtocolHandler.h"
#include "nsNetUtil.h"
#include "nsStreamUtils.h"
#include "nsStringStream.h"
#include "mozilla/dom/File.h"
@ -23,14 +30,23 @@
namespace mozilla {
namespace dom {
FetchDriver::FetchDriver(InternalRequest* aRequest)
: mRequest(aRequest)
NS_IMPL_ISUPPORTS(FetchDriver, nsIStreamListener)
FetchDriver::FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
nsILoadGroup* aLoadGroup)
: mPrincipal(aPrincipal)
, mLoadGroup(aLoadGroup)
, mRequest(aRequest)
, mFetchRecursionCount(0)
, mResponseAvailableCalled(false)
{
}
FetchDriver::~FetchDriver()
{
// We assert this since even on failures, we should call
// FailWithNetworkError().
MOZ_ASSERT(mResponseAvailableCalled);
}
nsresult
@ -54,7 +70,11 @@ FetchDriver::Fetch(bool aCORSFlag)
if (!mRequest->IsSynchronous() && mFetchRecursionCount <= 1) {
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableMethodWithArg<bool>(this, &FetchDriver::ContinueFetch, aCORSFlag);
return NS_DispatchToCurrentThread(r);
nsresult rv = NS_DispatchToCurrentThread(r);
if (NS_WARN_IF(NS_FAILED(rv))) {
FailWithNetworkError();
}
return rv;
}
MOZ_CRASH("Synchronous fetch not supported");
@ -83,16 +103,7 @@ FetchDriver::ContinueFetch(bool aCORSFlag)
return FailWithNetworkError();
}
nsAutoCString originURL;
mRequest->GetOrigin(originURL);
nsCOMPtr<nsIURI> originURI;
rv = NS_NewURI(getter_AddRefs(originURI), originURL, nullptr, nullptr);
if (NS_WARN_IF(NS_FAILED(rv))) {
return FailWithNetworkError();
}
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
rv = ssm->CheckSameOriginURI(requestURI, originURI, false);
rv = mPrincipal->CheckMayLoad(requestURI, false /* report */, false /* allowIfInheritsPrincipal */);
if ((!aCORSFlag && NS_SUCCEEDED(rv)) ||
(scheme.EqualsLiteral("data") && mRequest->SameOriginDataURL()) ||
scheme.EqualsLiteral("about")) {
@ -112,14 +123,14 @@ FetchDriver::ContinueFetch(bool aCORSFlag)
return FailWithNetworkError();
}
bool corsPreflight = false;
if (mRequest->Mode() == RequestMode::Cors_with_forced_preflight ||
(mRequest->UnsafeRequest() && (mRequest->HasSimpleMethod() || !mRequest->Headers()->HasOnlySimpleHeaders()))) {
// FIXME(nsm): Set corsPreflight;
corsPreflight = true;
}
mRequest->SetResponseTainting(InternalRequest::RESPONSETAINT_CORS);
// FIXME(nsm): HttpFetch.
return FailWithNetworkError();
return HttpFetch(true /* aCORSFlag */, corsPreflight);
}
nsresult
@ -132,11 +143,17 @@ FetchDriver::BasicFetch()
url,
nullptr,
nullptr);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
FailWithNetworkError();
return rv;
}
nsCString scheme;
nsAutoCString scheme;
rv = uri->GetScheme(scheme);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
FailWithNetworkError();
return rv;
}
if (scheme.LowerCaseEqualsLiteral("about")) {
if (url.EqualsLiteral("about:blank")) {
@ -150,7 +167,8 @@ FetchDriver::BasicFetch()
nsCOMPtr<nsIInputStream> body;
rv = NS_NewCStringInputStream(getter_AddRefs(body), EmptyCString());
if (NS_WARN_IF(NS_FAILED(rv))) {
return FailWithNetworkError();
FailWithNetworkError();
return rv;
}
response->SetBody(body);
@ -165,7 +183,8 @@ FetchDriver::BasicFetch()
rv = NS_GetBlobForBlobURI(uri, getter_AddRefs(blobImpl));
FileImpl* blob = static_cast<FileImpl*>(blobImpl.get());
if (NS_WARN_IF(NS_FAILED(rv))) {
return FailWithNetworkError();
FailWithNetworkError();
return rv;
}
nsRefPtr<InternalResponse> response = new InternalResponse(200, NS_LITERAL_CSTRING("OK"));
@ -173,28 +192,32 @@ FetchDriver::BasicFetch()
ErrorResult result;
uint64_t size = blob->GetSize(result);
if (NS_WARN_IF(result.Failed())) {
return FailWithNetworkError();
FailWithNetworkError();
return result.ErrorCode();
}
nsAutoString sizeStr;
sizeStr.AppendInt(size);
response->Headers()->Append(NS_LITERAL_CSTRING("Content-Length"), NS_ConvertUTF16toUTF8(sizeStr), result);
if (NS_WARN_IF(result.Failed())) {
return FailWithNetworkError();
FailWithNetworkError();
return result.ErrorCode();
}
nsAutoString type;
blob->GetType(type);
response->Headers()->Append(NS_LITERAL_CSTRING("Content-Type"), NS_ConvertUTF16toUTF8(type), result);
if (NS_WARN_IF(result.Failed())) {
return FailWithNetworkError();
FailWithNetworkError();
return result.ErrorCode();
}
}
nsCOMPtr<nsIInputStream> stream;
rv = blob->GetInternalStream(getter_AddRefs(stream));
if (NS_WARN_IF(NS_FAILED(rv))) {
return FailWithNetworkError();
FailWithNetworkError();
return rv;
}
response->SetBody(stream);
@ -245,15 +268,171 @@ FetchDriver::BasicFetch()
if (scheme.LowerCaseEqualsLiteral("file")) {
} else if (scheme.LowerCaseEqualsLiteral("http") ||
scheme.LowerCaseEqualsLiteral("https")) {
// FIXME(nsm): HttpFetch.
return FailWithNetworkError();
return HttpFetch();
}
return FailWithNetworkError();
}
nsresult
FetchDriver::BeginResponse(InternalResponse* aResponse)
FetchDriver::HttpFetch(bool aCORSFlag, bool aPreflightCORSFlag, bool aAuthenticationFlag)
{
mResponse = nullptr;
// XXXnsm: The ServiceWorker interception should happen automatically.
return ContinueHttpFetchAfterServiceWorker();
}
nsresult
FetchDriver::ContinueHttpFetchAfterServiceWorker()
{
if (!mResponse) {
// FIXME(nsm): Set skip SW flag.
// FIXME(nsm): Deal with CORS flags cases which will also call
// ContinueHttpFetchAfterCORSPreflight().
return ContinueHttpFetchAfterCORSPreflight();
}
// Otherwise ServiceWorker replied with a response.
return ContinueHttpFetchAfterNetworkFetch();
}
nsresult
FetchDriver::ContinueHttpFetchAfterCORSPreflight()
{
// mResponse is currently the CORS response.
// We may have to pass it via argument.
if (mResponse && mResponse->IsError()) {
return FailWithNetworkError();
}
return HttpNetworkFetch();
}
nsresult
FetchDriver::HttpNetworkFetch()
{
// We don't create a HTTPRequest copy since Necko sets the information on the
// nsIHttpChannel instead.
nsresult rv;
nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
FailWithNetworkError();
return rv;
}
nsAutoCString url;
mRequest->GetURL(url);
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri),
url,
nullptr,
nullptr,
ios);
if (NS_WARN_IF(NS_FAILED(rv))) {
FailWithNetworkError();
return rv;
}
MOZ_ASSERT(mLoadGroup);
nsCOMPtr<nsIChannel> chan;
rv = NS_NewChannel(getter_AddRefs(chan),
uri,
mPrincipal,
nsILoadInfo::SEC_NORMAL,
mRequest->GetContext(),
mLoadGroup,
nullptr, /* aCallbacks */
nsIRequest::LOAD_NORMAL,
ios);
mLoadGroup = nullptr;
if (NS_WARN_IF(NS_FAILED(rv))) {
FailWithNetworkError();
return rv;
}
nsCOMPtr<nsIHttpChannel> httpChan = do_QueryInterface(chan);
if (httpChan) {
nsAutoCString method;
mRequest->GetMethod(method);
rv = httpChan->SetRequestMethod(method);
if (NS_WARN_IF(NS_FAILED(rv))) {
FailWithNetworkError();
return rv;
}
nsAutoTArray<InternalHeaders::Entry, 5> headers;
mRequest->Headers()->GetEntries(headers);
for (uint32_t i = 0; i < headers.Length(); ++i) {
httpChan->SetRequestHeader(headers[i].mName, headers[i].mValue, false /* merge */);
}
MOZ_ASSERT(mRequest->ReferrerIsURL());
nsCString referrer = mRequest->ReferrerAsURL();
if (!referrer.IsEmpty()) {
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), referrer, nullptr, nullptr, ios);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = httpChan->SetReferrer(uri);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
if (mRequest->ForceOriginHeader()) {
nsAutoString origin;
rv = nsContentUtils::GetUTFOrigin(mPrincipal, origin);
if (NS_WARN_IF(NS_FAILED(rv))) {
FailWithNetworkError();
return rv;
}
httpChan->SetRequestHeader(NS_LITERAL_CSTRING("origin"),
NS_ConvertUTF16toUTF8(origin),
false /* merge */);
}
}
nsCOMPtr<nsIUploadChannel2> uploadChan = do_QueryInterface(chan);
if (uploadChan) {
nsAutoCString contentType;
ErrorResult result;
mRequest->Headers()->Get(NS_LITERAL_CSTRING("content-type"), contentType, result);
// This is an error because the Request constructor explicitly extracts and
// sets a content-type per spec.
if (result.Failed()) {
return result.ErrorCode();
}
nsCOMPtr<nsIInputStream> bodyStream;
mRequest->GetBody(getter_AddRefs(bodyStream));
if (bodyStream) {
nsAutoCString method;
mRequest->GetMethod(method);
rv = uploadChan->ExplicitSetUploadStream(bodyStream, contentType, -1, method, false /* aStreamHasHeaders */);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
}
return chan->AsyncOpen(this, nullptr);
}
nsresult
FetchDriver::ContinueHttpFetchAfterNetworkFetch()
{
workers::AssertIsOnMainThread();
MOZ_ASSERT(mResponse);
MOZ_ASSERT(!mResponse->IsError());
return SucceedWithResponse();
}
already_AddRefed<InternalResponse>
FetchDriver::BeginAndGetFilteredResponse(InternalResponse* aResponse)
{
MOZ_ASSERT(aResponse);
nsAutoCString reqURL;
@ -279,21 +458,164 @@ FetchDriver::BeginResponse(InternalResponse* aResponse)
MOZ_ASSERT(filteredResponse);
mObserver->OnResponseAvailable(filteredResponse);
return NS_OK;
mResponseAvailableCalled = true;
return filteredResponse.forget();
}
void
FetchDriver::BeginResponse(InternalResponse* aResponse)
{
nsRefPtr<InternalResponse> r = BeginAndGetFilteredResponse(aResponse);
// Release the ref.
}
nsresult
FetchDriver::SucceedWithResponse()
{
mObserver->OnResponseEnd();
return NS_OK;
}
nsresult
FetchDriver::FailWithNetworkError()
{
MOZ_ASSERT(mObserver);
nsRefPtr<InternalResponse> error = InternalResponse::NetworkError();
mObserver->OnResponseAvailable(error);
// FIXME(nsm): Some sort of shutdown?
mResponseAvailableCalled = true;
mObserver->OnResponseEnd();
return NS_OK;
}
namespace {
class FillResponseHeaders MOZ_FINAL : public nsIHttpHeaderVisitor {
InternalResponse* mResponse;
~FillResponseHeaders()
{ }
public:
NS_DECL_ISUPPORTS
explicit FillResponseHeaders(InternalResponse* aResponse)
: mResponse(aResponse)
{
}
NS_IMETHOD
VisitHeader(const nsACString & aHeader, const nsACString & aValue) MOZ_OVERRIDE
{
ErrorResult result;
mResponse->Headers()->Append(aHeader, aValue, result);
return result.ErrorCode();
}
};
NS_IMPL_ISUPPORTS(FillResponseHeaders, nsIHttpHeaderVisitor)
} // anonymous namespace
NS_IMETHODIMP
FetchDriver::OnStartRequest(nsIRequest* aRequest,
nsISupports* aContext)
{
MOZ_ASSERT(!mPipeOutputStream);
nsresult rv;
aRequest->GetStatus(&rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
FailWithNetworkError();
return rv;
}
nsCOMPtr<nsIHttpChannel> channel = do_QueryInterface(aRequest);
// For now we only support HTTP.
MOZ_ASSERT(channel);
aRequest->GetStatus(&rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
FailWithNetworkError();
return rv;
}
uint32_t responseStatus;
channel->GetResponseStatus(&responseStatus);
nsAutoCString statusText;
channel->GetResponseStatusText(statusText);
nsRefPtr<InternalResponse> response = new InternalResponse(responseStatus, statusText);
nsRefPtr<FillResponseHeaders> visitor = new FillResponseHeaders(response);
rv = channel->VisitResponseHeaders(visitor);
if (NS_WARN_IF(NS_FAILED(rv))) {
NS_WARNING("Failed to visit all headers.");
}
mResponse = BeginAndGetFilteredResponse(response);
// We open a pipe so that we can immediately set the pipe's read end as the
// response's body. Setting the segment size to UINT32_MAX means that the
// pipe has infinite space. The nsIChannel will continue to buffer data in
// xpcom events even if we block on a fixed size pipe. It might be possible
// to suspend the channel and then resume when there is space available, but
// for now use an infinite pipe to avoid blocking.
nsCOMPtr<nsIInputStream> pipeInputStream;
rv = NS_NewPipe(getter_AddRefs(pipeInputStream),
getter_AddRefs(mPipeOutputStream),
0, /* default segment size */
UINT32_MAX /* infinite pipe */);
if (NS_WARN_IF(NS_FAILED(rv))) {
FailWithNetworkError();
// Cancel request.
return rv;
}
mResponse->SetBody(pipeInputStream);
nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
FailWithNetworkError();
// Cancel request.
return rv;
}
// Try to retarget off main thread.
nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(aRequest);
if (rr) {
rr->RetargetDeliveryTo(sts);
}
return NS_OK;
}
NS_IMETHODIMP
FetchDriver::OnDataAvailable(nsIRequest* aRequest,
nsISupports* aContext,
nsIInputStream* aInputStream,
uint64_t aOffset,
uint32_t aCount)
{
uint32_t aRead;
MOZ_ASSERT(mResponse);
MOZ_ASSERT(mPipeOutputStream);
nsresult rv = aInputStream->ReadSegments(NS_CopySegmentToStream,
mPipeOutputStream,
aCount, &aRead);
return rv;
}
NS_IMETHODIMP
FetchDriver::OnStopRequest(nsIRequest* aRequest,
nsISupports* aContext,
nsresult aStatusCode)
{
MOZ_ASSERT(mPipeOutputStream);
mPipeOutputStream->Close();
if (NS_FAILED(aStatusCode)) {
FailWithNetworkError();
return aStatusCode;
}
ContinueHttpFetchAfterNetworkFetch();
return NS_OK;
}

View File

@ -6,14 +6,20 @@
#ifndef mozilla_dom_FetchDriver_h
#define mozilla_dom_FetchDriver_h
#include "nsAutoPtr.h"
#include "nsIStreamListener.h"
#include "nsRefPtr.h"
class nsPIDOMWindow;
#include "mozilla/DebugOnly.h"
class nsIOutputStream;
class nsILoadGroup;
class nsIPrincipal;
namespace mozilla {
namespace dom {
class BlobSet;
class InternalRequest;
class InternalResponse;
@ -22,24 +28,35 @@ class FetchDriverObserver
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FetchDriverObserver);
virtual void OnResponseAvailable(InternalResponse* aResponse) = 0;
virtual void OnResponseEnd() = 0;
protected:
virtual ~FetchDriverObserver()
{ };
};
class FetchDriver MOZ_FINAL
class FetchDriver MOZ_FINAL : public nsIStreamListener
{
NS_INLINE_DECL_REFCOUNTING(FetchDriver)
public:
explicit FetchDriver(InternalRequest* aRequest);
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
explicit FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
nsILoadGroup* aLoadGroup);
NS_IMETHOD Fetch(FetchDriverObserver* aObserver);
private:
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsRefPtr<InternalRequest> mRequest;
nsRefPtr<InternalResponse> mResponse;
nsCOMPtr<nsIOutputStream> mPipeOutputStream;
nsRefPtr<FetchDriverObserver> mObserver;
uint32_t mFetchRecursionCount;
DebugOnly<bool> mResponseAvailableCalled;
FetchDriver() = delete;
FetchDriver(const FetchDriver&) = delete;
FetchDriver& operator=(const FetchDriver&) = delete;
@ -48,8 +65,18 @@ private:
nsresult Fetch(bool aCORSFlag);
nsresult ContinueFetch(bool aCORSFlag);
nsresult BasicFetch();
nsresult HttpFetch(bool aCORSFlag = false, bool aPreflightCORSFlag = false, bool aAuthenticationFlag = false);
nsresult ContinueHttpFetchAfterServiceWorker();
nsresult ContinueHttpFetchAfterCORSPreflight();
nsresult HttpNetworkFetch();
nsresult ContinueHttpFetchAfterNetworkFetch();
// Returns the filtered response sent to the observer.
already_AddRefed<InternalResponse>
BeginAndGetFilteredResponse(InternalResponse* aResponse);
// Utility since not all cases need to do any post processing of the filtered
// response.
void BeginResponse(InternalResponse* aResponse);
nsresult FailWithNetworkError();
nsresult BeginResponse(InternalResponse* aResponse);
nsresult SucceedWithResponse();
};

View File

@ -324,5 +324,12 @@ InternalHeaders::CORSHeaders(InternalHeaders* aHeaders)
return cors.forget();
}
void
InternalHeaders::GetEntries(nsTArray<InternalHeaders::Entry>& aEntries) const
{
MOZ_ASSERT(aEntries.IsEmpty());
aEntries.AppendElements(mList);
}
} // namespace dom
} // namespace mozilla

View File

@ -29,7 +29,7 @@ class InternalHeaders MOZ_FINAL
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalHeaders)
private:
public:
struct Entry
{
Entry(const nsACString& aName, const nsACString& aValue)
@ -43,6 +43,7 @@ private:
nsCString mValue;
};
private:
HeadersGuardEnum mGuard;
nsTArray<Entry> mList;
@ -85,6 +86,9 @@ public:
static already_AddRefed<InternalHeaders>
CORSHeaders(InternalHeaders* aHeaders);
void
GetEntries(nsTArray<InternalHeaders::Entry>& aEntries) const;
private:
virtual ~InternalHeaders();

View File

@ -29,25 +29,10 @@ InternalRequest::GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult
copy->mBodyStream = mBodyStream;
copy->mPreserveContentCodings = true;
if (NS_IsMainThread()) {
nsIPrincipal* principal = aGlobal->PrincipalOrNull();
MOZ_ASSERT(principal);
aRv = nsContentUtils::GetASCIIOrigin(principal, copy->mOrigin);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
} else {
workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
worker->AssertIsOnWorkerThread();
workers::WorkerPrivate::LocationInfo& location = worker->GetLocationInfo();
copy->mOrigin = NS_ConvertUTF16toUTF8(location.mOrigin);
}
copy->mContext = nsIContentPolicy::TYPE_FETCH;
copy->mMode = mMode;
copy->mCredentialsMode = mCredentialsMode;
copy->mCacheMode = mCacheMode;
return copy.forget();
}

View File

@ -61,6 +61,7 @@ public:
, mMode(RequestMode::No_cors)
, mCredentialsMode(RequestCredentials::Omit)
, mResponseTainting(RESPONSETAINT_BASIC)
, mCacheMode(RequestCache::Default)
, mRedirectCount(0)
, mAuthenticationFlag(false)
, mForceOriginHeader(false)
@ -84,13 +85,13 @@ public:
, mHeaders(aOther.mHeaders)
, mBodyStream(aOther.mBodyStream)
, mContext(aOther.mContext)
, mOrigin(aOther.mOrigin)
, mContextFrameType(aOther.mContextFrameType)
, mReferrerType(aOther.mReferrerType)
, mReferrerURL(aOther.mReferrerURL)
, mMode(aOther.mMode)
, mCredentialsMode(aOther.mCredentialsMode)
, mResponseTainting(aOther.mResponseTainting)
, mCacheMode(aOther.mCacheMode)
, mRedirectCount(aOther.mRedirectCount)
, mAuthenticationFlag(aOther.mAuthenticationFlag)
, mForceOriginHeader(aOther.mForceOriginHeader)
@ -201,6 +202,12 @@ public:
mResponseTainting = aTainting;
}
RequestCache
GetCacheMode() const
{
return mCacheMode;
}
nsContentPolicyType
GetContext() const
{
@ -225,12 +232,6 @@ public:
return mForceOriginHeader;
}
void
GetOrigin(nsCString& aOrigin) const
{
aOrigin.Assign(mOrigin);
}
bool
SameOriginDataURL() const
{
@ -240,6 +241,8 @@ public:
void
SetBody(nsIInputStream* aStream)
{
// A request's body may not be reset once set.
MOZ_ASSERT(!mBodyStream);
mBodyStream = aStream;
}
@ -274,8 +277,6 @@ private:
// but it is a good start.
nsContentPolicyType mContext;
nsCString mOrigin;
ContextFrameType mContextFrameType;
ReferrerType mReferrerType;
@ -285,6 +286,7 @@ private:
RequestMode mMode;
RequestCredentials mCredentialsMode;
ResponseTainting mResponseTainting;
RequestCache mCacheMode;
uint32_t mRedirectCount;

View File

@ -104,6 +104,8 @@ public:
void
SetBody(nsIInputStream* aBody)
{
// A request's body may not be reset once set.
MOZ_ASSERT(!mBody);
mBody = aBody;
}

View File

@ -58,12 +58,17 @@ Request::Constructor(const GlobalObject& aGlobal,
if (aInput.IsRequest()) {
nsRefPtr<Request> inputReq = &aInput.GetAsRequest();
if (inputReq->BodyUsed()) {
aRv.ThrowTypeError(MSG_REQUEST_BODY_CONSUMED_ERROR);
return nullptr;
nsCOMPtr<nsIInputStream> body;
inputReq->GetBody(getter_AddRefs(body));
if (body) {
if (inputReq->BodyUsed()) {
aRv.ThrowTypeError(MSG_REQUEST_BODY_CONSUMED_ERROR);
return nullptr;
} else {
inputReq->SetBodyUsed();
}
}
inputReq->SetBodyUsed();
request = inputReq->GetInternalRequest();
} else {
request = new InternalRequest();
@ -123,6 +128,16 @@ Request::Constructor(const GlobalObject& aGlobal,
fallbackCredentials = RequestCredentials::Omit;
}
// CORS-with-forced-preflight is not publicly exposed and should not be
// considered a valid value.
if (aInit.mMode.WasPassed() &&
aInit.mMode.Value() == RequestMode::Cors_with_forced_preflight) {
NS_NAMED_LITERAL_STRING(sourceDescription, "'mode' member of RequestInit");
NS_NAMED_LITERAL_STRING(value, "cors-with-forced-preflight");
NS_NAMED_LITERAL_STRING(type, "RequestMode");
aRv.ThrowTypeError(MSG_INVALID_ENUM_VALUE, &sourceDescription, &value, &type);
return nullptr;
}
RequestMode mode = aInit.mMode.WasPassed() ? aInit.mMode.Value() : fallbackMode;
RequestCredentials credentials =
aInit.mCredentials.WasPassed() ? aInit.mCredentials.Value()

View File

@ -26,8 +26,8 @@ class Promise;
class RequestOrUSVString;
class Request MOZ_FINAL : public nsISupports
, public nsWrapperCache
, public FetchBody<Request>
, public nsWrapperCache
{
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Request)
@ -56,6 +56,9 @@ public:
RequestMode
Mode() const
{
if (mRequest->mMode == RequestMode::Cors_with_forced_preflight) {
return RequestMode::Cors;
}
return mRequest->mMode;
}
@ -65,6 +68,12 @@ public:
return mRequest->mCredentialsMode;
}
RequestCache
Cache() const
{
return mRequest->GetCacheMode();
}
void
GetReferrer(DOMString& aReferrer) const
{

View File

@ -25,8 +25,8 @@ class InternalHeaders;
class Promise;
class Response MOZ_FINAL : public nsISupports
, public nsWrapperCache
, public FetchBody<Response>
, public nsWrapperCache
{
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Response)

View File

@ -166,10 +166,10 @@ TimeRanges::Find(double aTime, double aError /* = 0 */)
return NoIndex;
}
JSObject*
TimeRanges::WrapObject(JSContext* aCx)
bool
TimeRanges::WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector)
{
return TimeRangesBinding::Wrap(aCx, this);
return TimeRangesBinding::Wrap(aCx, this, aReflector);
}
} // namespace dom

View File

@ -50,7 +50,7 @@ public:
// Mutate this TimeRange to be the intersection of this and aOtherRanges.
void Intersection(const TimeRanges* aOtherRanges);
JSObject* WrapObject(JSContext* aCx);
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
uint32_t Length() const
{

View File

@ -247,10 +247,10 @@ IDBKeyRange::DropJSObjects()
mozilla::DropJSObjects(this);
}
JSObject*
IDBKeyRange::WrapObject(JSContext* aCx)
bool
IDBKeyRange::WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector)
{
return IDBKeyRangeBinding::Wrap(aCx, this);
return IDBKeyRangeBinding::Wrap(aCx, this, aReflector);
}
void

View File

@ -140,8 +140,8 @@ public:
DropJSObjects();
// WebIDL
JSObject*
WrapObject(JSContext* aCx);
bool
WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
nsISupports*
GetParentObject() const

View File

@ -1802,8 +1802,8 @@ ContentChild::ProcessingError(Result what)
{
switch (what) {
case MsgDropped:
QuickExit();
NS_WARNING("MsgDropped in ContentChild");
return;
case MsgNotKnown:
NS_RUNTIMEABORT("aborting because of MsgNotKnown");
case MsgNotAllowed:

View File

@ -994,11 +994,6 @@ ContentParent::CreateBrowserOrApp(const TabContext& aContext,
return nullptr;
}
if (TabParent* parent = TabParent::GetNextTabParent()) {
parent->SetOwnerElement(aFrameElement);
return parent;
}
ProcessPriority initialPriority = GetInitialProcessPriority(aFrameElement);
bool isInContentProcess = (XRE_GetProcessType() != GeckoProcessType_Default);
TabId tabId;

View File

@ -79,12 +79,6 @@ struct ShowInfo
double defaultScale;
};
struct FrameScriptInfo
{
nsString url;
bool runInGlobalScope;
};
prio(normal upto urgent) intr protocol PBrowser
{
manager PContent or PContentBridge;
@ -123,8 +117,7 @@ parent:
Event(RemoteDOMEvent aEvent);
sync CreateWindow(PBrowser aNewTab,
uint32_t aChromeFlags,
intr CreateWindow(uint32_t aChromeFlags,
bool aCalledFromJS,
bool aPositionSpecified,
bool aSizeSpecified,
@ -132,7 +125,7 @@ parent:
nsString aName,
nsString aFeatures,
nsString aBaseURI)
returns (bool windowOpened, FrameScriptInfo[] frameScripts);
returns (bool windowIsNew, PBrowser window);
sync SyncMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal)

View File

@ -1429,53 +1429,93 @@ TabChild::ProvideWindow(nsIDOMWindow* aParent, uint32_t aChromeFlags,
// isn't a request to open a modal-type window, we're going to create a new
// <iframe mozbrowser/mozapp> and return its window here.
nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent);
bool iframeMoz = (docshell && docshell->GetIsInBrowserOrApp() &&
!(aChromeFlags & (nsIWebBrowserChrome::CHROME_MODAL |
nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
nsIWebBrowserChrome::CHROME_OPENAS_CHROME)));
if (docshell && docshell->GetIsInBrowserOrApp() &&
!(aChromeFlags & (nsIWebBrowserChrome::CHROME_MODAL |
nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
nsIWebBrowserChrome::CHROME_OPENAS_CHROME))) {
if (!iframeMoz) {
int32_t openLocation =
nsWindowWatcher::GetWindowOpenLocation(aParent, aChromeFlags, aCalledFromJS,
aPositionSpecified, aSizeSpecified);
// If it turns out we're opening in the current browser, just hand over the
// current browser's docshell.
if (openLocation == nsIBrowserDOMWindow::OPEN_CURRENTWINDOW) {
nsCOMPtr<nsIWebBrowser> browser = do_GetInterface(WebNavigation());
*aWindowIsNew = false;
return browser->GetContentDOMWindow(aReturn);
}
// Note that BrowserFrameProvideWindow may return NS_ERROR_ABORT if the
// open window call was canceled. It's important that we pass this error
// code back to our caller.
return BrowserFrameProvideWindow(aParent, aURI, aName, aFeatures,
aWindowIsNew, aReturn);
}
// Note that ProvideWindowCommon may return NS_ERROR_ABORT if the
// open window call was canceled. It's important that we pass this error
// code back to our caller.
return ProvideWindowCommon(aParent,
iframeMoz,
aChromeFlags,
aCalledFromJS,
aPositionSpecified,
aSizeSpecified,
aURI,
aName,
aFeatures,
aWindowIsNew,
aReturn);
int32_t openLocation =
nsWindowWatcher::GetWindowOpenLocation(aParent, aChromeFlags, aCalledFromJS,
aPositionSpecified, aSizeSpecified);
// If it turns out we're opening in the current browser, just hand over the
// current browser's docshell.
if (openLocation == nsIBrowserDOMWindow::OPEN_CURRENTWINDOW) {
nsCOMPtr<nsIWebBrowser> browser = do_GetInterface(WebNavigation());
*aWindowIsNew = false;
return browser->GetContentDOMWindow(aReturn);
}
// Otherwise, we're opening a new tab or a new window. We have to contact
// TabParent in order to do either.
PBrowserChild* newChild;
nsAutoCString uriString;
if (aURI) {
aURI->GetSpec(uriString);
}
nsCOMPtr<nsIDOMDocument> domDoc;
aParent->GetDocument(getter_AddRefs(domDoc));
if (!domDoc) {
NS_ERROR("Could retrieve document from nsIBaseWindow");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDocument> doc;
doc = do_QueryInterface(domDoc);
if (!doc) {
NS_ERROR("Document from nsIBaseWindow didn't QI to nsIDocument");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
if (!baseURI) {
NS_ERROR("nsIDocument didn't return a base URI");
return NS_ERROR_FAILURE;
}
nsAutoCString baseURIString;
baseURI->GetSpec(baseURIString);
nsAutoString nameString;
nameString.Assign(aName);
nsAutoCString features;
// We can assume that if content is requesting to open a window from a remote
// tab, then we want to enforce that the new window is also a remote tab.
features.Assign(aFeatures);
features.Append(",remote");
if (!CallCreateWindow(aChromeFlags, aCalledFromJS, aPositionSpecified,
aSizeSpecified, NS_ConvertUTF8toUTF16(uriString),
nameString, NS_ConvertUTF8toUTF16(features),
NS_ConvertUTF8toUTF16(baseURIString),
aWindowIsNew, &newChild)) {
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIDOMWindow> win =
do_GetInterface(static_cast<TabChild*>(newChild)->WebNavigation());
win.forget(aReturn);
return NS_OK;
}
nsresult
TabChild::ProvideWindowCommon(nsIDOMWindow* aOpener,
bool aIframeMoz,
uint32_t aChromeFlags,
bool aCalledFromJS,
bool aPositionSpecified,
bool aSizeSpecified,
nsIURI* aURI,
const nsAString& aName,
const nsACString& aFeatures,
bool* aWindowIsNew,
nsIDOMWindow** aReturn)
TabChild::BrowserFrameProvideWindow(nsIDOMWindow* aOpener,
nsIURI* aURI,
const nsAString& aName,
const nsACString& aFeatures,
bool* aWindowIsNew,
nsIDOMWindow** aReturn)
{
*aReturn = nullptr;
@ -1499,7 +1539,7 @@ TabChild::ProvideWindowCommon(nsIDOMWindow* aOpener,
&tabId);
nsRefPtr<TabChild> newChild = new TabChild(ContentChild::GetSingleton(), tabId,
/* TabContext */ *this, aChromeFlags);
/* TabContext */ *this, /* chromeFlags */ 0);
if (NS_FAILED(newChild->Init())) {
return NS_ERROR_ABORT;
}
@ -1508,7 +1548,7 @@ TabChild::ProvideWindowCommon(nsIDOMWindow* aOpener,
unused << Manager()->SendPBrowserConstructor(
// We release this ref in DeallocPBrowserChild
nsRefPtr<TabChild>(newChild).forget().take(),
tabId, IPCTabContext(context, mScrolling), aChromeFlags,
tabId, IPCTabContext(context, mScrolling), /* chromeFlags */ 0,
cc->GetID(), cc->IsForApp(), cc->IsForBrowser());
nsAutoCString spec;
@ -1518,51 +1558,9 @@ TabChild::ProvideWindowCommon(nsIDOMWindow* aOpener,
NS_ConvertUTF8toUTF16 url(spec);
nsString name(aName);
nsAutoCString features(aFeatures);
nsTArray<FrameScriptInfo> frameScripts;
if (aIframeMoz) {
newChild->SendBrowserFrameOpenWindow(this, url, name,
NS_ConvertUTF8toUTF16(features),
aWindowIsNew);
} else {
nsCOMPtr<nsIDOMDocument> domDoc;
aOpener->GetDocument(getter_AddRefs(domDoc));
if (!domDoc) {
NS_ERROR("Could retrieve document from nsIBaseWindow");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDocument> doc;
doc = do_QueryInterface(domDoc);
if (!doc) {
NS_ERROR("Document from nsIBaseWindow didn't QI to nsIDocument");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
if (!baseURI) {
NS_ERROR("nsIDocument didn't return a base URI");
return NS_ERROR_FAILURE;
}
nsAutoCString baseURIString;
baseURI->GetSpec(baseURIString);
// We can assume that if content is requesting to open a window from a remote
// tab, then we want to enforce that the new window is also a remote tab.
features.AppendLiteral(",remote");
if (!SendCreateWindow(newChild,
aChromeFlags, aCalledFromJS, aPositionSpecified,
aSizeSpecified, url,
name, NS_ConvertUTF8toUTF16(features),
NS_ConvertUTF8toUTF16(baseURIString),
aWindowIsNew,
&frameScripts)) {
return NS_ERROR_NOT_AVAILABLE;
}
}
NS_ConvertUTF8toUTF16 features(aFeatures);
newChild->SendBrowserFrameOpenWindow(this, url, name,
features, aWindowIsNew);
if (!*aWindowIsNew) {
PBrowserChild::Send__delete__(newChild);
return NS_ERROR_ABORT;
@ -1585,13 +1583,6 @@ TabChild::ProvideWindowCommon(nsIDOMWindow* aOpener,
// pretty bogus; see bug 763602.
newChild->DoFakeShow(scrolling, textureFactoryIdentifier, layersId, renderFrame);
for (size_t i = 0; i < frameScripts.Length(); i++) {
FrameScriptInfo& info = frameScripts[i];
if (!newChild->RecvLoadRemoteScript(info.url(), info.runInGlobalScope())) {
MOZ_CRASH();
}
}
nsCOMPtr<nsIDOMWindow> win = do_GetInterface(newChild->WebNavigation());
win.forget(aReturn);
return NS_OK;
@ -1923,14 +1914,7 @@ TabChild::ApplyShowInfo(const ShowInfo& aInfo)
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
if (docShell) {
nsCOMPtr<nsIDocShellTreeItem> item = do_GetInterface(docShell);
if (IsBrowserOrApp()) {
// B2G allows window.name to be set by changing the name attribute on the
// <iframe mozbrowser> element. window.open calls cause this attribute to
// be set to the correct value. A normal <xul:browser> element has no such
// attribute. The data we get here comes from reading the attribute, so we
// shouldn't trust it for <xul:browser> elements.
item->SetName(aInfo.name());
}
item->SetName(aInfo.name());
docShell->SetFullscreenAllowed(aInfo.fullscreenAllowed());
if (aInfo.isPrivate()) {
bool nonBlank;

View File

@ -574,17 +574,12 @@ private:
void UpdateTapState(const WidgetTouchEvent& aEvent, nsEventStatus aStatus);
nsresult
ProvideWindowCommon(nsIDOMWindow* aOpener,
bool aIframeMoz,
uint32_t aChromeFlags,
bool aCalledFromJS,
bool aPositionSpecified,
bool aSizeSpecified,
nsIURI* aURI,
const nsAString& aName,
const nsACString& aFeatures,
bool* aWindowIsNew,
nsIDOMWindow** aReturn);
BrowserFrameProvideWindow(nsIDOMWindow* aOpener,
nsIURI* aURI,
const nsAString& aName,
const nsACString& aFeatures,
bool* aWindowIsNew,
nsIDOMWindow** aReturn);
bool HasValidInnerSize();

View File

@ -272,7 +272,6 @@ TabParent::TabParent(nsIContentParent* aManager,
, mChromeFlags(aChromeFlags)
, mInitedByParent(false)
, mTabId(aTabId)
, mSkipLoad(false)
{
MOZ_ASSERT(aManager);
}
@ -450,49 +449,18 @@ TabParent::RecvEvent(const RemoteDOMEvent& aEvent)
return true;
}
struct MOZ_STACK_CLASS TabParent::AutoUseNewTab MOZ_FINAL
{
public:
AutoUseNewTab(TabParent* aNewTab, bool* aWindowIsNew)
: mNewTab(aNewTab), mWindowIsNew(aWindowIsNew)
{
MOZ_ASSERT(!TabParent::sNextTabParent);
TabParent::sNextTabParent = aNewTab;
aNewTab->mSkipLoad = true;
}
~AutoUseNewTab()
{
mNewTab->mSkipLoad = false;
if (TabParent::sNextTabParent) {
MOZ_ASSERT(TabParent::sNextTabParent == mNewTab);
TabParent::sNextTabParent = nullptr;
*mWindowIsNew = false;
}
}
private:
TabParent* mNewTab;
bool* mWindowIsNew;
};
bool
TabParent::RecvCreateWindow(PBrowserParent* aNewTab,
const uint32_t& aChromeFlags,
const bool& aCalledFromJS,
const bool& aPositionSpecified,
const bool& aSizeSpecified,
const nsString& aURI,
const nsString& aName,
const nsString& aFeatures,
const nsString& aBaseURI,
bool* aWindowIsNew,
InfallibleTArray<FrameScriptInfo>* aFrameScripts)
TabParent::AnswerCreateWindow(const uint32_t& aChromeFlags,
const bool& aCalledFromJS,
const bool& aPositionSpecified,
const bool& aSizeSpecified,
const nsString& aURI,
const nsString& aName,
const nsString& aFeatures,
const nsString& aBaseURI,
bool* aWindowIsNew,
PBrowserParent** aRetVal)
{
// We always expect to open a new window here. If we don't, it's an error.
*aWindowIsNew = true;
if (IsBrowserOrApp()) {
return false;
}
@ -502,8 +470,6 @@ TabParent::RecvCreateWindow(PBrowserParent* aNewTab,
do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, false);
TabParent* newTab = static_cast<TabParent*>(aNewTab);
nsCOMPtr<nsIContent> frame(do_QueryInterface(mFrameElement));
NS_ENSURE_TRUE(frame, false);
@ -517,6 +483,8 @@ TabParent::RecvCreateWindow(PBrowserParent* aNewTab,
MOZ_ASSERT(openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
openLocation == nsIBrowserDOMWindow::OPEN_NEWWINDOW);
*aWindowIsNew = true;
// Opening new tabs is the easy case...
if (openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB) {
NS_ENSURE_TRUE(mBrowserDOMWindow, false);
@ -529,18 +497,17 @@ TabParent::RecvCreateWindow(PBrowserParent* aNewTab,
params->SetReferrer(aBaseURI);
params->SetIsPrivate(isPrivate);
AutoUseNewTab aunt(newTab, aWindowIsNew);
nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner;
mBrowserDOMWindow->OpenURIInFrame(nullptr, params,
openLocation,
nsIBrowserDOMWindow::OPEN_NEWTAB,
nsIBrowserDOMWindow::OPEN_NEW,
getter_AddRefs(frameLoaderOwner));
if (!frameLoaderOwner) {
*aWindowIsNew = false;
}
NS_ENSURE_TRUE(frameLoaderOwner, false);
aFrameScripts->SwapElements(newTab->mDelayedFrameScripts);
nsRefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
NS_ENSURE_TRUE(frameLoader, false);
*aRetVal = frameLoader->GetRemoteBrowser();
return true;
}
@ -563,8 +530,6 @@ TabParent::RecvCreateWindow(PBrowserParent* aNewTab,
nsCOMPtr<nsIDOMWindow> window;
AutoUseNewTab aunt(newTab, aWindowIsNew);
rv = pwwatch->OpenWindow2(parent, finalURIString.get(),
NS_ConvertUTF16toUTF8(aName).get(),
NS_ConvertUTF16toUTF8(aFeatures).get(), aCalledFromJS,
@ -580,45 +545,15 @@ TabParent::RecvCreateWindow(PBrowserParent* aNewTab,
nsCOMPtr<nsITabParent> newRemoteTab = newDocShell->GetOpenedRemote();
NS_ENSURE_TRUE(newRemoteTab, false);
MOZ_ASSERT(static_cast<TabParent*>(newRemoteTab.get()) == newTab);
aFrameScripts->SwapElements(newTab->mDelayedFrameScripts);
*aRetVal = static_cast<TabParent*>(newRemoteTab.get());
return true;
}
TabParent* TabParent::sNextTabParent;
/* static */ TabParent*
TabParent::GetNextTabParent()
{
TabParent* result = sNextTabParent;
sNextTabParent = nullptr;
return result;
}
bool
TabParent::SendLoadRemoteScript(const nsString& aURL,
const bool& aRunInGlobalScope)
{
if (mSkipLoad) {
mDelayedFrameScripts.AppendElement(FrameScriptInfo(aURL, aRunInGlobalScope));
return true;
}
MOZ_ASSERT(mDelayedFrameScripts.IsEmpty());
return PBrowserParent::SendLoadRemoteScript(aURL, aRunInGlobalScope);
}
void
TabParent::LoadURL(nsIURI* aURI)
{
MOZ_ASSERT(aURI);
if (mSkipLoad) {
// Don't send the message if the child wants to load its own URL.
return;
}
if (mIsDestroyed) {
return;
}

View File

@ -134,17 +134,16 @@ public:
const nsString& aName,
const nsString& aFeatures,
bool* aOutWindowOpened) MOZ_OVERRIDE;
virtual bool RecvCreateWindow(PBrowserParent* aOpener,
const uint32_t& aChromeFlags,
const bool& aCalledFromJS,
const bool& aPositionSpecified,
const bool& aSizeSpecified,
const nsString& aURI,
const nsString& aName,
const nsString& aFeatures,
const nsString& aBaseURI,
bool* aWindowIsNew,
InfallibleTArray<FrameScriptInfo>* aFrameScripts) MOZ_OVERRIDE;
virtual bool AnswerCreateWindow(const uint32_t& aChromeFlags,
const bool& aCalledFromJS,
const bool& aPositionSpecified,
const bool& aSizeSpecified,
const nsString& aURI,
const nsString& aName,
const nsString& aFeatures,
const nsString& aBaseURI,
bool* aWindowIsNew,
PBrowserParent** aRetVal) MOZ_OVERRIDE;
virtual bool RecvSyncMessage(const nsString& aMessage,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
@ -353,11 +352,6 @@ public:
void SetInitedByParent() { mInitedByParent = true; }
bool IsInitedByParent() const { return mInitedByParent; }
static TabParent* GetNextTabParent();
bool SendLoadRemoteScript(const nsString& aURL,
const bool& aRunInGlobalScope);
protected:
bool ReceiveMessage(const nsString& aMessage,
bool aSync,
@ -474,35 +468,6 @@ private:
TabId mTabId;
// Helper class for RecvCreateWindow.
struct AutoUseNewTab;
// When loading a new tab or window via window.open, the child process sends
// a new PBrowser to use. We store that tab in sNextTabParent and then
// proceed through the browser's normal paths to create a new
// window/tab. When it comes time to create a new TabParent, we instead use
// sNextTabParent.
static TabParent* sNextTabParent;
// When loading a new tab or window via window.open, the child is
// responsible for loading the URL it wants into the new
// TabChild. Simultaneously, though, the parent sends a LoadURL message to
// every new PBrowser (usually for about:blank). This message usually
// arrives after the child has started to load the URL it wants, and
// overrides it. To prevent this, we set mSkipLoad to true when creating the
// new tab. This flag prevents the unwanted LoadURL message from being sent
// by the parent.
bool mSkipLoad;
// When loading a new tab or window via window.open, we want to ensure that
// frame scripts for that tab are loaded before any scripts start to run in
// the window. We can't load the frame scripts the normal way, using
// separate IPC messages, since they won't be processed by the child until
// returning to the event loop, which is too late. Instead, we queue up
// frame scripts that we intend to load and send them as part of the
// CreateWindow response. Then TabChild loads them immediately.
nsTArray<FrameScriptInfo> mDelayedFrameScripts;
private:
// This is used when APZ needs to find the TabParent associated with a layer
// to dispatch events.

View File

@ -243,6 +243,12 @@ public:
mDecoder = nullptr;
}
// Returns true if the reader implements RequestAudioData()
// and RequestVideoData() asynchronously, rather than using the
// implementation in this class to adapt the old synchronous to
// the newer async model.
virtual bool IsAsync() const { return false; }
protected:
virtual ~MediaDecoderReader();

View File

@ -202,6 +202,8 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mAmpleVideoFrames(2),
mLowAudioThresholdUsecs(LOW_AUDIO_USECS),
mAmpleAudioThresholdUsecs(AMPLE_AUDIO_USECS),
mIsAudioPrerolling(false),
mIsVideoPrerolling(false),
mAudioRequestStatus(RequestStatus::Idle),
mVideoRequestStatus(RequestStatus::Idle),
mAudioCaptured(false),
@ -612,15 +614,20 @@ MediaDecoderStateMachine::NeedToSkipToNextKeyframe()
// data to decode. If we're running low on downloaded data to decode,
// we won't start keyframe skipping, as we'll be pausing playback to buffer
// soon anyway and we'll want to be able to display frames immediately
// after buffering finishes.
bool isLowOnDecodedAudio = !mIsAudioPrerolling && IsAudioDecoding() &&
// after buffering finishes. We ignore the low audio calculations for
// readers that are async, as since their audio decode runs on a different
// task queue it should never run low and skipping won't help their decode.
bool isLowOnDecodedAudio = !mReader->IsAsync() &&
!mIsAudioPrerolling && IsAudioDecoding() &&
(GetDecodedAudioDuration() <
mLowAudioThresholdUsecs * mPlaybackRate);
bool isLowOnDecodedVideo = !mIsVideoPrerolling &&
(mDecodedVideoEndTime - GetClock() <
LOW_VIDEO_THRESHOLD_USECS * mPlaybackRate);
if ((isLowOnDecodedAudio || isLowOnDecodedVideo) && !HasLowUndecodedData()) {
DECODER_LOG("Skipping video decode to the next keyframe");
bool lowUndecoded = HasLowUndecodedData();
if ((isLowOnDecodedAudio || isLowOnDecodedVideo) && !lowUndecoded) {
DECODER_LOG("Skipping video decode to the next keyframe lowAudio=%d lowVideo=%d lowUndecoded=%d async=%d",
isLowOnDecodedAudio, isLowOnDecodedVideo, lowUndecoded, mReader->IsAsync());
return true;
}
@ -994,10 +1001,14 @@ MediaDecoderStateMachine::OnVideoDecoded(VideoData* aVideoSample)
StopPrerollingVideo();
}
// If the requested video sample was slow to arrive, increase the
// amount of audio we buffer to ensure that we don't run out of audio.
// TODO: Detect when we're truly async, and don't do this if so, as
// it's not necessary.
// For non async readers, if the requested video sample was slow to
// arrive, increase the amount of audio we buffer to ensure that we
// don't run out of audio. This is unnecessary for async readers,
// since they decode audio and video on different threads so they
// are unlikely to run out of decoded audio.
if (mReader->IsAsync()) {
return;
}
TimeDuration decodeTime = TimeStamp::Now() - mVideoDecodeStartTime;
if (THRESHOLD_FACTOR * DurationToUsecs(decodeTime) > mLowAudioThresholdUsecs &&
!HasLowUndecodedData())

View File

@ -109,12 +109,12 @@ template <class T> class MediaQueue : private nsDeque {
// Returns the approximate number of microseconds of items in the queue.
int64_t Duration() {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (GetSize() < 2) {
if (GetSize() == 0) {
return 0;
}
T* last = Peek();
T* first = PeekFront();
return last->mTime - first->mTime;
return last->GetEndTime() - first->mTime;
}
void LockedForEach(nsDequeFunctor& aFunctor) const {

View File

@ -82,6 +82,8 @@ public:
virtual nsRefPtr<ShutdownPromise> Shutdown() MOZ_OVERRIDE;
virtual bool IsAsync() const MOZ_OVERRIDE { return true; }
private:
bool InitDemuxer();

View File

@ -180,7 +180,7 @@ GeckoMediaPluginService::Init()
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, "profile-change-teardown", false)));
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false)));
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, "last-pb-context-exited", false)));
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, "gmp-clear-storage", false)));
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, "browser:purge-session-history", false)));
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (prefs) {
@ -324,11 +324,23 @@ GeckoMediaPluginService::Observe(nsISupports* aSubject,
// mode, we'll get the NodeId salt stored on-disk, and if we try to
// open a PB mode origin-pair, we'll re-generate new salt.
mTempNodeIds.Clear();
} else if (!strcmp("gmp-clear-storage", aTopic)) {
nsresult rv = GMPDispatch(
NS_NewRunnableMethod(this, &GeckoMediaPluginService::ClearStorage));
NS_ENSURE_SUCCESS(rv, rv);
} else if (!strcmp("browser:purge-session-history", aTopic)) {
// Clear everything!
if (!aSomeData || nsDependentString(aSomeData).IsEmpty()) {
return GMPDispatch(NS_NewRunnableMethod(
this, &GeckoMediaPluginService::ClearStorage));
}
// Clear nodeIds/records modified after |t|.
nsresult rv;
PRTime t = nsDependentString(aSomeData).ToInteger64(&rv, 10);
if (NS_FAILED(rv)) {
return rv;
}
return GMPDispatch(NS_NewRunnableMethodWithArg<PRTime>(
this, &GeckoMediaPluginService::ClearRecentHistoryOnGMPThread, t));
}
return NS_OK;
}
@ -1213,46 +1225,53 @@ private:
};
void
GeckoMediaPluginService::ForgetThisSiteOnGMPThread(const nsACString& aOrigin)
GeckoMediaPluginService::ClearNodeIdAndPlugin(DirectoryFilter& aFilter)
{
#define ERR_RET(x) NS_ENSURE_SUCCESS_VOID(x)
#define ERR_CONT(x) if (NS_FAILED(x)) { continue; }
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
LOGD(("%s::%s: origin=%s", __CLASS__, __FUNCTION__, aOrigin.Data()));
nsresult rv;
nsCOMPtr<nsIFile> path;
// $profileDir/gmp/
ERR_RET(GetStorageDir(getter_AddRefs(path)));
rv = GetStorageDir(getter_AddRefs(path));
if (NS_FAILED(rv)) {
return;
}
// $profileDir/gmp/id/
ERR_RET(path->AppendNative(NS_LITERAL_CSTRING("id")));
rv = path->AppendNative(NS_LITERAL_CSTRING("id"));
if (NS_FAILED(rv)) {
return;
}
// Iterate all sub-folders of $profileDir/gmp/id/
nsCOMPtr<nsISimpleEnumerator> iter;
ERR_RET(path->GetDirectoryEntries(getter_AddRefs(iter)));
rv = path->GetDirectoryEntries(getter_AddRefs(iter));
if (NS_FAILED(rv)) {
return;
}
bool hasMore = false;
nsTArray<nsCString> nodeIDsToClear;
while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
nsCOMPtr<nsISupports> supports;
ERR_CONT(iter->GetNext(getter_AddRefs(supports)));
// $profileDir/gmp/id/$hash
nsCOMPtr<nsIFile> dirEntry(do_QueryInterface(supports, &rv));
ERR_CONT(rv);
// Skip non-directory files.
bool isDirectory = false;
ERR_CONT(dirEntry->IsDirectory(&isDirectory));
if (!isDirectory) {
rv = iter->GetNext(getter_AddRefs(supports));
if (NS_FAILED(rv)) {
continue;
}
// Check if origin or topLevelOrigin match the origin being forgotten.
if (!MatchOrigin(dirEntry, aOrigin)) {
// $profileDir/gmp/id/$hash
nsCOMPtr<nsIFile> dirEntry(do_QueryInterface(supports, &rv));
if (NS_FAILED(rv)) {
continue;
}
// Skip non-directory files.
bool isDirectory = false;
rv = dirEntry->IsDirectory(&isDirectory);
if (NS_FAILED(rv) || !isDirectory) {
continue;
}
if (!aFilter(dirEntry)) {
continue;
}
@ -1273,28 +1292,50 @@ GeckoMediaPluginService::ForgetThisSiteOnGMPThread(const nsACString& aOrigin)
KillPlugins(mPlugins, mMutex, NodeFilter(nodeIDsToClear));
// Clear all matching $profileDir/gmp/storage/$nodeId/
ERR_RET(GetStorageDir(getter_AddRefs(path)));
ERR_RET(path->AppendNative(NS_LITERAL_CSTRING("storage")));
rv = GetStorageDir(getter_AddRefs(path));
if (NS_FAILED(rv)) {
return;
}
rv = path->AppendNative(NS_LITERAL_CSTRING("storage"));
if (NS_FAILED(rv)) {
return;
}
for (size_t i = 0; i < nodeIDsToClear.Length(); i++) {
nsCOMPtr<nsIFile> dirEntry;
ERR_CONT(path->Clone(getter_AddRefs(dirEntry)));
ERR_CONT(dirEntry->AppendNative(nodeIDsToClear[i]));
rv = path->Clone(getter_AddRefs(dirEntry));
if (NS_FAILED(rv)) {
continue;
}
rv = dirEntry->AppendNative(nodeIDsToClear[i]);
if (NS_FAILED(rv)) {
continue;
}
if (NS_FAILED(DeleteDir(dirEntry))) {
NS_WARNING("Failed to delete GMP storage directory for the node");
}
}
#undef ERR_RET
#undef ERR_CONT
}
NS_IMETHODIMP
GeckoMediaPluginService::ForgetThisSite(const nsAString& aOrigin)
void
GeckoMediaPluginService::ForgetThisSiteOnGMPThread(const nsACString& aOrigin)
{
MOZ_ASSERT(NS_IsMainThread());
return GMPDispatch(NS_NewRunnableMethodWithArg<nsCString>(
this, &GeckoMediaPluginService::ForgetThisSiteOnGMPThread,
NS_ConvertUTF16toUTF8(aOrigin)));
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
LOGD(("%s::%s: origin=%s", __CLASS__, __FUNCTION__, aOrigin.Data()));
struct OriginFilter : public DirectoryFilter {
explicit OriginFilter(const nsACString& aOrigin) : mOrigin(aOrigin) {}
virtual bool operator()(nsIFile* aPath) {
return MatchOrigin(aPath, mOrigin);
}
private:
const nsACString& mOrigin;
} filter(aOrigin);
ClearNodeIdAndPlugin(filter);
}
class StorageClearedTask : public nsRunnable {
@ -1310,6 +1351,102 @@ public:
}
};
void
GeckoMediaPluginService::ClearRecentHistoryOnGMPThread(PRTime aSince)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
LOGD(("%s::%s: since=%lld", __CLASS__, __FUNCTION__, (int64_t)aSince));
nsCOMPtr<nsIFile> storagePath;
nsCOMPtr<nsIFile> temp;
if (NS_SUCCEEDED(GetStorageDir(getter_AddRefs(temp))) &&
NS_SUCCEEDED(temp->AppendNative(NS_LITERAL_CSTRING("storage")))) {
storagePath = temp.forget();
}
struct MTimeFilter : public DirectoryFilter {
explicit MTimeFilter(PRTime aSince, already_AddRefed<nsIFile> aPath)
: mSince(aSince), mStoragePath(aPath) {}
// Return true if any files under aPath is modified after |mSince|.
bool IsModifiedAfter(nsIFile* aPath) {
PRTime lastModified;
nsresult rv = aPath->GetLastModifiedTime(&lastModified);
if (NS_SUCCEEDED(rv) && lastModified >= mSince) {
return true;
}
// Check sub-directories recursively
nsCOMPtr<nsISimpleEnumerator> iter;
rv = aPath->GetDirectoryEntries(getter_AddRefs(iter));
if (NS_FAILED(rv)) {
return false;
}
bool hasMore = false;
while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
nsCOMPtr<nsISupports> supports;
rv = iter->GetNext(getter_AddRefs(supports));
if (NS_FAILED(rv)) {
continue;
}
nsCOMPtr<nsIFile> path(do_QueryInterface(supports, &rv));
if (NS_FAILED(rv)) {
continue;
}
if (IsModifiedAfter(path)) {
return true;
}
}
return false;
}
// |aPath| is $profileDir/gmp/id/$hash
virtual bool operator()(nsIFile* aPath) {
if (IsModifiedAfter(aPath)) {
return true;
}
nsAutoCString salt;
nsresult rv = ReadSalt(aPath, salt);
if (NS_FAILED(rv)) {
return false;
}
// $profileDir/gmp/storage/
if (!mStoragePath) {
return false;
}
// $profileDir/gmp/storage/$nodeId/
nsCOMPtr<nsIFile> path;
rv = mStoragePath->Clone(getter_AddRefs(path));
if (NS_FAILED(rv)) {
return false;
}
rv = path->AppendNative(salt);
return NS_SUCCEEDED(rv) && IsModifiedAfter(path);
}
private:
const PRTime mSince;
const nsCOMPtr<nsIFile> mStoragePath;
} filter(aSince, storagePath.forget());
ClearNodeIdAndPlugin(filter);
NS_DispatchToMainThread(new StorageClearedTask(), NS_DISPATCH_NORMAL);
}
NS_IMETHODIMP
GeckoMediaPluginService::ForgetThisSite(const nsAString& aOrigin)
{
MOZ_ASSERT(NS_IsMainThread());
return GMPDispatch(NS_NewRunnableMethodWithArg<nsCString>(
this, &GeckoMediaPluginService::ForgetThisSiteOnGMPThread,
NS_ConvertUTF16toUTF8(aOrigin)));
}
static bool IsNodeIdValid(GMPParent* aParent) {
return !aParent->GetNodeId().IsEmpty();
}

View File

@ -76,7 +76,14 @@ private:
nsresult SetAsyncShutdownTimeout();
struct DirectoryFilter {
virtual bool operator()(nsIFile* aPath) = 0;
~DirectoryFilter() {}
};
void ClearNodeIdAndPlugin(DirectoryFilter& aFilter);
void ForgetThisSiteOnGMPThread(const nsACString& aOrigin);
void ClearRecentHistoryOnGMPThread(PRTime aSince);
protected:
friend class GMPParent;

View File

@ -120,25 +120,18 @@ GetGMPThread()
return thread.forget();
}
/**
* Enumerate files under |aPath| (non-recursive).
*/
template<typename T>
static nsresult
EnumerateDir(const nsACString& aDir, T&& aDirIter)
EnumerateDir(nsIFile* aPath, T&& aDirIter)
{
nsRefPtr<GeckoMediaPluginService> service =
GeckoMediaPluginService::GetGeckoMediaPluginService();
MOZ_ASSERT(service);
// $profileDir/gmp/
nsCOMPtr<nsIFile> path;
nsresult rv = service->GetStorageDir(getter_AddRefs(path));
NS_ENSURE_SUCCESS(rv, rv);
// $profileDir/gmp/$aDir/
rv = path->AppendNative(aDir);
NS_ENSURE_SUCCESS(rv, rv);
// Iterate all sub-folders of $profileDir/gmp/$aDir/
nsCOMPtr<nsISimpleEnumerator> iter;
rv = path->GetDirectoryEntries(getter_AddRefs(iter));
NS_ENSURE_SUCCESS(rv, rv);
nsresult rv = aPath->GetDirectoryEntries(getter_AddRefs(iter));
if (NS_FAILED(rv)) {
return rv;
}
bool hasMore = false;
while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
@ -147,15 +140,44 @@ EnumerateDir(const nsACString& aDir, T&& aDirIter)
if (NS_FAILED(rv)) {
continue;
}
nsCOMPtr<nsIFile> entry(do_QueryInterface(supports, &rv));
if (NS_FAILED(rv)) {
continue;
}
aDirIter(entry);
}
return NS_OK;
}
/**
* Enumerate files under $profileDir/gmp/$aDir/ (non-recursive).
*/
template<typename T>
static nsresult
EnumerateGMPStorageDir(const nsACString& aDir, T&& aDirIter)
{
nsRefPtr<GeckoMediaPluginService> service =
GeckoMediaPluginService::GetGeckoMediaPluginService();
MOZ_ASSERT(service);
// $profileDir/gmp/
nsCOMPtr<nsIFile> path;
nsresult rv = service->GetStorageDir(getter_AddRefs(path));
if (NS_FAILED(rv)) {
return rv;
}
// $profileDir/gmp/$aDir/
rv = path->AppendNative(aDir);
if (NS_FAILED(rv)) {
return rv;
}
return EnumerateDir(path, aDirIter);
}
class GMPShutdownObserver : public nsIRunnable
, public nsIObserver {
public:
@ -227,9 +249,10 @@ class ClearGMPStorageTask : public nsIRunnable
, public nsIObserver {
public:
ClearGMPStorageTask(nsIRunnable* Continuation,
nsIThread* aTarget)
nsIThread* aTarget, PRTime aSince)
: mContinuation(Continuation)
, mTarget(aTarget)
, mSince(aSince)
{}
NS_DECL_THREADSAFE_ISUPPORTS
@ -241,7 +264,12 @@ public:
EXPECT_TRUE(observerService);
observerService->AddObserver(this, "gmp-clear-storage-complete", false);
if (observerService) {
observerService->NotifyObservers(nullptr, "gmp-clear-storage", nullptr);
nsAutoString str;
if (mSince >= 0) {
str.AppendInt(static_cast<int64_t>(mSince));
}
observerService->NotifyObservers(
nullptr, "browser:purge-session-history", str.Data());
}
return NS_OK;
}
@ -264,15 +292,17 @@ private:
virtual ~ClearGMPStorageTask() {}
nsRefPtr<nsIRunnable> mContinuation;
nsCOMPtr<nsIThread> mTarget;
const PRTime mSince;
};
NS_IMPL_ISUPPORTS(ClearGMPStorageTask, nsIRunnable, nsIObserver)
static void
ClearGMPStorage(nsIRunnable* aContinuation,
nsIThread* aTarget)
nsIThread* aTarget, PRTime aSince = -1)
{
nsRefPtr<ClearGMPStorageTask> task(new ClearGMPStorageTask(aContinuation, aTarget));
nsRefPtr<ClearGMPStorageTask> task(
new ClearGMPStorageTask(aContinuation, aTarget, aSince));
NS_DispatchToMainThread(task, NS_DISPATCH_NORMAL);
}
@ -508,7 +538,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
nsAutoPtr<NodeInfo> siteInfo(
new NodeInfo(NS_LITERAL_CSTRING("example1.com")));
// Collect nodeIds that are expected to remain for later comparison.
EnumerateDir(NS_LITERAL_CSTRING("id"), NodeIdCollector(siteInfo));
EnumerateGMPStorageDir(NS_LITERAL_CSTRING("id"), NodeIdCollector(siteInfo));
// Invoke "Forget this site" on the main thread.
NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<nsAutoPtr<NodeInfo>>(
this, &GMPStorageTest::TestForgetThisSite_Forget, siteInfo));
@ -571,15 +601,176 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
};
void TestForgetThisSite_Verify(nsAutoPtr<NodeInfo> aSiteInfo) {
nsresult rv = EnumerateDir(
nsresult rv = EnumerateGMPStorageDir(
NS_LITERAL_CSTRING("id"), NodeIdVerifier(aSiteInfo));
EXPECT_TRUE(NS_SUCCEEDED(rv));
rv = EnumerateDir(
rv = EnumerateGMPStorageDir(
NS_LITERAL_CSTRING("storage"), StorageVerifier(aSiteInfo));
EXPECT_TRUE(NS_SUCCEEDED(rv));
}
/**
* 1. Generate some storage data.
* 2. Find the max mtime |t| in $profileDir/gmp/id/.
* 3. Pass |t| to clear recent history.
* 4. Check if all directories in $profileDir/gmp/id/ and
* $profileDir/gmp/storage are removed.
*/
void TestClearRecentHistory1() {
AssertIsOnGMPThread();
EXPECT_TRUE(IsGMPStorageIsEmpty());
// Generate storage data for some site.
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
NS_LITERAL_STRING("example2.com"),
false);
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
this, &GMPStorageTest::TestClearRecentHistory1_Clear);
Expect(NS_LITERAL_CSTRING("test-storage complete"), r);
Update(NS_LITERAL_CSTRING("test-storage"));
}
/**
* 1. Generate some storage data.
* 2. Find the max mtime |t| in $profileDir/gmp/storage/.
* 3. Pass |t| to clear recent history.
* 4. Check if all directories in $profileDir/gmp/id/ and
* $profileDir/gmp/storage are removed.
*/
void TestClearRecentHistory2() {
AssertIsOnGMPThread();
EXPECT_TRUE(IsGMPStorageIsEmpty());
// Generate storage data for some site.
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
NS_LITERAL_STRING("example2.com"),
false);
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
this, &GMPStorageTest::TestClearRecentHistory2_Clear);
Expect(NS_LITERAL_CSTRING("test-storage complete"), r);
Update(NS_LITERAL_CSTRING("test-storage"));
}
/**
* 1. Generate some storage data.
* 2. Find the max mtime |t| in $profileDir/gmp/storage/.
* 3. Pass |t+1| to clear recent history.
* 4. Check if all directories in $profileDir/gmp/id/ and
* $profileDir/gmp/storage remain unchanged.
*/
void TestClearRecentHistory3() {
AssertIsOnGMPThread();
EXPECT_TRUE(IsGMPStorageIsEmpty());
// Generate storage data for some site.
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
NS_LITERAL_STRING("example2.com"),
false);
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
this, &GMPStorageTest::TestClearRecentHistory3_Clear);
Expect(NS_LITERAL_CSTRING("test-storage complete"), r);
Update(NS_LITERAL_CSTRING("test-storage"));
}
class MaxMTimeFinder {
public:
MaxMTimeFinder() : mMaxTime(0) {}
void operator()(nsIFile* aFile) {
PRTime lastModified;
nsresult rv = aFile->GetLastModifiedTime(&lastModified);
if (NS_SUCCEEDED(rv) && lastModified > mMaxTime) {
mMaxTime = lastModified;
}
EnumerateDir(aFile, *this);
}
PRTime GetResult() const { return mMaxTime; }
private:
PRTime mMaxTime;
};
void TestClearRecentHistory1_Clear() {
MaxMTimeFinder f;
nsresult rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("id"), f);
EXPECT_TRUE(NS_SUCCEEDED(rv));
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
this, &GMPStorageTest::TestClearRecentHistory_CheckEmpty);
nsCOMPtr<nsIThread> t(GetGMPThread());
ClearGMPStorage(r, t, f.GetResult());
}
void TestClearRecentHistory2_Clear() {
MaxMTimeFinder f;
nsresult rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("storage"), f);
EXPECT_TRUE(NS_SUCCEEDED(rv));
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
this, &GMPStorageTest::TestClearRecentHistory_CheckEmpty);
nsCOMPtr<nsIThread> t(GetGMPThread());
ClearGMPStorage(r, t, f.GetResult());
}
void TestClearRecentHistory3_Clear() {
MaxMTimeFinder f;
nsresult rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("storage"), f);
EXPECT_TRUE(NS_SUCCEEDED(rv));
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
this, &GMPStorageTest::TestClearRecentHistory_CheckNonEmpty);
nsCOMPtr<nsIThread> t(GetGMPThread());
ClearGMPStorage(r, t, f.GetResult() + 1);
}
class FileCounter {
public:
FileCounter() : mCount(0) {}
void operator()(nsIFile* aFile) {
++mCount;
}
int GetCount() const { return mCount; }
private:
int mCount;
};
void TestClearRecentHistory_CheckEmpty() {
FileCounter c1;
nsresult rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("id"), c1);
EXPECT_TRUE(NS_SUCCEEDED(rv));
// There should be no files under $profileDir/gmp/id/
EXPECT_EQ(c1.GetCount(), 0);
FileCounter c2;
rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("storage"), c2);
EXPECT_TRUE(NS_SUCCEEDED(rv));
// There should be no files under $profileDir/gmp/storage/
EXPECT_EQ(c2.GetCount(), 0);
SetFinished();
}
void TestClearRecentHistory_CheckNonEmpty() {
FileCounter c1;
nsresult rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("id"), c1);
EXPECT_TRUE(NS_SUCCEEDED(rv));
// There should be one directory under $profileDir/gmp/id/
EXPECT_EQ(c1.GetCount(), 1);
FileCounter c2;
rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("storage"), c2);
EXPECT_TRUE(NS_SUCCEEDED(rv));
// There should be one directory under $profileDir/gmp/storage/
EXPECT_EQ(c2.GetCount(), 1);
SetFinished();
}
void TestCrossOriginStorage() {
EXPECT_TRUE(!mDecryptor);
@ -991,6 +1182,21 @@ TEST(GeckoMediaPlugins, GMPStorageForgetThisSite) {
runner->DoTest(&GMPStorageTest::TestForgetThisSite);
}
TEST(GeckoMediaPlugins, GMPStorageClearRecentHistory1) {
nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
runner->DoTest(&GMPStorageTest::TestClearRecentHistory1);
}
TEST(GeckoMediaPlugins, GMPStorageClearRecentHistory2) {
nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
runner->DoTest(&GMPStorageTest::TestClearRecentHistory2);
}
TEST(GeckoMediaPlugins, GMPStorageClearRecentHistory3) {
nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
runner->DoTest(&GMPStorageTest::TestClearRecentHistory3);
}
TEST(GeckoMediaPlugins, GMPStorageCrossOrigin) {
nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
runner->DoTest(&GMPStorageTest::TestCrossOriginStorage);

View File

@ -130,6 +130,11 @@ public:
nsresult SetCDMProxy(CDMProxy* aProxy);
#endif
virtual bool IsAsync() const MOZ_OVERRIDE {
return (!mAudioReader || mAudioReader->IsAsync()) &&
(!mVideoReader || mVideoReader->IsAsync());
}
private:
// Switch the current audio/video reader to the reader that
// contains aTarget (or up to aError after target). Both

Some files were not shown because too many files have changed in this diff Show More