mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
Merge remote-tracking branch 'origin/master' into media-works
This commit is contained in:
+4
-5
@@ -366,11 +366,6 @@ pref("security.apps.certified.CSP.default", "default-src * data: blob:; script-s
|
||||
// Default Content Security Policy to apply to trusted apps.
|
||||
pref("security.apps.trusted.CSP.default", "default-src * data: blob:; object-src 'none'; frame-src 'none'");
|
||||
|
||||
// Temporarily force-enable GL compositing. This is default-disabled
|
||||
// deep within the bowels of the widgetry system. Remove me when GL
|
||||
// compositing isn't default disabled in widget/android.
|
||||
pref("layers.acceleration.force-enabled", true);
|
||||
|
||||
// handle links targeting new windows
|
||||
// 1=current window/tab, 2=new window, 3=new tab in most recent window
|
||||
pref("browser.link.open_newwindow", 3);
|
||||
@@ -939,6 +934,10 @@ pref("network.proxy.browsing.app_origins", "app://system.gaiamobile.org");
|
||||
// Enable Web Speech synthesis API
|
||||
pref("media.webspeech.synth.enabled", true);
|
||||
|
||||
// Enable Web Speech recognition API
|
||||
pref("media.webspeech.recognition.enable", true);
|
||||
pref("media.webspeech.service.default", "pocketsphinx");
|
||||
|
||||
// Downloads API
|
||||
pref("dom.mozDownloads.enabled", true);
|
||||
pref("dom.downloads.max_retention_days", 7);
|
||||
|
||||
@@ -28,6 +28,17 @@ NSS_DISABLE_DBM=1
|
||||
MOZ_NO_EV_CERTS=1
|
||||
MOZ_DISABLE_EXPORT_JS=1
|
||||
|
||||
# Bug 1171082 - Broken on Windows B2G Desktop
|
||||
if test "$OS_TARGET" != "WINNT"; then
|
||||
MOZ_WEBSPEECH=1
|
||||
|
||||
if test -n "$NIGHTLY_BUILD"; then
|
||||
MOZ_WEBSPEECH_MODELS=1
|
||||
MOZ_WEBSPEECH_POCKETSPHINX=1
|
||||
fi # NIGHTLY_BUILD
|
||||
MOZ_WEBSPEECH_TEST_BACKEND=1
|
||||
fi # !WINNT
|
||||
|
||||
if test "$OS_TARGET" = "Android"; then
|
||||
MOZ_CAPTURE=1
|
||||
MOZ_RAW=1
|
||||
|
||||
@@ -137,6 +137,9 @@
|
||||
@RESPATH@/run-mozilla.sh
|
||||
#endif
|
||||
#endif
|
||||
#ifdef MOZ_WEBSPEECH_MODELS
|
||||
@BINPATH@/models/
|
||||
#endif
|
||||
|
||||
; [Components]
|
||||
@RESPATH@/components/components.manifest
|
||||
|
||||
@@ -857,7 +857,7 @@ function onBlockImage()
|
||||
if (checkbox.checked)
|
||||
permissionManager.add(uri, "image", nsIPermissionManager.DENY_ACTION);
|
||||
else
|
||||
permissionManager.remove(uri.host, "image");
|
||||
permissionManager.remove(uri, "image");
|
||||
}
|
||||
|
||||
function onImageSelect()
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
let gHttpTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||
let gPageInfo = null;
|
||||
let gNextTest = null;
|
||||
let gTestBrowser = null;
|
||||
let gPluginHost = Components.classes["@mozilla.org/plugin/host;1"]
|
||||
.getService(Components.interfaces.nsIPluginHost);
|
||||
let gPermissionManager = Components.classes["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Components.interfaces.nsIPermissionManager);
|
||||
let gTestPermissionString = gPluginHost.getPermissionStringForType("application/x-test");
|
||||
let gSecondTestPermissionString = gPluginHost.getPermissionStringForType("application/x-second-test");
|
||||
|
||||
function doOnPageLoad(url, continuation) {
|
||||
gNextTest = continuation;
|
||||
gTestBrowser.addEventListener("load", pageLoad, true);
|
||||
gTestBrowser.contentWindow.location = url;
|
||||
}
|
||||
|
||||
function pageLoad() {
|
||||
gTestBrowser.removeEventListener("load", pageLoad);
|
||||
// The plugin events are async dispatched and can come after the load event
|
||||
// This just allows the events to fire before we then go on to test the states
|
||||
executeSoon(gNextTest);
|
||||
}
|
||||
|
||||
function doOnOpenPageInfo(continuation) {
|
||||
Services.obs.addObserver(pageInfoObserve, "page-info-dialog-loaded", false);
|
||||
gNextTest = continuation;
|
||||
// An explanation: it looks like the test harness complains about leaked
|
||||
// windows if we don't keep a reference to every window we've opened.
|
||||
// So, don't reuse pointers to opened Page Info windows - simply append
|
||||
// to this list.
|
||||
gPageInfo = BrowserPageInfo(null, "permTab");
|
||||
}
|
||||
|
||||
function pageInfoObserve(win, topic, data) {
|
||||
Services.obs.removeObserver(pageInfoObserve, "page-info-dialog-loaded");
|
||||
executeSoon(gNextTest);
|
||||
}
|
||||
|
||||
function finishTest() {
|
||||
gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gTestPermissionString);
|
||||
gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gSecondTestPermissionString);
|
||||
Services.prefs.clearUserPref("plugins.click_to_play");
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
gPageInfo = null;
|
||||
gNextTest = null;
|
||||
gTestBrowser = null;
|
||||
gPluginHost = null;
|
||||
gPermissionManager = null;
|
||||
|
||||
executeSoon(finish);
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gTestBrowser = gBrowser.selectedBrowser;
|
||||
gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gTestPermissionString);
|
||||
gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gSecondTestPermissionString);
|
||||
doOnPageLoad(gHttpTestRoot + "plugin_two_types.html", testPart1a);
|
||||
}
|
||||
|
||||
// The first test plugin is CtP and the second test plugin is enabled.
|
||||
function testPart1a() {
|
||||
let test = gTestBrowser.contentDocument.getElementById("test");
|
||||
let objLoadingContent = test.QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
ok(!objLoadingContent.activated, "part 1a: Test plugin should not be activated");
|
||||
let secondtest = gTestBrowser.contentDocument.getElementById("secondtestA");
|
||||
objLoadingContent = secondtest.QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
ok(objLoadingContent.activated, "part 1a: Second Test plugin should be activated");
|
||||
|
||||
doOnOpenPageInfo(testPart1b);
|
||||
}
|
||||
|
||||
function testPart1b() {
|
||||
let testRadioGroup = gPageInfo.document.getElementById(gTestPermissionString + "RadioGroup");
|
||||
let testRadioDefault = gPageInfo.document.getElementById(gTestPermissionString + "#0");
|
||||
|
||||
var qString = "#" + gTestPermissionString.replace(':', '\\:') + "\\#0";
|
||||
is(testRadioGroup.selectedItem, testRadioDefault, "part 1b: Test radio group should be set to 'Default'");
|
||||
let testRadioAllow = gPageInfo.document.getElementById(gTestPermissionString + "#1");
|
||||
testRadioGroup.selectedItem = testRadioAllow;
|
||||
testRadioAllow.doCommand();
|
||||
|
||||
let secondtestRadioGroup = gPageInfo.document.getElementById(gSecondTestPermissionString + "RadioGroup");
|
||||
let secondtestRadioDefault = gPageInfo.document.getElementById(gSecondTestPermissionString + "#0");
|
||||
is(secondtestRadioGroup.selectedItem, secondtestRadioDefault, "part 1b: Second Test radio group should be set to 'Default'");
|
||||
let secondtestRadioAsk = gPageInfo.document.getElementById(gSecondTestPermissionString + "#3");
|
||||
secondtestRadioGroup.selectedItem = secondtestRadioAsk;
|
||||
secondtestRadioAsk.doCommand();
|
||||
|
||||
doOnPageLoad(gHttpTestRoot + "plugin_two_types.html", testPart2);
|
||||
}
|
||||
|
||||
// Now, the Test plugin should be allowed, and the Test2 plugin should be CtP
|
||||
function testPart2() {
|
||||
let test = gTestBrowser.contentDocument.getElementById("test").
|
||||
QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
ok(test.activated, "part 2: Test plugin should be activated");
|
||||
|
||||
let secondtest = gTestBrowser.contentDocument.getElementById("secondtestA").
|
||||
QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
ok(!secondtest.activated, "part 2: Second Test plugin should not be activated");
|
||||
is(secondtest.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
|
||||
"part 2: Second test plugin should be click-to-play.");
|
||||
|
||||
let testRadioGroup = gPageInfo.document.getElementById(gTestPermissionString + "RadioGroup");
|
||||
let testRadioAllow = gPageInfo.document.getElementById(gTestPermissionString + "#1");
|
||||
is(testRadioGroup.selectedItem, testRadioAllow, "part 2: Test radio group should be set to 'Allow'");
|
||||
let testRadioBlock = gPageInfo.document.getElementById(gTestPermissionString + "#2");
|
||||
testRadioGroup.selectedItem = testRadioBlock;
|
||||
testRadioBlock.doCommand();
|
||||
|
||||
let secondtestRadioGroup = gPageInfo.document.getElementById(gSecondTestPermissionString + "RadioGroup");
|
||||
let secondtestRadioAsk = gPageInfo.document.getElementById(gSecondTestPermissionString + "#3");
|
||||
is(secondtestRadioGroup.selectedItem, secondtestRadioAsk, "part 2: Second Test radio group should be set to 'Always Ask'");
|
||||
let secondtestRadioBlock = gPageInfo.document.getElementById(gSecondTestPermissionString + "#2");
|
||||
secondtestRadioGroup.selectedItem = secondtestRadioBlock;
|
||||
secondtestRadioBlock.doCommand();
|
||||
|
||||
doOnPageLoad(gHttpTestRoot + "plugin_two_types.html", testPart3);
|
||||
}
|
||||
|
||||
// Now, all the things should be blocked
|
||||
function testPart3() {
|
||||
let test = gTestBrowser.contentDocument.getElementById("test").
|
||||
QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
ok(!test.activated, "part 3: Test plugin should not be activated");
|
||||
is(test.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_DISABLED,
|
||||
"part 3: Test plugin should be marked as PLUGIN_DISABLED");
|
||||
|
||||
let secondtest = gTestBrowser.contentDocument.getElementById("secondtestA").
|
||||
QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
|
||||
ok(!secondtest.activated, "part 3: Second Test plugin should not be activated");
|
||||
is(secondtest.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_DISABLED,
|
||||
"part 3: Second test plugin should be marked as PLUGIN_DISABLED");
|
||||
|
||||
// reset permissions
|
||||
gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gTestPermissionString);
|
||||
gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gSecondTestPermissionString);
|
||||
// check that changing the permissions affects the radio state in the
|
||||
// open Page Info window
|
||||
let testRadioGroup = gPageInfo.document.getElementById(gTestPermissionString + "RadioGroup");
|
||||
let testRadioDefault = gPageInfo.document.getElementById(gTestPermissionString + "#0");
|
||||
is(testRadioGroup.selectedItem, testRadioDefault, "part 3: Test radio group should be set to 'Default'");
|
||||
let secondtestRadioGroup = gPageInfo.document.getElementById(gSecondTestPermissionString + "RadioGroup");
|
||||
let secondtestRadioDefault = gPageInfo.document.getElementById(gSecondTestPermissionString + "#0");
|
||||
is(secondtestRadioGroup.selectedItem, secondtestRadioDefault, "part 3: Second Test radio group should be set to 'Default'");
|
||||
|
||||
doOnPageLoad(gHttpTestRoot + "plugin_two_types.html", testPart4a);
|
||||
}
|
||||
|
||||
// Now test that setting permission directly (as from the popup notification)
|
||||
// immediately influences Page Info.
|
||||
function testPart4a() {
|
||||
// simulate "allow" from the doorhanger
|
||||
gPermissionManager.add(gTestBrowser.currentURI, gTestPermissionString, Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
gPermissionManager.add(gTestBrowser.currentURI, gSecondTestPermissionString, Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
|
||||
// check (again) that changing the permissions affects the radio state in the
|
||||
// open Page Info window
|
||||
let testRadioGroup = gPageInfo.document.getElementById(gTestPermissionString + "RadioGroup");
|
||||
let testRadioAllow = gPageInfo.document.getElementById(gTestPermissionString + "#1");
|
||||
is(testRadioGroup.selectedItem, testRadioAllow, "part 4a: Test radio group should be set to 'Allow'");
|
||||
let secondtestRadioGroup = gPageInfo.document.getElementById(gSecondTestPermissionString + "RadioGroup");
|
||||
let secondtestRadioAllow = gPageInfo.document.getElementById(gSecondTestPermissionString + "#1");
|
||||
is(secondtestRadioGroup.selectedItem, secondtestRadioAllow, "part 4a: Second Test radio group should be set to 'Always Allow'");
|
||||
|
||||
// now close Page Info and see that it opens with the right settings
|
||||
gPageInfo.close();
|
||||
doOnOpenPageInfo(testPart4b);
|
||||
}
|
||||
|
||||
// check that "always allow" resulted in the radio buttons getting set to allow
|
||||
function testPart4b() {
|
||||
let testRadioGroup = gPageInfo.document.getElementById(gTestPermissionString + "RadioGroup");
|
||||
let testRadioAllow = gPageInfo.document.getElementById(gTestPermissionString + "#1");
|
||||
is(testRadioGroup.selectedItem, testRadioAllow, "part 4b: Test radio group should be set to 'Allow'");
|
||||
|
||||
let secondtestRadioGroup = gPageInfo.document.getElementById(gSecondTestPermissionString + "RadioGroup");
|
||||
let secondtestRadioAllow = gPageInfo.document.getElementById(gSecondTestPermissionString + "#1");
|
||||
is(secondtestRadioGroup.selectedItem, secondtestRadioAllow, "part 4b: Second Test radio group should be set to 'Allow'");
|
||||
|
||||
Services.prefs.setBoolPref("plugins.click_to_play", false);
|
||||
gPageInfo.close();
|
||||
finishTest();
|
||||
}
|
||||
@@ -200,7 +200,7 @@ Site.prototype = {
|
||||
* e.g. "cookie", "geo", "indexedDB", "popup", "image"
|
||||
*/
|
||||
clearPermission: function Site_clearPermission(aType) {
|
||||
Services.perms.remove(this.host, aType);
|
||||
Services.perms.remove(this.httpURI, aType);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -377,7 +377,7 @@ var gAdvancedPane = {
|
||||
},
|
||||
|
||||
// XXX: duplicated in browser.js
|
||||
_getOfflineAppUsage: function (host, groups)
|
||||
_getOfflineAppUsage: function (perm, groups)
|
||||
{
|
||||
var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"].
|
||||
getService(Components.interfaces.nsIApplicationCacheService);
|
||||
@@ -390,7 +390,7 @@ var gAdvancedPane = {
|
||||
var usage = 0;
|
||||
for (var i = 0; i < groups.length; i++) {
|
||||
var uri = ios.newURI(groups[i], null, null);
|
||||
if (uri.asciiHost == host) {
|
||||
if (uri.asciiHost == perm.host) {
|
||||
var cache = cacheService.getActiveCache(groups[i]);
|
||||
usage += cache.usage;
|
||||
}
|
||||
@@ -429,7 +429,7 @@ var gAdvancedPane = {
|
||||
row.className = "offlineapp";
|
||||
row.setAttribute("host", perm.host);
|
||||
var converted = DownloadUtils.
|
||||
convertByteUnits(this._getOfflineAppUsage(perm.host, groups));
|
||||
convertByteUnits(this._getOfflineAppUsage(perm, groups));
|
||||
row.setAttribute("usage",
|
||||
bundle.getFormattedString("offlineAppUsage",
|
||||
converted));
|
||||
@@ -476,7 +476,7 @@ var gAdvancedPane = {
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
var groups = cacheService.getGroups();
|
||||
for (var i = 0; i < groups.length; i++) {
|
||||
var uri = ios.newURI(groups[i], null, null);
|
||||
let uri = ios.newURI(groups[i], null, null);
|
||||
if (uri.asciiHost == host) {
|
||||
var cache = cacheService.getActiveCache(groups[i]);
|
||||
cache.discard();
|
||||
@@ -486,10 +486,15 @@ var gAdvancedPane = {
|
||||
// remove the permission
|
||||
var pm = Components.classes["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Components.interfaces.nsIPermissionManager);
|
||||
pm.remove(host, "offline-app",
|
||||
Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
|
||||
pm.remove(host, "offline-app",
|
||||
Components.interfaces.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
|
||||
let uri;
|
||||
try {
|
||||
// file:// URIs are stored with their scheme. We try to parse them first, as
|
||||
// URIs like http://file:///foo/bar/baz.html will parse as HTTP URIs.
|
||||
uri = ios.newURI(host, null, null);
|
||||
} catch (e) {
|
||||
uri = ios.newURI("http://" + host, null, null);
|
||||
}
|
||||
pm.remove(uri, "offline-app");
|
||||
|
||||
list.removeChild(item);
|
||||
gAdvancedPane.offlineAppSelected();
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* 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/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
const nsIPermissionManager = Components.interfaces.nsIPermissionManager;
|
||||
const nsICookiePermission = Components.interfaces.nsICookiePermission;
|
||||
|
||||
@@ -83,9 +85,7 @@ var gPermissionManager = {
|
||||
var textbox = document.getElementById("url");
|
||||
var host = textbox.value.replace(/^\s*([-\w]*:\/+)?/, ""); // trim any leading space and scheme
|
||||
try {
|
||||
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
var uri = ioService.newURI("http://"+host, null, null);
|
||||
var uri = NetUtil.newURI("http://" + host);
|
||||
host = uri.host;
|
||||
} catch(ex) {
|
||||
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
@@ -112,7 +112,7 @@ var gPermissionManager = {
|
||||
|
||||
if (!exists) {
|
||||
host = (host.charAt(0) == ".") ? host.substring(1,host.length) : host;
|
||||
var uri = ioService.newURI("http://" + host, null, null);
|
||||
var uri = NetUtil.newURI("http://" + host);
|
||||
this._pm.add(uri, this._type, aCapability);
|
||||
}
|
||||
textbox.value = "";
|
||||
@@ -257,7 +257,8 @@ var gPermissionManager = {
|
||||
gTreeUtils.deleteSelectedItems(this._tree, this._view, this._permissions, removedPermissions);
|
||||
for (var i = 0; i < removedPermissions.length; ++i) {
|
||||
var p = removedPermissions[i];
|
||||
this._pm.remove(p.host, p.type);
|
||||
let uri = NetUtil.newURI("http://" + p.host);
|
||||
this._pm.remove(uri, p.type);
|
||||
}
|
||||
document.getElementById("removePermission").disabled = !this._permissions.length;
|
||||
document.getElementById("removeAllPermissions").disabled = !this._permissions.length;
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
Components.utils.import("resource://gre/modules/ForgetAboutSite.jsm");
|
||||
|
||||
const ABOUT_PERMISSIONS_SPEC = "about:permissions";
|
||||
|
||||
const TEST_URI_1 = NetUtil.newURI("http://mozilla.com/");
|
||||
const TEST_URI_2 = NetUtil.newURI("http://mozilla.org/");
|
||||
const TEST_URI_3 = NetUtil.newURI("http://wikipedia.org/");
|
||||
|
||||
// values from DefaultPermissions object
|
||||
const PERM_UNKNOWN = 0;
|
||||
const PERM_ALLOW = 1;
|
||||
const PERM_DENY = 2;
|
||||
|
||||
// used to set permissions on test sites
|
||||
const TEST_PERMS = {
|
||||
"password": PERM_ALLOW,
|
||||
"cookie": PERM_ALLOW,
|
||||
"geo": PERM_UNKNOWN,
|
||||
"indexedDB": PERM_UNKNOWN,
|
||||
"popup": PERM_DENY
|
||||
};
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
registerCleanupFunction(cleanUp);
|
||||
setup(function() {
|
||||
runNextTest();
|
||||
});
|
||||
}
|
||||
|
||||
function setup(aCallback) {
|
||||
// add test history visit
|
||||
PlacesTestUtils.addVisits(TEST_URI_1).then(() => {
|
||||
// set permissions ourselves to avoid problems with different defaults
|
||||
// from test harness configuration
|
||||
for (let type in TEST_PERMS) {
|
||||
if (type == "password") {
|
||||
Services.logins.setLoginSavingEnabled(TEST_URI_2.prePath, true);
|
||||
} else {
|
||||
// set permissions on a site without history visits to test enumerateServices
|
||||
Services.perms.add(TEST_URI_2, type, TEST_PERMS[type]);
|
||||
}
|
||||
}
|
||||
|
||||
Services.perms.add(TEST_URI_3, "popup", TEST_PERMS["popup"]);
|
||||
aCallback();
|
||||
});
|
||||
}
|
||||
|
||||
function cleanUp() {
|
||||
for (let type in TEST_PERMS) {
|
||||
if (type != "password") {
|
||||
Services.perms.remove(TEST_URI_1, type);
|
||||
Services.perms.remove(TEST_URI_2, type);
|
||||
Services.perms.remove(TEST_URI_3, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
if (gTestIndex == tests.length) {
|
||||
PlacesTestUtils.clearHistory().then(finish);
|
||||
return;
|
||||
}
|
||||
|
||||
let nextTest = tests[gTestIndex++];
|
||||
info(nextTest.desc);
|
||||
|
||||
function preinit_observer() {
|
||||
Services.obs.removeObserver(preinit_observer, "browser-permissions-preinit");
|
||||
nextTest.preInit();
|
||||
}
|
||||
Services.obs.addObserver(preinit_observer, "browser-permissions-preinit", false);
|
||||
|
||||
function init_observer() {
|
||||
Services.obs.removeObserver(init_observer, "browser-permissions-initialized");
|
||||
nextTest.run();
|
||||
}
|
||||
Services.obs.addObserver(init_observer, "browser-permissions-initialized", false);
|
||||
|
||||
// open about:permissions
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab("about:permissions");
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
}
|
||||
|
||||
var gSitesList;
|
||||
|
||||
var gTestIndex = 0;
|
||||
var tests = [
|
||||
// 'preInit' occurs after opening about:permissions, before sites-list is populated
|
||||
// 'run' occurs after sites-list is populated
|
||||
{
|
||||
desc: "test filtering before sites-list is fully constructed.",
|
||||
preInit: function() {
|
||||
let sitesFilter = gBrowser.contentDocument.getElementById("sites-filter");
|
||||
sitesFilter.value = TEST_URI_2.host;
|
||||
sitesFilter.doCommand();
|
||||
},
|
||||
run: function() {
|
||||
let testSite1 = getSiteItem(TEST_URI_1.host);
|
||||
ok(testSite1.collapsed, "test site 1 is collapsed after early filtering");
|
||||
let testSite2 = getSiteItem(TEST_URI_2.host);
|
||||
ok(!testSite2.collapsed, "test site 2 is not collapsed after early filtering");
|
||||
let testSite3 = getSiteItem(TEST_URI_3.host);
|
||||
ok(testSite3.collapsed, "test site 3 is collapsed after early filtering");
|
||||
|
||||
runNextTest();
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "test removing from sites-list before it is fully constructed.",
|
||||
preInit: function() {
|
||||
ForgetAboutSite.removeDataFromDomain(TEST_URI_2.host);
|
||||
},
|
||||
run: function() {
|
||||
let testSite1 = getSiteItem(TEST_URI_1.host);
|
||||
ok(testSite1, "test site 1 was not removed from sites list");
|
||||
let testSite2 = getSiteItem(TEST_URI_2.host);
|
||||
ok(!testSite2, "test site 2 was pre-removed from sites list");
|
||||
let testSite3 = getSiteItem(TEST_URI_3.host);
|
||||
ok(testSite3, "test site 3 was not removed from sites list");
|
||||
|
||||
runNextTest();
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
function getSiteItem(aHost) {
|
||||
return gBrowser.contentDocument.
|
||||
querySelector(".site[value='" + aHost + "']");
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
testRunner.runTests();
|
||||
}
|
||||
|
||||
var testRunner = {
|
||||
|
||||
tests:
|
||||
[
|
||||
{
|
||||
test: function(params) {
|
||||
params.url.value = "test.com";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.rowCount, 1, "added exception shows up in treeview");
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission text should be set correctly");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", host: "test.com", data: "added",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
|
||||
},
|
||||
{
|
||||
test: function(params) {
|
||||
params.url.value = "test.com";
|
||||
params.btnBlock.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.denyText,
|
||||
"permission should change to deny in UI");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", host: "test.com", data: "changed",
|
||||
capability: Ci.nsIPermissionManager.DENY_ACTION }],
|
||||
},
|
||||
{
|
||||
test: function(params) {
|
||||
params.url.value = "test.com";
|
||||
params.btnAllow.doCommand();
|
||||
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
|
||||
"permission should revert back to allow");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", host: "test.com", data: "changed",
|
||||
capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
|
||||
},
|
||||
{
|
||||
test: function(params) {
|
||||
params.url.value = "test.com";
|
||||
params.btnRemove.doCommand();
|
||||
is(params.tree.view.rowCount, 0, "exception should be removed");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "cookie", host: "test.com", data: "deleted" }],
|
||||
},
|
||||
{
|
||||
test: function(params) {
|
||||
let uri = params.ioService.newURI("http://test.com", null, null);
|
||||
params.pm.add(uri, "popup", Ci.nsIPermissionManager.DENY_ACTION);
|
||||
is(params.tree.view.rowCount, 0, "adding unrelated permission should not change display");
|
||||
params.btnApplyChanges.doCommand();
|
||||
},
|
||||
observances: [{ type: "popup", host: "test.com", data: "added",
|
||||
capability: Ci.nsIPermissionManager.DENY_ACTION }],
|
||||
cleanUp: function(params) {
|
||||
let uri = params.ioService.newURI("http://test.com", null, null);
|
||||
params.pm.remove(uri, "popup");
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
_currentTest: -1,
|
||||
|
||||
runTests: function() {
|
||||
this._currentTest++;
|
||||
|
||||
info("Running test #" + (this._currentTest + 1) + "\n");
|
||||
let that = this;
|
||||
let p = this.runCurrentTest();
|
||||
p.then(function() {
|
||||
if (that._currentTest == that.tests.length - 1) {
|
||||
finish();
|
||||
}
|
||||
else {
|
||||
that.runTests();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
runCurrentTest: function() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
|
||||
let helperFunctions = {
|
||||
|
||||
prefWindowObserver: function(subject, topic, data) {
|
||||
if (topic != "domwindowopened")
|
||||
return;
|
||||
|
||||
Services.ww.unregisterNotification(helperFunctions.prefWindowObserver);
|
||||
|
||||
let win = subject.QueryInterface(Ci.nsIDOMEventTarget);
|
||||
|
||||
win.addEventListener("load", function(event) {
|
||||
let historyMode = event.target.getElementById("historyMode");
|
||||
historyMode.value = "custom";
|
||||
historyMode.doCommand();
|
||||
Services.ww.registerNotification(helperFunctions.cookiesWindowObserver);
|
||||
event.target.getElementById("cookieExceptions").doCommand();
|
||||
}, false);
|
||||
},
|
||||
|
||||
cookiesWindowObserver: function(subject, topic, data) {
|
||||
if (topic != "domwindowopened")
|
||||
return;
|
||||
|
||||
Services.ww.unregisterNotification(helperFunctions.cookiesWindowObserver);
|
||||
|
||||
let win = subject.QueryInterface(Ci.nsIDOMEventTarget);
|
||||
|
||||
win.addEventListener("load", function(event) {
|
||||
SimpleTest.executeSoon(function() helperFunctions.windowLoad(event, win));
|
||||
}, false);
|
||||
},
|
||||
|
||||
windowLoad: function(event, win) {
|
||||
let params = {
|
||||
doc: event.target,
|
||||
tree: event.target.getElementById("permissionsTree"),
|
||||
statusCol: event.target.getElementById("permissionsTree").treeBoxObject.columns.getColumnAt(1),
|
||||
url: event.target.getElementById("url"),
|
||||
btnAllow: event.target.getElementById("btnAllow"),
|
||||
btnBlock: event.target.getElementById("btnBlock"),
|
||||
btnApplyChanges: event.target.getElementById("btnApplyChanges"),
|
||||
btnRemove: event.target.getElementById("removePermission"),
|
||||
pm: Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Ci.nsIPermissionManager),
|
||||
ioService: Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService),
|
||||
allowText: win.gPermissionManager._getCapabilityString(
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION),
|
||||
denyText: win.gPermissionManager._getCapabilityString(
|
||||
Ci.nsIPermissionManager.DENY_ACTION),
|
||||
allow: Ci.nsIPermissionManager.ALLOW_ACTION,
|
||||
deny: Ci.nsIPermissionManager.DENY_ACTION,
|
||||
};
|
||||
|
||||
let permObserver = {
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (aTopic != "perm-changed")
|
||||
return;
|
||||
|
||||
if (testRunner.tests[testRunner._currentTest].observances.length == 0) {
|
||||
// Should fail here as we are not expecting a notification, but we don't.
|
||||
// See bug 1063410.
|
||||
return;
|
||||
}
|
||||
|
||||
let permission = aSubject.QueryInterface(Ci.nsIPermission);
|
||||
let expected = testRunner.tests[testRunner._currentTest].observances.shift();
|
||||
|
||||
is(aData, expected.data, "type of message should be the same");
|
||||
for each (let prop in ["type", "host", "capability"]) {
|
||||
if (expected[prop])
|
||||
is(permission[prop], expected[prop],
|
||||
"property: \"" + prop + "\" should be equal");
|
||||
}
|
||||
|
||||
os.removeObserver(permObserver, "perm-changed");
|
||||
|
||||
if (testRunner.tests[testRunner._currentTest].cleanup) {
|
||||
testRunner.tests[testRunner._currentTest].cleanup();
|
||||
}
|
||||
|
||||
testRunner.dialog.close(params);
|
||||
win.close();
|
||||
resolve();
|
||||
},
|
||||
};
|
||||
|
||||
let os = Cc["@mozilla.org/observer-service;1"]
|
||||
.getService(Ci.nsIObserverService);
|
||||
|
||||
os.addObserver(permObserver, "perm-changed", false);
|
||||
|
||||
if (testRunner._currentTest == 0) {
|
||||
is(params.tree.view.rowCount, 0, "no cookie exceptions");
|
||||
}
|
||||
|
||||
testRunner.tests[testRunner._currentTest].test(params);
|
||||
},
|
||||
};
|
||||
|
||||
Services.ww.registerNotification(helperFunctions.prefWindowObserver);
|
||||
|
||||
testRunner.dialog = openDialog("chrome://browser/content/preferences/preferences.xul",
|
||||
"Preferences", "chrome,titlebar,toolbar,centerscreen,dialog=no",
|
||||
"panePrivacy");
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,313 @@
|
||||
/* 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/. */
|
||||
|
||||
// tests the translation infobar, using a fake 'Translation' implementation.
|
||||
|
||||
let tmp = {};
|
||||
Cu.import("resource:///modules/translation/Translation.jsm", tmp);
|
||||
Cu.import("resource://gre/modules/Promise.jsm", tmp);
|
||||
let {Translation, Promise} = tmp;
|
||||
|
||||
const kLanguagesPref = "browser.translation.neverForLanguages";
|
||||
const kShowUIPref = "browser.translation.ui.show";
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
Services.prefs.setBoolPref(kShowUIPref, true);
|
||||
let tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
registerCleanupFunction(function () {
|
||||
gBrowser.removeTab(tab);
|
||||
Services.prefs.clearUserPref(kShowUIPref);
|
||||
});
|
||||
tab.linkedBrowser.addEventListener("load", function onload() {
|
||||
tab.linkedBrowser.removeEventListener("load", onload, true);
|
||||
Task.spawn(function* () {
|
||||
for (let test of gTests) {
|
||||
info(test.desc);
|
||||
yield test.run();
|
||||
}
|
||||
}).then(finish, ex => {
|
||||
ok(false, "Unexpected Exception: " + ex);
|
||||
finish();
|
||||
});
|
||||
}, true);
|
||||
|
||||
content.location = "http://example.com/";
|
||||
}
|
||||
|
||||
function getLanguageExceptions() {
|
||||
let langs = Services.prefs.getCharPref(kLanguagesPref);
|
||||
return langs ? langs.split(",") : [];
|
||||
}
|
||||
|
||||
function getDomainExceptions() {
|
||||
let results = [];
|
||||
let enumerator = Services.perms.enumerator;
|
||||
while (enumerator.hasMoreElements()) {
|
||||
let perm = enumerator.getNext().QueryInterface(Ci.nsIPermission);
|
||||
|
||||
if (perm.type == "translate" &&
|
||||
perm.capability == Services.perms.DENY_ACTION)
|
||||
results.push(perm.host);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
function getInfoBar() {
|
||||
return gBrowser.getNotificationBox().getNotificationWithValue("translation");
|
||||
}
|
||||
|
||||
function openPopup(aPopup) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
aPopup.addEventListener("popupshown", function popupShown() {
|
||||
aPopup.removeEventListener("popupshown", popupShown);
|
||||
deferred.resolve();
|
||||
});
|
||||
|
||||
aPopup.focus();
|
||||
// One down event to open the popup.
|
||||
EventUtils.synthesizeKey("VK_DOWN",
|
||||
{ altKey: !navigator.platform.includes("Mac") });
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function waitForWindowLoad(aWin) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
aWin.addEventListener("load", function onload() {
|
||||
aWin.removeEventListener("load", onload, true);
|
||||
deferred.resolve();
|
||||
}, true);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
|
||||
let gTests = [
|
||||
|
||||
{
|
||||
desc: "clean exception lists at startup",
|
||||
run: function checkNeverForLanguage() {
|
||||
is(getLanguageExceptions().length, 0,
|
||||
"we start with an empty list of languages to never translate");
|
||||
is(getDomainExceptions().length, 0,
|
||||
"we start with an empty list of sites to never translate");
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
desc: "never for language",
|
||||
run: function* checkNeverForLanguage() {
|
||||
// Show the infobar for example.com and fr.
|
||||
Translation.documentStateReceived(gBrowser.selectedBrowser,
|
||||
{state: Translation.STATE_OFFER,
|
||||
originalShown: true,
|
||||
detectedLanguage: "fr"});
|
||||
let notif = getInfoBar();
|
||||
ok(notif, "the infobar is visible");
|
||||
let ui = gBrowser.selectedBrowser.translationUI;
|
||||
let uri = gBrowser.selectedBrowser.currentURI;
|
||||
ok(ui.shouldShowInfoBar(uri, "fr"),
|
||||
"check shouldShowInfoBar initially returns true");
|
||||
|
||||
// Open the "options" drop down.
|
||||
yield openPopup(notif._getAnonElt("options"));
|
||||
ok(notif._getAnonElt("options").getAttribute("open"),
|
||||
"the options menu is open");
|
||||
|
||||
// Check that the item is not disabled.
|
||||
ok(!notif._getAnonElt("neverForLanguage").disabled,
|
||||
"The 'Never translate <language>' item isn't disabled");
|
||||
|
||||
// Click the 'Never for French' item.
|
||||
notif._getAnonElt("neverForLanguage").click();
|
||||
ok(!getInfoBar(), "infobar hidden");
|
||||
|
||||
// Check this has been saved to the exceptions list.
|
||||
let langs = getLanguageExceptions();
|
||||
is(langs.length, 1, "one language in the exception list");
|
||||
is(langs[0], "fr", "correct language in the exception list");
|
||||
ok(!ui.shouldShowInfoBar(uri, "fr"),
|
||||
"the infobar wouldn't be shown anymore");
|
||||
|
||||
// Reopen the infobar.
|
||||
PopupNotifications.getNotification("translate").anchorElement.click();
|
||||
notif = getInfoBar();
|
||||
// Open the "options" drop down.
|
||||
yield openPopup(notif._getAnonElt("options"));
|
||||
ok(notif._getAnonElt("neverForLanguage").disabled,
|
||||
"The 'Never translate French' item is disabled");
|
||||
|
||||
// Cleanup.
|
||||
Services.prefs.setCharPref(kLanguagesPref, "");
|
||||
notif.close();
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
desc: "never for site",
|
||||
run: function* checkNeverForSite() {
|
||||
// Show the infobar for example.com and fr.
|
||||
Translation.documentStateReceived(gBrowser.selectedBrowser,
|
||||
{state: Translation.STATE_OFFER,
|
||||
originalShown: true,
|
||||
detectedLanguage: "fr"});
|
||||
let notif = getInfoBar();
|
||||
ok(notif, "the infobar is visible");
|
||||
let ui = gBrowser.selectedBrowser.translationUI;
|
||||
let uri = gBrowser.selectedBrowser.currentURI;
|
||||
ok(ui.shouldShowInfoBar(uri, "fr"),
|
||||
"check shouldShowInfoBar initially returns true");
|
||||
|
||||
// Open the "options" drop down.
|
||||
yield openPopup(notif._getAnonElt("options"));
|
||||
ok(notif._getAnonElt("options").getAttribute("open"),
|
||||
"the options menu is open");
|
||||
|
||||
// Check that the item is not disabled.
|
||||
ok(!notif._getAnonElt("neverForSite").disabled,
|
||||
"The 'Never translate site' item isn't disabled");
|
||||
|
||||
// Click the 'Never for French' item.
|
||||
notif._getAnonElt("neverForSite").click();
|
||||
ok(!getInfoBar(), "infobar hidden");
|
||||
|
||||
// Check this has been saved to the exceptions list.
|
||||
let sites = getDomainExceptions();
|
||||
is(sites.length, 1, "one site in the exception list");
|
||||
is(sites[0], "example.com", "correct site in the exception list");
|
||||
ok(!ui.shouldShowInfoBar(uri, "fr"),
|
||||
"the infobar wouldn't be shown anymore");
|
||||
|
||||
// Reopen the infobar.
|
||||
PopupNotifications.getNotification("translate").anchorElement.click();
|
||||
notif = getInfoBar();
|
||||
// Open the "options" drop down.
|
||||
yield openPopup(notif._getAnonElt("options"));
|
||||
ok(notif._getAnonElt("neverForSite").disabled,
|
||||
"The 'Never translate French' item is disabled");
|
||||
|
||||
// Cleanup.
|
||||
Services.perms.remove(makeURI("http://example.com"), "translate");
|
||||
notif.close();
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
desc: "language exception list",
|
||||
run: function* checkLanguageExceptions() {
|
||||
// Put 2 languages in the pref before opening the window to check
|
||||
// the list is displayed on load.
|
||||
Services.prefs.setCharPref(kLanguagesPref, "fr,de");
|
||||
|
||||
// Open the translation exceptions dialog.
|
||||
let win = openDialog("chrome://browser/content/preferences/translation.xul",
|
||||
"Browser:TranslationExceptions",
|
||||
"", null);
|
||||
yield waitForWindowLoad(win);
|
||||
|
||||
// Check that the list of language exceptions is loaded.
|
||||
let getById = win.document.getElementById.bind(win.document);
|
||||
let tree = getById("languagesTree");
|
||||
let remove = getById("removeLanguage");
|
||||
let removeAll = getById("removeAllLanguages");
|
||||
is(tree.view.rowCount, 2, "The language exceptions list has 2 items");
|
||||
ok(remove.disabled, "The 'Remove Language' button is disabled");
|
||||
ok(!removeAll.disabled, "The 'Remove All Languages' button is enabled");
|
||||
|
||||
// Select the first item.
|
||||
tree.view.selection.select(0);
|
||||
ok(!remove.disabled, "The 'Remove Language' button is enabled");
|
||||
|
||||
// Click the 'Remove' button.
|
||||
remove.click();
|
||||
is(tree.view.rowCount, 1, "The language exceptions now contains 1 item");
|
||||
is(getLanguageExceptions().length, 1, "One exception in the pref");
|
||||
|
||||
// Clear the pref, and check the last item is removed from the display.
|
||||
Services.prefs.setCharPref(kLanguagesPref, "");
|
||||
is(tree.view.rowCount, 0, "The language exceptions list is empty");
|
||||
ok(remove.disabled, "The 'Remove Language' button is disabled");
|
||||
ok(removeAll.disabled, "The 'Remove All Languages' button is disabled");
|
||||
|
||||
// Add an item and check it appears.
|
||||
Services.prefs.setCharPref(kLanguagesPref, "fr");
|
||||
is(tree.view.rowCount, 1, "The language exceptions list has 1 item");
|
||||
ok(remove.disabled, "The 'Remove Language' button is disabled");
|
||||
ok(!removeAll.disabled, "The 'Remove All Languages' button is enabled");
|
||||
|
||||
// Click the 'Remove All' button.
|
||||
removeAll.click();
|
||||
is(tree.view.rowCount, 0, "The language exceptions list is empty");
|
||||
ok(remove.disabled, "The 'Remove Language' button is disabled");
|
||||
ok(removeAll.disabled, "The 'Remove All Languages' button is disabled");
|
||||
is(Services.prefs.getCharPref(kLanguagesPref), "", "The pref is empty");
|
||||
|
||||
win.close();
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
desc: "domains exception list",
|
||||
run: function* checkDomainExceptions() {
|
||||
// Put 2 exceptions before opening the window to check the list is
|
||||
// displayed on load.
|
||||
let perms = Services.perms;
|
||||
perms.add(makeURI("http://example.org"), "translate", perms.DENY_ACTION);
|
||||
perms.add(makeURI("http://example.com"), "translate", perms.DENY_ACTION);
|
||||
|
||||
// Open the translation exceptions dialog.
|
||||
let win = openDialog("chrome://browser/content/preferences/translation.xul",
|
||||
"Browser:TranslationExceptions",
|
||||
"", null);
|
||||
yield waitForWindowLoad(win);
|
||||
|
||||
// Check that the list of language exceptions is loaded.
|
||||
let getById = win.document.getElementById.bind(win.document);
|
||||
let tree = getById("sitesTree");
|
||||
let remove = getById("removeSite");
|
||||
let removeAll = getById("removeAllSites");
|
||||
is(tree.view.rowCount, 2, "The sites exceptions list has 2 items");
|
||||
ok(remove.disabled, "The 'Remove Site' button is disabled");
|
||||
ok(!removeAll.disabled, "The 'Remove All Sites' button is enabled");
|
||||
|
||||
// Select the first item.
|
||||
tree.view.selection.select(0);
|
||||
ok(!remove.disabled, "The 'Remove Site' button is enabled");
|
||||
|
||||
// Click the 'Remove' button.
|
||||
remove.click();
|
||||
is(tree.view.rowCount, 1, "The site exceptions now contains 1 item");
|
||||
is(getDomainExceptions().length, 1, "One exception in the permissions");
|
||||
|
||||
// Clear the permissions, and check the last item is removed from the display.
|
||||
perms.remove(makeURI("http://example.org"), "translate");
|
||||
perms.remove(makeURI("http://example.com"), "translate");
|
||||
is(tree.view.rowCount, 0, "The site exceptions list is empty");
|
||||
ok(remove.disabled, "The 'Remove Site' button is disabled");
|
||||
ok(removeAll.disabled, "The 'Remove All Site' button is disabled");
|
||||
|
||||
// Add an item and check it appears.
|
||||
perms.add(makeURI("http://example.com"), "translate", perms.DENY_ACTION);
|
||||
is(tree.view.rowCount, 1, "The site exceptions list has 1 item");
|
||||
ok(remove.disabled, "The 'Remove Site' button is disabled");
|
||||
ok(!removeAll.disabled, "The 'Remove All Sites' button is enabled");
|
||||
|
||||
// Click the 'Remove All' button.
|
||||
removeAll.click();
|
||||
is(tree.view.rowCount, 0, "The site exceptions list is empty");
|
||||
ok(remove.disabled, "The 'Remove Site' button is disabled");
|
||||
ok(removeAll.disabled, "The 'Remove All Sites' button is disabled");
|
||||
is(getDomainExceptions().length, 0, "No exceptions in the permissions");
|
||||
|
||||
win.close();
|
||||
}
|
||||
}
|
||||
|
||||
];
|
||||
@@ -93,7 +93,7 @@ this.SitePermissions = {
|
||||
if (!this.isSupportedURI(aURI))
|
||||
return;
|
||||
|
||||
Services.perms.remove(aURI.host, aPermissionID);
|
||||
Services.perms.remove(aURI, aPermissionID);
|
||||
|
||||
if (aPermissionID in gPermissionObject &&
|
||||
gPermissionObject[aPermissionID].onChange)
|
||||
@@ -216,7 +216,7 @@ let gPermissionObject = {
|
||||
},
|
||||
onChange: function (aURI, aState) {
|
||||
if (aState == SitePermissions.ALLOW || aState == SitePermissions.BLOCK)
|
||||
Services.perms.remove(aURI.host, "indexedDB-unlimited");
|
||||
Services.perms.remove(aURI, "indexedDB-unlimited");
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -863,18 +863,12 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
|
||||
}
|
||||
}
|
||||
|
||||
// resource: and chrome: are equivalent, securitywise
|
||||
// That's bogus!! Fix this. But watch out for
|
||||
// the view-source stylesheet?
|
||||
bool sourceIsChrome;
|
||||
rv = NS_URIChainHasFlags(sourceURI,
|
||||
nsIProtocolHandler::URI_IS_UI_RESOURCE,
|
||||
&sourceIsChrome);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (sourceIsChrome) {
|
||||
// Allow chrome://
|
||||
if (sourceScheme.EqualsLiteral("chrome")) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Nothing else.
|
||||
if (reportErrors) {
|
||||
ReportError(nullptr, errorTag, sourceURI, aTargetURI);
|
||||
}
|
||||
|
||||
Vendored
+6
@@ -48,6 +48,12 @@ if CONFIG['MOZ_JXR']:
|
||||
if CONFIG['CPU_ARCH'] == 'arm':
|
||||
external_dirs += ['media/openmax_dl']
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH_POCKETSPHINX']:
|
||||
external_dirs += [
|
||||
'media/sphinxbase',
|
||||
'media/pocketsphinx',
|
||||
]
|
||||
|
||||
external_dirs += [
|
||||
'media/kiss_fft',
|
||||
'media/libcubeb',
|
||||
|
||||
@@ -3793,6 +3793,9 @@ MOZ_NATIVE_LIBWEBP=
|
||||
MOZ_VPX=
|
||||
MOZ_VPX_ERROR_CONCEALMENT=
|
||||
MOZ_WEBSPEECH=1
|
||||
MOZ_WEBSPEECH_MODELS=
|
||||
MOZ_WEBSPEECH_POCKETSPHINX=
|
||||
MOZ_WEBSPEECH_TEST_BACKEND=1
|
||||
MOZ_JXR=1
|
||||
VPX_AS=
|
||||
VPX_ASFLAGS=
|
||||
@@ -4996,6 +4999,15 @@ else
|
||||
AC_SUBST(MOZ_SAMPLE_TYPE_FLOAT32)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Disable Speech API pocketsphinx backend
|
||||
dnl ========================================================
|
||||
if test -n "$MOZ_WEBSPEECH_POCKETSPHINX"; then
|
||||
AC_DEFINE(MOZ_WEBSPEECH_POCKETSPHINX)
|
||||
fi
|
||||
|
||||
AC_SUBST(MOZ_WEBSPEECH_POCKETSPHINX)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Disable Speech API code
|
||||
dnl ========================================================
|
||||
@@ -5010,6 +5022,37 @@ fi
|
||||
|
||||
AC_SUBST(MOZ_WEBSPEECH)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Disable Speech API test backend
|
||||
dnl ========================================================
|
||||
MOZ_ARG_DISABLE_BOOL(webspeechtestbackend,
|
||||
[ --disable-webspeechtestbackend Disable support for HTML Speech API Test Backend],
|
||||
MOZ_WEBSPEECH_TEST_BACKEND=,
|
||||
MOZ_WEBSPEECH_TEST_BACKEND=1)
|
||||
|
||||
if test -z "$MOZ_WEBSPEECH"; then
|
||||
MOZ_WEBSPEECH_TEST_BACKEND=
|
||||
fi
|
||||
|
||||
if test -n "$MOZ_WEBSPEECH_TEST_BACKEND"; then
|
||||
AC_DEFINE(MOZ_WEBSPEECH_TEST_BACKEND)
|
||||
fi
|
||||
|
||||
AC_SUBST(MOZ_WEBSPEECH_TEST_BACKEND)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Disable Speech API models
|
||||
dnl ========================================================
|
||||
if test -z "$MOZ_WEBSPEECH"; then
|
||||
MOZ_WEBSPEECH_MODELS=
|
||||
fi
|
||||
|
||||
if test -n "$MOZ_WEBSPEECH_MODELS"; then
|
||||
AC_DEFINE(MOZ_WEBSPEECH_MODELS)
|
||||
fi
|
||||
|
||||
AC_SUBST(MOZ_WEBSPEECH_MODELS)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Disable JPEG-XR (JXR) decoder support
|
||||
dnl ========================================================
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
/* static functions */
|
||||
const DEBUG = false;
|
||||
const REQUEST_CPU_LOCK_TIMEOUT = 10 * 1000; // 10 seconds.
|
||||
|
||||
function debug(aStr) {
|
||||
if (DEBUG)
|
||||
@@ -18,8 +19,15 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gPowerManagerService",
|
||||
"@mozilla.org/power/powermanagerservice;1",
|
||||
"nsIPowerManagerService");
|
||||
|
||||
function AlarmsManager() {
|
||||
debug("Constructor");
|
||||
|
||||
// A <requestId, {cpuLock, timer}> map.
|
||||
this._cpuLockDict = new Map();
|
||||
}
|
||||
|
||||
AlarmsManager.prototype = {
|
||||
@@ -71,8 +79,10 @@ AlarmsManager.prototype = {
|
||||
data = JSON.parse(Cu.evalInSandbox("JSON.stringify(data)", sandbox));
|
||||
}
|
||||
let request = this.createRequest();
|
||||
let requestId = this.getRequestId(request);
|
||||
this._lockCpuForRequest(requestId);
|
||||
this._cpmm.sendAsyncMessage("AlarmsManager:Add",
|
||||
{ requestId: this.getRequestId(request),
|
||||
{ requestId: requestId,
|
||||
date: aDate,
|
||||
ignoreTimezone: isIgnoreTimezone,
|
||||
data: data,
|
||||
@@ -111,6 +121,7 @@ AlarmsManager.prototype = {
|
||||
|
||||
switch (aMessage.name) {
|
||||
case "AlarmsManager:Add:Return:OK":
|
||||
this._unlockCpuForRequest(json.requestId);
|
||||
Services.DOMRequest.fireSuccess(request, json.id);
|
||||
break;
|
||||
|
||||
@@ -131,6 +142,7 @@ AlarmsManager.prototype = {
|
||||
break;
|
||||
|
||||
case "AlarmsManager:Add:Return:KO":
|
||||
this._unlockCpuForRequest(json.requestId);
|
||||
Services.DOMRequest.fireError(request, json.errorMsg);
|
||||
break;
|
||||
|
||||
@@ -172,6 +184,44 @@ AlarmsManager.prototype = {
|
||||
uninit: function uninit() {
|
||||
debug("uninit()");
|
||||
},
|
||||
|
||||
_lockCpuForRequest: function (aRequestId) {
|
||||
if (this._cpuLockDict.has(aRequestId)) {
|
||||
debug('Cpu wakelock for request ' + aRequestId + ' has been acquired. ' +
|
||||
'You may call this function repeatedly or requestId is collision.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Acquire a lock for given request and save for lookup lately.
|
||||
debug('Acquire cpu lock for request ' + aRequestId);
|
||||
let cpuLockInfo = {
|
||||
cpuLock: gPowerManagerService.newWakeLock("cpu"),
|
||||
timer: Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer)
|
||||
};
|
||||
this._cpuLockDict.set(aRequestId, cpuLockInfo);
|
||||
|
||||
// Start a timer to prevent from non-responding request.
|
||||
cpuLockInfo.timer.initWithCallback(() => {
|
||||
debug('Request timeout! Release the cpu lock');
|
||||
this._unlockCpuForRequest(aRequestId);
|
||||
}, REQUEST_CPU_LOCK_TIMEOUT, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
},
|
||||
|
||||
_unlockCpuForRequest: function(aRequestId) {
|
||||
let cpuLockInfo = this._cpuLockDict.get(aRequestId);
|
||||
if (!cpuLockInfo) {
|
||||
debug('The cpu lock for requestId ' + aRequestId + ' is either invalid ' +
|
||||
'or has been released.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Release the cpu lock and cancel the timer.
|
||||
debug('Release the cpu lock for ' + aRequestId);
|
||||
cpuLockInfo.cpuLock.unlock();
|
||||
cpuLockInfo.timer.cancel();
|
||||
this._cpuLockDict.delete(aRequestId);
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AlarmsManager])
|
||||
|
||||
@@ -69,6 +69,7 @@ EventSource::EventSource(nsPIDOMWindow* aOwnerWindow) :
|
||||
mLastConvertionResult(NS_OK),
|
||||
mReadyState(CONNECTING),
|
||||
mScriptLine(0),
|
||||
mScriptColumn(0),
|
||||
mInnerWindowID(0)
|
||||
{
|
||||
}
|
||||
@@ -205,7 +206,8 @@ EventSource::Init(nsISupports* aOwner,
|
||||
|
||||
// The conditional here is historical and not necessarily sane.
|
||||
if (JSContext *cx = nsContentUtils::GetCurrentJSContext()) {
|
||||
nsJSUtils::GetCallingLocation(cx, mScriptFile, &mScriptLine);
|
||||
nsJSUtils::GetCallingLocation(cx, mScriptFile, &mScriptLine,
|
||||
&mScriptColumn);
|
||||
mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx);
|
||||
}
|
||||
|
||||
@@ -997,7 +999,7 @@ EventSource::PrintErrorOnConsole(const char *aBundleURI,
|
||||
rv = errObj->InitWithWindowID(message,
|
||||
mScriptFile,
|
||||
EmptyString(),
|
||||
mScriptLine, 0,
|
||||
mScriptLine, mScriptColumn,
|
||||
nsIScriptError::errorFlag,
|
||||
"Event Source", mInnerWindowID);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@@ -255,12 +255,14 @@ protected:
|
||||
|
||||
// Event Source owner information:
|
||||
// - the script file name
|
||||
// - source code line number where the Event Source object was constructed.
|
||||
// - source code line number and column number where the Event Source object
|
||||
// was constructed.
|
||||
// - the ID of the inner window where the script lives. Note that this may not
|
||||
// be the same as the Event Source owner window.
|
||||
// These attributes are used for error reporting.
|
||||
nsString mScriptFile;
|
||||
uint32_t mScriptLine;
|
||||
uint32_t mScriptColumn;
|
||||
uint64_t mInnerWindowID;
|
||||
|
||||
private:
|
||||
|
||||
+23
-11
@@ -94,6 +94,7 @@ public:
|
||||
, mCloseEventWasClean(false)
|
||||
, mCloseEventCode(nsIWebSocketChannel::CLOSE_ABNORMAL)
|
||||
, mScriptLine(0)
|
||||
, mScriptColumn(0)
|
||||
, mInnerWindowID(0)
|
||||
, mWorkerPrivate(nullptr)
|
||||
#ifdef DEBUG
|
||||
@@ -123,6 +124,7 @@ public:
|
||||
nsTArray<nsString>& aProtocolArray,
|
||||
const nsACString& aScriptFile,
|
||||
uint32_t aScriptLine,
|
||||
uint32_t aScriptColumn,
|
||||
ErrorResult& aRv,
|
||||
bool* aConnectionFailed);
|
||||
|
||||
@@ -200,12 +202,14 @@ public:
|
||||
|
||||
// Web Socket owner information:
|
||||
// - the script file name, UTF8 encoded.
|
||||
// - source code line number where the Web Socket object was constructed.
|
||||
// - source code line number and column number where the Web Socket object
|
||||
// was constructed.
|
||||
// - the ID of the inner window where the script lives. Note that this may not
|
||||
// be the same as the Web Socket owner window.
|
||||
// These attributes are used for error reporting.
|
||||
nsCString mScriptFile;
|
||||
uint32_t mScriptLine;
|
||||
uint32_t mScriptColumn;
|
||||
uint64_t mInnerWindowID;
|
||||
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
@@ -373,13 +377,14 @@ WebSocketImpl::PrintErrorOnConsole(const char *aBundleURI,
|
||||
if (mInnerWindowID) {
|
||||
rv = errorObject->InitWithWindowID(message,
|
||||
NS_ConvertUTF8toUTF16(mScriptFile),
|
||||
EmptyString(), mScriptLine, 0,
|
||||
EmptyString(), mScriptLine,
|
||||
mScriptColumn,
|
||||
nsIScriptError::errorFlag, "Web Socket",
|
||||
mInnerWindowID);
|
||||
} else {
|
||||
rv = errorObject->Init(message,
|
||||
NS_ConvertUTF8toUTF16(mScriptFile),
|
||||
EmptyString(), mScriptLine, 0,
|
||||
EmptyString(), mScriptLine, mScriptColumn,
|
||||
nsIScriptError::errorFlag, "Web Socket");
|
||||
}
|
||||
|
||||
@@ -1080,6 +1085,7 @@ public:
|
||||
InitRunnable(WebSocketImpl* aImpl, const nsAString& aURL,
|
||||
nsTArray<nsString>& aProtocolArray,
|
||||
const nsACString& aScriptFile, uint32_t aScriptLine,
|
||||
uint32_t aScriptColumn,
|
||||
ErrorResult& aRv, bool* aConnectionFailed)
|
||||
: WebSocketMainThreadRunnable(aImpl->mWorkerPrivate)
|
||||
, mImpl(aImpl)
|
||||
@@ -1087,6 +1093,7 @@ public:
|
||||
, mProtocolArray(aProtocolArray)
|
||||
, mScriptFile(aScriptFile)
|
||||
, mScriptLine(aScriptLine)
|
||||
, mScriptColumn(aScriptColumn)
|
||||
, mRv(aRv)
|
||||
, mConnectionFailed(aConnectionFailed)
|
||||
{
|
||||
@@ -1118,7 +1125,7 @@ protected:
|
||||
}
|
||||
|
||||
mImpl->Init(jsapi.cx(), principal, mURL, mProtocolArray, mScriptFile,
|
||||
mScriptLine, mRv, mConnectionFailed);
|
||||
mScriptLine, mScriptColumn, mRv, mConnectionFailed);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1128,7 +1135,7 @@ protected:
|
||||
MOZ_ASSERT(aTopLevelWorkerPrivate && !aTopLevelWorkerPrivate->GetWindow());
|
||||
|
||||
mImpl->Init(nullptr, aTopLevelWorkerPrivate->GetPrincipal(), mURL,
|
||||
mProtocolArray, mScriptFile, mScriptLine, mRv,
|
||||
mProtocolArray, mScriptFile, mScriptLine, mScriptColumn, mRv,
|
||||
mConnectionFailed);
|
||||
return true;
|
||||
}
|
||||
@@ -1140,6 +1147,7 @@ protected:
|
||||
nsTArray<nsString>& mProtocolArray;
|
||||
nsCString mScriptFile;
|
||||
uint32_t mScriptLine;
|
||||
uint32_t mScriptColumn;
|
||||
ErrorResult& mRv;
|
||||
bool* mConnectionFailed;
|
||||
};
|
||||
@@ -1261,7 +1269,7 @@ WebSocket::Constructor(const GlobalObject& aGlobal,
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
webSocket->mImpl->Init(aGlobal.Context(), principal, aUrl, protocolArray,
|
||||
EmptyCString(), 0, aRv, &connectionFailed);
|
||||
EmptyCString(), 0, 0, aRv, &connectionFailed);
|
||||
} else {
|
||||
// In workers we have to keep the worker alive using a feature in order to
|
||||
// dispatch messages correctly.
|
||||
@@ -1270,15 +1278,16 @@ WebSocket::Constructor(const GlobalObject& aGlobal,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned lineno;
|
||||
unsigned lineno, column;
|
||||
JS::AutoFilename file;
|
||||
if (!JS::DescribeScriptedCaller(aGlobal.Context(), &file, &lineno)) {
|
||||
if (!JS::DescribeScriptedCaller(aGlobal.Context(), &file, &lineno,
|
||||
&column)) {
|
||||
NS_WARNING("Failed to get line number and filename in workers.");
|
||||
}
|
||||
|
||||
nsRefPtr<InitRunnable> runnable =
|
||||
new InitRunnable(webSocket->mImpl, aUrl, protocolArray,
|
||||
nsAutoCString(file.get()), lineno, aRv,
|
||||
nsAutoCString(file.get()), lineno, column, aRv,
|
||||
&connectionFailed);
|
||||
runnable->Dispatch(aGlobal.Context());
|
||||
}
|
||||
@@ -1439,6 +1448,7 @@ WebSocketImpl::Init(JSContext* aCx,
|
||||
nsTArray<nsString>& aProtocolArray,
|
||||
const nsACString& aScriptFile,
|
||||
uint32_t aScriptLine,
|
||||
uint32_t aScriptColumn,
|
||||
ErrorResult& aRv,
|
||||
bool* aConnectionFailed)
|
||||
{
|
||||
@@ -1478,14 +1488,16 @@ WebSocketImpl::Init(JSContext* aCx,
|
||||
if (mWorkerPrivate) {
|
||||
mScriptFile = aScriptFile;
|
||||
mScriptLine = aScriptLine;
|
||||
mScriptColumn = aScriptColumn;
|
||||
} else {
|
||||
MOZ_ASSERT(aCx);
|
||||
|
||||
unsigned lineno;
|
||||
unsigned lineno, column;
|
||||
JS::AutoFilename file;
|
||||
if (JS::DescribeScriptedCaller(aCx, &file, &lineno)) {
|
||||
if (JS::DescribeScriptedCaller(aCx, &file, &lineno, &column)) {
|
||||
mScriptFile = file.get();
|
||||
mScriptLine = lineno;
|
||||
mScriptColumn = column;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3492,7 +3492,7 @@ nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText,
|
||||
if (!aLineNumber) {
|
||||
JSContext *cx = GetCurrentJSContext();
|
||||
if (cx) {
|
||||
nsJSUtils::GetCallingLocation(cx, spec, &aLineNumber);
|
||||
nsJSUtils::GetCallingLocation(cx, spec, &aLineNumber, &aColumnNumber);
|
||||
}
|
||||
}
|
||||
if (spec.IsEmpty() && aURI)
|
||||
|
||||
@@ -155,7 +155,6 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
|
||||
, mObservingOwnerContent(false)
|
||||
, mVisible(true)
|
||||
{
|
||||
ResetPermissionManagerStatus();
|
||||
mRemoteFrame = ShouldUseRemoteProcess();
|
||||
}
|
||||
|
||||
@@ -395,6 +394,9 @@ nsFrameLoader::ReallyStartLoadingInternal()
|
||||
mURIToLoad = nullptr;
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Track the appId's reference count if this frame is in-process
|
||||
ResetPermissionManagerStatus();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -2663,7 +2665,9 @@ nsFrameLoader::ResetPermissionManagerStatus()
|
||||
{
|
||||
// The resetting of the permissions status can run only
|
||||
// in the main process.
|
||||
if (XRE_IsContentProcess()) {
|
||||
// only in-main-process && in-process frame is handled here and all other
|
||||
// cases are handled by ContentParent.
|
||||
if (XRE_IsContentProcess() || mRemoteFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -643,16 +643,29 @@ JSONCreator(const char16_t* aBuf, uint32_t aLen, void* aData)
|
||||
|
||||
static bool
|
||||
GetParamsForMessage(JSContext* aCx,
|
||||
const JS::Value& aJSON,
|
||||
const JS::Value& aData,
|
||||
JSAutoStructuredCloneBuffer& aBuffer,
|
||||
StructuredCloneClosure& aClosure)
|
||||
{
|
||||
JS::Rooted<JS::Value> v(aCx, aJSON);
|
||||
// First try to use structured clone on the whole thing.
|
||||
JS::RootedValue v(aCx, aData);
|
||||
if (WriteStructuredClone(aCx, v, aBuffer, aClosure)) {
|
||||
return true;
|
||||
}
|
||||
JS_ClearPendingException(aCx);
|
||||
|
||||
nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
|
||||
if (console) {
|
||||
nsAutoString filename;
|
||||
uint32_t lineno = 0, column = 0;
|
||||
nsJSUtils::GetCallingLocation(aCx, filename, &lineno, &column);
|
||||
nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
|
||||
error->Init(NS_LITERAL_STRING("Sending message that cannot be cloned. Are you trying to send an XPCOM object?"),
|
||||
filename, EmptyString(), lineno, column,
|
||||
nsIScriptError::warningFlag, "chrome javascript");
|
||||
console->LogMessage(error);
|
||||
}
|
||||
|
||||
// Not clonable, try JSON
|
||||
//XXX This is ugly but currently structured cloning doesn't handle
|
||||
// properly cases when interface is implemented in JS and used
|
||||
|
||||
+20
-13
@@ -2378,6 +2378,17 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
||||
jsapi.Init();
|
||||
JSContext *cx = jsapi.cx();
|
||||
|
||||
// Check if we're anywhere near the stack limit before we reach the
|
||||
// transplanting code, since it has no good way to handle errors. This uses
|
||||
// the untrusted script limit, which is not strictly necessary since no
|
||||
// actual script should run.
|
||||
bool overrecursed = false;
|
||||
JS_CHECK_RECURSION_CONSERVATIVE_DONT_REPORT(cx, overrecursed = true);
|
||||
if (overrecursed) {
|
||||
NS_WARNING("Overrecursion in SetNewDocument");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!mDoc) {
|
||||
// First document load.
|
||||
|
||||
@@ -2434,12 +2445,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
||||
|
||||
bool thisChrome = IsChromeWindow();
|
||||
|
||||
// Check if we're anywhere near the stack limit before we reach the
|
||||
// transplanting code, since it has no good way to handle errors. This uses
|
||||
// the untrusted script limit, which is not strictly necessary since no
|
||||
// actual script should run.
|
||||
JS_CHECK_RECURSION_CONSERVATIVE(cx, return NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
|
||||
NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
|
||||
|
||||
@@ -12109,7 +12114,8 @@ nsGlobalWindow::SetTimeout(JSContext* aCx, Function& aFunction,
|
||||
const Sequence<JS::Value>& aArguments,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
return SetTimeoutOrInterval(aFunction, aTimeout, aArguments, false, aError);
|
||||
return SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments, false,
|
||||
aError);
|
||||
}
|
||||
|
||||
int32_t
|
||||
@@ -12143,7 +12149,7 @@ nsGlobalWindow::SetInterval(JSContext* aCx, Function& aFunction,
|
||||
{
|
||||
int32_t timeout;
|
||||
bool isInterval = IsInterval(aTimeout, timeout);
|
||||
return SetTimeoutOrInterval(aFunction, timeout, aArguments, isInterval,
|
||||
return SetTimeoutOrInterval(aCx, aFunction, timeout, aArguments, isInterval,
|
||||
aError);
|
||||
}
|
||||
|
||||
@@ -12285,7 +12291,8 @@ nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
|
||||
}
|
||||
|
||||
int32_t
|
||||
nsGlobalWindow::SetTimeoutOrInterval(Function& aFunction, int32_t aTimeout,
|
||||
nsGlobalWindow::SetTimeoutOrInterval(JSContext *aCx, Function& aFunction,
|
||||
int32_t aTimeout,
|
||||
const Sequence<JS::Value>& aArguments,
|
||||
bool aIsInterval, ErrorResult& aError)
|
||||
{
|
||||
@@ -12295,12 +12302,12 @@ nsGlobalWindow::SetTimeoutOrInterval(Function& aFunction, int32_t aTimeout,
|
||||
}
|
||||
|
||||
if (inner != this) {
|
||||
return inner->SetTimeoutOrInterval(aFunction, aTimeout, aArguments,
|
||||
return inner->SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments,
|
||||
aIsInterval, aError);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptTimeoutHandler> handler =
|
||||
NS_CreateJSTimeoutHandler(this, aFunction, aArguments, aError);
|
||||
NS_CreateJSTimeoutHandler(aCx, this, aFunction, aArguments, aError);
|
||||
if (!handler) {
|
||||
return 0;
|
||||
}
|
||||
@@ -12382,8 +12389,8 @@ nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout,
|
||||
NS_ASSERTION(script, "timeout has no script nor handler text!");
|
||||
|
||||
const char* filename = nullptr;
|
||||
uint32_t lineNo = 0;
|
||||
handler->GetLocation(&filename, &lineNo);
|
||||
uint32_t lineNo = 0, dummyColumn = 0;
|
||||
handler->GetLocation(&filename, &lineNo, &dummyColumn);
|
||||
|
||||
// New script entry point required, due to the "Create a script" sub-step of
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#timer-initialisation-steps
|
||||
|
||||
@@ -130,7 +130,7 @@ class VRHMDInfo;
|
||||
} // namespace mozilla
|
||||
|
||||
extern already_AddRefed<nsIScriptTimeoutHandler>
|
||||
NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow,
|
||||
NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
|
||||
mozilla::dom::Function& aFunction,
|
||||
const mozilla::dom::Sequence<JS::Value>& aArguments,
|
||||
mozilla::ErrorResult& aError);
|
||||
@@ -1390,7 +1390,8 @@ public:
|
||||
nsresult SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
|
||||
int32_t interval,
|
||||
bool aIsInterval, int32_t* aReturn) override;
|
||||
int32_t SetTimeoutOrInterval(mozilla::dom::Function& aFunction,
|
||||
int32_t SetTimeoutOrInterval(JSContext* aCx,
|
||||
mozilla::dom::Function& aFunction,
|
||||
int32_t aTimeout,
|
||||
const mozilla::dom::Sequence<JS::Value>& aArguments,
|
||||
bool aIsInterval, mozilla::ErrorResult& aError);
|
||||
|
||||
@@ -39,7 +39,8 @@ public:
|
||||
// Get the location of the script.
|
||||
// Note: The memory pointed to by aFileName is owned by the
|
||||
// nsIScriptTimeoutHandler and should not be freed by the caller.
|
||||
virtual void GetLocation(const char **aFileName, uint32_t *aLineNo) = 0;
|
||||
virtual void GetLocation(const char **aFileName, uint32_t *aLineNo,
|
||||
uint32_t *aColumn) = 0;
|
||||
|
||||
// If we have a Function, get the arguments for passing to it.
|
||||
virtual const nsTArray<JS::Value>& GetArgs() = 0;
|
||||
|
||||
@@ -35,7 +35,8 @@ public:
|
||||
|
||||
nsJSScriptTimeoutHandler();
|
||||
// This will call SwapElements on aArguments with an empty array.
|
||||
nsJSScriptTimeoutHandler(nsGlobalWindow *aWindow, Function& aFunction,
|
||||
nsJSScriptTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
|
||||
Function& aFunction,
|
||||
FallibleTArray<JS::Heap<JS::Value> >& aArguments,
|
||||
ErrorResult& aError);
|
||||
nsJSScriptTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
|
||||
@@ -47,10 +48,12 @@ public:
|
||||
{
|
||||
return mFunction;
|
||||
}
|
||||
virtual void GetLocation(const char** aFileName, uint32_t* aLineNo) override
|
||||
virtual void GetLocation(const char** aFileName, uint32_t* aLineNo,
|
||||
uint32_t* aColumn) override
|
||||
{
|
||||
*aFileName = mFileName.get();
|
||||
*aLineNo = mLineNo;
|
||||
*aColumn = mColumn;
|
||||
}
|
||||
|
||||
virtual const nsTArray<JS::Value>& GetArgs() override
|
||||
@@ -67,6 +70,7 @@ private:
|
||||
// caller of setTimeout()
|
||||
nsCString mFileName;
|
||||
uint32_t mLineNo;
|
||||
uint32_t mColumn;
|
||||
nsTArray<JS::Heap<JS::Value> > mArgs;
|
||||
|
||||
// The expression to evaluate or function to call. If mFunction is non-null
|
||||
@@ -106,6 +110,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSScriptTimeoutHandler)
|
||||
name.Append(tmp->mFileName);
|
||||
name.Append(':');
|
||||
name.AppendInt(tmp->mLineNo);
|
||||
name.Append(':');
|
||||
name.AppendInt(tmp->mColumn);
|
||||
name.Append(']');
|
||||
}
|
||||
cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name.get());
|
||||
@@ -183,17 +189,20 @@ CheckCSPForEval(JSContext* aCx, nsGlobalWindow* aWindow, ErrorResult& aError)
|
||||
return allowsEval;
|
||||
}
|
||||
|
||||
nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler() :
|
||||
mLineNo(0)
|
||||
nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler()
|
||||
: mLineNo(0)
|
||||
, mColumn(0)
|
||||
{
|
||||
}
|
||||
|
||||
nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(nsGlobalWindow *aWindow,
|
||||
nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
|
||||
nsGlobalWindow *aWindow,
|
||||
Function& aFunction,
|
||||
FallibleTArray<JS::Heap<JS::Value> >& aArguments,
|
||||
ErrorResult& aError) :
|
||||
mLineNo(0),
|
||||
mFunction(&aFunction)
|
||||
ErrorResult& aError)
|
||||
: mLineNo(0)
|
||||
, mColumn(0)
|
||||
, mFunction(&aFunction)
|
||||
{
|
||||
if (!aWindow->GetContextInternal() || !aWindow->FastGetGlobalJSObject()) {
|
||||
// This window was already closed, or never properly initialized,
|
||||
@@ -204,15 +213,19 @@ nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(nsGlobalWindow *aWindow,
|
||||
|
||||
mozilla::HoldJSObjects(this);
|
||||
mArgs.SwapElements(aArguments);
|
||||
|
||||
// Get the calling location.
|
||||
nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo, &mColumn);
|
||||
}
|
||||
|
||||
nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
|
||||
nsGlobalWindow *aWindow,
|
||||
const nsAString& aExpression,
|
||||
bool* aAllowEval,
|
||||
ErrorResult& aError) :
|
||||
mLineNo(0),
|
||||
mExpr(aExpression)
|
||||
ErrorResult& aError)
|
||||
: mLineNo(0)
|
||||
, mColumn(0)
|
||||
, mExpr(aExpression)
|
||||
{
|
||||
if (!aWindow->GetContextInternal() || !aWindow->FastGetGlobalJSObject()) {
|
||||
// This window was already closed, or never properly initialized,
|
||||
@@ -227,7 +240,7 @@ nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
|
||||
}
|
||||
|
||||
// Get the calling location.
|
||||
nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo);
|
||||
nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo, &mColumn);
|
||||
}
|
||||
|
||||
nsJSScriptTimeoutHandler::~nsJSScriptTimeoutHandler()
|
||||
@@ -253,7 +266,8 @@ nsJSScriptTimeoutHandler::GetHandlerText()
|
||||
}
|
||||
|
||||
already_AddRefed<nsIScriptTimeoutHandler>
|
||||
NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow, Function& aFunction,
|
||||
NS_CreateJSTimeoutHandler(JSContext *aCx, nsGlobalWindow *aWindow,
|
||||
Function& aFunction,
|
||||
const Sequence<JS::Value>& aArguments,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
@@ -264,7 +278,7 @@ NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow, Function& aFunction,
|
||||
}
|
||||
|
||||
nsRefPtr<nsJSScriptTimeoutHandler> handler =
|
||||
new nsJSScriptTimeoutHandler(aWindow, aFunction, args, aError);
|
||||
new nsJSScriptTimeoutHandler(aCx, aWindow, aFunction, args, aError);
|
||||
return aError.Failed() ? nullptr : handler.forget();
|
||||
}
|
||||
|
||||
|
||||
@@ -35,10 +35,10 @@ using namespace mozilla::dom;
|
||||
|
||||
bool
|
||||
nsJSUtils::GetCallingLocation(JSContext* aContext, nsACString& aFilename,
|
||||
uint32_t* aLineno)
|
||||
uint32_t* aLineno, uint32_t* aColumn)
|
||||
{
|
||||
JS::AutoFilename filename;
|
||||
if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno)) {
|
||||
if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno, aColumn)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -48,10 +48,10 @@ nsJSUtils::GetCallingLocation(JSContext* aContext, nsACString& aFilename,
|
||||
|
||||
bool
|
||||
nsJSUtils::GetCallingLocation(JSContext* aContext, nsAString& aFilename,
|
||||
uint32_t* aLineno)
|
||||
uint32_t* aLineno, uint32_t* aColumn)
|
||||
{
|
||||
JS::AutoFilename filename;
|
||||
if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno)) {
|
||||
if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno, aColumn)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,9 +35,11 @@ class nsJSUtils
|
||||
{
|
||||
public:
|
||||
static bool GetCallingLocation(JSContext* aContext, nsACString& aFilename,
|
||||
uint32_t* aLineno);
|
||||
uint32_t* aLineno = nullptr,
|
||||
uint32_t* aColumn = nullptr);
|
||||
static bool GetCallingLocation(JSContext* aContext, nsAString& aFilename,
|
||||
uint32_t* aLineno);
|
||||
uint32_t* aLineno = nullptr,
|
||||
uint32_t* aColumn = nullptr);
|
||||
|
||||
static nsIScriptGlobalObject *GetStaticScriptGlobal(JSObject* aObj);
|
||||
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
#include "mozilla/dom/MimeTypeArrayBinding.h"
|
||||
#include "mozilla/dom/MimeTypeBinding.h"
|
||||
#include "nsIDOMNavigator.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsPluginArray.h"
|
||||
#include "nsIMIMEService.h"
|
||||
#include "nsIMIMEInfo.h"
|
||||
#include "Navigator.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsPluginTags.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@@ -27,8 +29,7 @@ NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsMimeTypeArray,
|
||||
mWindow,
|
||||
mMimeTypes,
|
||||
mHiddenMimeTypes)
|
||||
mMimeTypes)
|
||||
|
||||
nsMimeTypeArray::nsMimeTypeArray(nsPIDOMWindow* aWindow)
|
||||
: mWindow(aWindow)
|
||||
@@ -49,7 +50,6 @@ void
|
||||
nsMimeTypeArray::Refresh()
|
||||
{
|
||||
mMimeTypes.Clear();
|
||||
mHiddenMimeTypes.Clear();
|
||||
}
|
||||
|
||||
nsPIDOMWindow*
|
||||
@@ -114,10 +114,6 @@ nsMimeTypeArray::NamedGetter(const nsAString& aName, bool &aFound)
|
||||
ToLowerCase(lowerName);
|
||||
|
||||
nsMimeType* mimeType = FindMimeType(mMimeTypes, lowerName);
|
||||
if (!mimeType) {
|
||||
mimeType = FindMimeType(mHiddenMimeTypes, lowerName);
|
||||
}
|
||||
|
||||
if (mimeType) {
|
||||
aFound = true;
|
||||
return mimeType;
|
||||
@@ -164,11 +160,8 @@ nsMimeTypeArray::NamedGetter(const nsAString& aName, bool &aFound)
|
||||
// If we got here, we support this type! Say so.
|
||||
aFound = true;
|
||||
|
||||
// We don't want navigator.mimeTypes enumeration to expose MIME types with
|
||||
// application handlers, so add them to the list of hidden MIME types.
|
||||
nsMimeType *mt = new nsMimeType(mWindow, lowerName);
|
||||
mHiddenMimeTypes.AppendElement(mt);
|
||||
|
||||
mMimeTypes.AppendElement(mt);
|
||||
return mt;
|
||||
}
|
||||
|
||||
@@ -199,7 +192,7 @@ nsMimeTypeArray::GetSupportedNames(unsigned, nsTArray< nsString >& aRetval)
|
||||
void
|
||||
nsMimeTypeArray::EnsurePluginMimeTypes()
|
||||
{
|
||||
if (!mMimeTypes.IsEmpty() || !mHiddenMimeTypes.IsEmpty() || !mWindow) {
|
||||
if (!mMimeTypes.IsEmpty() || !mWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -217,7 +210,7 @@ nsMimeTypeArray::EnsurePluginMimeTypes()
|
||||
return;
|
||||
}
|
||||
|
||||
pluginArray->GetMimeTypes(mMimeTypes, mHiddenMimeTypes);
|
||||
pluginArray->GetMimeTypes(mMimeTypes);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsMimeType, AddRef)
|
||||
@@ -225,19 +218,22 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsMimeType, Release)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsMimeType, mWindow, mPluginElement)
|
||||
|
||||
nsMimeType::nsMimeType(nsPIDOMWindow* aWindow, nsPluginElement* aPluginElement,
|
||||
uint32_t aPluginTagMimeIndex, const nsAString& aType)
|
||||
nsMimeType::nsMimeType(nsPIDOMWindow* aWindow,
|
||||
nsPluginElement* aPluginElement,
|
||||
const nsAString& aType,
|
||||
const nsAString& aDescription,
|
||||
const nsAString& aExtension)
|
||||
: mWindow(aWindow),
|
||||
mPluginElement(aPluginElement),
|
||||
mPluginTagMimeIndex(aPluginTagMimeIndex),
|
||||
mType(aType)
|
||||
mType(aType),
|
||||
mDescription(aDescription),
|
||||
mExtension(aExtension)
|
||||
{
|
||||
}
|
||||
|
||||
nsMimeType::nsMimeType(nsPIDOMWindow* aWindow, const nsAString& aType)
|
||||
: mWindow(aWindow),
|
||||
mPluginElement(nullptr),
|
||||
mPluginTagMimeIndex(0),
|
||||
mType(aType)
|
||||
{
|
||||
}
|
||||
@@ -260,14 +256,9 @@ nsMimeType::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
}
|
||||
|
||||
void
|
||||
nsMimeType::GetDescription(nsString& retval) const
|
||||
nsMimeType::GetDescription(nsString& aRetval) const
|
||||
{
|
||||
retval.Truncate();
|
||||
|
||||
if (mPluginElement) {
|
||||
CopyUTF8toUTF16(mPluginElement->PluginTag()->
|
||||
mMimeDescriptions[mPluginTagMimeIndex], retval);
|
||||
}
|
||||
aRetval = mDescription;
|
||||
}
|
||||
|
||||
nsPluginElement*
|
||||
@@ -280,14 +271,9 @@ nsMimeType::GetEnabledPlugin() const
|
||||
}
|
||||
|
||||
void
|
||||
nsMimeType::GetSuffixes(nsString& retval) const
|
||||
nsMimeType::GetSuffixes(nsString& aRetval) const
|
||||
{
|
||||
retval.Truncate();
|
||||
|
||||
if (mPluginElement) {
|
||||
CopyUTF8toUTF16(mPluginElement->PluginTag()->
|
||||
mExtensions[mPluginTagMimeIndex], retval);
|
||||
}
|
||||
aRetval = mExtension;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -47,16 +47,9 @@ protected:
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
|
||||
// mMimeTypes contains MIME types handled by non-hidden plugins, those
|
||||
// popular plugins that must be exposed in navigator.plugins enumeration to
|
||||
// avoid breaking web content. Likewise, mMimeTypes are exposed in
|
||||
// navigator.mimeTypes enumeration.
|
||||
// mMimeTypes contains MIME types handled by plugins or by an OS
|
||||
// PreferredApplicationHandler.
|
||||
nsTArray<nsRefPtr<nsMimeType> > mMimeTypes;
|
||||
|
||||
// mHiddenMimeTypes contains MIME types handled by plugins hidden from
|
||||
// navigator.plugins enumeration or by an OS PreferredApplicationHandler.
|
||||
// mHiddenMimeTypes are hidden from navigator.mimeTypes enumeration.
|
||||
nsTArray<nsRefPtr<nsMimeType> > mHiddenMimeTypes;
|
||||
};
|
||||
|
||||
class nsMimeType final : public nsWrapperCache
|
||||
@@ -65,8 +58,11 @@ public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsMimeType)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(nsMimeType)
|
||||
|
||||
nsMimeType(nsPIDOMWindow* aWindow, nsPluginElement* aPluginElement,
|
||||
uint32_t aPluginTagMimeIndex, const nsAString& aMimeType);
|
||||
nsMimeType(nsPIDOMWindow* aWindow,
|
||||
nsPluginElement* aPluginElement,
|
||||
const nsAString& aType,
|
||||
const nsAString& aDescription,
|
||||
const nsAString& aExtension);
|
||||
nsMimeType(nsPIDOMWindow* aWindow, const nsAString& aMimeType);
|
||||
nsPIDOMWindow* GetParentObject() const;
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
@@ -92,8 +88,9 @@ protected:
|
||||
// mimetype array. We rely on the cycle collector to break this
|
||||
// cycle.
|
||||
nsRefPtr<nsPluginElement> mPluginElement;
|
||||
uint32_t mPluginTagMimeIndex;
|
||||
nsString mType;
|
||||
nsString mDescription;
|
||||
nsString mExtension;
|
||||
};
|
||||
|
||||
#endif /* nsMimeTypeArray_h___ */
|
||||
|
||||
+26
-76
@@ -6,11 +6,9 @@
|
||||
|
||||
#include "nsPluginArray.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/PluginArrayBinding.h"
|
||||
#include "mozilla/dom/PluginBinding.h"
|
||||
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsMimeTypeArray.h"
|
||||
#include "Navigator.h"
|
||||
#include "nsIDocShell.h"
|
||||
@@ -68,8 +66,7 @@ NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginArray,
|
||||
mWindow,
|
||||
mPlugins,
|
||||
mHiddenPlugins)
|
||||
mPlugins)
|
||||
|
||||
static void
|
||||
GetPluginMimeTypes(const nsTArray<nsRefPtr<nsPluginElement> >& aPlugins,
|
||||
@@ -89,11 +86,9 @@ operator<(const nsRefPtr<nsMimeType>& lhs, const nsRefPtr<nsMimeType>& rhs)
|
||||
}
|
||||
|
||||
void
|
||||
nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes,
|
||||
nsTArray<nsRefPtr<nsMimeType> >& aHiddenMimeTypes)
|
||||
nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType>>& aMimeTypes)
|
||||
{
|
||||
aMimeTypes.Clear();
|
||||
aHiddenMimeTypes.Clear();
|
||||
|
||||
if (!AllowPlugins()) {
|
||||
return;
|
||||
@@ -102,7 +97,6 @@ nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes,
|
||||
EnsurePlugins();
|
||||
|
||||
GetPluginMimeTypes(mPlugins, aMimeTypes);
|
||||
GetPluginMimeTypes(mHiddenPlugins, aHiddenMimeTypes);
|
||||
|
||||
// Alphabetize the enumeration order of non-hidden MIME types to reduce
|
||||
// fingerprintable entropy based on plugins' installation file times.
|
||||
@@ -136,7 +130,7 @@ nsPluginArray::Refresh(bool aReloadDocuments)
|
||||
// that plugins did not change and was not reloaded
|
||||
if (pluginHost->ReloadPlugins() ==
|
||||
NS_ERROR_PLUGINS_PLUGINSNOTCHANGED) {
|
||||
nsTArray<nsRefPtr<nsPluginTag> > newPluginTags;
|
||||
nsTArray<nsCOMPtr<nsIInternalPluginTag> > newPluginTags;
|
||||
pluginHost->GetPlugins(newPluginTags);
|
||||
|
||||
// Check if the number of plugins we know about are different from
|
||||
@@ -146,14 +140,12 @@ nsPluginArray::Refresh(bool aReloadDocuments)
|
||||
// happens, and therefore the lengths will be in sync only when
|
||||
// the both arrays contain the same plugin tags (though as
|
||||
// different types).
|
||||
uint32_t pluginCount = mPlugins.Length() + mHiddenPlugins.Length();
|
||||
if (newPluginTags.Length() == pluginCount) {
|
||||
if (newPluginTags.Length() == mPlugins.Length()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mPlugins.Clear();
|
||||
mHiddenPlugins.Clear();
|
||||
|
||||
nsCOMPtr<nsIDOMNavigator> navigator;
|
||||
mWindow->GetNavigator(getter_AddRefs(navigator));
|
||||
@@ -229,10 +221,6 @@ nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound)
|
||||
EnsurePlugins();
|
||||
|
||||
nsPluginElement* plugin = FindPlugin(mPlugins, aName);
|
||||
if (!plugin) {
|
||||
plugin = FindPlugin(mHiddenPlugins, aName);
|
||||
}
|
||||
|
||||
aFound = (plugin != nullptr);
|
||||
return plugin;
|
||||
}
|
||||
@@ -290,40 +278,18 @@ nsPluginArray::AllowPlugins() const
|
||||
return docShell && docShell->PluginsAllowedInCurrentDoc();
|
||||
}
|
||||
|
||||
static bool
|
||||
HasStringPrefix(const nsCString& str, const nsACString& prefix) {
|
||||
return str.Compare(prefix.BeginReading(), false, prefix.Length()) == 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsPluginEnumerable(const nsTArray<nsCString>& enumerableNames,
|
||||
const nsPluginTag* pluginTag)
|
||||
{
|
||||
const nsCString& pluginName = pluginTag->mName;
|
||||
|
||||
const uint32_t length = enumerableNames.Length();
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
const nsCString& name = enumerableNames[i];
|
||||
if (HasStringPrefix(pluginName, name)) {
|
||||
return true; // don't hide plugin
|
||||
}
|
||||
}
|
||||
|
||||
return false; // hide plugin!
|
||||
}
|
||||
|
||||
static bool
|
||||
operator<(const nsRefPtr<nsPluginElement>& lhs,
|
||||
const nsRefPtr<nsPluginElement>& rhs)
|
||||
{
|
||||
// Sort plugins alphabetically by name.
|
||||
return lhs->PluginTag()->mName < rhs->PluginTag()->mName;
|
||||
return lhs->PluginTag()->Name() < rhs->PluginTag()->Name();
|
||||
}
|
||||
|
||||
void
|
||||
nsPluginArray::EnsurePlugins()
|
||||
{
|
||||
if (!mPlugins.IsEmpty() || !mHiddenPlugins.IsEmpty()) {
|
||||
if (!mPlugins.IsEmpty()) {
|
||||
// We already have an array of plugin elements.
|
||||
return;
|
||||
}
|
||||
@@ -334,39 +300,13 @@ nsPluginArray::EnsurePlugins()
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<nsRefPtr<nsPluginTag> > pluginTags;
|
||||
nsTArray<nsCOMPtr<nsIInternalPluginTag> > pluginTags;
|
||||
pluginHost->GetPlugins(pluginTags);
|
||||
|
||||
nsTArray<nsCString> enumerableNames;
|
||||
|
||||
const nsAdoptingCString& enumerableNamesPref =
|
||||
Preferences::GetCString("plugins.enumerable_names");
|
||||
|
||||
bool disablePluginHiding = !enumerableNamesPref ||
|
||||
enumerableNamesPref.EqualsLiteral("*");
|
||||
|
||||
if (!disablePluginHiding) {
|
||||
nsCCharSeparatedTokenizer tokens(enumerableNamesPref, ',');
|
||||
while (tokens.hasMoreTokens()) {
|
||||
const nsCSubstring& token = tokens.nextToken();
|
||||
if (!token.IsEmpty()) {
|
||||
enumerableNames.AppendElement(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// need to wrap each of these with a nsPluginElement, which is
|
||||
// scriptable.
|
||||
for (uint32_t i = 0; i < pluginTags.Length(); ++i) {
|
||||
nsPluginTag* pluginTag = pluginTags[i];
|
||||
|
||||
// Add the plugin to the list of hidden plugins or non-hidden plugins?
|
||||
nsTArray<nsRefPtr<nsPluginElement> >& pluginArray =
|
||||
(disablePluginHiding || IsPluginEnumerable(enumerableNames, pluginTag))
|
||||
? mPlugins
|
||||
: mHiddenPlugins;
|
||||
|
||||
pluginArray.AppendElement(new nsPluginElement(mWindow, pluginTag));
|
||||
mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i]));
|
||||
}
|
||||
|
||||
// Alphabetize the enumeration order of non-hidden plugins to reduce
|
||||
@@ -386,7 +326,7 @@ NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginElement, mWindow, mMimeTypes)
|
||||
|
||||
nsPluginElement::nsPluginElement(nsPIDOMWindow* aWindow,
|
||||
nsPluginTag* aPluginTag)
|
||||
nsIInternalPluginTag* aPluginTag)
|
||||
: mWindow(aWindow),
|
||||
mPluginTag(aPluginTag)
|
||||
{
|
||||
@@ -412,25 +352,25 @@ nsPluginElement::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
void
|
||||
nsPluginElement::GetDescription(nsString& retval) const
|
||||
{
|
||||
CopyUTF8toUTF16(mPluginTag->mDescription, retval);
|
||||
CopyUTF8toUTF16(mPluginTag->Description(), retval);
|
||||
}
|
||||
|
||||
void
|
||||
nsPluginElement::GetFilename(nsString& retval) const
|
||||
{
|
||||
CopyUTF8toUTF16(mPluginTag->mFileName, retval);
|
||||
CopyUTF8toUTF16(mPluginTag->FileName(), retval);
|
||||
}
|
||||
|
||||
void
|
||||
nsPluginElement::GetVersion(nsString& retval) const
|
||||
{
|
||||
CopyUTF8toUTF16(mPluginTag->mVersion, retval);
|
||||
CopyUTF8toUTF16(mPluginTag->Version(), retval);
|
||||
}
|
||||
|
||||
void
|
||||
nsPluginElement::GetName(nsString& retval) const
|
||||
{
|
||||
CopyUTF8toUTF16(mPluginTag->mName, retval);
|
||||
CopyUTF8toUTF16(mPluginTag->Name(), retval);
|
||||
}
|
||||
|
||||
nsMimeType*
|
||||
@@ -519,8 +459,18 @@ nsPluginElement::EnsurePluginMimeTypes()
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mPluginTag->mMimeTypes.Length(); ++i) {
|
||||
NS_ConvertUTF8toUTF16 type(mPluginTag->mMimeTypes[i]);
|
||||
mMimeTypes.AppendElement(new nsMimeType(mWindow, this, i, type));
|
||||
if (mPluginTag->MimeTypes().Length() != mPluginTag->MimeDescriptions().Length() ||
|
||||
mPluginTag->MimeTypes().Length() != mPluginTag->Extensions().Length()) {
|
||||
MOZ_ASSERT(false, "mime type arrays expected to be the same length");
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mPluginTag->MimeTypes().Length(); ++i) {
|
||||
NS_ConvertUTF8toUTF16 type(mPluginTag->MimeTypes()[i]);
|
||||
NS_ConvertUTF8toUTF16 description(mPluginTag->MimeDescriptions()[i]);
|
||||
NS_ConvertUTF8toUTF16 extension(mPluginTag->Extensions()[i]);
|
||||
|
||||
mMimeTypes.AppendElement(new nsMimeType(mWindow, this, type, description,
|
||||
extension));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsPluginTags.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
class nsPluginElement;
|
||||
class nsMimeType;
|
||||
class nsIInternalPluginTag;
|
||||
|
||||
class nsPluginArray final : public nsIObserver,
|
||||
public nsSupportsWeakReference,
|
||||
@@ -40,8 +40,7 @@ public:
|
||||
void Init();
|
||||
void Invalidate();
|
||||
|
||||
void GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes,
|
||||
nsTArray<nsRefPtr<nsMimeType> >& aHiddenMimeTypes);
|
||||
void GetMimeTypes(nsTArray<nsRefPtr<nsMimeType>>& aMimeTypes);
|
||||
|
||||
// PluginArray WebIDL methods
|
||||
|
||||
@@ -61,18 +60,7 @@ private:
|
||||
void EnsurePlugins();
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
|
||||
// Many sites check whether a particular plugin is installed by enumerating
|
||||
// all navigator.plugins, checking each plugin's name. These sites should
|
||||
// just check navigator.plugins["Popular Plugin Name"] instead. mPlugins
|
||||
// contains those popular plugins that must be exposed in navigator.plugins
|
||||
// enumeration to avoid breaking web content.
|
||||
nsTArray<nsRefPtr<nsPluginElement> > mPlugins;
|
||||
|
||||
// mHiddenPlugins contains plugins that can be queried by
|
||||
// navigator.plugins["Hidden Plugin Name"] but do not need to be exposed in
|
||||
// navigator.plugins enumeration.
|
||||
nsTArray<nsRefPtr<nsPluginElement> > mHiddenPlugins;
|
||||
};
|
||||
|
||||
class nsPluginElement final : public nsISupports,
|
||||
@@ -82,12 +70,12 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsPluginElement)
|
||||
|
||||
nsPluginElement(nsPIDOMWindow* aWindow, nsPluginTag* aPluginTag);
|
||||
nsPluginElement(nsPIDOMWindow* aWindow, nsIInternalPluginTag* aPluginTag);
|
||||
|
||||
nsPIDOMWindow* GetParentObject() const;
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
nsPluginTag* PluginTag() const
|
||||
nsIInternalPluginTag* PluginTag() const
|
||||
{
|
||||
return mPluginTag;
|
||||
}
|
||||
@@ -114,7 +102,7 @@ protected:
|
||||
void EnsurePluginMimeTypes();
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
nsRefPtr<nsPluginTag> mPluginTag;
|
||||
nsCOMPtr<nsIInternalPluginTag> mPluginTag;
|
||||
nsTArray<nsRefPtr<nsMimeType> > mMimeTypes;
|
||||
};
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
var SimpleURI = Cc["@mozilla.org/network/simple-uri;1"];
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
var contentSecManager = Cc["@mozilla.org/contentsecuritymanager;1"]
|
||||
.getService(Ci.nsIContentSecurityManager);
|
||||
|
||||
var PROTOCOL_SCHEME = "jsproto";
|
||||
|
||||
@@ -68,12 +70,22 @@ CustomChannel.prototype = {
|
||||
listener.onStopRequest(this, context, Cr.NS_OK);
|
||||
} catch(e) {}
|
||||
},
|
||||
asyncOpen2: function(listener) {
|
||||
// throws an error if security checks fail
|
||||
var outListener = contentSecManager.performSecurityCheck(this, listener);
|
||||
return this.asyncOpen(outListener, null);
|
||||
},
|
||||
open: function() {
|
||||
let data = "bar";
|
||||
let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
|
||||
stream.setData(data, data.length);
|
||||
return stream;
|
||||
},
|
||||
open2: function() {
|
||||
// throws an error if security checks fail
|
||||
contentSecManager.performSecurityCheck(this, null);
|
||||
return this.open();
|
||||
},
|
||||
isPending: function() {
|
||||
return false;
|
||||
},
|
||||
|
||||
@@ -8446,7 +8446,7 @@ class CGMemberJITInfo(CGThing):
|
||||
"""
|
||||
{
|
||||
{ ${opName} },
|
||||
prototypes::id::${name},
|
||||
{ prototypes::id::${name} },
|
||||
PrototypeTraits<prototypes::id::${name}>::Depth,
|
||||
JSJitInfo::${opType},
|
||||
JSJitInfo::${aliasSet}, /* aliasSet. Not relevant for setters. */
|
||||
@@ -8827,7 +8827,7 @@ class CGStaticMethodJitinfo(CGGeneric):
|
||||
"\n"
|
||||
"static const JSJitInfo %s_methodinfo = {\n"
|
||||
" { (JSJitGetterOp)%s },\n"
|
||||
" prototypes::id::_ID_Count, 0, JSJitInfo::StaticMethod,\n"
|
||||
" { prototypes::id::_ID_Count }, 0, JSJitInfo::StaticMethod,\n"
|
||||
" JSJitInfo::AliasEverything, JSVAL_TYPE_MISSING, false, false,\n"
|
||||
" false, false, 0\n"
|
||||
"};\n" %
|
||||
|
||||
@@ -162,31 +162,6 @@ DOMProxyHandler::isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaseDOMProxyHandler::getPropertyDescriptor(JSContext* cx,
|
||||
JS::Handle<JSObject*> proxy,
|
||||
JS::Handle<jsid> id,
|
||||
MutableHandle<JSPropertyDescriptor> desc) const
|
||||
{
|
||||
if (!getOwnPropertyDescriptor(cx, proxy, id, desc)) {
|
||||
return false;
|
||||
}
|
||||
if (desc.object()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> proto(cx);
|
||||
if (!js::GetObjectProto(cx, proxy, &proto)) {
|
||||
return false;
|
||||
}
|
||||
if (!proto) {
|
||||
desc.object().set(nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
return JS_GetPropertyDescriptorById(cx, proto, id, desc);
|
||||
}
|
||||
|
||||
bool
|
||||
BaseDOMProxyHandler::getOwnPropertyDescriptor(JSContext* cx,
|
||||
JS::Handle<JSObject*> proxy,
|
||||
|
||||
@@ -59,10 +59,6 @@ public:
|
||||
virtual bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::AutoIdVector &props) const override;
|
||||
|
||||
bool getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JSPropertyDescriptor> desc) const override;
|
||||
|
||||
virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> proxy,
|
||||
JS::MutableHandle<JSObject*> objp) const override;
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ skip-if = debug == false
|
||||
[test_bug963382.html]
|
||||
skip-if = debug == false
|
||||
[test_bug1041646.html]
|
||||
[test_bug1123875.html]
|
||||
[test_barewordGetsWindow.html]
|
||||
[test_callback_default_thisval.html]
|
||||
[test_cloneAndImportNode.html]
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>Test for Bug 1123875</title>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<div id=log></div>
|
||||
<script>
|
||||
test(() => {
|
||||
assert_throws(new TypeError, () => {
|
||||
"use strict";
|
||||
document.childNodes.length = 0;
|
||||
});
|
||||
}, "setting a readonly attribute on a proxy in strict mode should throw a TypeError");
|
||||
</script>
|
||||
@@ -427,6 +427,10 @@ const kEventConstructors = {
|
||||
return e;
|
||||
},
|
||||
},
|
||||
SpeechRecognitionError: { create: function (aName, aProps) {
|
||||
return new SpeechRecognitionError(aName, aProps);
|
||||
},
|
||||
},
|
||||
SpeechRecognitionEvent: { create: function (aName, aProps) {
|
||||
return new SpeechRecognitionEvent(aName, aProps);
|
||||
},
|
||||
|
||||
@@ -187,6 +187,7 @@ class IDBDatabase::LogWarningRunnable final
|
||||
nsCString mMessageName;
|
||||
nsString mFilename;
|
||||
uint32_t mLineNumber;
|
||||
uint32_t mColumnNumber;
|
||||
uint64_t mInnerWindowID;
|
||||
bool mIsChrome;
|
||||
|
||||
@@ -194,11 +195,13 @@ public:
|
||||
LogWarningRunnable(const char* aMessageName,
|
||||
const nsAString& aFilename,
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber,
|
||||
bool aIsChrome,
|
||||
uint64_t aInnerWindowID)
|
||||
: mMessageName(aMessageName)
|
||||
, mFilename(aFilename)
|
||||
, mLineNumber(aLineNumber)
|
||||
, mColumnNumber(aColumnNumber)
|
||||
, mInnerWindowID(aInnerWindowID)
|
||||
, mIsChrome(aIsChrome)
|
||||
{
|
||||
@@ -209,6 +212,7 @@ public:
|
||||
LogWarning(const char* aMessageName,
|
||||
const nsAString& aFilename,
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber,
|
||||
bool aIsChrome,
|
||||
uint64_t aInnerWindowID);
|
||||
|
||||
@@ -955,10 +959,10 @@ IDBDatabase::AbortTransactions(bool aShouldWarn)
|
||||
MOZ_ASSERT(transaction);
|
||||
|
||||
nsString filename;
|
||||
uint32_t lineNo;
|
||||
transaction->GetCallerLocation(filename, &lineNo);
|
||||
uint32_t lineNo, column;
|
||||
transaction->GetCallerLocation(filename, &lineNo, &column);
|
||||
|
||||
aDatabase->LogWarning(kWarningMessage, filename, lineNo);
|
||||
aDatabase->LogWarning(kWarningMessage, filename, lineNo, column);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1333,7 +1337,8 @@ IDBDatabase::Invalidate()
|
||||
void
|
||||
IDBDatabase::LogWarning(const char* aMessageName,
|
||||
const nsAString& aFilename,
|
||||
uint32_t aLineNumber)
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aMessageName);
|
||||
@@ -1342,6 +1347,7 @@ IDBDatabase::LogWarning(const char* aMessageName,
|
||||
LogWarningRunnable::LogWarning(aMessageName,
|
||||
aFilename,
|
||||
aLineNumber,
|
||||
aColumnNumber,
|
||||
mFactory->IsChrome(),
|
||||
mFactory->InnerWindowID());
|
||||
} else {
|
||||
@@ -1349,6 +1355,7 @@ IDBDatabase::LogWarning(const char* aMessageName,
|
||||
new LogWarningRunnable(aMessageName,
|
||||
aFilename,
|
||||
aLineNumber,
|
||||
aColumnNumber,
|
||||
mFactory->IsChrome(),
|
||||
mFactory->InnerWindowID());
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
|
||||
@@ -1624,6 +1631,7 @@ IDBDatabase::
|
||||
LogWarningRunnable::LogWarning(const char* aMessageName,
|
||||
const nsAString& aFilename,
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber,
|
||||
bool aIsChrome,
|
||||
uint64_t aInnerWindowID)
|
||||
{
|
||||
@@ -1660,7 +1668,7 @@ LogWarningRunnable::LogWarning(const char* aMessageName,
|
||||
aFilename,
|
||||
/* aSourceLine */ EmptyString(),
|
||||
aLineNumber,
|
||||
/* aColumnNumber */ 0,
|
||||
aColumnNumber,
|
||||
nsIScriptError::warningFlag,
|
||||
category,
|
||||
aInnerWindowID)));
|
||||
@@ -1670,7 +1678,7 @@ LogWarningRunnable::LogWarning(const char* aMessageName,
|
||||
aFilename,
|
||||
/* aSourceLine */ EmptyString(),
|
||||
aLineNumber,
|
||||
/* aColumnNumber */ 0,
|
||||
aColumnNumber,
|
||||
nsIScriptError::warningFlag,
|
||||
category.get())));
|
||||
}
|
||||
@@ -1689,6 +1697,7 @@ LogWarningRunnable::Run()
|
||||
LogWarning(mMessageName.get(),
|
||||
mFilename,
|
||||
mLineNumber,
|
||||
mColumnNumber,
|
||||
mIsChrome,
|
||||
mInnerWindowID);
|
||||
|
||||
|
||||
@@ -313,7 +313,8 @@ private:
|
||||
void
|
||||
LogWarning(const char* aMessageName,
|
||||
const nsAString& aFilename,
|
||||
uint32_t aLineNumber);
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber);
|
||||
};
|
||||
|
||||
} // namespace indexedDB
|
||||
|
||||
@@ -92,6 +92,7 @@ IDBRequest::InitMembers()
|
||||
mLoggingSerialNumber = NextSerialNumber();
|
||||
mErrorCode = NS_OK;
|
||||
mLineNo = 0;
|
||||
mColumn = 0;
|
||||
mHaveResultOrErrorCode = false;
|
||||
}
|
||||
|
||||
@@ -104,7 +105,7 @@ IDBRequest::Create(IDBDatabase* aDatabase,
|
||||
aDatabase->AssertIsOnOwningThread();
|
||||
|
||||
nsRefPtr<IDBRequest> request = new IDBRequest(aDatabase);
|
||||
CaptureCaller(request->mFilename, &request->mLineNo);
|
||||
CaptureCaller(request->mFilename, &request->mLineNo, &request->mColumn);
|
||||
|
||||
request->mTransaction = aTransaction;
|
||||
request->SetScriptOwner(aDatabase->GetScriptOwner());
|
||||
@@ -168,13 +169,15 @@ IDBRequest::SetLoggingSerialNumber(uint64_t aLoggingSerialNumber)
|
||||
}
|
||||
|
||||
void
|
||||
IDBRequest::CaptureCaller(nsAString& aFilename, uint32_t* aLineNo)
|
||||
IDBRequest::CaptureCaller(nsAString& aFilename, uint32_t* aLineNo,
|
||||
uint32_t* aColumn)
|
||||
{
|
||||
MOZ_ASSERT(aFilename.IsEmpty());
|
||||
MOZ_ASSERT(aLineNo);
|
||||
MOZ_ASSERT(aColumn);
|
||||
|
||||
ThreadsafeAutoJSContext cx;
|
||||
nsJSUtils::GetCallingLocation(cx, aFilename, aLineNo);
|
||||
nsJSUtils::GetCallingLocation(cx, aFilename, aLineNo, aColumn);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -271,13 +274,16 @@ IDBRequest::GetErrorAfterResult() const
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
IDBRequest::GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo) const
|
||||
IDBRequest::GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo,
|
||||
uint32_t* aColumn) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aLineNo);
|
||||
MOZ_ASSERT(aColumn);
|
||||
|
||||
aFilename = mFilename;
|
||||
*aLineNo = mLineNo;
|
||||
*aColumn = mColumn;
|
||||
}
|
||||
|
||||
IDBRequestReadyState
|
||||
@@ -516,7 +522,7 @@ IDBOpenDBRequest::CreateForWindow(IDBFactory* aFactory,
|
||||
MOZ_ASSERT(aScriptOwner);
|
||||
|
||||
nsRefPtr<IDBOpenDBRequest> request = new IDBOpenDBRequest(aFactory, aOwner);
|
||||
CaptureCaller(request->mFilename, &request->mLineNo);
|
||||
CaptureCaller(request->mFilename, &request->mLineNo, &request->mColumn);
|
||||
|
||||
request->SetScriptOwner(aScriptOwner);
|
||||
|
||||
@@ -533,7 +539,7 @@ IDBOpenDBRequest::CreateForJS(IDBFactory* aFactory,
|
||||
MOZ_ASSERT(aScriptOwner);
|
||||
|
||||
nsRefPtr<IDBOpenDBRequest> request = new IDBOpenDBRequest(aFactory, nullptr);
|
||||
CaptureCaller(request->mFilename, &request->mLineNo);
|
||||
CaptureCaller(request->mFilename, &request->mLineNo, &request->mColumn);
|
||||
|
||||
request->SetScriptOwner(aScriptOwner);
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ protected:
|
||||
uint64_t mLoggingSerialNumber;
|
||||
nsresult mErrorCode;
|
||||
uint32_t mLineNo;
|
||||
uint32_t mColumn;
|
||||
bool mHaveResultOrErrorCode;
|
||||
|
||||
public:
|
||||
@@ -82,7 +83,7 @@ public:
|
||||
IDBTransaction* aTransaction);
|
||||
|
||||
static void
|
||||
CaptureCaller(nsAString& aFilename, uint32_t* aLineNo);
|
||||
CaptureCaller(nsAString& aFilename, uint32_t* aLineNo, uint32_t* aColumn);
|
||||
|
||||
static uint64_t
|
||||
NextSerialNumber();
|
||||
@@ -130,7 +131,8 @@ public:
|
||||
GetError(ErrorResult& aRv);
|
||||
|
||||
void
|
||||
GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo) const;
|
||||
GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo,
|
||||
uint32_t* aColumn) const;
|
||||
|
||||
bool
|
||||
IsPending() const
|
||||
|
||||
@@ -82,6 +82,7 @@ IDBTransaction::IDBTransaction(IDBDatabase* aDatabase,
|
||||
, mAbortCode(NS_OK)
|
||||
, mPendingRequestCount(0)
|
||||
, mLineNo(0)
|
||||
, mColumn(0)
|
||||
, mReadyState(IDBTransaction::INITIAL)
|
||||
, mMode(aMode)
|
||||
, mCreating(false)
|
||||
@@ -186,7 +187,7 @@ IDBTransaction::CreateVersionChange(
|
||||
emptyObjectStoreNames,
|
||||
VERSION_CHANGE);
|
||||
aOpenRequest->GetCallerLocation(transaction->mFilename,
|
||||
&transaction->mLineNo);
|
||||
&transaction->mLineNo, &transaction->mColumn);
|
||||
|
||||
transaction->SetScriptOwner(aDatabase->GetScriptOwner());
|
||||
|
||||
@@ -219,7 +220,8 @@ IDBTransaction::Create(IDBDatabase* aDatabase,
|
||||
|
||||
nsRefPtr<IDBTransaction> transaction =
|
||||
new IDBTransaction(aDatabase, aObjectStoreNames, aMode);
|
||||
IDBRequest::CaptureCaller(transaction->mFilename, &transaction->mLineNo);
|
||||
IDBRequest::CaptureCaller(transaction->mFilename, &transaction->mLineNo,
|
||||
&transaction->mColumn);
|
||||
|
||||
transaction->SetScriptOwner(aDatabase->GetScriptOwner());
|
||||
|
||||
@@ -492,13 +494,16 @@ IDBTransaction::IsOpen() const
|
||||
}
|
||||
|
||||
void
|
||||
IDBTransaction::GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo) const
|
||||
IDBTransaction::GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo,
|
||||
uint32_t* aColumn) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aLineNo);
|
||||
MOZ_ASSERT(aColumn);
|
||||
|
||||
aFilename = mFilename;
|
||||
*aLineNo = mLineNo;
|
||||
*aColumn = mColumn;
|
||||
}
|
||||
|
||||
already_AddRefed<IDBObjectStore>
|
||||
|
||||
@@ -100,6 +100,7 @@ private:
|
||||
|
||||
nsString mFilename;
|
||||
uint32_t mLineNo;
|
||||
uint32_t mColumn;
|
||||
|
||||
ReadyState mReadyState;
|
||||
Mode mMode;
|
||||
@@ -205,7 +206,8 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo) const;
|
||||
GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo,
|
||||
uint32_t* aColumn) const;
|
||||
|
||||
// 'Get' prefix is to avoid name collisions with the enum
|
||||
Mode
|
||||
|
||||
@@ -480,7 +480,7 @@ IndexedDatabaseManager::CommonPostHandleEvent(EventChainPostVisitor& aVisitor,
|
||||
|
||||
ThreadsafeAutoJSContext cx;
|
||||
RootedDictionary<ErrorEventInit> init(cx);
|
||||
request->GetCallerLocation(init.mFilename, &init.mLineno);
|
||||
request->GetCallerLocation(init.mFilename, &init.mLineno, &init.mColno);
|
||||
|
||||
init.mMessage = errorName;
|
||||
init.mCancelable = true;
|
||||
@@ -556,7 +556,7 @@ IndexedDatabaseManager::CommonPostHandleEvent(EventChainPostVisitor& aVisitor,
|
||||
init.mFilename,
|
||||
/* aSourceLine */ EmptyString(),
|
||||
init.mLineno,
|
||||
/* aColumnNumber */ 0,
|
||||
init.mColno,
|
||||
nsIScriptError::errorFlag,
|
||||
category,
|
||||
innerWindowID)));
|
||||
@@ -566,7 +566,7 @@ IndexedDatabaseManager::CommonPostHandleEvent(EventChainPostVisitor& aVisitor,
|
||||
init.mFilename,
|
||||
/* aSourceLine */ EmptyString(),
|
||||
init.mLineno,
|
||||
/* aColumnNumber */ 0,
|
||||
init.mColno,
|
||||
nsIScriptError::errorFlag,
|
||||
category.get())));
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIContentSecurityManager.idl',
|
||||
'nsIContentSecurityPolicy.idl'
|
||||
]
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIChannel;
|
||||
interface nsIStreamListener;
|
||||
|
||||
/**
|
||||
* nsIContentSecurityManager
|
||||
* Describes an XPCOM component used to perform security checks
|
||||
* right before opnening a channel.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(70eaa956-1077-41f6-bef8-d722cea31245)]
|
||||
interface nsIContentSecurityManager : nsISupports
|
||||
{
|
||||
/**
|
||||
* Checks whether a channel is allowed to access the given URI and
|
||||
* whether the channel should be openend or should be blocked consulting
|
||||
* internal security checks like Same Origin Policy, Content Security
|
||||
* Policy, Mixed Content Blocker, etc.
|
||||
*
|
||||
* If security checks within performSecurityCheck fail, the function
|
||||
* throws an exception.
|
||||
*
|
||||
* @param aChannel
|
||||
* The channel about to be openend
|
||||
* @param aStreamListener
|
||||
* The Streamlistener of the channel potentially wrapped
|
||||
* into CORSListenerProxy.
|
||||
* @return
|
||||
* The StreamListener of the channel wrapped into CORSListenerProxy.
|
||||
*
|
||||
* @throws NS_ERROR_DOM_BAD_URI
|
||||
* If accessing the URI is not allowed (e.g. prohibted by SOP)
|
||||
* @throws NS_ERROR_CONTENT_BLOCKED
|
||||
* If any of the security policies (CSP, Mixed content) is violated
|
||||
*/
|
||||
nsIStreamListener performSecurityCheck(in nsIChannel aChannel,
|
||||
in nsIStreamListener aStreamListener);
|
||||
};
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "nsIObserverService.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::jsipc;
|
||||
@@ -21,8 +20,7 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS(ContentBridgeChild,
|
||||
nsIContentChild,
|
||||
nsIObserver)
|
||||
nsIContentChild)
|
||||
|
||||
ContentBridgeChild::ContentBridgeChild(Transport* aTransport)
|
||||
: mTransport(aTransport)
|
||||
@@ -36,10 +34,6 @@ ContentBridgeChild::~ContentBridgeChild()
|
||||
void
|
||||
ContentBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (os) {
|
||||
os->RemoveObserver(this, "content-child-shutdown");
|
||||
}
|
||||
MessageLoop::current()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(this, &ContentBridgeChild::DeferredDestroy));
|
||||
@@ -55,11 +49,6 @@ ContentBridgeChild::Create(Transport* aTransport, ProcessId aOtherPid)
|
||||
DebugOnly<bool> ok = bridge->Open(aTransport, aOtherPid, XRE_GetIOMessageLoop());
|
||||
MOZ_ASSERT(ok);
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (os) {
|
||||
os->AddObserver(bridge, "content-child-shutdown", false);
|
||||
}
|
||||
|
||||
return bridge;
|
||||
}
|
||||
|
||||
@@ -180,16 +169,5 @@ ContentBridgeChild::DeallocPBlobChild(PBlobChild* aActor)
|
||||
return nsIContentChild::DeallocPBlobChild(aActor);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContentBridgeChild::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
if (!strcmp(aTopic, "content-child-shutdown")) {
|
||||
Close();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -9,20 +9,17 @@
|
||||
|
||||
#include "mozilla/dom/PContentBridgeChild.h"
|
||||
#include "mozilla/dom/nsIContentChild.h"
|
||||
#include "nsIObserver.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ContentBridgeChild final : public PContentBridgeChild
|
||||
, public nsIContentChild
|
||||
, public nsIObserver
|
||||
{
|
||||
public:
|
||||
explicit ContentBridgeChild(Transport* aTransport);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
static ContentBridgeChild*
|
||||
Create(Transport* aTransport, ProcessId aOtherProcess);
|
||||
|
||||
@@ -163,6 +163,17 @@ ContentBridgeParent::DeallocPBrowserParent(PBrowserParent* aParent)
|
||||
return nsIContentParent::DeallocPBrowserParent(aParent);
|
||||
}
|
||||
|
||||
void
|
||||
ContentBridgeParent::NotifyTabDestroyed()
|
||||
{
|
||||
int32_t numLiveTabs = ManagedPBrowserParent().Length();
|
||||
if (numLiveTabs == 1) {
|
||||
MessageLoop::current()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(this, &ContentBridgeParent::Close));
|
||||
}
|
||||
}
|
||||
|
||||
// This implementation is identical to ContentParent::GetCPOWManager but we can't
|
||||
// move it to nsIContentParent because it calls ManagedPJavaScriptParent() which
|
||||
// only exists in PContentParent and PContentBridgeParent.
|
||||
|
||||
@@ -28,6 +28,8 @@ public:
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
void DeferredDestroy();
|
||||
virtual bool IsContentBridgeParent() override { return true; }
|
||||
void NotifyTabDestroyed();
|
||||
|
||||
static ContentBridgeParent*
|
||||
Create(Transport* aTransport, ProcessId aOtherProcess);
|
||||
|
||||
+150
-37
@@ -1422,7 +1422,9 @@ ContentParent::Init()
|
||||
}
|
||||
Preferences::AddStrongObserver(this, "");
|
||||
if (obs) {
|
||||
obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-created", nullptr);
|
||||
nsAutoString cpId;
|
||||
cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
|
||||
obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-created", cpId.get());
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
@@ -1800,11 +1802,12 @@ ContentParent::OnBeginSyncTransaction() {
|
||||
if (!sDisableUnsafeCPOWWarnings) {
|
||||
if (console && cx) {
|
||||
nsAutoString filename;
|
||||
uint32_t lineno = 0;
|
||||
nsJSUtils::GetCallingLocation(cx, filename, &lineno);
|
||||
uint32_t lineno = 0, column = 0;
|
||||
nsJSUtils::GetCallingLocation(cx, filename, &lineno, &column);
|
||||
nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
|
||||
error->Init(NS_LITERAL_STRING("unsafe CPOW usage"), filename, EmptyString(),
|
||||
lineno, 0, nsIScriptError::warningFlag, "chrome javascript");
|
||||
error->Init(NS_LITERAL_STRING("unsafe CPOW usage"), filename,
|
||||
EmptyString(), lineno, column,
|
||||
nsIScriptError::warningFlag, "chrome javascript");
|
||||
console->LogMessage(error);
|
||||
} else {
|
||||
NS_WARNING("Unsafe synchronous IPC message");
|
||||
@@ -1990,9 +1993,20 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
|
||||
props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), true);
|
||||
|
||||
}
|
||||
obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", nullptr);
|
||||
nsAutoString cpId;
|
||||
cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
|
||||
obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", cpId.get());
|
||||
}
|
||||
|
||||
// Remove any and all idle listeners.
|
||||
nsCOMPtr<nsIIdleService> idleService =
|
||||
do_GetService("@mozilla.org/widget/idleservice;1");
|
||||
MOZ_ASSERT(idleService);
|
||||
nsRefPtr<ParentIdleListener> listener;
|
||||
for (int32_t i = mIdleListeners.Length() - 1; i >= 0; --i) {
|
||||
listener = static_cast<ParentIdleListener*>(mIdleListeners[i].get());
|
||||
idleService->RemoveIdleObserver(listener, listener->mTime);
|
||||
}
|
||||
mIdleListeners.Clear();
|
||||
|
||||
MessageLoop::current()->
|
||||
@@ -2009,10 +2023,35 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
|
||||
// least until after the current task finishes running.
|
||||
NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this));
|
||||
|
||||
// Destroy any processes created by this ContentParent
|
||||
ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
|
||||
// Release the appId's reference count of any processes
|
||||
// created by this ContentParent and the frame opened by this ContentParent
|
||||
// if this ContentParent crashes.
|
||||
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
|
||||
nsTArray<ContentParentId> childIDArray =
|
||||
cpm->GetAllChildProcessById(this->ChildID());
|
||||
if (why == AbnormalShutdown) {
|
||||
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
|
||||
if(permMgr) {
|
||||
// Release the appId's reference count of its child-processes
|
||||
for (uint32_t i = 0; i < childIDArray.Length(); i++) {
|
||||
nsTArray<TabContext> tabCtxs = cpm->GetTabContextByContentProcess(childIDArray[i]);
|
||||
for (uint32_t j = 0 ; j < tabCtxs.Length() ; j++) {
|
||||
if (tabCtxs[j].OwnOrContainingAppId() != nsIScriptSecurityManager::NO_APP_ID) {
|
||||
permMgr->ReleaseAppId(tabCtxs[j].OwnOrContainingAppId());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Release the appId's reference count belong to itself
|
||||
nsTArray<TabContext> tabCtxs = cpm->GetTabContextByContentProcess(mChildID);
|
||||
for (uint32_t i = 0; i < tabCtxs.Length() ; i++) {
|
||||
if (tabCtxs[i].OwnOrContainingAppId()!= nsIScriptSecurityManager::NO_APP_ID) {
|
||||
permMgr->ReleaseAppId(tabCtxs[i].OwnOrContainingAppId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy any processes created by this ContentParent
|
||||
for(uint32_t i = 0; i < childIDArray.Length(); i++) {
|
||||
ContentParent* cp = cpm->GetContentProcessById(childIDArray[i]);
|
||||
MessageLoop::current()->PostTask(
|
||||
@@ -2028,23 +2067,33 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
|
||||
}
|
||||
|
||||
void
|
||||
ContentParent::NotifyTabDestroying(PBrowserParent* aTab)
|
||||
ContentParent::NotifyTabDestroying(const TabId& aTabId,
|
||||
const ContentParentId& aCpId)
|
||||
{
|
||||
if (XRE_IsParentProcess()) {
|
||||
// There can be more than one PBrowser for a given app process
|
||||
// because of popup windows. PBrowsers can also destroy
|
||||
// concurrently. When all the PBrowsers are destroying, kick off
|
||||
// another task to ensure the child process *really* shuts down,
|
||||
// even if the PBrowsers themselves never finish destroying.
|
||||
int32_t numLiveTabs = ManagedPBrowserParent().Length();
|
||||
++mNumDestroyingTabs;
|
||||
if (mNumDestroyingTabs != numLiveTabs) {
|
||||
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
|
||||
ContentParent* cp = cpm->GetContentProcessById(aCpId);
|
||||
if (!cp) {
|
||||
return;
|
||||
}
|
||||
++cp->mNumDestroyingTabs;
|
||||
nsTArray<TabId> tabIds = cpm->GetTabParentsByProcessId(aCpId);
|
||||
if (static_cast<size_t>(cp->mNumDestroyingTabs) != tabIds.Length()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We're dying now, so prevent this content process from being
|
||||
// recycled during its shutdown procedure.
|
||||
MarkAsDead();
|
||||
StartForceKillTimer();
|
||||
cp->MarkAsDead();
|
||||
cp->StartForceKillTimer();
|
||||
} else {
|
||||
ContentChild::GetSingleton()->SendNotifyTabDestroying(aTabId, aCpId);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t
|
||||
@@ -2072,16 +2121,15 @@ ContentParent::StartForceKillTimer()
|
||||
}
|
||||
|
||||
void
|
||||
ContentParent::NotifyTabDestroyed(PBrowserParent* aTab,
|
||||
ContentParent::NotifyTabDestroyed(const TabId& aTabId,
|
||||
bool aNotifiedDestroying)
|
||||
{
|
||||
if (aNotifiedDestroying) {
|
||||
--mNumDestroyingTabs;
|
||||
}
|
||||
|
||||
TabId id = static_cast<TabParent*>(aTab)->GetTabId();
|
||||
nsTArray<PContentPermissionRequestParent*> parentArray =
|
||||
nsContentPermissionUtils::GetContentPermissionRequestParentById(id);
|
||||
nsContentPermissionUtils::GetContentPermissionRequestParentById(aTabId);
|
||||
|
||||
// Need to close undeleted ContentPermissionRequestParents before tab is closed.
|
||||
for (auto& permissionRequestParent : parentArray) {
|
||||
@@ -2094,7 +2142,9 @@ ContentParent::NotifyTabDestroyed(PBrowserParent* aTab,
|
||||
// There can be more than one PBrowser for a given app process
|
||||
// because of popup windows. When the last one closes, shut
|
||||
// us down.
|
||||
if (ManagedPBrowserParent().Length() == 1) {
|
||||
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
|
||||
nsTArray<TabId> tabIds = cpm->GetTabParentsByProcessId(this->ChildID());
|
||||
if (tabIds.Length() == 1) {
|
||||
// In the case of normal shutdown, send a shutdown message to child to
|
||||
// allow it to perform shutdown tasks.
|
||||
MessageLoop::current()->PostTask(
|
||||
@@ -4555,30 +4605,34 @@ ContentParent::RecvAddIdleObserver(const uint64_t& aObserver, const uint32_t& aI
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIIdleService> idleService =
|
||||
do_GetService("@mozilla.org/widget/idleservice;1", &rv);
|
||||
do_GetService("@mozilla.org/widget/idleservice;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
nsRefPtr<ParentIdleListener> listener = new ParentIdleListener(this, aObserver);
|
||||
mIdleListeners.Put(aObserver, listener);
|
||||
idleService->AddIdleObserver(listener, aIdleTimeInS);
|
||||
nsRefPtr<ParentIdleListener> listener =
|
||||
new ParentIdleListener(this, aObserver, aIdleTimeInS);
|
||||
rv = idleService->AddIdleObserver(listener, aIdleTimeInS);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
mIdleListeners.AppendElement(listener);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvRemoveIdleObserver(const uint64_t& aObserver, const uint32_t& aIdleTimeInS)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIIdleService> idleService =
|
||||
do_GetService("@mozilla.org/widget/idleservice;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
nsRefPtr<ParentIdleListener> listener;
|
||||
bool found = mIdleListeners.Get(aObserver, &listener);
|
||||
if (found) {
|
||||
mIdleListeners.Remove(aObserver);
|
||||
idleService->RemoveIdleObserver(listener, aIdleTimeInS);
|
||||
for (int32_t i = mIdleListeners.Length() - 1; i >= 0; --i) {
|
||||
listener = static_cast<ParentIdleListener*>(mIdleListeners[i].get());
|
||||
if (listener->mObserver == aObserver &&
|
||||
listener->mTime == aIdleTimeInS) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIIdleService> idleService =
|
||||
do_GetService("@mozilla.org/widget/idleservice;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
idleService->RemoveIdleObserver(listener, aIdleTimeInS);
|
||||
mIdleListeners.RemoveElementAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4780,8 +4834,12 @@ ContentParent::AllocateTabId(const TabId& aOpenerTabId,
|
||||
{
|
||||
TabId tabId;
|
||||
if (XRE_IsParentProcess()) {
|
||||
ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
|
||||
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
|
||||
tabId = cpm->AllocateTabId(aOpenerTabId, aContext, aCpId);
|
||||
// Add appId's reference count in oop case
|
||||
if (tabId) {
|
||||
PermissionManagerAddref(aCpId, tabId);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ContentChild::GetSingleton()->SendAllocateTabId(aOpenerTabId,
|
||||
@@ -4794,14 +4852,27 @@ ContentParent::AllocateTabId(const TabId& aOpenerTabId,
|
||||
|
||||
/*static*/ void
|
||||
ContentParent::DeallocateTabId(const TabId& aTabId,
|
||||
const ContentParentId& aCpId)
|
||||
const ContentParentId& aCpId,
|
||||
bool aMarkedDestroying)
|
||||
{
|
||||
if (XRE_IsParentProcess()) {
|
||||
// Release appId's reference count in oop case
|
||||
if (aTabId) {
|
||||
PermissionManagerRelease(aCpId, aTabId);
|
||||
}
|
||||
|
||||
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
|
||||
ContentParent* cp = cpm->GetContentProcessById(aCpId);
|
||||
|
||||
cp->NotifyTabDestroyed(aTabId, aMarkedDestroying);
|
||||
|
||||
ContentProcessManager::GetSingleton()->DeallocateTabId(aCpId,
|
||||
aTabId);
|
||||
}
|
||||
else {
|
||||
ContentChild::GetSingleton()->SendDeallocateTabId(aTabId);
|
||||
ContentChild::GetSingleton()->SendDeallocateTabId(aTabId,
|
||||
aCpId,
|
||||
aMarkedDestroying);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4819,9 +4890,19 @@ ContentParent::RecvAllocateTabId(const TabId& aOpenerTabId,
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvDeallocateTabId(const TabId& aTabId)
|
||||
ContentParent::RecvDeallocateTabId(const TabId& aTabId,
|
||||
const ContentParentId& aCpId,
|
||||
const bool& aMarkedDestroying)
|
||||
{
|
||||
DeallocateTabId(aTabId, this->ChildID());
|
||||
DeallocateTabId(aTabId, aCpId, aMarkedDestroying);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvNotifyTabDestroying(const TabId& aTabId,
|
||||
const ContentParentId& aCpId)
|
||||
{
|
||||
NotifyTabDestroying(aTabId, aCpId);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4992,6 +5073,38 @@ ContentParent::DeallocPContentPermissionRequestParent(PContentPermissionRequestP
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
ContentParent::PermissionManagerAddref(const ContentParentId& aCpId,
|
||||
const TabId& aTabId)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Call PermissionManagerAddref in content process!");
|
||||
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
|
||||
uint32_t appId = cpm->GetAppIdByProcessAndTabId(aCpId, aTabId);
|
||||
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
|
||||
if (appId != nsIScriptSecurityManager::NO_APP_ID && permMgr) {
|
||||
permMgr->AddrefAppId(appId);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
ContentParent::PermissionManagerRelease(const ContentParentId& aCpId,
|
||||
const TabId& aTabId)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Call PermissionManagerRelease in content process!");
|
||||
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
|
||||
uint32_t appId = cpm->GetAppIdByProcessAndTabId(aCpId, aTabId);
|
||||
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
|
||||
if (appId != nsIScriptSecurityManager::NO_APP_ID && permMgr) {
|
||||
permMgr->ReleaseAppId(appId);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvGetBrowserConfiguration(const nsCString& aURI, BrowserConfiguration* aConfig)
|
||||
{
|
||||
|
||||
+30
-7
@@ -208,9 +208,10 @@ public:
|
||||
virtual bool KillChild() override;
|
||||
|
||||
/** Notify that a tab is beginning its destruction sequence. */
|
||||
void NotifyTabDestroying(PBrowserParent* aTab);
|
||||
static void NotifyTabDestroying(const TabId& aTabId,
|
||||
const ContentParentId& aCpId);
|
||||
/** Notify that a tab was destroyed during normal operation. */
|
||||
void NotifyTabDestroyed(PBrowserParent* aTab,
|
||||
void NotifyTabDestroyed(const TabId& aTabId,
|
||||
bool aNotifiedDestroying);
|
||||
|
||||
TestShellParent* CreateTestShell();
|
||||
@@ -223,7 +224,21 @@ public:
|
||||
const IPCTabContext& aContext,
|
||||
const ContentParentId& aCpId);
|
||||
static void
|
||||
DeallocateTabId(const TabId& aTabId, const ContentParentId& aCpId);
|
||||
DeallocateTabId(const TabId& aTabId,
|
||||
const ContentParentId& aCpId,
|
||||
bool aMarkedDestroying);
|
||||
|
||||
/*
|
||||
* Add the appId's reference count by the given ContentParentId and TabId
|
||||
*/
|
||||
static bool
|
||||
PermissionManagerAddref(const ContentParentId& aCpId, const TabId& aTabId);
|
||||
|
||||
/*
|
||||
* Release the appId's reference count by the given ContentParentId and TabId
|
||||
*/
|
||||
static bool
|
||||
PermissionManagerRelease(const ContentParentId& aCpId, const TabId& aTabId);
|
||||
|
||||
static bool
|
||||
GetBrowserConfiguration(const nsCString& aURI, BrowserConfiguration& aConfig);
|
||||
@@ -344,7 +359,12 @@ public:
|
||||
const ContentParentId& aCpId,
|
||||
TabId* aTabId) override;
|
||||
|
||||
virtual bool RecvDeallocateTabId(const TabId& aTabId) override;
|
||||
virtual bool RecvDeallocateTabId(const TabId& aTabId,
|
||||
const ContentParentId& aCpId,
|
||||
const bool& aMarkedDestroying) override;
|
||||
|
||||
virtual bool RecvNotifyTabDestroying(const TabId& aTabId,
|
||||
const ContentParentId& aCpId) override;
|
||||
|
||||
nsTArray<TabContext> GetManagedTabContext();
|
||||
|
||||
@@ -914,7 +934,7 @@ private:
|
||||
nsRefPtr<nsConsoleService> mConsoleService;
|
||||
nsConsoleService* GetConsoleService();
|
||||
|
||||
nsDataHashtable<nsUint64HashKey, nsRefPtr<ParentIdleListener> > mIdleListeners;
|
||||
nsTArray<nsCOMPtr<nsIObserver>> mIdleListeners;
|
||||
|
||||
#ifdef MOZ_X11
|
||||
// Dup of child's X socket, used to scope its resources to this
|
||||
@@ -945,17 +965,20 @@ private:
|
||||
} // namespace mozilla
|
||||
|
||||
class ParentIdleListener : public nsIObserver {
|
||||
friend class mozilla::dom::ContentParent;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
ParentIdleListener(mozilla::dom::ContentParent* aParent, uint64_t aObserver)
|
||||
: mParent(aParent), mObserver(aObserver)
|
||||
ParentIdleListener(mozilla::dom::ContentParent* aParent, uint64_t aObserver, uint32_t aTime)
|
||||
: mParent(aParent), mObserver(aObserver), mTime(aTime)
|
||||
{}
|
||||
private:
|
||||
virtual ~ParentIdleListener() {}
|
||||
nsRefPtr<mozilla::dom::ContentParent> mParent;
|
||||
uint64_t mObserver;
|
||||
uint32_t mTime;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
|
||||
// XXX need another bug to move this to a common header.
|
||||
#ifdef DISABLE_ASSERTS_FOR_FUZZING
|
||||
@@ -334,5 +335,40 @@ ContentProcessManager::GetTopLevelTabParentByProcessAndTabId(const ContentParent
|
||||
return GetTabParentByProcessAndTabId(currentCpId, currentTabId);
|
||||
}
|
||||
|
||||
nsTArray<TabId>
|
||||
ContentProcessManager::GetTabParentsByProcessId(const ContentParentId& aChildCpId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsTArray<TabId> tabIdList;
|
||||
auto iter = mContentParentMap.find(aChildCpId);
|
||||
if (NS_WARN_IF(iter == mContentParentMap.end())) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return Move(tabIdList);
|
||||
}
|
||||
|
||||
for (auto remoteFrameIter = iter->second.mRemoteFrames.begin();
|
||||
remoteFrameIter != iter->second.mRemoteFrames.end();
|
||||
++remoteFrameIter) {
|
||||
tabIdList.AppendElement(remoteFrameIter->first);
|
||||
}
|
||||
|
||||
return Move(tabIdList);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ContentProcessManager::GetAppIdByProcessAndTabId(const ContentParentId& aChildCpId,
|
||||
const TabId& aChildTabId)
|
||||
{
|
||||
uint32_t appId = nsIScriptSecurityManager::NO_APP_ID;
|
||||
if (aChildCpId && aChildTabId) {
|
||||
TabContext tabContext;
|
||||
if (GetTabContextByProcessAndTabId(aChildCpId, aChildTabId, &tabContext)) {
|
||||
appId = tabContext.OwnOrContainingAppId();
|
||||
}
|
||||
}
|
||||
return appId;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -110,6 +110,13 @@ public:
|
||||
const TabId& aChildTabId,
|
||||
/*out*/ TabId* aOpenerTabId);
|
||||
|
||||
/**
|
||||
* Get all TabParents' Ids managed by the givent content process.
|
||||
* Return empty array when TabParent couldn't be found via aChildCpId
|
||||
*/
|
||||
nsTArray<TabId>
|
||||
GetTabParentsByProcessId(const ContentParentId& aChildCpId);
|
||||
|
||||
/**
|
||||
* Get the TabParent by the given content process and tab id.
|
||||
* Return nullptr when TabParent couldn't be found via aChildCpId
|
||||
@@ -135,6 +142,15 @@ public:
|
||||
GetTopLevelTabParentByProcessAndTabId(const ContentParentId& aChildCpId,
|
||||
const TabId& aChildTabId);
|
||||
|
||||
/**
|
||||
* Return appId by given TabId and ContentParentId.
|
||||
* It will return nsIScriptSecurityManager::NO_APP_ID
|
||||
* if the given tab is not an app.
|
||||
*/
|
||||
uint32_t
|
||||
GetAppIdByProcessAndTabId(const ContentParentId& aChildCpId,
|
||||
const TabId& aChildTabId);
|
||||
|
||||
private:
|
||||
static StaticAutoPtr<ContentProcessManager> sSingleton;
|
||||
TabId mUniqueId;
|
||||
|
||||
@@ -980,8 +980,15 @@ parent:
|
||||
*/
|
||||
sync AllocateTabId(TabId openerTabId, IPCTabContext context, ContentParentId cpId)
|
||||
returns (TabId tabId);
|
||||
async DeallocateTabId(TabId tabId);
|
||||
async DeallocateTabId(TabId tabId,
|
||||
ContentParentId cpId,
|
||||
bool aMarkedDestroying);
|
||||
|
||||
/**
|
||||
* Tell the chrome process there is a destruction of PBrowser(Tab)
|
||||
*/
|
||||
async NotifyTabDestroying(TabId tabId,
|
||||
ContentParentId cpId);
|
||||
/**
|
||||
* Starts an offline application cache update.
|
||||
* @param manifestURI
|
||||
|
||||
@@ -750,7 +750,7 @@ HangMonitoredProcess::GetPluginName(nsACString& aPluginName)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
aPluginName = tag->mName;
|
||||
aPluginName = tag->Name();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
+46
-12
@@ -16,8 +16,10 @@
|
||||
#include "nsAccessibilityService.h"
|
||||
#endif
|
||||
#include "mozilla/BrowserElementParent.h"
|
||||
#include "mozilla/dom/ContentBridgeParent.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/DataTransfer.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/indexedDB/ActorsParent.h"
|
||||
#include "mozilla/plugins/PluginWidgetParent.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
@@ -430,11 +432,9 @@ TabParent::IsVisible()
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::Destroy()
|
||||
TabParent::DestroyInternal()
|
||||
{
|
||||
if (mIsDestroyed) {
|
||||
return;
|
||||
}
|
||||
IMEStateManager::OnTabParentDestroying(this);
|
||||
|
||||
RemoveWindowListeners();
|
||||
|
||||
@@ -447,11 +447,6 @@ TabParent::Destroy()
|
||||
RemoveTabParentFromTable(frame->GetLayersId());
|
||||
frame->Destroy();
|
||||
}
|
||||
mIsDestroyed = true;
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
Manager()->AsContentParent()->NotifyTabDestroying(this);
|
||||
}
|
||||
|
||||
// Let all PluginWidgets know we are tearing down. Prevents
|
||||
// these objects from sending async events after the child side
|
||||
@@ -460,6 +455,24 @@ TabParent::Destroy()
|
||||
for (uint32_t idx = 0; idx < kids.Length(); ++idx) {
|
||||
static_cast<mozilla::plugins::PluginWidgetParent*>(kids[idx])->ParentDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::Destroy()
|
||||
{
|
||||
if (mIsDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
DestroyInternal();
|
||||
|
||||
mIsDestroyed = true;
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
ContentParent::NotifyTabDestroying(this->GetTabId(), Manager()->AsContentParent()->ChildID());
|
||||
} else {
|
||||
ContentParent::NotifyTabDestroying(this->GetTabId(), Manager()->ChildID());
|
||||
}
|
||||
|
||||
mMarkedDestroying = true;
|
||||
}
|
||||
@@ -468,12 +481,15 @@ bool
|
||||
TabParent::Recv__delete__()
|
||||
{
|
||||
if (XRE_IsParentProcess()) {
|
||||
Manager()->AsContentParent()->NotifyTabDestroyed(this, mMarkedDestroying);
|
||||
ContentParent::DeallocateTabId(mTabId,
|
||||
Manager()->AsContentParent()->ChildID());
|
||||
Manager()->AsContentParent()->ChildID(),
|
||||
mMarkedDestroying);
|
||||
}
|
||||
else {
|
||||
ContentParent::DeallocateTabId(mTabId, ContentParentId(0));
|
||||
Manager()->AsContentBridgeParent()->NotifyTabDestroyed();
|
||||
ContentParent::DeallocateTabId(mTabId,
|
||||
Manager()->ChildID(),
|
||||
mMarkedDestroying);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -482,8 +498,26 @@ TabParent::Recv__delete__()
|
||||
void
|
||||
TabParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
// Even though TabParent::Destroy calls this, we need to do it here too in
|
||||
// case of a crash.
|
||||
IMEStateManager::OnTabParentDestroying(this);
|
||||
|
||||
// Prevent executing ContentParent::NotifyTabDestroying in
|
||||
// TabParent::Destroy() called by frameLoader->DestroyComplete() below
|
||||
// when tab crashes in contentprocess because ContentParent::ActorDestroy()
|
||||
// in main process will be triggered before this function
|
||||
// and remove the process information that
|
||||
// ContentParent::NotifyTabDestroying need from mContentParentMap.
|
||||
|
||||
// When tab crashes in content process,
|
||||
// there is no need to call ContentParent::NotifyTabDestroying
|
||||
// because the jobs in ContentParent::NotifyTabDestroying
|
||||
// will be done by ContentParent::ActorDestroy.
|
||||
if (XRE_IsContentProcess() && why == AbnormalShutdown && !mIsDestroyed) {
|
||||
DestroyInternal();
|
||||
mIsDestroyed = true;
|
||||
}
|
||||
|
||||
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (frameLoader) {
|
||||
|
||||
@@ -478,6 +478,7 @@ protected:
|
||||
LayoutDeviceIntPoint mChromeOffset;
|
||||
|
||||
private:
|
||||
void DestroyInternal();
|
||||
already_AddRefed<nsFrameLoader> GetFrameLoader(bool aUseCachedFrameLoaderAfterDestroy = false) const;
|
||||
nsRefPtr<nsIContentParent> mManager;
|
||||
void TryCacheDPIAndScale();
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/ContentBridgeParent.h"
|
||||
#include "mozilla/dom/PTabContext.h"
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
#include "mozilla/dom/StructuredCloneUtils.h"
|
||||
@@ -46,6 +47,13 @@ nsIContentParent::AsContentParent()
|
||||
return static_cast<ContentParent*>(this);
|
||||
}
|
||||
|
||||
ContentBridgeParent*
|
||||
nsIContentParent::AsContentBridgeParent()
|
||||
{
|
||||
MOZ_ASSERT(IsContentBridgeParent());
|
||||
return static_cast<ContentBridgeParent*>(this);
|
||||
}
|
||||
|
||||
PJavaScriptParent*
|
||||
nsIContentParent::AllocPJavaScriptParent()
|
||||
{
|
||||
|
||||
@@ -38,6 +38,7 @@ class BlobConstructorParams;
|
||||
class BlobImpl;
|
||||
class BlobParent;
|
||||
class ContentParent;
|
||||
class ContentBridgeParent;
|
||||
class IPCTabContext;
|
||||
class PBlobParent;
|
||||
class PBrowserParent;
|
||||
@@ -77,6 +78,8 @@ public:
|
||||
|
||||
virtual bool IsContentParent() { return false; }
|
||||
ContentParent* AsContentParent();
|
||||
virtual bool IsContentBridgeParent() { return false; }
|
||||
ContentBridgeParent* AsContentBridgeParent();
|
||||
|
||||
protected: // methods
|
||||
bool CanOpenBrowser(const IPCTabContext& aContext);
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
var gBasePath = "tests/dom/ipc/tests/";
|
||||
|
||||
function handleRequest(request, response) {
|
||||
var query = getQuery(request);
|
||||
|
||||
var testToken = '';
|
||||
if ('testToken' in query) {
|
||||
testToken = query.testToken;
|
||||
}
|
||||
|
||||
var template = '';
|
||||
if ('template' in query) {
|
||||
template = query.template;
|
||||
}
|
||||
var template = gBasePath + template;
|
||||
response.setHeader("Content-Type", "application/x-web-app-manifest+json", false);
|
||||
response.write(readTemplate(template).replace(/TESTTOKEN/g, testToken));
|
||||
}
|
||||
|
||||
// Copy-pasted incantations. There ought to be a better way to synchronously read
|
||||
// a file into a string, but I guess we're trying to discourage that.
|
||||
function readTemplate(path) {
|
||||
var file = Components.classes["@mozilla.org/file/directory_service;1"].
|
||||
getService(Components.interfaces.nsIProperties).
|
||||
get("CurWorkD", Components.interfaces.nsILocalFile);
|
||||
var fis = Components.classes['@mozilla.org/network/file-input-stream;1'].
|
||||
createInstance(Components.interfaces.nsIFileInputStream);
|
||||
var cis = Components.classes["@mozilla.org/intl/converter-input-stream;1"].
|
||||
createInstance(Components.interfaces.nsIConverterInputStream);
|
||||
var split = path.split("/");
|
||||
for(var i = 0; i < split.length; ++i) {
|
||||
file.append(split[i]);
|
||||
}
|
||||
fis.init(file, -1, -1, false);
|
||||
cis.init(fis, "UTF-8", 0, 0);
|
||||
|
||||
var data = "";
|
||||
let str = {};
|
||||
let read = 0;
|
||||
do {
|
||||
read = cis.readString(0xffffffff, str); // read as much as we can and put it in str.value
|
||||
data += str.value;
|
||||
} while (read != 0);
|
||||
cis.close();
|
||||
return data;
|
||||
}
|
||||
|
||||
function getQuery(request) {
|
||||
var query = {};
|
||||
request.queryString.split('&').forEach(function (val) {
|
||||
var [name, value] = val.split('=');
|
||||
query[name] = unescape(value);
|
||||
});
|
||||
return query;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "Nested-OOP",
|
||||
"description": "Nested-OOP test app used for mochitest.",
|
||||
"launch_path": "/tests/dom/ipc/tests/TESTTOKEN",
|
||||
"icons": { "128": "default_icon" }
|
||||
}
|
||||
@@ -12,3 +12,39 @@ skip-if = toolkit != 'gonk'
|
||||
run-if = toolkit == 'gonk'
|
||||
[test_child_docshell.html]
|
||||
run-if = toolkit != 'cocoa' # disabled due to hangs, see changeset 6852e7c47edf
|
||||
[test_permission_for_in_process_app.html]
|
||||
skip-if = e10s || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
|
||||
support-files =
|
||||
test_permission_helper.js
|
||||
[test_permission_for_oop_app.html]
|
||||
skip-if = buildapp == 'mulet' || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
|
||||
support-files =
|
||||
file_app.sjs
|
||||
file_app.template.webapp
|
||||
test_permission_helper.js
|
||||
test_permission_embed.html
|
||||
test_permission_framescript.js
|
||||
[test_permission_for_nested_oop_app.html]
|
||||
skip-if = buildapp == 'mulet' || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
|
||||
support-files =
|
||||
file_app.sjs
|
||||
file_app.template.webapp
|
||||
test_permission_helper.js
|
||||
test_permission_embed.html
|
||||
test_permission_framescript.js
|
||||
[test_permission_for_two_oop_apps.html]
|
||||
skip-if = buildapp == 'mulet' || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
|
||||
support-files =
|
||||
file_app.sjs
|
||||
file_app.template.webapp
|
||||
test_permission_helper.js
|
||||
test_permission_embed.html
|
||||
test_permission_framescript.js
|
||||
[test_permission_when_oop_app_crashes.html]
|
||||
skip-if = buildapp == 'mulet' || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
|
||||
support-files =
|
||||
file_app.sjs
|
||||
file_app.template.webapp
|
||||
test_permission_helper.js
|
||||
test_permission_embed.html
|
||||
test_permission_framescript.js
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>oop-test apps</title>
|
||||
<script type="application/javascript">
|
||||
"use strict";
|
||||
|
||||
var queryString = decodeURIComponent(window.location.hash.substring(1));
|
||||
|
||||
// test-target-app
|
||||
var APP_URL = "http://example.org";
|
||||
var APP_MANIFEST = "http://example.org/manifest.webapp";
|
||||
var APP_IFRAME_ID = "test-target";
|
||||
|
||||
function removeAppFrame(){
|
||||
var ifr = document.getElementById(APP_IFRAME_ID);
|
||||
ifr.remove();
|
||||
}
|
||||
|
||||
function allocateAppFrame(source, manifestURL, useRemote) {
|
||||
var ifr = document.createElement('iframe');
|
||||
ifr.setAttribute('id', APP_IFRAME_ID);
|
||||
ifr.setAttribute('remote', useRemote? "true" : "false");
|
||||
ifr.setAttribute('mozbrowser', 'true');
|
||||
ifr.setAttribute('mozapp', manifestURL);
|
||||
ifr.setAttribute('src', source);
|
||||
|
||||
ifr.addEventListener('mozbrowserloadend', function () {
|
||||
if (queryString == "crash") {
|
||||
// Send a crash request to parent-process
|
||||
sendMessgeToParent('crash');
|
||||
} else {
|
||||
removeAppFrame();
|
||||
}
|
||||
});
|
||||
|
||||
document.body.appendChild(ifr);
|
||||
}
|
||||
|
||||
function sendMessgeToParent(msg) {
|
||||
window.alert(msg);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
allocateAppFrame(APP_URL, APP_MANIFEST, true);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1114507
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1114507</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1114507">Mozilla Bug1114507</a>
|
||||
<p id="display"></p>
|
||||
<div id="container" style="display: none"></div>
|
||||
<script type="text/javascript" src="test_permission_helper.js"></script>
|
||||
<script type="application/javascript">
|
||||
// Put all the tests in order
|
||||
var tests = [
|
||||
// Setup preferences and permissions
|
||||
setupPrefsAndPermissions,
|
||||
|
||||
// +-------------------------------------------+
|
||||
// | Test 1: Open and close a in-process |
|
||||
// | test-target-app in chrome-process |
|
||||
// +-------------------------------------------+
|
||||
//
|
||||
// level
|
||||
// 1 chrome process <-- app is here
|
||||
|
||||
// Add permission to app
|
||||
function () {
|
||||
addPermissionToApp(APP_URL, APP_MANIFEST);
|
||||
},
|
||||
|
||||
test1
|
||||
];
|
||||
|
||||
runTests();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,75 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1114507
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1114507</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1114507">Mozilla Bug1114507</a>
|
||||
<p id="display"></p>
|
||||
<div id="container" style="display: none"></div>
|
||||
<script type="text/javascript" src="test_permission_helper.js"></script>
|
||||
<script type="application/javascript">
|
||||
// Put all the tests in order
|
||||
var tests = [
|
||||
// Setup preferences and permissions
|
||||
setupPrefsAndPermissions,
|
||||
|
||||
// ****************************************************
|
||||
// Setup the enviroment for testing nested-oop cases: *
|
||||
// test 3,4,5 *
|
||||
// ****************************************************
|
||||
|
||||
// Install the app
|
||||
installApp,
|
||||
|
||||
// Allow permission for embedApp to open mozbrowser and mozapp
|
||||
function() {
|
||||
var appId = gAppsService.getAppLocalIdByManifestURL(embedAppHostedManifestURL);
|
||||
var context = { url: embedApp.origin,
|
||||
appId: appId,
|
||||
isInBrowserElement: false };
|
||||
setupOpenAppPermission(context, runTests);
|
||||
},
|
||||
|
||||
// +-------------------------------------------+
|
||||
// | Test 3: Open a test-target-app on 3rd |
|
||||
// | level child-process then close it |
|
||||
// +-------------------------------------------+
|
||||
//
|
||||
// level
|
||||
// 1 chrome process
|
||||
// |
|
||||
// 2 child process
|
||||
// |
|
||||
// 3 child process <-- app is here
|
||||
|
||||
// Add permission to app
|
||||
function() {
|
||||
addPermissionToApp(APP_URL, APP_MANIFEST);
|
||||
},
|
||||
|
||||
test3,
|
||||
|
||||
// Remove the child-process on 2nd level
|
||||
function() {
|
||||
var afterShutdown = function() {
|
||||
runTests();
|
||||
};
|
||||
afterContentShutdown(1, afterShutdown);
|
||||
removeAppFrame(APP_IFRAME_ID);
|
||||
},
|
||||
|
||||
uninstallApp
|
||||
];
|
||||
|
||||
runTests();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,45 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1114507
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1114507</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1114507">Mozilla Bug1114507</a>
|
||||
<p id="display"></p>
|
||||
<div id="container" style="display: none"></div>
|
||||
<script type="text/javascript" src="test_permission_helper.js"></script>
|
||||
<script type="application/javascript">
|
||||
// Put all the tests in order
|
||||
var tests = [
|
||||
// Setup preferences and permissions
|
||||
setupPrefsAndPermissions,
|
||||
|
||||
// +------------------------------------------+
|
||||
// | Test 2: Open and close a test-target-app |
|
||||
// | on 2nd level child-process |
|
||||
// +------------------------------------------+
|
||||
//
|
||||
// level
|
||||
// 1 chrome process
|
||||
// |
|
||||
// 2 child process <-- app is here
|
||||
|
||||
// Add permission to app
|
||||
function() {
|
||||
addPermissionToApp(APP_URL, APP_MANIFEST);
|
||||
},
|
||||
|
||||
test2,
|
||||
];
|
||||
|
||||
runTests();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,88 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1114507
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1114507</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1114507">Mozilla Bug1114507</a>
|
||||
<p id="display"></p>
|
||||
<div id="container" style="display: none"></div>
|
||||
<script type="text/javascript" src="test_permission_helper.js"></script>
|
||||
<script type="application/javascript">
|
||||
// Put all the tests in order
|
||||
var tests = [
|
||||
// Setup preferences and permissions
|
||||
setupPrefsAndPermissions,
|
||||
|
||||
// ****************************************************
|
||||
// Setup the enviroment for testing nested-oop cases: *
|
||||
// test 3,4,5 *
|
||||
// ****************************************************
|
||||
|
||||
// Install the app
|
||||
installApp,
|
||||
|
||||
// Allow permission for embedApp to open mozbrowser and mozapp
|
||||
function() {
|
||||
var appId = gAppsService.getAppLocalIdByManifestURL(embedAppHostedManifestURL);
|
||||
var context = { url: embedApp.origin,
|
||||
appId: appId,
|
||||
isInBrowserElement: false };
|
||||
setupOpenAppPermission(context, runTests);
|
||||
},
|
||||
|
||||
// +---------------------------------------------------------+
|
||||
// | Test 4: Open two test-target-app on 2nd and 3rd level |
|
||||
// | child-processes then close the one on 3rd level |
|
||||
// +---------------------------------------------------------+
|
||||
//
|
||||
// level
|
||||
// 1 chrome process
|
||||
// / \
|
||||
// 2 child process child process <-- app is here
|
||||
// /
|
||||
// 3 child process <-- app is here
|
||||
|
||||
// Add permission to app
|
||||
function() {
|
||||
addPermissionToApp(APP_URL, APP_MANIFEST);
|
||||
},
|
||||
|
||||
test4,
|
||||
|
||||
// Remove another test-target-app on 2nd level process
|
||||
function() {
|
||||
var afterShutdown = function() {
|
||||
// We expect there is no permission for the test-target-app now
|
||||
runNextIfAppHasPermission(4, false, APP_URL, APP_MANIFEST);
|
||||
};
|
||||
// Test permission after test-target-app
|
||||
// on 2nd level process is killed
|
||||
afterContentShutdown(1, afterShutdown);
|
||||
|
||||
removeAppFrame(APP_IFRAME_ID2);
|
||||
},
|
||||
|
||||
// Remove the last child-process on 2nd level
|
||||
function() {
|
||||
var afterShutdown = function() {
|
||||
runTests();
|
||||
};
|
||||
afterContentShutdown(1, afterShutdown);
|
||||
removeAppFrame(APP_IFRAME_ID);
|
||||
},
|
||||
|
||||
uninstallApp
|
||||
];
|
||||
|
||||
runTests();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,31 @@
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
let cm = Services.crashmanager;
|
||||
var cpIdList = [];
|
||||
|
||||
var shutdownObs = {
|
||||
observe: function(subject, topic, data) {
|
||||
if (topic == 'ipc:content-shutdown') {
|
||||
var index = cpIdList.indexOf(parseInt(data));
|
||||
if (index > -1) {
|
||||
cpIdList.splice(index, 1);
|
||||
sendAsyncMessage('content-shutdown', '');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var createdObs = {
|
||||
observe: function(subject, topic, data) {
|
||||
if (topic == 'ipc:content-created') {
|
||||
cpIdList.push(parseInt(data));
|
||||
sendAsyncMessage('content-created', '');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
addMessageListener('crashreporter-status', function(message) {
|
||||
sendAsyncMessage('crashreporter-enable', !!cm);
|
||||
});
|
||||
|
||||
Services.obs.addObserver(shutdownObs, 'ipc:content-shutdown', false);
|
||||
Services.obs.addObserver(createdObs, 'ipc:content-created', false);
|
||||
@@ -0,0 +1,362 @@
|
||||
"use strict";
|
||||
|
||||
// Used to access the DOM node in this test
|
||||
const DOM_PARENT_ID = "container";
|
||||
const DOM_PARENT = document.getElementById(DOM_PARENT_ID);
|
||||
const APP_IFRAME_ID = "appFrame";
|
||||
const APP_IFRAME_ID2 = "appFrame2";
|
||||
|
||||
// Settings for testing the permission
|
||||
const SESSION_PERSIST_MINUTES = 10;
|
||||
const PERMISSION_TYPE = "geolocation";
|
||||
const permManager = SpecialPowers.Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(SpecialPowers.Ci.nsIPermissionManager);
|
||||
|
||||
// Used to access App's information like appId
|
||||
const gAppsService = SpecialPowers.Cc["@mozilla.org/AppsService;1"]
|
||||
.getService(SpecialPowers.Ci.nsIAppsService);
|
||||
|
||||
// Target-app for this testing
|
||||
const APP_URL = "http://example.org";
|
||||
const APP_MANIFEST = "http://example.org/manifest.webapp";
|
||||
|
||||
// Used to embed a remote app that open the test-target-app above
|
||||
const embedAppHostedManifestURL = window.location.origin +
|
||||
'/tests/dom/ipc/tests/file_app.sjs?testToken=test_permission_embed.html&template=file_app.template.webapp';
|
||||
var embedApp;
|
||||
|
||||
// Used to add listener for ipc:content-shutdown that
|
||||
// will be triggered after ContentParent::DeallocateTabId
|
||||
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('test_permission_framescript.js'));
|
||||
|
||||
// Delay reporting a result until after finish() got called
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
// Allow tests to disable the per platform app validity checks
|
||||
SpecialPowers.setAllAppsLaunchable(true);
|
||||
|
||||
// Run tests in order
|
||||
function runTests() {
|
||||
if (!tests.length) {
|
||||
ok(true, "pass all tests!");
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
function test1() {
|
||||
allocateAppFrame(APP_IFRAME_ID, DOM_PARENT, APP_URL, APP_MANIFEST);
|
||||
|
||||
var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
|
||||
|
||||
if (!SpecialPowers.hasPermission( PERMISSION_TYPE,
|
||||
{ url: APP_URL,
|
||||
appId: appId,
|
||||
isInBrowserElement: false })) {
|
||||
errorHandler('[test 1] App should have permission: ' + PERMISSION_TYPE);
|
||||
}
|
||||
|
||||
removeAppFrame(APP_IFRAME_ID);
|
||||
|
||||
// We expect there is no permission for the test-target-app
|
||||
// after removing the in-process iframe embedding this app
|
||||
runNextIfAppHasPermission(1, false, APP_URL, APP_MANIFEST);
|
||||
}
|
||||
|
||||
function test2() {
|
||||
var afterShutdown = function () {
|
||||
// We expect there is no permission for the test-target-app
|
||||
// after removing the remote iframe embedding this app
|
||||
runNextIfAppHasPermission(2, false, APP_URL, APP_MANIFEST);
|
||||
};
|
||||
|
||||
// Test permission after the child-process containing
|
||||
// test-target-app is killed
|
||||
afterContentShutdown(1, afterShutdown);
|
||||
|
||||
allocateAppFrame(APP_IFRAME_ID, DOM_PARENT, APP_URL, APP_MANIFEST, true);
|
||||
|
||||
var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
|
||||
|
||||
if (!SpecialPowers.hasPermission( PERMISSION_TYPE,
|
||||
{ url: APP_URL,
|
||||
appId: appId,
|
||||
isInBrowserElement: false })) {
|
||||
errorHandler('[test 2] App should have permission: ' + PERMISSION_TYPE);
|
||||
}
|
||||
|
||||
removeAppFrame(APP_IFRAME_ID);
|
||||
}
|
||||
|
||||
function test3() {
|
||||
var afterGrandchildShutdown = function () {
|
||||
// We expect there is no permission for the test-target-app
|
||||
// after removing the remote iframe embedding this app
|
||||
runNextIfAppHasPermission(3, false, APP_URL, APP_MANIFEST);
|
||||
};
|
||||
|
||||
// Test permission after the grandchild-process
|
||||
// containing test-target-app is killed
|
||||
afterContentShutdown(1, afterGrandchildShutdown);
|
||||
|
||||
allocateAppFrame(APP_IFRAME_ID,
|
||||
DOM_PARENT,
|
||||
embedApp.manifest.launch_path,
|
||||
embedApp.manifestURL,
|
||||
true);
|
||||
|
||||
var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
|
||||
|
||||
if (!SpecialPowers.hasPermission(PERMISSION_TYPE,
|
||||
{ url: APP_URL,
|
||||
appId: appId,
|
||||
isInBrowserElement: false })) {
|
||||
errorHandler('[test 3] App should have permission: ' + PERMISSION_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
function test4() {
|
||||
var afterGrandchildShutdown = function () {
|
||||
// We expect there is still a permission for the test-target-app
|
||||
// after killing test-target-app on 3rd-level process
|
||||
runNextIfAppHasPermission(4, true, APP_URL, APP_MANIFEST);
|
||||
};
|
||||
|
||||
// Test permission after the grandchild-process
|
||||
// containing test-target-app is killed
|
||||
afterContentShutdown(1, afterGrandchildShutdown);
|
||||
|
||||
// Open a child process(2nd level) and a grandchild process(3rd level)
|
||||
// that contains a test-target-app
|
||||
allocateAppFrame(APP_IFRAME_ID,
|
||||
DOM_PARENT,
|
||||
embedApp.manifest.launch_path,
|
||||
embedApp.manifestURL,
|
||||
true);
|
||||
|
||||
// Open another child process that contains
|
||||
// another test-target-app(2nd level)
|
||||
allocateAppFrame(APP_IFRAME_ID2,
|
||||
DOM_PARENT,
|
||||
APP_URL,
|
||||
APP_MANIFEST,
|
||||
true);
|
||||
|
||||
var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
|
||||
|
||||
if (!SpecialPowers.hasPermission(PERMISSION_TYPE,
|
||||
{ url: APP_URL,
|
||||
appId: appId,
|
||||
isInBrowserElement: false })) {
|
||||
errorHandler('[test 4] App should have permission: ' + PERMISSION_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
function test5() {
|
||||
var afterShutdown = function () {
|
||||
// We expect there is no permission for the test-target-app
|
||||
// after crashing its parent-process
|
||||
runNextIfAppHasPermission(5, false, APP_URL, APP_MANIFEST);
|
||||
};
|
||||
|
||||
// Test permission after the parent-process of test-target-app is crashed.
|
||||
afterContentShutdown(2, afterShutdown);
|
||||
|
||||
allocateAppFrame(APP_IFRAME_ID,
|
||||
DOM_PARENT,
|
||||
embedApp.manifest.launch_path + '#' + encodeURIComponent('crash'),
|
||||
embedApp.manifestURL,
|
||||
true);
|
||||
|
||||
var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
|
||||
|
||||
if (!SpecialPowers.hasPermission( PERMISSION_TYPE,
|
||||
{ url: APP_URL,
|
||||
appId: appId,
|
||||
isInBrowserElement: false })) {
|
||||
errorHandler('[test 5] App should have permission: ' + PERMISSION_TYPE);
|
||||
}
|
||||
|
||||
// Crash the child-process on 2nd level after
|
||||
// the grandchild process on 3rd is allocated
|
||||
var handler = {'crash': function() {
|
||||
gScript.sendAsyncMessage("crashreporter-status", {});
|
||||
|
||||
getCrashReporterStatus(function(enable) {
|
||||
if (enable) {
|
||||
SimpleTest.expectChildProcessCrash();
|
||||
}
|
||||
crashChildProcess(APP_IFRAME_ID);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
receiveMessageFromChildFrame(APP_IFRAME_ID, handler);
|
||||
}
|
||||
|
||||
// Setup the prefrences and permissions.
|
||||
// This function should be called before any tests
|
||||
function setupPrefsAndPermissions() {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["dom.ipc.tabs.nested.enabled", true],
|
||||
["dom.ipc.tabs.disabled", false]]},
|
||||
function() {
|
||||
var autoManageApp = function () {
|
||||
SpecialPowers.setAllAppsLaunchable(true);
|
||||
// No confirmation needed when an app is installed and uninstalled.
|
||||
SpecialPowers.autoConfirmAppInstall(() => {
|
||||
// This callback should trigger the first test
|
||||
SpecialPowers.autoConfirmAppUninstall(runTests);
|
||||
});
|
||||
};
|
||||
|
||||
setupOpenAppPermission(document, autoManageApp);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function setupOpenAppPermission(ctx, callback) {
|
||||
SpecialPowers.pushPermissions([
|
||||
{ "type": "browser", "allow": true, "context": ctx}, // for mozbrowser
|
||||
{ "type": "embed-apps", "allow": true, "context": ctx }, // for mozapp
|
||||
{ "type": "webapps-manage", "allow": true, "context": ctx }], // for (un)installing apps
|
||||
function checkPermissions() {
|
||||
if (SpecialPowers.hasPermission("browser", ctx) &&
|
||||
SpecialPowers.hasPermission("embed-apps", ctx) &&
|
||||
SpecialPowers.hasPermission("webapps-manage", ctx)) {
|
||||
callback();
|
||||
} else {
|
||||
errorHandler(">> At least one of required permissions to open app is disallowed!\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function installApp() {
|
||||
// Install App from manifest
|
||||
var request = navigator.mozApps.install(embedAppHostedManifestURL);
|
||||
request.onerror = cbError;
|
||||
request.onsuccess = function() {
|
||||
// Get installed app
|
||||
embedApp = request.result; // Assign to global variable
|
||||
runTests();
|
||||
}
|
||||
}
|
||||
|
||||
function uninstallApp() {
|
||||
var request = navigator.mozApps.mgmt.uninstall(embedApp);
|
||||
request.onerror = cbError;
|
||||
request.onsuccess = function() {
|
||||
info("uninstall app susseccfully!");
|
||||
runTests();
|
||||
}
|
||||
}
|
||||
|
||||
function removeAppFrame(id) {
|
||||
var ifr = document.getElementById(id);
|
||||
ifr.remove();
|
||||
}
|
||||
|
||||
function allocateAppFrame(id, parentNode, appSRC, manifestURL, useRemote = false) {
|
||||
var ifr = document.createElement('iframe');
|
||||
ifr.setAttribute('id', id);
|
||||
ifr.setAttribute('remote', useRemote? "true" : "false");
|
||||
ifr.setAttribute('mozbrowser', 'true');
|
||||
ifr.setAttribute('mozapp', manifestURL);
|
||||
ifr.setAttribute('src', appSRC);
|
||||
parentNode.appendChild(ifr);
|
||||
}
|
||||
|
||||
function receiveMessageFromChildFrame(id, handlers) {
|
||||
var ifr = document.getElementById(id);
|
||||
ifr.addEventListener('mozbrowsershowmodalprompt', function (recvMsg) {
|
||||
var msg = recvMsg.detail.message;
|
||||
handlers[msg]();
|
||||
});
|
||||
}
|
||||
|
||||
function addPermissionToApp(appURL, manifestURL) {
|
||||
var appId = gAppsService.getAppLocalIdByManifestURL(manifestURL);
|
||||
|
||||
// Get the time now. This is used for permission manager's expire_time
|
||||
var now = Number(Date.now());
|
||||
|
||||
// Add app's permission asynchronously
|
||||
SpecialPowers.pushPermissions([
|
||||
{ "type":PERMISSION_TYPE,
|
||||
"allow": 1,
|
||||
"expireType":permManager.EXPIRE_SESSION,
|
||||
"expireTime":now + SESSION_PERSIST_MINUTES*60*1000,
|
||||
"context": { url: appURL,
|
||||
appId: appId,
|
||||
isInBrowserElement:false }
|
||||
}
|
||||
], function() {
|
||||
runTests();
|
||||
});
|
||||
}
|
||||
|
||||
function runNextIfAppHasPermission(round, expect, appURL, manifestURL) {
|
||||
var appId = gAppsService.getAppLocalIdByManifestURL(manifestURL);
|
||||
|
||||
var hasPerm = SpecialPowers.hasPermission(PERMISSION_TYPE,
|
||||
{ url: appURL,
|
||||
appId: appId,
|
||||
isInBrowserElement: false });
|
||||
var result = (expect==hasPerm);
|
||||
if (result) {
|
||||
runTests();
|
||||
} else {
|
||||
errorHandler( '[test ' + round + '] App should ' + ((expect)? '':'NOT ') +
|
||||
'have permission: ' + PERMISSION_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
function afterContentShutdown(times, callback) {
|
||||
// handle the message from test_permission_framescript.js
|
||||
var num = 0;
|
||||
gScript.addMessageListener('content-shutdown', function onShutdown(data) {
|
||||
num += 1;
|
||||
if (num >= times) {
|
||||
gScript.removeMessageListener('content-shutdown', onShutdown);
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getCrashReporterStatus(callback) {
|
||||
gScript.addMessageListener('crashreporter-enable', function getStatus(data) {
|
||||
gScript.removeMessageListener('crashreporter-enable', getStatus);
|
||||
callback(data);
|
||||
});
|
||||
}
|
||||
|
||||
// Inject a frame script that crashes the content process
|
||||
function crashChildProcess(frameId) {
|
||||
var child = document.getElementById(frameId);
|
||||
var mm = SpecialPowers.getBrowserFrameMessageManager(child);
|
||||
var childFrameScriptStr =
|
||||
'function ContentScriptScope() {' +
|
||||
'var Cu = Components.utils;' +
|
||||
'Cu.import("resource://gre/modules/ctypes.jsm");' +
|
||||
'var crash = function() {' +
|
||||
'var zero = new ctypes.intptr_t(8);' +
|
||||
'var badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));' +
|
||||
'badptr.contents;' +
|
||||
'};' +
|
||||
'privateNoteIntentionalCrash();' +
|
||||
'crash();' +
|
||||
'}';
|
||||
mm.loadFrameScript('data:,new ' + childFrameScriptStr, false);
|
||||
}
|
||||
|
||||
function errorHandler(errMsg) {
|
||||
ok(false, errMsg);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function cbError(e) {
|
||||
errorHandler("Error callback invoked: " + this.error.name);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1114507
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1114507</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1114507">Mozilla Bug1114507</a>
|
||||
<p id="display"></p>
|
||||
<div id="container" style="display: none"></div>
|
||||
<script type="text/javascript" src="test_permission_helper.js"></script>
|
||||
<script type="application/javascript">
|
||||
// Put all the tests in order
|
||||
var tests = [
|
||||
// Setup preferences and permissions
|
||||
setupPrefsAndPermissions,
|
||||
|
||||
// ****************************************************
|
||||
// Setup the enviroment for testing nested-oop cases: *
|
||||
// test 3,4,5 *
|
||||
// ****************************************************
|
||||
|
||||
// Install the app
|
||||
installApp,
|
||||
|
||||
// Allow permission for embedApp to open mozbrowser and mozapp
|
||||
function() {
|
||||
var appId = gAppsService.getAppLocalIdByManifestURL(embedAppHostedManifestURL);
|
||||
var context = { url: embedApp.origin,
|
||||
appId: appId,
|
||||
isInBrowserElement: false };
|
||||
setupOpenAppPermission(context, runTests);
|
||||
},
|
||||
|
||||
// +-----------------------------------------------+
|
||||
// | Test 5: Open a test-target-app on 3rd level |
|
||||
// | process then crash its parent-process |
|
||||
// +-----------------------------------------------+
|
||||
//
|
||||
// level
|
||||
// 1 chrome process
|
||||
// |
|
||||
// 2 child process <-- crash this process
|
||||
// |
|
||||
// 3 child process <-- app is here
|
||||
|
||||
// Add permission to app
|
||||
function() {
|
||||
addPermissionToApp(APP_URL, APP_MANIFEST);
|
||||
},
|
||||
|
||||
test5,
|
||||
|
||||
uninstallApp
|
||||
|
||||
];
|
||||
|
||||
runTests();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -565,6 +565,15 @@ nsJSChannel::Open2(nsIInputStream** aStream)
|
||||
NS_IMETHODIMP
|
||||
nsJSChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = nsIChannel::GetLoadInfo();
|
||||
MOZ_ASSERT(!loadInfo || loadInfo->GetSecurityMode() == 0 ||
|
||||
loadInfo->GetInitialSecurityCheckDone(),
|
||||
"security flags in loadInfo but asyncOpen2() not called");
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_ENSURE_ARG(aListener);
|
||||
|
||||
// First make sure that we have a usable inner window; we'll want to make
|
||||
|
||||
@@ -34,7 +34,7 @@ const GUID MF_XVP_PLAYBACK_MODE =
|
||||
{ 0xaf, 0x12, 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9 }
|
||||
};
|
||||
|
||||
DEFINE_GUID(MF_LOW_LATENCY,
|
||||
DEFINE_GUID(MF_LOW_LATENCY,
|
||||
0x9c27891a, 0xed7a, 0x40e1, 0x88, 0xe8, 0xb2, 0x27, 0x27, 0xa0, 0x24, 0xee);
|
||||
|
||||
namespace mozilla {
|
||||
@@ -44,6 +44,7 @@ using layers::ImageContainer;
|
||||
using layers::D3D9SurfaceImage;
|
||||
using layers::D3D9RecycleAllocator;
|
||||
using layers::D3D11ShareHandleImage;
|
||||
using layers::D3D11RecycleAllocator;
|
||||
|
||||
class D3D9DXVA2Manager : public DXVA2Manager
|
||||
{
|
||||
@@ -412,12 +413,13 @@ private:
|
||||
HRESULT CreateFormatConverter();
|
||||
|
||||
HRESULT CreateOutputSample(RefPtr<IMFSample>& aSample,
|
||||
RefPtr<ID3D11Texture2D>& aTexture);
|
||||
ID3D11Texture2D* aTexture);
|
||||
|
||||
RefPtr<ID3D11Device> mDevice;
|
||||
RefPtr<ID3D11DeviceContext> mContext;
|
||||
RefPtr<IMFDXGIDeviceManager> mDXGIDeviceManager;
|
||||
RefPtr<MFTDecoder> mTransform;
|
||||
RefPtr<D3D11RecycleAllocator> mTextureClientAllocator;
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
UINT mDeviceManagerToken;
|
||||
@@ -483,41 +485,27 @@ D3D11DXVA2Manager::Init(nsACString& aFailureReason)
|
||||
return hr;
|
||||
}
|
||||
|
||||
mTextureClientAllocator = new D3D11RecycleAllocator(layers::ImageBridgeChild::GetSingleton(),
|
||||
mDevice);
|
||||
mTextureClientAllocator->SetMaxPoolSize(5);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
D3D11DXVA2Manager::CreateOutputSample(RefPtr<IMFSample>& aSample, RefPtr<ID3D11Texture2D>& aTexture)
|
||||
D3D11DXVA2Manager::CreateOutputSample(RefPtr<IMFSample>& aSample, ID3D11Texture2D* aTexture)
|
||||
{
|
||||
RefPtr<IMFSample> sample;
|
||||
HRESULT hr = wmf::MFCreateSample(byRef(sample));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
desc.Width = mWidth;
|
||||
desc.Height = mHeight;
|
||||
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
|
||||
desc.CPUAccessFlags = 0;
|
||||
desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
|
||||
|
||||
RefPtr<ID3D11Texture2D> texture;
|
||||
hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(texture));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
RefPtr<IMFMediaBuffer> buffer;
|
||||
hr = wmf::MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), texture, 0, FALSE, byRef(buffer));
|
||||
hr = wmf::MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), aTexture, 0, FALSE, byRef(buffer));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
sample->AddBuffer(buffer);
|
||||
|
||||
aSample = sample;
|
||||
aTexture = texture;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -535,11 +523,23 @@ D3D11DXVA2Manager::CopyToImage(IMFSample* aVideoSample,
|
||||
// to create a copy of that frame as a sharable resource, save its share
|
||||
// handle, and put that handle into the rendering pipeline.
|
||||
|
||||
HRESULT hr = mTransform->Input(aVideoSample);
|
||||
ImageFormat format = ImageFormat::D3D11_SHARE_HANDLE_TEXTURE;
|
||||
nsRefPtr<Image> image(aContainer->CreateImage(format));
|
||||
NS_ENSURE_TRUE(image, E_FAIL);
|
||||
NS_ASSERTION(image->GetFormat() == ImageFormat::D3D11_SHARE_HANDLE_TEXTURE,
|
||||
"Wrong format?");
|
||||
|
||||
D3D11ShareHandleImage* videoImage = static_cast<D3D11ShareHandleImage*>(image.get());
|
||||
HRESULT hr = videoImage->SetData(D3D11ShareHandleImage::Data(mTextureClientAllocator,
|
||||
gfx::IntSize(mWidth, mHeight),
|
||||
aRegion));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
hr = mTransform->Input(aVideoSample);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
RefPtr<IMFSample> sample;
|
||||
RefPtr<ID3D11Texture2D> texture;
|
||||
RefPtr<ID3D11Texture2D> texture = videoImage->GetTexture();
|
||||
hr = CreateOutputSample(sample, texture);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
@@ -555,16 +555,6 @@ D3D11DXVA2Manager::CopyToImage(IMFSample* aVideoSample,
|
||||
keyedMutex->ReleaseSync(0);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
ImageFormat format = ImageFormat::D3D11_SHARE_HANDLE_TEXTURE;
|
||||
nsRefPtr<Image> image(aContainer->CreateImage(format));
|
||||
NS_ENSURE_TRUE(image, E_FAIL);
|
||||
NS_ASSERTION(image->GetFormat() == ImageFormat::D3D11_SHARE_HANDLE_TEXTURE,
|
||||
"Wrong format?");
|
||||
|
||||
D3D11ShareHandleImage* videoImage = static_cast<D3D11ShareHandleImage*>(image.get());
|
||||
hr = videoImage->SetData(D3D11ShareHandleImage::Data(texture, mDevice, mContext, aRegion));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
image.forget(aOutImage);
|
||||
|
||||
return S_OK;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
ifdef MOZ_WEBSPEECH_MODELS
|
||||
MODELSPS_KEEP_PATH := 1
|
||||
|
||||
MODELSPS_FILES := models/dict/cmu07a.dic \
|
||||
models/en-us-semi/mixture_weights \
|
||||
models/en-us-semi/feat.params \
|
||||
models/en-us-semi/mdef \
|
||||
models/en-us-semi/means \
|
||||
models/en-us-semi/noisedict \
|
||||
models/en-us-semi/sendump \
|
||||
models/en-us-semi/transition_matrices \
|
||||
models/en-us-semi/variances
|
||||
|
||||
MODELSPS_DEST := $(DIST)/bin/models
|
||||
INSTALL_TARGETS += MODELSPS
|
||||
endif
|
||||
@@ -0,0 +1,345 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
#include "PocketSphinxSpeechRecognitionService.h"
|
||||
#include "nsIFile.h"
|
||||
#include "SpeechGrammar.h"
|
||||
#include "SpeechRecognition.h"
|
||||
#include "SpeechRecognitionAlternative.h"
|
||||
#include "SpeechRecognitionResult.h"
|
||||
#include "SpeechRecognitionResultList.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsMemory.h"
|
||||
|
||||
extern "C" {
|
||||
#include "pocketsphinx/pocketsphinx.h"
|
||||
#include "sphinxbase/sphinx_config.h"
|
||||
#include "sphinxbase/jsgf.h"
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace dom;
|
||||
|
||||
class DecodeResultTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
DecodeResultTask(const nsString& hypstring,
|
||||
WeakPtr<dom::SpeechRecognition> recognition)
|
||||
: mResult(hypstring),
|
||||
mRecognition(recognition),
|
||||
mWorkerThread(do_GetCurrentThread())
|
||||
{
|
||||
MOZ_ASSERT(
|
||||
!NS_IsMainThread()); // This should be running on the worker thread
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread()); // This method is supposed to run on the main
|
||||
// thread!
|
||||
|
||||
// Declare javascript result events
|
||||
nsRefPtr<SpeechEvent> event = new SpeechEvent(
|
||||
mRecognition, SpeechRecognition::EVENT_RECOGNITIONSERVICE_FINAL_RESULT);
|
||||
SpeechRecognitionResultList* resultList =
|
||||
new SpeechRecognitionResultList(mRecognition);
|
||||
SpeechRecognitionResult* result = new SpeechRecognitionResult(mRecognition);
|
||||
SpeechRecognitionAlternative* alternative =
|
||||
new SpeechRecognitionAlternative(mRecognition);
|
||||
|
||||
alternative->mTranscript = mResult;
|
||||
alternative->mConfidence = 100;
|
||||
|
||||
result->mItems.AppendElement(alternative);
|
||||
resultList->mItems.AppendElement(result);
|
||||
|
||||
event->mRecognitionResultList = resultList;
|
||||
NS_DispatchToMainThread(event);
|
||||
|
||||
// If we don't destroy the thread when we're done with it, it will hang
|
||||
// around forever... bad!
|
||||
// But thread->Shutdown must be called from the main thread, not from the
|
||||
// thread itself.
|
||||
return mWorkerThread->Shutdown();
|
||||
}
|
||||
|
||||
private:
|
||||
nsString mResult;
|
||||
WeakPtr<dom::SpeechRecognition> mRecognition;
|
||||
nsCOMPtr<nsIThread> mWorkerThread;
|
||||
};
|
||||
|
||||
class DecodeTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
DecodeTask(WeakPtr<dom::SpeechRecognition> recogntion,
|
||||
const nsTArray<int16_t>& audiovector, ps_decoder_t* ps)
|
||||
: mRecognition(recogntion), mAudiovector(audiovector), mPs(ps)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
char const* hyp;
|
||||
int rv;
|
||||
int32 score;
|
||||
nsAutoCString hypoValue;
|
||||
|
||||
rv = ps_start_utt(mPs);
|
||||
rv = ps_process_raw(mPs, &mAudiovector[0], mAudiovector.Length(), FALSE,
|
||||
FALSE);
|
||||
|
||||
rv = ps_end_utt(mPs);
|
||||
if (rv >= 0) {
|
||||
hyp = ps_get_hyp(mPs, &score);
|
||||
if (hyp == nullptr) {
|
||||
hypoValue.Assign("ERROR");
|
||||
} else {
|
||||
hypoValue.Assign(hyp);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> resultrunnable =
|
||||
new DecodeResultTask(NS_ConvertUTF8toUTF16(hypoValue), mRecognition);
|
||||
return NS_DispatchToMainThread(resultrunnable);
|
||||
}
|
||||
|
||||
private:
|
||||
WeakPtr<dom::SpeechRecognition> mRecognition;
|
||||
nsTArray<int16_t> mAudiovector;
|
||||
ps_decoder_t* mPs;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(PocketSphinxSpeechRecognitionService,
|
||||
nsISpeechRecognitionService, nsIObserver)
|
||||
|
||||
PocketSphinxSpeechRecognitionService::PocketSphinxSpeechRecognitionService()
|
||||
{
|
||||
mSpeexState = nullptr;
|
||||
|
||||
// get root folder
|
||||
nsCOMPtr<nsIFile> tmpFile;
|
||||
nsAutoString aStringAMPath; // am folder
|
||||
nsAutoString aStringDictPath; // dict folder
|
||||
|
||||
NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(tmpFile));
|
||||
#if defined(XP_WIN) // for some reason, on windows NS_GRE_DIR is not bin root,
|
||||
// but bin/browser
|
||||
tmpFile->AppendRelativePath(NS_LITERAL_STRING(".."));
|
||||
#endif
|
||||
tmpFile->AppendRelativePath(NS_LITERAL_STRING("models"));
|
||||
tmpFile->AppendRelativePath(NS_LITERAL_STRING("en-us-semi"));
|
||||
tmpFile->GetPath(aStringAMPath);
|
||||
|
||||
NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(tmpFile));
|
||||
#if defined(XP_WIN) // for some reason, on windows NS_GRE_DIR is not bin root,
|
||||
// but bin/browser
|
||||
tmpFile->AppendRelativePath(NS_LITERAL_STRING(".."));
|
||||
#endif
|
||||
tmpFile->AppendRelativePath(NS_LITERAL_STRING("models")); //
|
||||
tmpFile->AppendRelativePath(NS_LITERAL_STRING("dict")); //
|
||||
tmpFile->AppendRelativePath(NS_LITERAL_STRING("cmu07a.dic")); //
|
||||
tmpFile->GetPath(aStringDictPath);
|
||||
|
||||
// FOR B2G PATHS HARDCODED (APPEND /DATA ON THE BEGINING, FOR DESKTOP, ONLY
|
||||
// MODELS/ RELATIVE TO ROOT
|
||||
mPSConfig = cmd_ln_init(nullptr, ps_args(), TRUE, "-hmm",
|
||||
ToNewUTF8String(aStringAMPath), // acoustic model
|
||||
"-dict", ToNewUTF8String(aStringDictPath), nullptr);
|
||||
if (mPSConfig == nullptr) {
|
||||
ISDecoderCreated = false;
|
||||
} else {
|
||||
mPSHandle = ps_init(mPSConfig);
|
||||
if (mPSHandle == nullptr) {
|
||||
ISDecoderCreated = false;
|
||||
} else {
|
||||
ISDecoderCreated = true;
|
||||
}
|
||||
}
|
||||
|
||||
ISGrammarCompiled = false;
|
||||
}
|
||||
|
||||
PocketSphinxSpeechRecognitionService::~PocketSphinxSpeechRecognitionService()
|
||||
{
|
||||
if (mPSConfig) {
|
||||
free(mPSConfig);
|
||||
}
|
||||
if (mPSHandle) {
|
||||
free(mPSHandle);
|
||||
}
|
||||
|
||||
mSpeexState = nullptr;
|
||||
}
|
||||
|
||||
// CALL START IN JS FALLS HERE
|
||||
NS_IMETHODIMP
|
||||
PocketSphinxSpeechRecognitionService::Initialize(
|
||||
WeakPtr<SpeechRecognition> aSpeechRecognition)
|
||||
{
|
||||
if (!ISDecoderCreated || !ISGrammarCompiled) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
} else {
|
||||
mAudioVector.Clear();
|
||||
|
||||
if (mSpeexState) {
|
||||
mSpeexState = nullptr;
|
||||
}
|
||||
|
||||
mRecognition = aSpeechRecognition;
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
obs->AddObserver(this, SPEECH_RECOGNITION_TEST_EVENT_REQUEST_TOPIC, false);
|
||||
obs->AddObserver(this, SPEECH_RECOGNITION_TEST_END_TOPIC, false);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PocketSphinxSpeechRecognitionService::ProcessAudioSegment(
|
||||
AudioSegment* aAudioSegment, int32_t aSampleRate)
|
||||
{
|
||||
if (!mSpeexState) {
|
||||
mSpeexState = speex_resampler_init(1, aSampleRate, 16000,
|
||||
SPEEX_RESAMPLER_QUALITY_MAX, nullptr);
|
||||
}
|
||||
aAudioSegment->ResampleChunks(mSpeexState, aSampleRate, 16000);
|
||||
|
||||
AudioSegment::ChunkIterator iterator(*aAudioSegment);
|
||||
|
||||
while (!iterator.IsEnded()) {
|
||||
mozilla::AudioChunk& chunk = *(iterator);
|
||||
MOZ_ASSERT(chunk.mBuffer);
|
||||
const int16_t* buf = static_cast<const int16_t*>(chunk.mChannelData[0]);
|
||||
|
||||
for (int i = 0; i < iterator->mDuration; i++) {
|
||||
mAudioVector.AppendElement((int16_t)buf[i]);
|
||||
}
|
||||
iterator.Next();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PocketSphinxSpeechRecognitionService::SoundEnd()
|
||||
{
|
||||
speex_resampler_destroy(mSpeexState);
|
||||
mSpeexState = nullptr;
|
||||
|
||||
// To create a new thread, get the thread manager
|
||||
nsCOMPtr<nsIThreadManager> tm = do_GetService(NS_THREADMANAGER_CONTRACTID);
|
||||
nsCOMPtr<nsIThread> decodethread;
|
||||
nsresult rv = tm->NewThread(0, 0, getter_AddRefs(decodethread));
|
||||
if (NS_FAILED(rv)) {
|
||||
// In case of failure, call back immediately with an empty string which
|
||||
// indicates failure
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
new DecodeTask(mRecognition, mAudioVector, mPSHandle);
|
||||
decodethread->Dispatch(r, nsIEventTarget::DISPATCH_NORMAL);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PocketSphinxSpeechRecognitionService::ValidateAndSetGrammarList(
|
||||
SpeechGrammar* aSpeechGrammar,
|
||||
nsISpeechGrammarCompilationCallback* aCallback)
|
||||
{
|
||||
if (!ISDecoderCreated) {
|
||||
ISGrammarCompiled = false;
|
||||
} else if (aSpeechGrammar) {
|
||||
nsAutoString grammar;
|
||||
ErrorResult rv;
|
||||
aSpeechGrammar->GetSrc(grammar, rv);
|
||||
|
||||
int result = ps_set_jsgf_string(mPSHandle, "name",
|
||||
NS_ConvertUTF16toUTF8(grammar).get());
|
||||
|
||||
ps_set_search(mPSHandle, "name");
|
||||
|
||||
if (result != 0) {
|
||||
ISGrammarCompiled = false;
|
||||
} else {
|
||||
ISGrammarCompiled = true;
|
||||
}
|
||||
} else {
|
||||
ISGrammarCompiled = false;
|
||||
}
|
||||
|
||||
return ISGrammarCompiled ? NS_OK : NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PocketSphinxSpeechRecognitionService::Abort()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PocketSphinxSpeechRecognitionService::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
MOZ_ASSERT(mRecognition->mTestConfig.mFakeRecognitionService,
|
||||
"Got request to fake recognition service event, "
|
||||
"but " TEST_PREFERENCE_FAKE_RECOGNITION_SERVICE " is not set");
|
||||
|
||||
if (!strcmp(aTopic, SPEECH_RECOGNITION_TEST_END_TOPIC)) {
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
obs->RemoveObserver(this, SPEECH_RECOGNITION_TEST_EVENT_REQUEST_TOPIC);
|
||||
obs->RemoveObserver(this, SPEECH_RECOGNITION_TEST_END_TOPIC);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const nsDependentString eventName = nsDependentString(aData);
|
||||
|
||||
if (eventName.EqualsLiteral("EVENT_RECOGNITIONSERVICE_ERROR")) {
|
||||
mRecognition->DispatchError(
|
||||
SpeechRecognition::EVENT_RECOGNITIONSERVICE_ERROR,
|
||||
SpeechRecognitionErrorCode::Network, // TODO different codes?
|
||||
NS_LITERAL_STRING("RECOGNITIONSERVICE_ERROR test event"));
|
||||
|
||||
} else if (eventName.EqualsLiteral("EVENT_RECOGNITIONSERVICE_FINAL_RESULT")) {
|
||||
nsRefPtr<SpeechEvent> event = new SpeechEvent(
|
||||
mRecognition, SpeechRecognition::EVENT_RECOGNITIONSERVICE_FINAL_RESULT);
|
||||
|
||||
event->mRecognitionResultList = BuildMockResultList();
|
||||
NS_DispatchToMainThread(event);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SpeechRecognitionResultList*
|
||||
PocketSphinxSpeechRecognitionService::BuildMockResultList()
|
||||
{
|
||||
SpeechRecognitionResultList* resultList =
|
||||
new SpeechRecognitionResultList(mRecognition);
|
||||
SpeechRecognitionResult* result = new SpeechRecognitionResult(mRecognition);
|
||||
SpeechRecognitionAlternative* alternative =
|
||||
new SpeechRecognitionAlternative(mRecognition);
|
||||
|
||||
alternative->mTranscript = NS_LITERAL_STRING("Mock final result");
|
||||
alternative->mConfidence = 0.0f;
|
||||
|
||||
result->mItems.AppendElement(alternative);
|
||||
resultList->mItems.AppendElement(result);
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -0,0 +1,85 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_PocketSphinxRecognitionService_h
|
||||
#define mozilla_dom_PocketSphinxRecognitionService_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsISpeechRecognitionService.h"
|
||||
#include "speex/speex_resampler.h"
|
||||
|
||||
extern "C" {
|
||||
#include <pocketsphinx/pocketsphinx.h>
|
||||
#include <sphinxbase/sphinx_config.h>
|
||||
}
|
||||
|
||||
#define NS_POCKETSPHINX_SPEECH_RECOGNITION_SERVICE_CID \
|
||||
{ \
|
||||
0x0ff5ce56, 0x5b09, 0x4db8, { \
|
||||
0xad, 0xc6, 0x82, 0x66, 0xaf, 0x95, 0xf8, 0x64 \
|
||||
} \
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* Pocketsphix implementation of the nsISpeechRecognitionService interface
|
||||
*/
|
||||
class PocketSphinxSpeechRecognitionService : public nsISpeechRecognitionService,
|
||||
public nsIObserver
|
||||
{
|
||||
public:
|
||||
// Add XPCOM glue code
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISPEECHRECOGNITIONSERVICE
|
||||
|
||||
// Add nsIObserver code
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
/**
|
||||
* Default constructs a PocketSphinxSpeechRecognitionService loading default
|
||||
* files
|
||||
*/
|
||||
PocketSphinxSpeechRecognitionService();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Private destructor to prevent bypassing of reference counting
|
||||
*/
|
||||
virtual ~PocketSphinxSpeechRecognitionService();
|
||||
|
||||
/** The associated SpeechRecognition */
|
||||
WeakPtr<dom::SpeechRecognition> mRecognition;
|
||||
|
||||
/**
|
||||
* Builds a mock SpeechRecognitionResultList
|
||||
*/
|
||||
dom::SpeechRecognitionResultList* BuildMockResultList();
|
||||
|
||||
/** Speex state */
|
||||
SpeexResamplerState* mSpeexState;
|
||||
|
||||
/** Pocksphix decoder */
|
||||
ps_decoder_t* mPSHandle;
|
||||
|
||||
/** Sphinxbase parsed command line arguments */
|
||||
cmd_ln_t* mPSConfig;
|
||||
|
||||
/** Flag to verify if decoder was created */
|
||||
bool ISDecoderCreated;
|
||||
|
||||
/** Flag to verify if grammar was compiled */
|
||||
bool ISGrammarCompiled;
|
||||
|
||||
/** Audio data */
|
||||
nsTArray<int16_t> mAudioVector;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -53,14 +53,14 @@ SpeechGrammar::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
void
|
||||
SpeechGrammar::GetSrc(nsString& aRetVal, ErrorResult& aRv) const
|
||||
{
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
aRetVal = mSrc;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
SpeechGrammar::SetSrc(const nsAString& aArg, ErrorResult& aRv)
|
||||
{
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
mSrc = aArg;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,8 @@ private:
|
||||
~SpeechGrammar();
|
||||
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
|
||||
nsString mSrc;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechGrammarList, mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechGrammarList, mParent, mItems)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechGrammarList)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechGrammarList)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechGrammarList)
|
||||
@@ -64,14 +64,14 @@ SpeechGrammarList::GetParentObject() const
|
||||
uint32_t
|
||||
SpeechGrammarList::Length() const
|
||||
{
|
||||
return 0;
|
||||
return mItems.Length();
|
||||
}
|
||||
|
||||
already_AddRefed<SpeechGrammar>
|
||||
SpeechGrammarList::Item(uint32_t aIndex, ErrorResult& aRv)
|
||||
{
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
return nullptr;
|
||||
nsRefPtr<SpeechGrammar> result = mItems.ElementAt(aIndex);
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -88,7 +88,10 @@ SpeechGrammarList::AddFromString(const nsAString& aString,
|
||||
const Optional<float>& aWeight,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
mRecognitionService->ValidateAndSetGrammarList(this, nullptr);
|
||||
SpeechGrammar* speechGrammar = new SpeechGrammar(mParent);
|
||||
speechGrammar->SetSrc(aString, aRv);
|
||||
mItems.AppendElement(speechGrammar);
|
||||
mRecognitionService->ValidateAndSetGrammarList(speechGrammar, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -96,8 +99,13 @@ already_AddRefed<SpeechGrammar>
|
||||
SpeechGrammarList::IndexedGetter(uint32_t aIndex, bool& aPresent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
return nullptr;
|
||||
if (aIndex >= Length()) {
|
||||
aPresent = false;
|
||||
return nullptr;
|
||||
}
|
||||
ErrorResult rv;
|
||||
aPresent = true;
|
||||
return Item(aIndex, rv);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -56,6 +56,8 @@ private:
|
||||
~SpeechGrammarList();
|
||||
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
|
||||
nsTArray<nsRefPtr<SpeechGrammar>> mItems;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
#define PREFERENCE_DEFAULT_RECOGNITION_SERVICE "media.webspeech.service.default"
|
||||
#define DEFAULT_RECOGNITION_SERVICE "google"
|
||||
#define DEFAULT_RECOGNITION_SERVICE "pocketsphinx"
|
||||
|
||||
#define PREFERENCE_ENDPOINTER_SILENCE_LENGTH "media.webspeech.silence_length"
|
||||
#define PREFERENCE_ENDPOINTER_LONG_SILENCE_LENGTH "media.webspeech.long_silence_length"
|
||||
@@ -84,9 +84,9 @@ GetSpeechRecognitionService()
|
||||
NS_SPEECH_RECOGNITION_SERVICE_CONTRACTID_PREFIX "fake";
|
||||
}
|
||||
|
||||
nsresult aRv;
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISpeechRecognitionService> recognitionService;
|
||||
recognitionService = do_GetService(speechRecognitionServiceCID.get(), &aRv);
|
||||
recognitionService = do_GetService(speechRecognitionServiceCID.get(), &rv);
|
||||
return recognitionService.forget();
|
||||
}
|
||||
|
||||
@@ -472,12 +472,12 @@ SpeechRecognition::NotifyFinalResult(SpeechEvent* aEvent)
|
||||
{
|
||||
ResetAndEnd();
|
||||
|
||||
SpeechRecognitionEventInit init;
|
||||
RootedDictionary<SpeechRecognitionEventInit> init(nsContentUtils::RootingCx());
|
||||
init.mBubbles = true;
|
||||
init.mCancelable = false;
|
||||
// init.mResultIndex = 0;
|
||||
init.mResults = aEvent->mRecognitionResultList;
|
||||
init.mInterpretation = NS_LITERAL_STRING("NOT_IMPLEMENTED");
|
||||
init.mInterpretation = JS::NullValue();
|
||||
// init.mEmma = nullptr;
|
||||
|
||||
nsRefPtr<SpeechRecognitionEvent> event =
|
||||
@@ -535,7 +535,9 @@ SpeechRecognition::StartRecording(DOMMediaStream* aDOMStream)
|
||||
// doesn't get Destroy()'ed
|
||||
mDOMStream = aDOMStream;
|
||||
|
||||
NS_ENSURE_STATE(mDOMStream->GetStream());
|
||||
if (NS_WARN_IF(!mDOMStream->GetStream())) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
mSpeechListener = new SpeechStreamListener(this);
|
||||
mDOMStream->GetStream()->AddListener(mSpeechListener);
|
||||
|
||||
@@ -698,11 +700,15 @@ SpeechRecognition::Start(const Optional<NonNull<DOMMediaStream>>& aStream, Error
|
||||
}
|
||||
|
||||
mRecognitionService = GetSpeechRecognitionService();
|
||||
NS_ENSURE_TRUE_VOID(mRecognitionService);
|
||||
if (NS_WARN_IF(!mRecognitionService)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
rv = mRecognitionService->Initialize(this);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
MediaStreamConstraints constraints;
|
||||
constraints.mAudio.SetAsBoolean() = true;
|
||||
@@ -957,7 +963,7 @@ SpeechRecognition::GetUserMediaErrorCallback::OnError(nsISupports* aError)
|
||||
}
|
||||
SpeechRecognitionErrorCode errorCode;
|
||||
|
||||
nsString name;
|
||||
nsAutoString name;
|
||||
error->GetName(name);
|
||||
if (name.EqualsLiteral("PERMISSION_DENIED")) {
|
||||
errorCode = SpeechRecognitionErrorCode::Not_allowed;
|
||||
@@ -965,7 +971,7 @@ SpeechRecognition::GetUserMediaErrorCallback::OnError(nsISupports* aError)
|
||||
errorCode = SpeechRecognitionErrorCode::Audio_capture;
|
||||
}
|
||||
|
||||
nsString message;
|
||||
nsAutoString message;
|
||||
error->GetMessage(message);
|
||||
mRecognition->DispatchError(SpeechRecognition::EVENT_AUDIO_ERROR, errorCode,
|
||||
message);
|
||||
|
||||
@@ -22,8 +22,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechRecognitionAlternative)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
SpeechRecognitionAlternative::SpeechRecognitionAlternative(SpeechRecognition* aParent)
|
||||
: mTranscript(NS_LITERAL_STRING(""))
|
||||
, mConfidence(0)
|
||||
: mConfidence(0)
|
||||
, mParent(aParent)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ SpeechRecognitionResult::Item(uint32_t aIndex)
|
||||
}
|
||||
|
||||
bool
|
||||
SpeechRecognitionResult::Final() const
|
||||
SpeechRecognitionResult::IsFinal() const
|
||||
{
|
||||
return true; // TODO
|
||||
}
|
||||
|
||||
@@ -38,11 +38,11 @@ public:
|
||||
|
||||
already_AddRefed<SpeechRecognitionAlternative> Item(uint32_t aIndex);
|
||||
|
||||
bool Final() const;
|
||||
bool IsFinal() const;
|
||||
|
||||
already_AddRefed<SpeechRecognitionAlternative> IndexedGetter(uint32_t aIndex, bool& aPresent);
|
||||
|
||||
nsTArray<nsRefPtr<SpeechRecognitionAlternative> > mItems;
|
||||
nsTArray<nsRefPtr<SpeechRecognitionAlternative>> mItems;
|
||||
|
||||
private:
|
||||
~SpeechRecognitionResult();
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
|
||||
already_AddRefed<SpeechRecognitionResult> IndexedGetter(uint32_t aIndex, bool& aPresent);
|
||||
|
||||
nsTArray<nsRefPtr<SpeechRecognitionResult> > mItems;
|
||||
nsTArray<nsRefPtr<SpeechRecognitionResult>> mItems;
|
||||
private:
|
||||
~SpeechRecognitionResultList();
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,34 @@
|
||||
/* ====================================================================
|
||||
* Copyright (c) 2015 Alpha Cephei Inc. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ALPHA CEPHEI INC. ``AS IS'' AND.
|
||||
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,.
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALPHA CEPHEI INC.
|
||||
* NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT.
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,.
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY.
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT.
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE.
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ====================================================================
|
||||
*
|
||||
*/
|
||||
|
||||
This directory contains generic US english acoustic model trained with
|
||||
latest sphinxtrain.
|
||||
@@ -0,0 +1,12 @@
|
||||
-lowerf 130
|
||||
-upperf 3700
|
||||
-nfilt 20
|
||||
-transform dct
|
||||
-lifter 22
|
||||
-feat 1s_c_d_dd
|
||||
-svspec 0-12/13-25/26-38
|
||||
-agc none
|
||||
-cmn current
|
||||
-varnorm no
|
||||
-cmninit 40,3,-1
|
||||
-model ptm
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
<s> SIL
|
||||
</s> SIL
|
||||
<sil> SIL
|
||||
[NOISE] +NSN+
|
||||
[SPEECH] +SPN+
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -19,9 +19,18 @@ EXPORTS.mozilla.dom += [
|
||||
'SpeechRecognitionResult.h',
|
||||
'SpeechRecognitionResultList.h',
|
||||
'SpeechStreamListener.h',
|
||||
'test/FakeSpeechRecognitionService.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH_TEST_BACKEND']:
|
||||
EXPORTS.mozilla.dom += [
|
||||
'test/FakeSpeechRecognitionService.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH_POCKETSPHINX']:
|
||||
EXPORTS.mozilla.dom += [
|
||||
'PocketSphinxSpeechRecognitionService.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'endpointer.cc',
|
||||
'energy_endpointer.cc',
|
||||
@@ -33,13 +42,28 @@ UNIFIED_SOURCES += [
|
||||
'SpeechRecognitionResult.cpp',
|
||||
'SpeechRecognitionResultList.cpp',
|
||||
'SpeechStreamListener.cpp',
|
||||
'test/FakeSpeechRecognitionService.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH_TEST_BACKEND']:
|
||||
UNIFIED_SOURCES += [
|
||||
'test/FakeSpeechRecognitionService.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH_POCKETSPHINX']:
|
||||
UNIFIED_SOURCES += [
|
||||
'PocketSphinxSpeechRecognitionService.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/base',
|
||||
'/media/sphinxbase',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH_POCKETSPHINX']:
|
||||
LOCAL_INCLUDES += [
|
||||
'/media/pocketsphinx',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
@@ -21,19 +21,19 @@ class SpeechGrammar;
|
||||
|
||||
native SpeechRecognitionWeakPtr(mozilla::WeakPtr<mozilla::dom::SpeechRecognition>);
|
||||
[ptr] native AudioSegmentPtr(mozilla::AudioSegment);
|
||||
[ptr] native SpeechGrammarListPtr(mozilla::dom::SpeechGrammarList);
|
||||
[ptr] native SpeechGrammarPtr(mozilla::dom::SpeechGrammar);
|
||||
[ptr] native SpeechGrammarListPtr(mozilla::dom::SpeechGrammarList);
|
||||
|
||||
[uuid(374583f0-4507-11e4-a183-164230d1df67)]
|
||||
[uuid(6fcb6ee8-a6db-49ba-9f06-355d7ee18ea7)]
|
||||
interface nsISpeechGrammarCompilationCallback : nsISupports {
|
||||
void grammarCompilationEnd(in SpeechGrammarPtr grammarObject, in boolean success);
|
||||
};
|
||||
|
||||
[uuid(857f3fa2-a980-4d3e-a959-a2f53af74232)]
|
||||
[uuid(8e97f287-f322-44e8-8888-8344fa408ef8)]
|
||||
interface nsISpeechRecognitionService : nsISupports {
|
||||
void initialize(in SpeechRecognitionWeakPtr aSpeechRecognition);
|
||||
void processAudioSegment(in AudioSegmentPtr aAudioSegment, in long aSampleRate);
|
||||
void validateAndSetGrammarList(in SpeechGrammarListPtr aSpeechGramarList, in nsISpeechGrammarCompilationCallback aCallback);
|
||||
void validateAndSetGrammarList(in SpeechGrammarPtr aSpeechGrammar, in nsISpeechGrammarCompilationCallback aCallback);
|
||||
void soundEnd();
|
||||
void abort();
|
||||
};
|
||||
|
||||
@@ -52,7 +52,7 @@ FakeSpeechRecognitionService::SoundEnd()
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FakeSpeechRecognitionService::ValidateAndSetGrammarList(mozilla::dom::SpeechGrammarList*, nsISpeechGrammarCompilationCallback*)
|
||||
FakeSpeechRecognitionService::ValidateAndSetGrammarList(mozilla::dom::SpeechGrammar*, nsISpeechGrammarCompilationCallback*)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user