mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-13 05:15:45 +00:00
Merge m-c to fx-team a=merge
This commit is contained in:
commit
805b38ff92
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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}
|
||||
|
||||
|
87
b2g/components/B2GPresentationDevicePrompt.js
Normal file
87
b2g/components/B2GPresentationDevicePrompt.js
Normal 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]);
|
@ -11,6 +11,7 @@ EXTRA_COMPONENTS += [
|
||||
'AlertsService.js',
|
||||
'B2GAboutRedirector.js',
|
||||
'B2GAppMigrator.js',
|
||||
'B2GPresentationDevicePrompt.js',
|
||||
'ContentPermissionPrompt.js',
|
||||
'FilePicker.js',
|
||||
'FxAccountsUIGlue.js',
|
||||
|
@ -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]
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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>
|
@ -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,
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "fe8bc669500de4e81dc5e1e0ef4e044222bdbeaa",
|
||||
"revision": "6d459c49070f4c80bf97795e86369ab2eb765c36",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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
|
||||
|
@ -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) { }
|
||||
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -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");
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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">
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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() {}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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': {
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -73,7 +73,7 @@ public:
|
||||
return mData;
|
||||
}
|
||||
|
||||
JSObject* WrapObject(JSContext* cx);
|
||||
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
|
||||
|
||||
private:
|
||||
void HoldData();
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -35,7 +35,7 @@ public:
|
||||
retval = mName;
|
||||
}
|
||||
|
||||
JSObject* WrapObject(JSContext* cx);
|
||||
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(WebGLActiveInfo)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -104,6 +104,8 @@ public:
|
||||
void
|
||||
SetBody(nsIInputStream* aBody)
|
||||
{
|
||||
// A request's body may not be reset once set.
|
||||
MOZ_ASSERT(!mBody);
|
||||
mBody = aBody;
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -140,8 +140,8 @@ public:
|
||||
DropJSObjects();
|
||||
|
||||
// WebIDL
|
||||
JSObject*
|
||||
WrapObject(JSContext* aCx);
|
||||
bool
|
||||
WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
|
||||
|
||||
nsISupports*
|
||||
GetParentObject() const
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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())
|
||||
|
@ -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 {
|
||||
|
@ -82,6 +82,8 @@ public:
|
||||
|
||||
virtual nsRefPtr<ShutdownPromise> Shutdown() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool IsAsync() const MOZ_OVERRIDE { return true; }
|
||||
|
||||
private:
|
||||
|
||||
bool InitDemuxer();
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user