Merge m-c to inbound a=merge

This commit is contained in:
Wes Kocher 2014-09-15 16:41:45 -07:00
commit 332233753a
91 changed files with 4349 additions and 1459 deletions

View File

@ -11,15 +11,12 @@
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
DIRS += ["source/modules/system"]
EXTRA_JS_MODULES.sdk += [
'source/app-extension/bootstrap.js',
]
EXTRA_JS_MODULES.sdk.system += [
'source/modules/system/Startup.js',
'source/modules/system/XulApp.js',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] != "gonk":
EXTRA_JS_MODULES.commonjs.method.test += [
'source/lib/method/test/browser.js',

View File

@ -14,25 +14,74 @@ module.metadata = {
require('chrome') // Otherwise CFX will complain about Components
require('toolkit/loader') // Otherwise CFX will stip out loader.js
require('sdk/addon/runner') // Otherwise CFX will stip out addon/runner.js
require('sdk/system/xul-app') // Otherwise CFX will stip out sdk/system/xul-app
*/
const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
const {
incompatibility
} = Cu.import("resource://gre/modules/sdk/system/XulApp.js", {}).XulApp;
// `loadSandbox` is exposed by bootstrap.js
const loaderURI = module.uri.replace("sdk/loader/cuddlefish.js",
"toolkit/loader.js");
const xulappURI = module.uri.replace("loader/cuddlefish.js",
"system/xul-app.js");
// We need to keep a reference to the sandbox in order to unload it in
// bootstrap.js
const loaderSandbox = loadSandbox(loaderURI);
const loaderModule = loaderSandbox.exports;
const xulappSandbox = loadSandbox(xulappURI);
const xulappModule = xulappSandbox.exports;
const { override, load } = loaderModule;
/**
* Ensure the current application satisfied the requirements specified in the
* module given. If not, an exception related to the incompatibility is
* returned; `null` otherwise.
*
* @param {Object} module
* The module to check
* @returns {Error}
*/
function incompatibility(module) {
let { metadata, id } = module;
// if metadata or engines are not specified we assume compatibility is not
// an issue.
if (!metadata || !("engines" in metadata))
return null;
let { engines } = metadata;
if (engines === null || typeof(engines) !== "object")
return new Error("Malformed engines' property in metadata");
let applications = Object.keys(engines);
let versionRange;
applications.forEach(function(name) {
if (xulappModule.is(name)) {
versionRange = engines[name];
// Continue iteration. We want to ensure the module doesn't
// contain a typo in the applications' name or some unknown
// application - `is` function throws an exception in that case.
}
});
if (typeof(versionRange) === "string") {
if (xulappModule.satisfiesVersion(versionRange))
return null;
return new Error("Unsupported Application version: The module " + id +
" currently supports only version " + versionRange + " of " +
xulappModule.name + ".");
}
return new Error("Unsupported Application: The module " + id +
" currently supports only " + applications.join(", ") + ".")
}
function CuddlefishLoader(options) {
let { manifest } = options;
@ -41,7 +90,8 @@ function CuddlefishLoader(options) {
// cache to avoid subsequent loads via `require`.
modules: override({
'toolkit/loader': loaderModule,
'sdk/loader/cuddlefish': exports
'sdk/loader/cuddlefish': exports,
'sdk/system/xul-app': xulappModule
}, options.modules),
resolve: function resolve(id, requirer) {
let entry = requirer && requirer in manifest && manifest[requirer];

View File

@ -42,9 +42,6 @@ const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
const { Reflect } = Cu.import("resource://gre/modules/reflect.jsm", {});
const { ConsoleAPI } = Cu.import("resource://gre/modules/devtools/Console.jsm");
const { join: pathJoin, normalize, dirname } = Cu.import("resource://gre/modules/osfile/ospath_unix.jsm");
const {
incompatibility
} = Cu.import("resource://gre/modules/sdk/system/XulApp.js", {}).XulApp;
// Define some shortcuts.
const bind = Function.call.bind(Function.bind);
@ -352,12 +349,6 @@ const load = iced(function load(loader, module) {
});
}
let (error = incompatibility(module)) {
if (error) {
throw error;
}
}
if (module.exports && typeof(module.exports) === 'object')
freeze(module.exports);

View File

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["Startup"];
var EXPORTED_SYMBOLS = ["Startup"];
const { utils: Cu, interfaces: Ci, classes: Cc } = Components;
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
@ -20,10 +20,10 @@ const NAME2TOPIC = {
'Thunderbird': 'mail-startup-done'
};
var exports = {
var Startup = {
initialized: !appStartupSrv.startingUp
};
this.Startup = exports;
var exports = Startup;
let gOnceInitializedDeferred = defer();
exports.onceInitialized = gOnceInitializedDeferred.promise;

View File

@ -3,16 +3,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["XulApp"];
var EXPORTED_SYMBOLS = ["XulApp"];
var { classes: Cc, interfaces: Ci } = Components;
var exports = {};
this.XulApp = exports;
var appInfo = Cc["@mozilla.org/xre/app-info;1"].
getService(Ci.nsIXULAppInfo);
var XulApp = exports;
var appInfo = Cc["@mozilla.org/xre/app-info;1"]
.getService(Ci.nsIXULAppInfo);
var vc = Cc["@mozilla.org/xpcom/version-comparator;1"]
.getService(Ci.nsIVersionComparator);
@ -184,51 +183,3 @@ function satisfiesVersion(version, versionRange) {
});
}
exports.satisfiesVersion = satisfiesVersion;
/**
* Ensure the current application satisfied the requirements specified in the
* module given. If not, an exception related to the incompatibility is
* returned; `null` otherwise.
*
* @param {Object} module
* The module to check
* @returns {Error}
*/
function incompatibility(module) {
let { metadata, id } = module;
// if metadata or engines are not specified we assume compatibility is not
// an issue.
if (!metadata || !("engines" in metadata))
return null;
let { engines } = metadata;
if (engines === null || typeof(engines) !== "object")
return new Error("Malformed engines' property in metadata");
let applications = Object.keys(engines);
let versionRange;
applications.forEach(function(name) {
if (is(name)) {
versionRange = engines[name];
// Continue iteration. We want to ensure the module doesn't
// contain a typo in the applications' name or some unknown
// application - `is` function throws an exception in that case.
}
});
if (typeof(versionRange) === "string") {
if (satisfiesVersion(versionRange))
return null;
return new Error("Unsupported Application version: The module " + id +
" currently supports only version " + versionRange + " of " +
name + ".");
}
return new Error("Unsupported Application: The module " + id +
" currently supports only " + applications.join(", ") + ".")
}
exports.incompatibility = incompatibility;

View File

@ -0,0 +1,10 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXTRA_JS_MODULES.sdk.system += [
'Startup.js',
'XulApp.js',
]

View File

@ -1,10 +1,10 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { Loader, Require, unload, override } = require('sdk/loader/cuddlefish');
const app = require('sdk/system/xul-app');
const packaging = require('@loader/options');
exports['test loader'] = function(assert) {
@ -44,19 +44,4 @@ exports['test loader'] = function(assert) {
'loader.unload() must call listeners in LIFO order.');
};
exports['test loader on unsupported modules'] = function(assert) {
let loader = Loader({});
let err = "";
assert.throws(() => {
if (!app.is('Firefox')) {
require('./fixtures/loader/unsupported/firefox');
}
else {
require('./fixtures/loader/unsupported/fennec');
}
}, /^Unsupported Application/, "throws Unsupported Application");
unload(loader);
};
require('sdk/test').run(exports);
require('test').run(exports);

View File

@ -1,6 +1,7 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
let {
@ -10,10 +11,9 @@ let { readURI } = require('sdk/net/url');
let root = module.uri.substr(0, module.uri.lastIndexOf('/'))
// The following adds Debugger constructor to the global namespace.
const { Cu } = require('chrome');
const app = require('sdk/system/xul-app');
const { addDebuggerToGlobal } = Cu.import('resource://gre/modules/jsdebugger.jsm', {});
addDebuggerToGlobal(this);
@ -331,7 +331,7 @@ exports['test console global by default'] = function (assert) {
let uri = root + '/fixtures/loader/globals/';
let loader = Loader({ paths: { '': uri }});
let program = main(loader, 'main');
assert.ok(typeof program.console === 'object', 'global `console` exists');
assert.ok(typeof program.console.log === 'function', 'global `console.log` exists');
@ -374,19 +374,4 @@ exports["test require#resolve"] = function(assert) {
assert.equal(root + "toolkit/loader.js", require.resolve("toolkit/loader"), "correct resolution of sdk module");
};
exports['test loader on unsupported modules'] = function(assert) {
let loader = Loader({});
let err = "";
assert.throws(() => {
if (!app.is('Firefox')) {
require('./fixtures/loader/unsupported/firefox');
}
else {
require('./fixtures/loader/unsupported/fennec');
}
}, /^Unsupported Application/, "throws Unsupported Application");
unload(loader);
};
require('sdk/test').run(exports);
require('test').run(exports);

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="fe92ddd450e03b38edb2d465de7897971d68ac68">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="855be6ade407c26e0596e7306a44deebc3f60933"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e2d70bee03b5380ac327a145e5d694fb2443f018"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="855be6ade407c26e0596e7306a44deebc3f60933"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e2d70bee03b5380ac327a145e5d694fb2443f018"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="855be6ade407c26e0596e7306a44deebc3f60933"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e2d70bee03b5380ac327a145e5d694fb2443f018"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="3b740054007bde98875b2def11eac24cf9c20e5c"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="fe92ddd450e03b38edb2d465de7897971d68ac68">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="855be6ade407c26e0596e7306a44deebc3f60933"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e2d70bee03b5380ac327a145e5d694fb2443f018"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="855be6ade407c26e0596e7306a44deebc3f60933"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e2d70bee03b5380ac327a145e5d694fb2443f018"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="fe92ddd450e03b38edb2d465de7897971d68ac68">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="855be6ade407c26e0596e7306a44deebc3f60933"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e2d70bee03b5380ac327a145e5d694fb2443f018"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="855be6ade407c26e0596e7306a44deebc3f60933"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e2d70bee03b5380ac327a145e5d694fb2443f018"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="3b740054007bde98875b2def11eac24cf9c20e5c"/>

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "b0a272695ccf247884000f785ed4cbfe49ae4141",
"revision": "123eb4378d299e61d73be5e290f7d9ca00f2fb41",
"repo_path": "/integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="855be6ade407c26e0596e7306a44deebc3f60933"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e2d70bee03b5380ac327a145e5d694fb2443f018"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -15,7 +15,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="855be6ade407c26e0596e7306a44deebc3f60933"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e2d70bee03b5380ac327a145e5d694fb2443f018"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="855be6ade407c26e0596e7306a44deebc3f60933"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e2d70bee03b5380ac327a145e5d694fb2443f018"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="3b740054007bde98875b2def11eac24cf9c20e5c"/>

View File

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="855be6ade407c26e0596e7306a44deebc3f60933"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e2d70bee03b5380ac327a145e5d694fb2443f018"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -258,12 +258,6 @@ XPCOMUtils.defineLazyGetter(this, "PageMenu", function() {
*/
function pageShowEventHandlers(persisted) {
XULBrowserWindow.asyncUpdateUI();
// The PluginClickToPlay events are not fired when navigating using the
// BF cache. |persisted| is true when the page is loaded from the
// BF cache, so this code reshows the notification if necessary.
if (persisted)
gPluginHandler.reshowClickToPlayNotification();
}
function UpdateBackForwardCommands(aWebNavigation) {
@ -780,13 +774,6 @@ var gBrowserInit = {
gBrowser.addEventListener("DOMUpdatePageReport", gPopupBlockerObserver, false);
// Note that the XBL binding is untrusted
gBrowser.addEventListener("PluginBindingAttached", gPluginHandler, true, true);
gBrowser.addEventListener("PluginCrashed", gPluginHandler, true);
gBrowser.addEventListener("PluginOutdated", gPluginHandler, true);
gBrowser.addEventListener("PluginInstantiated", gPluginHandler, true);
gBrowser.addEventListener("PluginRemoved", gPluginHandler, true);
gBrowser.addEventListener("NewPluginInstalled", gPluginHandler.newPluginInstalled, true);
Services.obs.addObserver(gPluginHandler.pluginCrashed, "plugin-crashed", false);

View File

@ -16,6 +16,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerContent",
"resource://gre/modules/LoginManagerContent.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "InsecurePasswordUtils",
"resource://gre/modules/InsecurePasswordUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluginContent",
"resource:///modules/PluginContent.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UITour",
@ -493,6 +495,9 @@ ClickEventHandler.init();
ContentLinkHandler.init(this);
// TODO: Load this lazily so the JSM is run only if a relevant event/message fires.
let pluginContent = new PluginContent(global);
addEventListener("DOMWebNotificationClicked", function(event) {
sendAsyncMessage("DOMWebNotificationClicked", {});
}, false);

View File

@ -1315,11 +1315,11 @@ nsContextMenu.prototype = {
},
playPlugin: function() {
gPluginHandler._showClickToPlayNotification(this.browser, this.target, true);
gPluginHandler.contextMenuCommand(this.browser, this.target, "play");
},
hidePlugin: function() {
gPluginHandler.hideClickToPlayOverlay(this.target);
gPluginHandler.contextMenuCommand(this.browser, this.target, "hide");
},
// Generate email address and put it on clipboard.

View File

@ -19,7 +19,11 @@ function testVal(aExpected) {
is(result, aExpected);
}
function test() {
add_task(function* () {
return new Promise(resolve => Services.search.init(resolve));
});
add_task(function* () {
const prefname = "browser.urlbar.formatting.enabled";
registerCleanupFunction(function () {
@ -109,4 +113,4 @@ function test() {
Services.prefs.setBoolPref(prefname, false);
testVal("https://mozilla.org");
}
});

View File

@ -8,6 +8,72 @@ const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browse
const gTestRoot = getRootDirectory(gTestPath);
var gTestBrowser = null;
/**
* Frame script that will be injected into the test browser
* to cause the crash, and then manipulate the crashed plugin
* UI. Specifically, after the crash, we ensure that the
* crashed plugin UI is using the right style rules and that
* the submit URL opt-in defaults to checked. Then, we fill in
* a comment with the crash report, uncheck the submit URL
* opt-in, and send the crash reports.
*/
function frameScript() {
function fail(reason) {
sendAsyncMessage("test:crash-plugin:fail", {
reason: `Failure from frameScript: ${reason}`,
});
}
addMessageListener("test:crash-plugin", () => {
let doc = content.document;
addEventListener("PluginCrashed", (event) => {
let plugin = doc.getElementById("test");
if (!plugin) {
fail("Could not find plugin element");
return;
}
let getUI = (anonid) => {
return doc.getAnonymousElementByAttribute(plugin, "anonid", anonid);
};
let style = content.getComputedStyle(getUI("pleaseSubmit"));
if (style.display != "block") {
fail("Submission UI visibility is not correct. Expected block, "
+ " got " + style.display);
return;
}
getUI("submitComment").value = "a test comment";
if (!getUI("submitURLOptIn").checked) {
fail("URL opt-in should default to true.");
return;
}
getUI("submitURLOptIn").click();
getUI("submitButton").click();
});
let plugin = doc.getElementById("test");
try {
plugin.crash()
} catch(e) {
}
});
addMessageListener("test:plugin-submit-status", () => {
let doc = content.document;
let plugin = doc.getElementById("test");
let submitStatusEl =
doc.getAnonymousElementByAttribute(plugin, "anonid", "submitStatus");
let submitStatus = submitStatusEl.getAttribute("status");
sendAsyncMessage("test:plugin-submit-status:result", {
submitStatus: submitStatus,
});
});
}
// Test that plugin crash submissions still work properly after
// click-to-play activation.
@ -31,14 +97,18 @@ function test() {
let tab = gBrowser.loadOneTab("about:blank", { inBackground: false });
gTestBrowser = gBrowser.getBrowserForTab(tab);
gTestBrowser.addEventListener("PluginCrashed", onCrash, false);
let mm = gTestBrowser.messageManager;
mm.loadFrameScript("data:,(" + frameScript.toString() + ")();", false);
mm.addMessageListener("test:crash-plugin:fail", (message) => {
ok(false, message.data.reason);
});
gTestBrowser.addEventListener("load", onPageLoad, true);
Services.obs.addObserver(onSubmitStatus, "crash-report-status", false);
registerCleanupFunction(function cleanUp() {
env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
env.set("MOZ_CRASHREPORTER_URL", serverURL);
gTestBrowser.removeEventListener("PluginCrashed", onCrash, false);
gTestBrowser.removeEventListener("load", onPageLoad, true);
Services.obs.removeObserver(onSubmitStatus, "crash-report-status");
gBrowser.removeCurrentTab();
@ -70,31 +140,8 @@ function afterBindingAttached() {
}
function pluginActivated() {
let plugin = gTestBrowser.contentDocument.getElementById("test");
try {
plugin.crash();
} catch (e) {
// The plugin crashed in the above call, an exception is expected.
}
}
function onCrash() {
try {
let plugin = gBrowser.contentDocument.getElementById("test");
let elt = gPluginHandler.getPluginUI.bind(gPluginHandler, plugin);
let style =
gBrowser.contentWindow.getComputedStyle(elt("pleaseSubmit"));
is(style.display, "block", "Submission UI visibility should be correct");
elt("submitComment").value = "a test comment";
is(elt("submitURLOptIn").checked, true, "URL opt-in should default to true");
EventUtils.synthesizeMouseAtCenter(elt("submitURLOptIn"), {}, gTestBrowser.contentWindow);
EventUtils.synthesizeMouseAtCenter(elt("submitButton"), {}, gTestBrowser.contentWindow);
// And now wait for the submission status notification.
}
catch (err) {
failWithException(err);
}
let mm = gTestBrowser.messageManager;
mm.sendAsyncMessage("test:crash-plugin");
}
function onSubmitStatus(subj, topic, data) {
@ -128,19 +175,23 @@ function onSubmitStatus(subj, topic, data) {
ok(val === undefined,
"URL should be absent from extra data when opt-in not checked");
// Execute this later in case the event to change submitStatus has not
// have been dispatched yet.
executeSoon(function () {
let plugin = gBrowser.contentDocument.getElementById("test");
let elt = gPluginHandler.getPluginUI.bind(gPluginHandler, plugin);
is(elt("submitStatus").getAttribute("status"), data,
"submitStatus data should match");
let submitStatus = null;
let mm = gTestBrowser.messageManager;
mm.addMessageListener("test:plugin-submit-status:result", (message) => {
submitStatus = message.data.submitStatus;
});
mm.sendAsyncMessage("test:plugin-submit-status");
let condition = () => submitStatus;
waitForCondition(condition, () => {
is(submitStatus, data, "submitStatus data should match");
finish();
}, "Waiting for submitStatus to be reported from frame script");
}
catch (err) {
failWithException(err);
}
finish();
}
function getPropertyBagValue(bag, key) {

View File

@ -29,11 +29,11 @@ function handleEvent() {
function part1() {
gBrowser.selectedBrowser.removeEventListener("PluginBindingAttached", handleEvent);
ok(PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser), "Should have a click-to-play notification in the initial tab");
gNextTest = part2;
gNewWindow = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
gNewWindow.addEventListener("load", handleEvent, true);
waitForNotificationPopup("click-to-play-plugins", gBrowser.selectedBrowser, () => {
gNextTest = part2;
gNewWindow = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
gNewWindow.addEventListener("load", handleEvent, true);
});
}
function part2() {
@ -62,10 +62,10 @@ function part4() {
function part5() {
gBrowser.selectedBrowser.removeEventListener("PluginBindingAttached", handleEvent);
ok(PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser), "Should have a click-to-play notification in the initial tab");
gNewWindow = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
waitForFocus(part6, gNewWindow);
waitForNotificationPopup("click-to-play-plugins", gBrowser.selectedBrowser, () => {
gNewWindow = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
waitForFocus(part6, gNewWindow);
});
}
function part6() {
@ -92,8 +92,10 @@ function part8() {
let plugin = gNewWindow.gBrowser.selectedBrowser.contentDocument.getElementById("test");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "plugin should be activated now");
waitForCondition(() => objLoadingContent.activated, shutdown, "plugin should be activated now");
}
function shutdown() {
gNewWindow.close();
gNewWindow = null;
finish();

View File

@ -74,13 +74,15 @@ function test1() {
let plugin = doc.getElementById("test");
ok(plugin, "Test 1, Found plugin in page");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
ok(overlay.classList.contains("visible"), "Test 1, Plugin overlay should exist, not be hidden");
let closeIcon = doc.getAnonymousElementByAttribute(plugin, "anonid", "closeIcon")
waitForNotificationPopup("click-to-play-plugins", gTestBrowser, () => {
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
ok(overlay.classList.contains("visible"), "Test 1, Plugin overlay should exist, not be hidden");
let closeIcon = doc.getAnonymousElementByAttribute(plugin, "anonid", "closeIcon");
EventUtils.synthesizeMouseAtCenter(closeIcon, {}, frame.contentWindow);
let condition = () => !overlay.classList.contains("visible");
waitForCondition(condition, test2, "Test 1, Waited too long for the overlay to become invisible.");
EventUtils.synthesizeMouseAtCenter(closeIcon, {}, frame.contentWindow);
let condition = () => !overlay.classList.contains("visible");
waitForCondition(condition, test2, "Test 1, Waited too long for the overlay to become invisible.");
});
}
function test2() {

View File

@ -63,43 +63,37 @@ function runAfterPluginBindingAttached(func) {
// Tests for the notification bar for hidden plugins.
function test1() {
let notification = PopupNotifications.getNotification("click-to-play-plugins");
ok(notification, "Test 1: There should be a plugin notification");
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
waitForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") !== null,
() => {
info("Test 1 - expecting a notification bar for hidden plugins.");
waitForNotificationPopup("click-to-play-plugins", gTestBrowser, () => {
waitForNotificationBar("plugin-hidden", gTestBrowser, () => {
// Don't use setTestPluginEnabledState here because we already saved the
// prior value
getTestPlugin().enabledState = Ci.nsIPluginTag.STATE_ENABLED;
prepareTest(test2, gTestRoot + "plugin_small.html");
},
"Test 1, expected to have a plugin notification bar");
});
});
}
function test2() {
let notification = PopupNotifications.getNotification("click-to-play-plugins");
ok(notification, "Test 2: There should be a plugin notification");
info("Test 2 - expecting no plugin notification bar on visible plugins.");
waitForNotificationPopup("click-to-play-plugins", gTestBrowser, () => {
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
waitForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") === null,
() => {
getTestPlugin().enabledState = Ci.nsIPluginTag.STATE_CLICKTOPLAY;
prepareTest(test3, gTestRoot + "plugin_overlayed.html");
},
"Test 2, expected to not have a plugin notification bar");
waitForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") === null,
() => {
getTestPlugin().enabledState = Ci.nsIPluginTag.STATE_CLICKTOPLAY;
prepareTest(test3, gTestRoot + "plugin_overlayed.html");
},
"expected to not have a plugin notification bar"
);
});
}
function test3() {
let notification = PopupNotifications.getNotification("click-to-play-plugins");
ok(notification, "Test 3: There should be a plugin notification");
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
waitForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") !== null,
test3b,
"Test 3, expected the plugin infobar to be triggered when plugin was overlayed");
info("Test 3 - expecting a plugin notification bar when plugins are overlaid");
waitForNotificationPopup("click-to-play-plugins", gTestBrowser, () => {
waitForNotificationBar("plugin-hidden", gTestBrowser, test3b);
});
}
function test3b()
@ -118,13 +112,10 @@ function test3b()
}
function test4() {
let notification = PopupNotifications.getNotification("click-to-play-plugins");
ok(notification, "Test 4: There should be a plugin notification");
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
waitForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") !== null,
test4b,
"Test 4, expected the plugin infobar to be triggered when plugin was overlayed");
info("Test 4 - expecting a plugin notification bar when plugins are overlaid offscreen")
waitForNotificationPopup("click-to-play-plugins", gTestBrowser, () => {
waitForNotificationBar("plugin-hidden", gTestBrowser, test4b);
});
}
function test4b() {
@ -141,9 +132,6 @@ function test4b() {
prepareTest(runAfterPluginBindingAttached(test5), gHttpTestRoot + "plugin_small.html");
}
// Test that the notification bar is getting dismissed when directly activating plugins
// via the doorhanger.
function test5() {
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
waitForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") !== null,
@ -151,23 +139,27 @@ function test5() {
"Test 5, expected a notification bar for hidden plugins");
}
// Test that the notification bar is getting dismissed when directly activating plugins
// via the doorhanger.
function test6() {
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 6, Should have a click-to-play notification");
let plugin = gTestBrowser.contentDocument.getElementById("test");
ok(plugin, "Test 6, Found plugin in page");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
"Test 6, Plugin should be click-to-play");
info("Test 6 - expecting the doorhanger to be dismissed when directly activating plugins.");
waitForNotificationPopup("click-to-play-plugins", gTestBrowser, (notification) => {
let plugin = gTestBrowser.contentDocument.getElementById("test");
ok(plugin, "Test 6, Found plugin in page");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
"Test 6, Plugin should be click-to-play");
// simulate "always allow"
notification.reshow();
PopupNotifications.panel.firstChild._primaryButton.click();
// simulate "always allow"
notification.reshow();
PopupNotifications.panel.firstChild._primaryButton.click();
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
waitForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") === null,
test7,
"Test 6, expected the notification bar for hidden plugins to get dismissed");
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
waitForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") === null,
test7,
"Test 6, expected the notification bar for hidden plugins to get dismissed");
});
}
function test7() {

View File

@ -60,10 +60,8 @@ function test1b() {
// Click the activate button on doorhanger to make sure it works
popupNotification.reshow();
PopupNotifications.panel.firstChild._primaryButton.click();
ok(objLoadingContent.activated, "Test 1b, Doorhanger should activate plugin");
test1c();
var condition = function() objLoadingContent.activated;
waitForCondition(condition, test1c, "Test 1b, Waited too long for plugin activation");
}
function test1c() {

View File

@ -36,12 +36,14 @@ function pluginBindingAttached() {
ok(testplugin, "should have test plugin");
var secondtestplugin = doc.getElementById("secondtest");
ok(!secondtestplugin, "should not yet have second test plugin");
var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "should have popup notification");
// We don't set up the action list until the notification is shown
notification.reshow();
is(notification.options.pluginData.size, 1, "should be 1 type of plugin in the popup notification");
XPCNativeWrapper.unwrap(gTestBrowser.contentWindow).addSecondPlugin();
var notification;
waitForNotificationPopup("click-to-play-plugins", gTestBrowser, (notification => {
ok(notification, "should have popup notification");
// We don't set up the action list until the notification is shown
notification.reshow();
is(notification.options.pluginData.size, 1, "should be 1 type of plugin in the popup notification");
XPCNativeWrapper.unwrap(gTestBrowser.contentWindow).addSecondPlugin();
}));
} else if (gNumPluginBindingsAttached == 2) {
var doc = gTestBrowser.contentDocument;
var testplugin = doc.getElementById("test");
@ -51,8 +53,8 @@ function pluginBindingAttached() {
var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "should have popup notification");
notification.reshow();
is(notification.options.pluginData.size, 2, "should be 2 types of plugin in the popup notification");
finish();
let condition = () => (notification.options.pluginData.size == 2);
waitForCondition(condition, finish, "Waited too long for 2 types of plugins in popup notification");
} else {
ok(false, "if we've gotten here, something is quite wrong");
}

View File

@ -59,11 +59,11 @@ function onCrash(event) {
is (propVal, val, "Correct property in detail propBag: " + name + ".");
}
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
let notification = notificationBox.getNotificationWithValue("plugin-crashed");
ok(notification, "Infobar was shown.");
is(notification.priority, notificationBox.PRIORITY_WARNING_MEDIUM, "Correct priority.");
is(notification.getAttribute("label"), "The GlobalTestPlugin plugin has crashed.", "Correct message.");
finish();
waitForNotificationBar("plugin-crashed", gTestBrowser, (notification) => {
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
ok(notification, "Infobar was shown.");
is(notification.priority, notificationBox.PRIORITY_WARNING_MEDIUM, "Correct priority.");
is(notification.getAttribute("label"), "The GlobalTestPlugin plugin has crashed.", "Correct message.");
finish();
});
}

View File

@ -6,9 +6,80 @@ Cu.import("resource://gre/modules/CrashSubmit.jsm", this);
Cu.import("resource://gre/modules/Services.jsm");
const CRASH_URL = "http://example.com/browser/browser/base/content/test/plugins/plugin_crashCommentAndURL.html";
const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
/**
* Frame script that will be injected into the test browser
* to cause plugin crashes, and then manipulate the crashed plugin
* UI. The specific actions and checks that occur in the frame
* script for the crashed plugin UI are set in the
* test:crash-plugin message object sent from the parent. The actions
* and checks that the parent can specify are:
*
* pleaseSubmitStyle: the display style that the pleaseSubmit anonymous element
* should have - example "block", "none".
* submitComment: the comment that should be put into the crash report
* urlOptIn: true if the submitURLOptIn element should be checked.
* sendCrashMessage: if true, the frame script will send a
* test:crash-plugin:crashed message when the plugin has
* crashed. This is used for the last test case, and
* causes the frame script to skip any of the crashed
* plugin UI manipulation, since the last test shows
* no crashed plugin UI.
*/
function frameScript() {
function fail(reason) {
sendAsyncMessage("test:crash-plugin:fail", {
reason: `Failure from frameScript: ${reason}`,
});
}
addMessageListener("test:crash-plugin", (message) => {
addEventListener("PluginCrashed", function onPluginCrashed(event) {
removeEventListener("PluginCrashed", onPluginCrashed);
let doc = content.document;
let plugin = doc.getElementById("plugin");
if (!plugin) {
fail("Could not find plugin element");
return;
}
let getUI = (anonid) => {
return doc.getAnonymousElementByAttribute(plugin, "anonid", anonid);
};
let style = content.getComputedStyle(getUI("pleaseSubmit"));
if (style.display != message.data.pleaseSubmitStyle) {
fail("Submission UI visibility is not correct. Expected " +
`${message.data.pleaseSubmitStyle} and got ${style.display}`);
return;
}
if (message.data.sendCrashMessage) {
let propBag = event.detail.QueryInterface(Ci.nsIPropertyBag2);
let crashID = propBag.getPropertyAsAString("pluginDumpID");
sendAsyncMessage("test:crash-plugin:crashed", {
crashID: crashID,
});
return;
}
if (message.data.submitComment) {
getUI("submitComment").value = message.data.submitComment;
}
getUI("submitURLOptIn").checked = message.data.urlOptIn;
getUI("submitButton").click();
});
let plugin = content.document.getElementById("test");
try {
plugin.crash()
} catch(e) {
}
});
}
function test() {
// Crashing the plugin takes up a lot of time, so extend the test timeout.
requestLongerTimeout(runs.length);
@ -29,14 +100,18 @@ function test() {
let tab = gBrowser.loadOneTab("about:blank", { inBackground: false });
let browser = gBrowser.getBrowserForTab(tab);
browser.addEventListener("PluginCrashed", onCrash, false);
let mm = browser.messageManager;
mm.loadFrameScript("data:,(" + frameScript.toString() + ")();", true);
mm.addMessageListener("test:crash-plugin:fail", (message) => {
ok(false, message.data.reason);
});
Services.obs.addObserver(onSubmitStatus, "crash-report-status", false);
registerCleanupFunction(function cleanUp() {
env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
env.set("MOZ_CRASHREPORTER_URL", serverURL);
gBrowser.selectedBrowser.removeEventListener("PluginCrashed", onCrash,
false);
Services.obs.removeObserver(onSubmitStatus, "crash-report-status");
gBrowser.removeCurrentTab();
});
@ -76,6 +151,24 @@ function doNextRun() {
memo[arg] = currentRun[arg];
return memo;
}, {});
let mm = gBrowser.selectedBrowser.messageManager;
if (!currentRun.shouldSubmittionUIBeVisible) {
mm.addMessageListener("test:crash-plugin:crash", function onCrash(message) {
mm.removeMessageListener("test:crash-plugin:crash", onCrash);
ok(!!message.data.crashID, "pluginDumpID should be set");
CrashSubmit.delete(message.data.crashID);
doNextRun();
});
}
mm.sendAsyncMessage("test:crash-plugin", {
pleaseSubmitStyle: currentRun.shouldSubmissionUIBeVisible ? "block" : "none",
submitComment: currentRun.comment,
urlOptIn: currentRun.urlOptIn,
sendOnCrashMessage: !currentRun.shouldSubmissionUIBeVisible,
});
gBrowser.loadURI(CRASH_URL + "?" +
encodeURIComponent(JSON.stringify(args)));
// And now wait for the crash.
@ -86,37 +179,6 @@ function doNextRun() {
}
}
function onCrash(event) {
try {
let plugin = gBrowser.contentDocument.getElementById("plugin");
let elt = gPluginHandler.getPluginUI.bind(gPluginHandler, plugin);
let style =
gBrowser.contentWindow.getComputedStyle(elt("pleaseSubmit"));
is(style.display,
currentRun.shouldSubmissionUIBeVisible ? "block" : "none",
"Submission UI visibility should be correct");
if (!currentRun.shouldSubmissionUIBeVisible) {
// Done with this run. We don't submit the crash, so we will have to
// remove the dump manually.
let propBag = event.detail.QueryInterface(Ci.nsIPropertyBag2);
let crashID = propBag.getPropertyAsAString("pluginDumpID");
ok(!!crashID, "pluginDumpID should be set");
CrashSubmit.delete(crashID);
doNextRun();
return;
}
elt("submitComment").value = currentRun.comment;
elt("submitURLOptIn").checked = currentRun.urlOptIn;
elt("submitButton").click();
// And now wait for the submission status notification.
}
catch (err) {
failWithException(err);
doNextRun();
}
}
function onSubmitStatus(subj, topic, data) {
try {
// Wait for success or failed, doesn't matter which.

View File

@ -56,6 +56,7 @@ TabOpenListener.prototype = {
function test() {
waitForExplicitFinish();
SimpleTest.requestCompleteLog();
requestLongerTimeout(2);
registerCleanupFunction(function() {
clearAllPluginPermissions();
@ -797,7 +798,10 @@ function test24a() {
// simulate "always allow"
notification.reshow();
PopupNotifications.panel.firstChild._primaryButton.click();
prepareTest(test24b, gHttpTestRoot + "plugin_test.html");
waitForCondition(() => objLoadingContent.activated, () => {
prepareTest(test24b, gHttpTestRoot + "plugin_test.html");
}, "Test 24a, plugin should now be activated.");
}
// did the "always allow" work as intended?
@ -805,11 +809,11 @@ function test24b() {
var plugin = gTestBrowser.contentDocument.getElementById("test");
ok(plugin, "Test 24b, Found plugin in page");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 24b, plugin should be activated");
setAndUpdateBlocklist(gHttpTestRoot + "blockPluginVulnerableUpdatable.xml",
function() {
prepareTest(runAfterPluginBindingAttached(test24c), gHttpTestRoot + "plugin_test.html");
});
waitForCondition(() => objLoadingContent.activated, () => {
setAndUpdateBlocklist(gHttpTestRoot + "blockPluginVulnerableUpdatable.xml", () => {
prepareTest(runAfterPluginBindingAttached(test24c), gHttpTestRoot + "plugin_test.html");
});
}, "Test 24b, plugin should be activated");
}
// the plugin is now blocklisted, so it should not automatically load
@ -820,13 +824,13 @@ function test24c() {
ok(plugin, "Test 24c, Found plugin in page");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE, "Test 24c, Plugin should be vulnerable/updatable");
ok(!objLoadingContent.activated, "Test 24c, plugin should not be activated");
waitForCondition(() => !objLoadingContent.activated, () => {
// simulate "always allow"
notification.reshow();
PopupNotifications.panel.firstChild._primaryButton.click();
// simulate "always allow"
notification.reshow();
PopupNotifications.panel.firstChild._primaryButton.click();
prepareTest(test24d, gHttpTestRoot + "plugin_test.html");
prepareTest(test24d, gHttpTestRoot + "plugin_test.html");
}, "Test 24c, plugin should not be activated");
}
// We should still be able to always allow a plugin after we've seen that it's
@ -835,15 +839,14 @@ function test24d() {
var plugin = gTestBrowser.contentDocument.getElementById("test");
ok(plugin, "Test 24d, Found plugin in page");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 24d, plugin should be activated");
// this resets the vulnerable plugin permission
setAndUpdateBlocklist(gHttpTestRoot + "blockNoPlugins.xml",
function() {
clearAllPluginPermissions();
resetBlocklist();
prepareTest(test25, gTestRoot + "plugin_syncRemoved.html");
});
waitForCondition(() => objLoadingContent.activated, () => {
// this resets the vulnerable plugin permission
setAndUpdateBlocklist(gHttpTestRoot + "blockNoPlugins.xml", () => {
clearAllPluginPermissions();
resetBlocklist();
prepareTest(test25, gTestRoot + "plugin_syncRemoved.html");
});
}, "Test 24d, plugin should be activated");
}
function test25() {

View File

@ -108,3 +108,28 @@ function setAndUpdateBlocklist(aURL, aCallback) {
function resetBlocklist() {
Services.prefs.setCharPref("extensions.blocklist.url", _originalTestBlocklistURL);
}
function waitForNotificationPopup(notificationID, browser, callback) {
let notification;
waitForCondition(
() => (notification = PopupNotifications.getNotification(notificationID, browser)),
() => {
ok(notification, `Successfully got the ${notificationID} notification popup`);
callback(notification);
},
`Waited too long for the ${notificationID} notification popup`
);
}
function waitForNotificationBar(notificationID, browser, callback) {
let notification;
let notificationBox = gBrowser.getNotificationBox(browser);
waitForCondition(
() => (notification = notificationBox.getNotificationWithValue(notificationID)),
() => {
ok(notification, `Successfully got the ${notificationID} notification bar`);
callback(notification);
},
`Waited too long for the ${notificationID} notification bar`
);
}

View File

@ -174,11 +174,23 @@
</method>
<field name="_formattingEnabled">true</field>
<field name="_searchServiceInitialized">false</field>
<method name="formatValue">
<body><![CDATA[
if (!this._formattingEnabled || this.focused)
return;
// Initialize the search service asynchronously if that hasn't
// happened yet. We will need it to highlight search terms later.
if (!this._searchServiceInitialized) {
Services.search.init(() => {
this._searchServiceInitialized = true;
this.formatValue();
});
return;
}
let controller = this.editor.selectionController;
let selection = controller.getSelection(controller.SELECTION_URLSECONDARY);
selection.removeAllRanges();
@ -213,20 +225,29 @@
subDomain = domain.slice(0, -baseDomain.length);
}
let rangeLength = preDomain.length + subDomain.length;
if (rangeLength) {
function addSelectionRange(start, end) {
let range = document.createRange();
range.setStart(textNode, 0);
range.setEnd(textNode, rangeLength);
range.setStart(textNode, start);
range.setEnd(textNode, end);
selection.addRange(range);
}
let rangeLength = preDomain.length + subDomain.length;
if (rangeLength) {
addSelectionRange(0, rangeLength);
}
let result = Services.search.parseSubmissionURL(value);
let startRest = preDomain.length + domain.length;
// Format search terms in the URL, if any.
if (result.termsOffset > -1 && result.termsLength) {
addSelectionRange(startRest, result.termsOffset);
startRest = result.termsOffset + result.termsLength;
}
if (startRest < value.length) {
let range = document.createRange();
range.setStart(textNode, startRest);
range.setEnd(textNode, value.length);
selection.addRange(range);
addSelectionRange(startRest, value.length);
}
]]></body>
</method>
@ -606,6 +627,7 @@
this.timeout = this._prefs.getIntPref(aData);
break;
case "formatting.enabled":
this._clearFormatting();
this._formattingEnabled = this._prefs.getBoolPref(aData);
break;
case "trimURLs":
@ -1954,7 +1976,7 @@
return;
}
let host = gPluginHandler._getHostFromPrincipal(this.notification.browser.contentWindow.document.nodePrincipal);
let host = this.notification.options.host;
this._setupDescription("pluginActivateMultiple.message", null, host);
var showBox = document.getAnonymousElementByAttribute(this, "anonid", "plugin-notification-showbox");

View File

@ -1,16 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
const CC = Components.Constructor;
// We also need a valid nsIXulAppInfo service as Webapps.jsm is querying it
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
let require = devtools.require;

View File

@ -7,6 +7,9 @@
// Tests the BezierCanvas API in the CubicBezierWidget module
const Cu = Components.utils;
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
let require = devtools.require;
let {CubicBezier, BezierCanvas} = require("devtools/shared/widgets/CubicBezierWidget");
function run_test() {

View File

@ -7,6 +7,9 @@
// Tests the CubicBezier API in the CubicBezierWidget module
const Cu = Components.utils;
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
let require = devtools.require;
let {CubicBezier} = require("devtools/shared/widgets/CubicBezierWidget");
function run_test() {

View File

@ -3,6 +3,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const Cu = Components.utils;
let {Loader} = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
let loader = new Loader.Loader({

View File

@ -1,5 +1,5 @@
[DEFAULT]
head = head.js
head =
tail =
firefox-appdir = browser

View File

@ -1,15 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
const CC = Components.Constructor;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
Cu.import("resource://gre/modules/devtools/Loader.jsm");

View File

@ -3,6 +3,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const Cu = Components.utils;
Cu.import("resource://gre/modules/devtools/Loader.jsm");
const {parseDeclarations} = devtools.require("devtools/styleinspector/css-parsing-utils");
const TEST_DATA = [

View File

@ -3,6 +3,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const Cu = Components.utils;
Cu.import("resource://gre/modules/devtools/Loader.jsm");
const {parseSingleValue} = devtools.require("devtools/styleinspector/css-parsing-utils");
const TEST_DATA = [

View File

@ -1,5 +1,5 @@
[DEFAULT]
head = head.js
head =
tail =
firefox-appdir = browser

View File

@ -368,7 +368,7 @@ Experiments.Experiments = function (policy=new Experiments.Policy()) {
// crashes. For forensics purposes, keep the last few log
// messages in memory and upload them in case of crash.
this._forensicsLogs = [];
this._forensicsLogs.length = 10;
this._forensicsLogs.length = 20;
this._log = Object.create(log);
this._log.log = (level, string, params) => {
this._forensicsLogs.shift();

View File

@ -0,0 +1,992 @@
# -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"use strict";
let Cc = Components.classes;
let Ci = Components.interfaces;
let Cu = Components.utils;
this.EXPORTED_SYMBOLS = [ "PluginContent" ];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
XPCOMUtils.defineLazyGetter(this, "gNavigatorBundle", function() {
const url = "chrome://browser/locale/browser.properties";
return Services.strings.createBundle(url);
});
this.PluginContent = function (global) {
this.init(global);
}
PluginContent.prototype = {
init: function (global) {
this.global = global;
// Need to hold onto the content window or else it'll get destroyed
this.content = this.global.content;
// Cache of plugin actions for the current page.
this.pluginData = new Map();
// Note that the XBL binding is untrusted
global.addEventListener("PluginBindingAttached", this, true, true);
global.addEventListener("PluginCrashed", this, true);
global.addEventListener("PluginOutdated", this, true);
global.addEventListener("PluginInstantiated", this, true);
global.addEventListener("PluginRemoved", this, true);
global.addEventListener("unload", this);
global.addEventListener("pageshow", (event) => this.onPageShow(event), true);
global.addMessageListener("BrowserPlugins:ActivatePlugins", this);
global.addMessageListener("BrowserPlugins:NotificationRemoved", this);
global.addMessageListener("BrowserPlugins:NotificationShown", this);
global.addMessageListener("BrowserPlugins:ContextMenuCommand", this);
},
uninit: function() {
delete this.global;
delete this.content;
},
receiveMessage: function (msg) {
switch (msg.name) {
case "BrowserPlugins:ActivatePlugins":
this.activatePlugins(msg.data.pluginInfo, msg.data.newState);
break;
case "BrowserPlugins:NotificationRemoved":
this.clearPluginDataCache();
break;
case "BrowserPlugins:NotificationShown":
setTimeout(() => this.updateNotificationUI(), 0);
break;
case "BrowserPlugins:ContextMenuCommand":
switch (msg.data.command) {
case "play":
this._showClickToPlayNotification(msg.objects.plugin, true);
break;
case "hide":
this.hideClickToPlayOverlay(msg.objects.plugin);
break;
}
break;
}
},
onPageShow: function (event) {
// Ignore events that aren't from the main document.
if (this.global.content && event.target != this.global.content.document) {
return;
}
// The PluginClickToPlay events are not fired when navigating using the
// BF cache. |persisted| is true when the page is loaded from the
// BF cache, so this code reshows the notification if necessary.
if (event.persisted) {
this.reshowClickToPlayNotification();
}
},
getPluginUI: function (plugin, anonid) {
return plugin.ownerDocument.
getAnonymousElementByAttribute(plugin, "anonid", anonid);
},
_getPluginInfo: function (pluginElement) {
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
pluginElement.QueryInterface(Ci.nsIObjectLoadingContent);
let tagMimetype;
let pluginName = gNavigatorBundle.GetStringFromName("pluginInfo.unknownPlugin");
let pluginTag = null;
let permissionString = null;
let fallbackType = null;
let blocklistState = null;
tagMimetype = pluginElement.actualType;
if (tagMimetype == "") {
tagMimetype = pluginElement.type;
}
if (this.isKnownPlugin(pluginElement)) {
pluginTag = pluginHost.getPluginTagForType(pluginElement.actualType);
pluginName = this.makeNicePluginName(pluginTag.name);
permissionString = pluginHost.getPermissionStringForType(pluginElement.actualType);
fallbackType = pluginElement.defaultFallbackType;
blocklistState = pluginHost.getBlocklistStateForType(pluginElement.actualType);
// Make state-softblocked == state-notblocked for our purposes,
// they have the same UI. STATE_OUTDATED should not exist for plugin
// items, but let's alias it anyway, just in case.
if (blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED ||
blocklistState == Ci.nsIBlocklistService.STATE_OUTDATED) {
blocklistState = Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
}
}
return { mimetype: tagMimetype,
pluginName: pluginName,
pluginTag: pluginTag,
permissionString: permissionString,
fallbackType: fallbackType,
blocklistState: blocklistState,
};
},
// Map the plugin's name to a filtered version more suitable for user UI.
makeNicePluginName : function (aName) {
if (aName == "Shockwave Flash")
return "Adobe Flash";
// Clean up the plugin name by stripping off parenthetical clauses,
// trailing version numbers or "plugin".
// EG, "Foo Bar (Linux) Plugin 1.23_02" --> "Foo Bar"
// Do this by first stripping the numbers, etc. off the end, and then
// removing "Plugin" (and then trimming to get rid of any whitespace).
// (Otherwise, something like "Java(TM) Plug-in 1.7.0_07" gets mangled)
let newName = aName.replace(/\(.*?\)/g, "").
replace(/[\s\d\.\-\_\(\)]+$/, "").
replace(/\bplug-?in\b/i, "").trim();
return newName;
},
/**
* Update the visibility of the plugin overlay.
*/
setVisibility : function (plugin, overlay, shouldShow) {
overlay.classList.toggle("visible", shouldShow);
},
/**
* Check whether the plugin should be visible on the page. A plugin should
* not be visible if the overlay is too big, or if any other page content
* overlays it.
*
* This function will handle showing or hiding the overlay.
* @returns true if the plugin is invisible.
*/
shouldShowOverlay : function (plugin, overlay) {
// If the overlay size is 0, we haven't done layout yet. Presume that
// plugins are visible until we know otherwise.
if (overlay.scrollWidth == 0) {
return true;
}
// Is the <object>'s size too small to hold what we want to show?
let pluginRect = plugin.getBoundingClientRect();
// XXX bug 446693. The text-shadow on the submitted-report text at
// the bottom causes scrollHeight to be larger than it should be.
let overflows = (overlay.scrollWidth > Math.ceil(pluginRect.width)) ||
(overlay.scrollHeight - 5 > Math.ceil(pluginRect.height));
if (overflows) {
return false;
}
// Is the plugin covered up by other content so that it is not clickable?
// Floating point can confuse .elementFromPoint, so inset just a bit
let left = pluginRect.left + 2;
let right = pluginRect.right - 2;
let top = pluginRect.top + 2;
let bottom = pluginRect.bottom - 2;
let centerX = left + (right - left) / 2;
let centerY = top + (bottom - top) / 2;
let points = [[left, top],
[left, bottom],
[right, top],
[right, bottom],
[centerX, centerY]];
if (right <= 0 || top <= 0) {
return false;
}
let contentWindow = plugin.ownerDocument.defaultView;
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
for (let [x, y] of points) {
let el = cwu.elementFromPoint(x, y, true, true);
if (el !== plugin) {
return false;
}
}
return true;
},
addLinkClickCallback: function (linkNode, callbackName /*callbackArgs...*/) {
// XXX just doing (callback)(arg) was giving a same-origin error. bug?
let self = this;
let callbackArgs = Array.prototype.slice.call(arguments).slice(2);
linkNode.addEventListener("click",
function(evt) {
if (!evt.isTrusted)
return;
evt.preventDefault();
if (callbackArgs.length == 0)
callbackArgs = [ evt ];
(self[callbackName]).apply(self, callbackArgs);
},
true);
linkNode.addEventListener("keydown",
function(evt) {
if (!evt.isTrusted)
return;
if (evt.keyCode == evt.DOM_VK_RETURN) {
evt.preventDefault();
if (callbackArgs.length == 0)
callbackArgs = [ evt ];
evt.preventDefault();
(self[callbackName]).apply(self, callbackArgs);
}
},
true);
},
// Helper to get the binding handler type from a plugin object
_getBindingType : function(plugin) {
if (!(plugin instanceof Ci.nsIObjectLoadingContent))
return null;
switch (plugin.pluginFallbackType) {
case Ci.nsIObjectLoadingContent.PLUGIN_UNSUPPORTED:
return "PluginNotFound";
case Ci.nsIObjectLoadingContent.PLUGIN_DISABLED:
return "PluginDisabled";
case Ci.nsIObjectLoadingContent.PLUGIN_BLOCKLISTED:
return "PluginBlocklisted";
case Ci.nsIObjectLoadingContent.PLUGIN_OUTDATED:
return "PluginOutdated";
case Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY:
return "PluginClickToPlay";
case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE:
return "PluginVulnerableUpdatable";
case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE:
return "PluginVulnerableNoUpdate";
case Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW:
return "PluginPlayPreview";
default:
// Not all states map to a handler
return null;
}
},
handleEvent: function (event) {
let eventType = event.type;
if (eventType == "unload") {
this.uninit();
return;
}
if (eventType == "PluginRemoved") {
this.updateNotificationUI();
return;
}
if (eventType == "click") {
this.onOverlayClick(event);
return;
}
if (eventType == "PluginCrashed" &&
!(event.target instanceof Ci.nsIObjectLoadingContent)) {
// If the event target is not a plugin object (i.e., an <object> or
// <embed> element), this call is for a window-global plugin.
this.pluginInstanceCrashed(event.target, event);
return;
}
let plugin = event.target;
let doc = plugin.ownerDocument;
if (!(plugin instanceof Ci.nsIObjectLoadingContent))
return;
if (eventType == "PluginBindingAttached") {
// The plugin binding fires this event when it is created.
// As an untrusted event, ensure that this object actually has a binding
// and make sure we don't handle it twice
let overlay = this.getPluginUI(plugin, "main");
if (!overlay || overlay._bindingHandled) {
return;
}
overlay._bindingHandled = true;
// Lookup the handler for this binding
eventType = this._getBindingType(plugin);
if (!eventType) {
// Not all bindings have handlers
return;
}
}
let shouldShowNotification = false;
switch (eventType) {
case "PluginCrashed":
this.pluginInstanceCrashed(plugin, event);
break;
case "PluginNotFound": {
let installable = this.showInstallNotification(plugin, eventType);
let contentWindow = plugin.ownerDocument.defaultView;
// For non-object plugin tags, register a click handler to install the
// plugin. Object tags can, and often do, deal with that themselves,
// so don't stomp on the page developers toes.
if (installable && !(plugin instanceof contentWindow.HTMLObjectElement)) {
let installStatus = this.getPluginUI(plugin, "installStatus");
installStatus.setAttribute("installable", "true");
let iconStatus = this.getPluginUI(plugin, "icon");
iconStatus.setAttribute("installable", "true");
let installLink = this.getPluginUI(plugin, "installPluginLink");
this.addLinkClickCallback(installLink, "installSinglePlugin", plugin);
}
break;
}
case "PluginBlocklisted":
case "PluginOutdated":
shouldShowNotification = true;
break;
case "PluginVulnerableUpdatable":
let updateLink = this.getPluginUI(plugin, "checkForUpdatesLink");
this.addLinkClickCallback(updateLink, "forwardCallback", "openPluginUpdatePage");
/* FALLTHRU */
case "PluginVulnerableNoUpdate":
case "PluginClickToPlay":
this._handleClickToPlayEvent(plugin);
let overlay = this.getPluginUI(plugin, "main");
let pluginName = this._getPluginInfo(plugin).pluginName;
let messageString = gNavigatorBundle.formatStringFromName("PluginClickToActivate", [pluginName], 1);
let overlayText = this.getPluginUI(plugin, "clickToPlay");
overlayText.textContent = messageString;
if (eventType == "PluginVulnerableUpdatable" ||
eventType == "PluginVulnerableNoUpdate") {
let vulnerabilityString = gNavigatorBundle.GetStringFromName(eventType);
let vulnerabilityText = this.getPluginUI(plugin, "vulnerabilityStatus");
vulnerabilityText.textContent = vulnerabilityString;
}
shouldShowNotification = true;
break;
case "PluginPlayPreview":
this._handlePlayPreviewEvent(plugin);
break;
case "PluginDisabled":
let manageLink = this.getPluginUI(plugin, "managePluginsLink");
this.addLinkClickCallback(manageLink, "forwardCallback", "managePlugins");
shouldShowNotification = true;
break;
case "PluginInstantiated":
shouldShowNotification = true;
break;
}
// Show the in-content UI if it's not too big. The crashed plugin handler already did this.
if (eventType != "PluginCrashed") {
let overlay = this.getPluginUI(plugin, "main");
if (overlay != null) {
this.setVisibility(plugin, overlay,
this.shouldShowOverlay(plugin, overlay));
let resizeListener = (event) => {
this.setVisibility(plugin, overlay,
this.shouldShowOverlay(plugin, overlay));
this.updateNotificationUI();
};
plugin.addEventListener("overflow", resizeListener);
plugin.addEventListener("underflow", resizeListener);
}
}
let closeIcon = this.getPluginUI(plugin, "closeIcon");
if (closeIcon) {
closeIcon.addEventListener("click", event => {
if (event.button == 0 && event.isTrusted)
this.hideClickToPlayOverlay(plugin);
}, true);
}
if (shouldShowNotification) {
this._showClickToPlayNotification(plugin, false);
}
},
isKnownPlugin: function (objLoadingContent) {
return (objLoadingContent.getContentTypeForMIMEType(objLoadingContent.actualType) ==
Ci.nsIObjectLoadingContent.TYPE_PLUGIN);
},
canActivatePlugin: function (objLoadingContent) {
// if this isn't a known plugin, we can't activate it
// (this also guards pluginHost.getPermissionStringForType against
// unexpected input)
if (!this.isKnownPlugin(objLoadingContent))
return false;
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
let permissionString = pluginHost.getPermissionStringForType(objLoadingContent.actualType);
let principal = objLoadingContent.ownerDocument.defaultView.top.document.nodePrincipal;
let pluginPermission = Services.perms.testPermissionFromPrincipal(principal, permissionString);
let isFallbackTypeValid =
objLoadingContent.pluginFallbackType >= Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY &&
objLoadingContent.pluginFallbackType <= Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE;
if (objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW) {
// checking if play preview is subject to CTP rules
let playPreviewInfo = pluginHost.getPlayPreviewInfo(objLoadingContent.actualType);
isFallbackTypeValid = !playPreviewInfo.ignoreCTP;
}
return !objLoadingContent.activated &&
pluginPermission != Ci.nsIPermissionManager.DENY_ACTION &&
isFallbackTypeValid;
},
hideClickToPlayOverlay: function (plugin) {
let overlay = this.getPluginUI(plugin, "main");
if (overlay) {
overlay.classList.remove("visible");
}
},
stopPlayPreview: function (plugin, playPlugin) {
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
if (objLoadingContent.activated)
return;
if (playPlugin)
objLoadingContent.playPlugin();
else
objLoadingContent.cancelPlayPreview();
},
// Callback for user clicking on a missing (unsupported) plugin.
installSinglePlugin: function (plugin) {
this.global.sendAsyncMessage("PluginContent:InstallSinglePlugin", {
pluginInfo: this._getPluginInfo(plugin),
});
},
// Forward a link click callback to the chrome process.
forwardCallback: function (name) {
this.global.sendAsyncMessage("PluginContent:LinkClickCallback", { name: name });
},
#ifdef MOZ_CRASHREPORTER
submitReport: function submitReport(pluginDumpID, browserDumpID, plugin) {
let keyVals = {};
if (plugin) {
let userComment = this.getPluginUI(plugin, "submitComment").value.trim();
if (userComment)
keyVals.PluginUserComment = userComment;
if (this.getPluginUI(plugin, "submitURLOptIn").checked)
keyVals.PluginContentURL = plugin.ownerDocument.URL;
}
this.global.sendAsyncMessage("PluginContent:SubmitReport", {
pluginDumpID: pluginDumpID,
browserDumpID: browserDumpID,
keyVals: keyVals,
});
},
#endif
reloadPage: function () {
this.global.content.location.reload();
},
showInstallNotification: function (plugin) {
let [shown] = this.global.sendSyncMessage("PluginContent:ShowInstallNotification", {
pluginInfo: this._getPluginInfo(plugin),
});
return shown;
},
// Event listener for click-to-play plugins.
_handleClickToPlayEvent: function (plugin) {
let doc = plugin.ownerDocument;
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
// guard against giving pluginHost.getPermissionStringForType a type
// not associated with any known plugin
if (!this.isKnownPlugin(objLoadingContent))
return;
let permissionString = pluginHost.getPermissionStringForType(objLoadingContent.actualType);
let principal = doc.defaultView.top.document.nodePrincipal;
let pluginPermission = Services.perms.testPermissionFromPrincipal(principal, permissionString);
let overlay = this.getPluginUI(plugin, "main");
if (pluginPermission == Ci.nsIPermissionManager.DENY_ACTION) {
if (overlay) {
overlay.classList.remove("visible");
}
return;
}
if (overlay) {
overlay.addEventListener("click", this, true);
}
},
onOverlayClick: function (event) {
let document = event.target.ownerDocument;
let plugin = document.getBindingParent(event.target);
let contentWindow = plugin.ownerDocument.defaultView.top;
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
// Have to check that the target is not the link to update the plugin
if (!(event.originalTarget instanceof contentWindow.HTMLAnchorElement) &&
(event.originalTarget.getAttribute('anonid') != 'closeIcon') &&
event.button == 0 && event.isTrusted) {
this._showClickToPlayNotification(plugin, true);
event.stopPropagation();
event.preventDefault();
}
},
_handlePlayPreviewEvent: function (plugin) {
let doc = plugin.ownerDocument;
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
let pluginInfo = this._getPluginInfo(plugin);
let playPreviewInfo = pluginHost.getPlayPreviewInfo(pluginInfo.mimetype);
let previewContent = this.getPluginUI(plugin, "previewPluginContent");
let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
if (!iframe) {
// lazy initialization of the iframe
iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
iframe.className = "previewPluginContentFrame";
previewContent.appendChild(iframe);
// Force a style flush, so that we ensure our binding is attached.
plugin.clientTop;
}
iframe.src = playPreviewInfo.redirectURL;
// MozPlayPlugin event can be dispatched from the extension chrome
// code to replace the preview content with the native plugin
let playPluginHandler = (event) => {
if (!event.isTrusted)
return;
previewContent.removeEventListener("MozPlayPlugin", playPluginHandler, true);
let playPlugin = !event.detail;
this.stopPlayPreview(plugin, playPlugin);
// cleaning up: removes overlay iframe from the DOM
let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
if (iframe)
previewContent.removeChild(iframe);
};
previewContent.addEventListener("MozPlayPlugin", playPluginHandler, true);
if (!playPreviewInfo.ignoreCTP) {
this._showClickToPlayNotification(plugin, false);
}
},
reshowClickToPlayNotification: function () {
let contentWindow = this.global.content;
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let plugins = cwu.plugins;
for (let plugin of plugins) {
let overlay = this.getPluginUI(plugin, "main");
if (overlay)
overlay.removeEventListener("click", this, true);
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
if (this.canActivatePlugin(objLoadingContent))
this._handleClickToPlayEvent(plugin);
}
this._showClickToPlayNotification(null, false);
},
// Match the behaviour of nsPermissionManager
_getHostFromPrincipal: function (principal) {
if (!principal.URI || principal.URI.schemeIs("moz-nullprincipal")) {
return "(null)";
}
try {
if (principal.URI.host)
return principal.URI.host;
} catch (e) {}
return principal.origin;
},
/**
* Activate the plugins that the user has specified.
*/
activatePlugins: function (pluginInfo, newState) {
let contentWindow = this.global.content;
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let plugins = cwu.plugins;
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
let pluginFound = false;
for (let plugin of plugins) {
plugin.QueryInterface(Ci.nsIObjectLoadingContent);
if (!this.isKnownPlugin(plugin)) {
continue;
}
if (pluginInfo.permissionString == pluginHost.getPermissionStringForType(plugin.actualType)) {
pluginFound = true;
if (newState == "block") {
plugin.reload(true);
} else {
if (this.canActivatePlugin(plugin)) {
let overlay = this.getPluginUI(plugin, "main");
if (overlay) {
overlay.removeEventListener("click", this, true);
}
plugin.playPlugin();
}
}
}
}
// If there are no instances of the plugin on the page any more, what the
// user probably needs is for us to allow and then refresh.
if (newState != "block" && !pluginFound) {
this.reloadPage();
}
this.updateNotificationUI();
},
_showClickToPlayNotification: function (plugin, showNow) {
let plugins = [];
// If plugin is null, that means the user has navigated back to a page with
// plugins, and we need to collect all the plugins.
if (plugin === null) {
let contentWindow = this.global.content;
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
// cwu.plugins may contain non-plugin <object>s, filter them out
plugins = cwu.plugins.filter((plugin) =>
plugin.getContentTypeForMIMEType(plugin.actualType) == Ci.nsIObjectLoadingContent.TYPE_PLUGIN);
if (plugins.length == 0) {
this.removeNotification("click-to-play-plugins");
return;
}
} else {
plugins = [plugin];
}
let pluginData = this.pluginData;
let principal = this.global.content.document.nodePrincipal;
let principalHost = this._getHostFromPrincipal(principal);
for (let p of plugins) {
let pluginInfo = this._getPluginInfo(p);
if (pluginInfo.permissionString === null) {
Cu.reportError("No permission string for active plugin.");
continue;
}
if (pluginData.has(pluginInfo.permissionString)) {
continue;
}
let permissionObj = Services.perms.
getPermissionObject(principal, pluginInfo.permissionString, false);
if (permissionObj) {
pluginInfo.pluginPermissionHost = permissionObj.host;
pluginInfo.pluginPermissionType = permissionObj.expireType;
}
else {
pluginInfo.pluginPermissionHost = principalHost;
pluginInfo.pluginPermissionType = undefined;
}
this.pluginData.set(pluginInfo.permissionString, pluginInfo);
}
this.global.sendAsyncMessage("PluginContent:ShowClickToPlayNotification", {
plugins: [... this.pluginData.values()],
showNow: showNow,
host: principalHost,
}, null, principal);
},
updateNotificationUI: function () {
// Make a copy of the actions from the last popup notification.
let haveInsecure = false;
let actions = new Map();
for (let action of this.pluginData.values()) {
switch (action.fallbackType) {
// haveInsecure will trigger the red flashing icon and the infobar
// styling below
case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE:
case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE:
haveInsecure = true;
// fall through
case Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY:
actions.set(action.permissionString, action);
continue;
}
}
// Remove plugins that are already active, or large enough to show an overlay.
let contentWindow = this.global.content;
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
for (let plugin of cwu.plugins) {
let info = this._getPluginInfo(plugin);
if (!actions.has(info.permissionString)) {
continue;
}
let fallbackType = info.fallbackType;
if (fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) {
actions.delete(info.permissionString);
if (actions.size == 0) {
break;
}
continue;
}
if (fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY &&
fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE &&
fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE) {
continue;
}
let overlay = this.getPluginUI(plugin, "main");
if (!overlay) {
continue;
}
let shouldShow = this.shouldShowOverlay(plugin, overlay);
this.setVisibility(plugin, overlay, shouldShow);
if (shouldShow) {
actions.delete(info.permissionString);
if (actions.size == 0) {
break;
}
}
}
// If there are any items remaining in `actions` now, they are hidden
// plugins that need a notification bar.
let principal = contentWindow.document.nodePrincipal;
this.global.sendAsyncMessage("PluginContent:UpdateHiddenPluginUI", {
haveInsecure: haveInsecure,
actions: [... actions.values()],
host: this._getHostFromPrincipal(principal),
}, null, principal);
},
removeNotification: function (name) {
this.global.sendAsyncMessage("PluginContent:RemoveNotification", { name: name });
},
clearPluginDataCache: function () {
this.pluginData.clear();
},
hideNotificationBar: function (name) {
this.global.sendAsyncMessage("PluginContent:HideNotificationBar", { name: name });
},
// Crashed-plugin event listener. Called for every instance of a
// plugin in content.
pluginInstanceCrashed: function (target, aEvent) {
// Ensure the plugin and event are of the right type.
if (!(aEvent instanceof Ci.nsIDOMCustomEvent))
return;
let propBag = aEvent.detail.QueryInterface(Ci.nsIPropertyBag2);
let submittedReport = propBag.getPropertyAsBool("submittedCrashReport");
let doPrompt = true; // XXX followup for .getPropertyAsBool("doPrompt");
let submitReports = true; // XXX followup for .getPropertyAsBool("submitReports");
let pluginName = propBag.getPropertyAsAString("pluginName");
let pluginDumpID = propBag.getPropertyAsAString("pluginDumpID");
let browserDumpID = null;
let gmpPlugin = false;
try {
browserDumpID = propBag.getPropertyAsAString("browserDumpID");
} catch (e) {
// For GMP crashes we don't get a browser dump.
}
try {
gmpPlugin = propBag.getPropertyAsBool("gmpPlugin");
} catch (e) {
// This property is only set for GMP plugins.
}
// For non-GMP plugins, remap the plugin name to a more user-presentable form.
if (!gmpPlugin) {
pluginName = this.makeNicePluginName(pluginName);
}
let messageString = gNavigatorBundle.formatStringFromName("crashedpluginsMessage.title", [pluginName], 1);
let plugin = null, doc;
if (target instanceof Ci.nsIObjectLoadingContent) {
plugin = target;
doc = plugin.ownerDocument;
} else {
doc = target.document;
if (!doc) {
return;
}
// doPrompt is specific to the crashed plugin overlay, and
// therefore is not applicable for window-global plugins.
doPrompt = false;
}
let status;
#ifdef MOZ_CRASHREPORTER
// Determine which message to show regarding crash reports.
if (submittedReport) { // submitReports && !doPrompt, handled in observer
status = "submitted";
}
else if (!submitReports && !doPrompt) {
status = "noSubmit";
}
else if (!pluginDumpID) {
// If we don't have a minidumpID, we can't (or didn't) submit anything.
// This can happen if the plugin is killed from the task manager.
status = "noReport";
}
else {
status = "please";
}
// If we don't have a minidumpID, we can't (or didn't) submit anything.
// This can happen if the plugin is killed from the task manager.
if (!pluginDumpID) {
status = "noReport";
}
// If we're showing the link to manually trigger report submission, we'll
// want to be able to update all the instances of the UI for this crash to
// show an updated message when a report is submitted.
if (doPrompt) {
let observer = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
observe : (subject, topic, data) => {
let propertyBag = subject;
if (!(propertyBag instanceof Ci.nsIPropertyBag2))
return;
// Ignore notifications for other crashes.
if (propertyBag.get("minidumpID") != pluginDumpID)
return;
let statusDiv = this.getPluginUI(plugin, "submitStatus");
statusDiv.setAttribute("status", data);
},
handleEvent : function(event) {
// Not expected to be called, just here for the closure.
}
}
// Use a weak reference, so we don't have to remove it...
Services.obs.addObserver(observer, "crash-report-status", true);
// ...alas, now we need something to hold a strong reference to prevent
// it from being GC. But I don't want to manually manage the reference's
// lifetime (which should be no greater than the page).
// Clever solution? Use a closue with an event listener on the document.
// When the doc goes away, so do the listener references and the closure.
doc.addEventListener("mozCleverClosureHack", observer, false);
}
#endif
let isShowing = false;
if (plugin) {
// If there's no plugin (an <object> or <embed> element), this call is
// for a window-global plugin. In this case, there's no overlay to show.
isShowing = _setUpPluginOverlay.call(this, plugin, doPrompt);
}
if (isShowing) {
// If a previous plugin on the page was too small and resulted in adding a
// notification bar, then remove it because this plugin instance it big
// enough to serve as in-content notification.
this.hideNotificationBar("plugin-crashed");
doc.mozNoPluginCrashedNotification = true;
} else {
// If another plugin on the page was large enough to show our UI, we don't
// want to show a notification bar.
if (!doc.mozNoPluginCrashedNotification) {
this.global.sendAsyncMessage("PluginContent:ShowPluginCrashedNotification", {
messageString: messageString,
pluginDumpID: pluginDumpID,
browserDumpID: browserDumpID,
});
// Remove the notification when the page is reloaded.
doc.defaultView.top.addEventListener("unload", event => {
this.hideNotificationBar("plugin-crashed");
}, false);
}
}
// Configure the crashed-plugin placeholder.
// Returns true if the plugin overlay is visible.
function _setUpPluginOverlay(plugin, doPromptSubmit) {
if (!plugin) {
return false;
}
// Force a layout flush so the binding is attached.
plugin.clientTop;
let overlay = this.getPluginUI(plugin, "main");
let statusDiv = this.getPluginUI(plugin, "submitStatus");
if (doPromptSubmit) {
this.getPluginUI(plugin, "submitButton").addEventListener("click",
function (event) {
if (event.button != 0 || !event.isTrusted)
return;
this.submitReport(pluginDumpID, browserDumpID, plugin);
pref.setBoolPref("", optInCB.checked);
}.bind(this));
let optInCB = this.getPluginUI(plugin, "submitURLOptIn");
let pref = Services.prefs.getBranch("dom.ipc.plugins.reportCrashURL");
optInCB.checked = pref.getBoolPref("");
}
statusDiv.setAttribute("status", status);
let helpIcon = this.getPluginUI(plugin, "helpIcon");
this.addLinkClickCallback(helpIcon, "openHelpPage");
let crashText = this.getPluginUI(plugin, "crashedText");
crashText.textContent = messageString;
let link = this.getPluginUI(plugin, "reloadLink");
this.addLinkClickCallback(link, "reloadPage");
let isShowing = this.shouldShowOverlay(plugin, overlay);
// Is the <object>'s size too small to hold what we want to show?
if (!isShowing) {
// First try hiding the crash report submission UI.
statusDiv.removeAttribute("status");
isShowing = this.shouldShowOverlay(plugin, overlay);
}
this.setVisibility(plugin, overlay, isShowing);
return isShowing;
}
}
};

View File

@ -44,6 +44,7 @@ if CONFIG['NIGHTLY_BUILD']:
EXTRA_PP_JS_MODULES += [
'AboutHome.jsm',
'PluginContent.jsm',
'RecentWindow.jsm',
'UITour.jsm',
'webrtcUI.jsm',

View File

@ -57,6 +57,9 @@ function SettingsLock(aSettingsManager) {
"Settings:Finalize:OK", "Settings:Finalize:KO"]);
this.sendMessage("Settings:CreateLock", {lockID: this._id, isServiceLock: false});
Services.tm.currentThread.dispatch(this._closeHelper.bind(this), Ci.nsIThread.DISPATCH_NORMAL);
// We only want to file closeHelper once per set of receiveMessage calls.
this._closeCalled = true;
}
SettingsLock.prototype = {
@ -84,8 +87,9 @@ SettingsLock.prototype = {
_closeHelper: function() {
if (DEBUG) debug("closing lock " + this._id);
this._open = false;
this._closeCalled = false;
if (!this._requests || Object.keys(this._requests).length == 0) {
if (DEBUG) debug("Requests exhausted, finalizing");
if (DEBUG) debug("Requests exhausted, finalizing " + this._id);
this._settingsManager.unregisterLock(this._id);
this.sendMessage("Settings:Finalize", {lockID: this._id});
} else {
@ -150,7 +154,11 @@ SettingsLock.prototype = {
// things like marionetteScriptFinished in them. Make sure we file
// our call to run/finalize BEFORE opening the lock and fulfilling
// DOMRequests.
Services.tm.currentThread.dispatch(this._closeHelper.bind(this), Ci.nsIThread.DISPATCH_NORMAL);
if (!this._closeCalled) {
// We only want to file closeHelper once per set of receiveMessage calls.
Services.tm.currentThread.dispatch(this._closeHelper.bind(this), Ci.nsIThread.DISPATCH_NORMAL);
this._closeCalled = true;
}
if (DEBUG) debug("receiveMessage: " + aMessage.name);
switch (aMessage.name) {
case "Settings:Get:OK":

View File

@ -574,14 +574,14 @@ let SettingsRequestManager = {
if (DEBUG) debug("Lock no longer alive, cannot run tasks");
return;
}
if (lock.finalizing) {
debug("TASK TRYING TO QUEUE AFTER FINALIZE CALLED. THIS IS BAD. Lock: " + aLockID);
return;
}
let currentTask = lock.tasks.shift();
let promises = [];
while (currentTask) {
if (DEBUG) debug("Running Operation " + currentTask.operation);
if (lock.finalizing) {
Cu.reportError("Settings lock trying to run more tasks after finalizing. Ignoring tasks, but this is bad. Lock: " + aLockID);
continue;
}
let p;
switch (currentTask.operation) {
case "get":

View File

@ -138,8 +138,6 @@ var steps = [
ok(true, "All requests on a failed lock should fail");
var lock = mozSettings.createLock();
lock.onsettingstransactionfailure = function (evt) {
// Stop listening at this point
lock.onsettingstransactionfailure = null;
ok(evt.error == "Lock failed a permissions check, all requests now failing.", "transaction failure on permissions error message correct.");
ok(true, "transaction failed (expected) ");
next();

View File

@ -3091,7 +3091,8 @@ RilObject.prototype = {
// ("Yes/No") command with command qualifier set to "Yes/No", it shall
// supply the value '01' when the answer is "positive" and the value
// '00' when the answer is "negative" in the Text string data object.
text = response.isYesNo ? 0x01 : 0x00;
text = response.isYesNo ? String.fromCharCode(0x01)
: String.fromCharCode(0x00);
} else {
text = response.input;
}

View File

@ -156,6 +156,81 @@ add_test(function test_stk_terminal_response() {
context.RIL.sendStkTerminalResponse(response);
});
/**
* Verify STK terminal response : GET_INKEY - YES/NO request
*/
add_test(function test_stk_terminal_response_get_inkey() {
function do_test(isYesNo) {
let worker = newUint8SupportOutgoingIndexWorker();
let context = worker.ContextPool._contexts[0];
let buf = context.Buf;
let pduHelper = context.GsmPDUHelper;
buf.sendParcel = function() {
// Type
do_check_eq(this.readInt32(), REQUEST_STK_SEND_TERMINAL_RESPONSE);
// Token : we don't care
this.readInt32();
// Data Size, 32 = 2 * (TLV_COMMAND_DETAILS_SIZE(5) +
// TLV_DEVICE_ID_SIZE(4) +
// TLV_RESULT_SIZE(3) +
// TEXT LENGTH(4))
do_check_eq(this.readInt32(), 32);
// Command Details, Type-Length-Value
do_check_eq(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_COMMAND_DETAILS |
COMPREHENSIONTLV_FLAG_CR);
do_check_eq(pduHelper.readHexOctet(), 3);
do_check_eq(pduHelper.readHexOctet(), 0x01);
do_check_eq(pduHelper.readHexOctet(), STK_CMD_GET_INKEY);
do_check_eq(pduHelper.readHexOctet(), 0x04);
// Device Identifies, Type-Length-Value(Source ID-Destination ID)
do_check_eq(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID);
do_check_eq(pduHelper.readHexOctet(), 2);
do_check_eq(pduHelper.readHexOctet(), STK_DEVICE_ID_ME);
do_check_eq(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM);
// Result
do_check_eq(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_RESULT |
COMPREHENSIONTLV_FLAG_CR);
do_check_eq(pduHelper.readHexOctet(), 1);
do_check_eq(pduHelper.readHexOctet(), STK_RESULT_OK);
// Yes/No response
do_check_eq(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_TEXT_STRING |
COMPREHENSIONTLV_FLAG_CR);
do_check_eq(pduHelper.readHexOctet(), 2);
do_check_eq(pduHelper.readHexOctet(), STK_TEXT_CODING_GSM_8BIT);
do_check_eq(pduHelper.readHexOctet(), isYesNo ? 0x01 : 0x00);
run_next_test();
};
let response = {
command: {
commandNumber: 0x01,
typeOfCommand: STK_CMD_GET_INKEY,
commandQualifier: 0x04,
options: {
isYesNoRequested: true
}
},
isYesNo: isYesNo,
resultCode: STK_RESULT_OK
};
context.RIL.sendStkTerminalResponse(response);
};
// Test "Yes" response
do_test(true);
// Test "No" response
do_test(false);
});
// Test ComprehensionTlvHelper
/**

View File

@ -25,6 +25,7 @@ import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.LocaleManager;
import org.mozilla.gecko.NewTabletUI;
import org.mozilla.gecko.PrefsHelper;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Telemetry;
@ -114,6 +115,7 @@ OnSharedPreferenceChangeListener
private static final String PREFS_HEALTHREPORT_LINK = NON_PREF_PREFIX + "healthreport.link";
private static final String PREFS_DEVTOOLS_REMOTE_ENABLED = "devtools.debugger.remote-enabled";
private static final String PREFS_DISPLAY_REFLOW_ON_ZOOM = "browser.zoom.reflowOnZoom";
private static final String PREFS_DISPLAY_TITLEBAR_MODE = "browser.chrome.titlebarMode";
private static final String PREFS_SYNC = NON_PREF_PREFIX + "sync";
private static final String PREFS_STUMBLER_ENABLED = AppConstants.ANDROID_PACKAGE_NAME + ".STUMBLER_PREF";
@ -724,6 +726,12 @@ OnSharedPreferenceChangeListener
return true;
}
});
} else if (PREFS_DISPLAY_TITLEBAR_MODE.equals(key) &&
NewTabletUI.isEnabled(this)) {
// New tablet always shows URLS, not titles.
preferences.removePreference(pref);
i--;
continue;
} else if (handlers.containsKey(key)) {
PrefHandler handler = handlers.get(key);
handler.setupPref(this, pref);

View File

@ -72,9 +72,7 @@
</style>
<style name="Widget.Home.HistoryListView">
<item name="android:paddingLeft">50dp</item>
<item name="android:paddingRight">100dp</item>
<item name="android:paddingTop">0dp</item>
<item name="topDivider">true</item>
<item name="android:scrollbarStyle">outsideOverlay</item>
</style>

View File

@ -24,11 +24,7 @@
</style>
<style name="Widget.BookmarksListView" parent="Widget.HomeListView">
<item name="android:paddingTop">30dp</item>
<item name="android:paddingLeft">120dp</item>
<item name="android:paddingRight">120dp</item>
<item name="android:scrollbarStyle">outsideOverlay</item>
<item name="topDivider">true</item>
</style>
<style name="Widget.TopSitesGridView" parent="Widget.GridView">

View File

@ -62,11 +62,7 @@
</style>
<style name="Widget.BookmarksListView" parent="Widget.HomeListView">
<item name="android:paddingTop">30dp</item>
<item name="android:paddingLeft">32dp</item>
<item name="android:paddingRight">32dp</item>
<item name="android:scrollbarStyle">outsideOverlay</item>
<item name="topDivider">true</item>
</style>
<style name="Widget.TopSitesGridView" parent="Widget.GridView">
@ -78,6 +74,9 @@
</style>
<style name="Widget.TopSitesListView" parent="Widget.BookmarksListView">
<item name="android:paddingTop">30dp</item>
<item name="android:paddingLeft">32dp</item>
<item name="android:paddingRight">32dp</item>
<item name="topDivider">false</item>
</style>

View File

@ -4,6 +4,12 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<resources>
<style name="Widget.TopSitesListView" parent="Widget.BookmarksListView">
<item name="android:paddingTop">30dp</item>
<item name="android:paddingLeft">120dp</item>
<item name="android:paddingRight">120dp</item>
<item name="topDivider">false</item>
</style>
<style name="Widget.TopSitesGridView" parent="Widget.GridView">
<item name="android:paddingLeft">55dp</item>
@ -14,9 +20,6 @@
</style>
<style name="Widget.Home.HistoryListView">
<item name="android:paddingLeft">50dp</item>
<item name="android:paddingRight">100dp</item>
<item name="android:paddingTop">30dp</item>
<item name="android:scrollbarStyle">outsideOverlay</item>
<item name="topDivider">true</item>
</style>

View File

@ -17,9 +17,6 @@
</style>
<style name="Widget.Home.HistoryListView">
<item name="android:paddingLeft">32dp</item>
<item name="android:paddingRight">32dp</item>
<item name="android:paddingTop">30dp</item>
<item name="android:scrollbarStyle">outsideOverlay</item>
<item name="topDivider">true</item>
</style>
@ -30,4 +27,11 @@
<item name="android:paddingRight">212dp</item>
</style>
<style name="Widget.TopSitesListView" parent="Widget.BookmarksListView">
<item name="android:paddingTop">30dp</item>
<item name="android:paddingLeft">32dp</item>
<item name="android:paddingRight">32dp</item>
<item name="topDivider">false</item>
</style>
</resources>

View File

@ -63,8 +63,10 @@
</style>
<style name="Widget.Home.HistoryListView">
<item name="android:paddingLeft">32dp</item>
<item name="android:paddingRight">32dp</item>
<item name="android:paddingTop">0dip</item>
<item name="android:paddingRight">0dip</item>
<item name="android:paddingLeft">0dip</item>
<item name="topDivider">true</item>
<item name="android:scrollbarStyle">outsideOverlay</item>
</style>

View File

@ -9,6 +9,8 @@ import java.util.Map.Entry;
import org.mozilla.gecko.Actions;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.NewTabletUI;
import org.mozilla.gecko.util.HardwareUtils;
/** This patch tests the Sections present in the Settings Menu and the
* default values for them
@ -46,10 +48,12 @@ public class testSettingsMenuItems extends PixelTest {
// Display menu items.
String[] PATH_DISPLAY = { StringHelper.DISPLAY_SECTION_LABEL };
final String[] TITLE_BAR_LABEL_ARR = { StringHelper.TITLE_BAR_LABEL, "Show page title",
"Show page title", "Show page address" };
String[][] OPTIONS_DISPLAY = {
{ StringHelper.TEXT_SIZE_LABEL },
{ StringHelper.TITLE_BAR_LABEL, "Show page title", "Show page title", "Show page address" },
{ StringHelper.SCROLL_TITLE_BAR_LABEL, "Hide the " + BRAND_NAME + " title bar when scrolling down a page" },
TITLE_BAR_LABEL_ARR,
{ StringHelper.SCROLL_TITLE_BAR_LABEL, "Hide the " + BRAND_NAME + " title bar when scrolling down a page" },
{ "Advanced" },
{ StringHelper.CHARACTER_ENCODING_LABEL, "Don't show menu", "Show menu", "Don't show menu" },
{ StringHelper.PLUGINS_LABEL, "Tap to play", "Enabled", "Tap to play", "Disabled" },
@ -112,20 +116,20 @@ public class testSettingsMenuItems extends PixelTest {
setupSettingsMap(settingsMenuItems);
// Set special handling for Settings items that are conditionally built.
addConditionalSettings(settingsMenuItems);
updateConditionalSettings(settingsMenuItems);
selectMenuItem("Settings");
waitForText("Settings");
mAsserter.ok(mSolo.waitForText("Settings"), "The Settings menu did not load", "");
// Dismiss the Settings screen and verify that the view is returned to about:home page
mActions.sendSpecialKey(Actions.SpecialKey.BACK);
// Waiting for page title to appear to be sure that is fully loaded before opening the menu
waitForText("Enter Search");
mAsserter.ok(mSolo.waitForText("Search or enter address"), "about:home did not load", "");
verifyUrl("about:home");
selectMenuItem("Settings");
waitForText("Settings");
mAsserter.ok(mSolo.waitForText("Settings"), "The Settings menu did not load", "");
checkForSync(mDevice);
@ -135,16 +139,10 @@ public class testSettingsMenuItems extends PixelTest {
/**
* Check for Sync in settings.
*
* Sync location is a top level menu item on phones, but is under "Customize" on tablets.
*
* Sync location is a top level menu item on phones and small tablets,
* but is under "Customize" on large tablets.
*/
public void checkForSync(Device device) {
if (device.type.equals("tablet")) {
// Select "Customize" from settings.
String customizeString = "^Customize$";
waitForEnabledText(customizeString);
mSolo.clickOnText(customizeString);
}
mAsserter.ok(mSolo.waitForText("Sync"), "Waiting for Sync option", "The Sync option is present");
}
@ -152,7 +150,7 @@ public class testSettingsMenuItems extends PixelTest {
* Check for conditions for building certain settings, and add them to be tested
* if they are present.
*/
public void addConditionalSettings(Map<String[], List<String[]>> settingsMap) {
public void updateConditionalSettings(Map<String[], List<String[]>> settingsMap) {
// Preferences dependent on RELEASE_BUILD
if (!AppConstants.RELEASE_BUILD) {
// Text reflow - only built if *not* release build
@ -163,6 +161,11 @@ public class testSettingsMenuItems extends PixelTest {
String[] newTabletUi = { StringHelper.NEW_TABLET_UI };
settingsMap.get(PATH_DISPLAY).add(newTabletUi);
// New tablet UI: we don't allow a page title option.
if (NewTabletUI.isEnabled(getActivity())) {
settingsMap.get(PATH_DISPLAY).remove(TITLE_BAR_LABEL_ARR);
}
// Anonymous cell tower/wifi collection - only built if *not* release build
String[] networkReportingUi = { "Mozilla Location Service", "Receives Wi-Fi and cellular location data when running in the background and shares it with Mozilla to improve our geolocation service" };
settingsMap.get(PATH_MOZILLA).add(networkReportingUi);

View File

@ -323,7 +323,7 @@ public class ToolbarDisplayLayout extends ThemedLinearLayout
}
// If the pref to show the URL isn't set, just use the tab's display title.
if (!mPrefs.shouldShowUrl() || url == null) {
if (!mPrefs.shouldShowUrl(mActivity) || url == null) {
setTitle(tab.getDisplayTitle());
return;
}

View File

@ -5,11 +5,14 @@
package org.mozilla.gecko.toolbar;
import org.mozilla.gecko.NewTabletUI;
import org.mozilla.gecko.PrefsHelper;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.util.ThreadUtils;
import android.content.Context;
class ToolbarPrefs {
private static final String PREF_AUTOCOMPLETE_ENABLED = "browser.urlbar.autocomplete.enabled";
private static final String PREF_TITLEBAR_MODE = "browser.chrome.titlebarMode";
@ -40,8 +43,8 @@ class ToolbarPrefs {
return enableAutocomplete;
}
boolean shouldShowUrl() {
return showUrl;
boolean shouldShowUrl(final Context context) {
return showUrl || NewTabletUI.isEnabled(context);
}
boolean shouldTrimUrls() {

View File

@ -1092,4 +1092,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
static const int32_t kUnknownId = -1;
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1418960624394000);
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1419283679619000);

View File

@ -34,6 +34,7 @@ crbug.com: did not receive HSTS header
crowdcurity.com: did not receive HSTS header
crypto.is: did not receive HSTS header
csawctf.poly.edu: did not receive HSTS header
dillonkorman.com: did not receive HSTS header
discovery.lookout.com: did not receive HSTS header
dl.google.com: did not receive HSTS header (error ignored - included regardless)
docs.google.com: did not receive HSTS header (error ignored - included regardless)
@ -67,12 +68,11 @@ hoerbuecher-und-hoerspiele.de: did not receive HSTS header
honeytracks.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 124" data: no]
hostedtalkgadget.google.com: did not receive HSTS header (error ignored - included regardless)
howrandom.org: could not connect to host
ihrlotto.de: could not connect to host
in.xero.com: max-age too low: 3600
intercom.io: did not receive HSTS header
iop.intuit.com: max-age too low: 86400
irccloud.com: did not receive HSTS header
jitsi.org: did not receive HSTS header
jonaswitmer.ch: could not connect to host
jottit.com: could not connect to host
keymaster.lookout.com: did not receive HSTS header
kiwiirc.com: max-age too low: 5256000
@ -112,12 +112,12 @@ prodpad.com: did not receive HSTS header
profiles.google.com: did not receive HSTS header (error ignored - included regardless)
promecon-gmbh.de: did not receive HSTS header
rapidresearch.me: could not connect to host
rippleunion.com: did not receive HSTS header
riseup.net: did not receive HSTS header
sah3.net: could not connect to host
saturngames.co.uk: did not receive HSTS header
script.google.com: did not receive HSTS header (error ignored - included regardless)
security.google.com: did not receive HSTS header (error ignored - included regardless)
securityheaders.com: did not receive HSTS header
semenkovich.com: did not receive HSTS header
serverdensity.io: did not receive HSTS header
shops.neonisi.com: could not connect to host
@ -134,6 +134,7 @@ square.com: did not receive HSTS header
ssl.google-analytics.com: did not receive HSTS header (error ignored - included regardless)
ssl.panoramio.com: did not receive HSTS header
stocktrade.de: could not connect to host
strongest-privacy.com: could not connect to host
sunshinepress.org: could not connect to host
surfeasy.com: did not receive HSTS header
talk.google.com: did not receive HSTS header (error ignored - included regardless)
@ -143,8 +144,7 @@ translate.googleapis.com: did not receive HSTS header (error ignored - included
uprotect.it: could not connect to host
wallet.google.com: did not receive HSTS header (error ignored - included regardless)
webmail.mayfirst.org: did not receive HSTS header
wf-training-master.appspot.com: could not connect to host
wf-training-master.appspot.com: could not connect to host (error ignored - included regardless)
wf-training-master.appspot.com: did not receive HSTS header (error ignored - included regardless)
whonix.org: did not receive HSTS header
www.calyxinstitute.org: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 124" data: no]
www.cueup.com: could not connect to host

View File

@ -8,7 +8,7 @@
/*****************************************************************************/
#include <stdint.h>
const PRTime gPreloadListExpirationTime = INT64_C(1421379819168000);
const PRTime gPreloadListExpirationTime = INT64_C(1421702876088000);
class nsSTSPreload
{
@ -122,7 +122,6 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "detectify.com", false },
{ "developer.mydigipass.com", false },
{ "die-besten-weisheiten.de", true },
{ "dillonkorman.com", true },
{ "dist.torproject.org", false },
{ "dl.google.com", true },
{ "dm.lookout.com", false },
@ -216,6 +215,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "jelmer.co.uk", true },
{ "jelmer.uk", true },
{ "jfreitag.de", true },
{ "jitsi.org", false },
{ "jonas-keidel.de", true },
{ "jonaswitmer.ch", true },
{ "julian-kipka.de", true },
@ -351,7 +351,6 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "reviews.anime.my", true },
{ "riccy.org", true },
{ "riesenmagnete.de", true },
{ "rippleunion.com", true },
{ "rme.li", false },
{ "robteix.com", true },
{ "roddis.net", false },
@ -370,6 +369,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "sdsl-speedtest.de", true },
{ "security-carpet.com", true },
{ "security.google.com", true },
{ "securityheaders.com", true },
{ "secuvera.de", true },
{ "seifried.org", true },
{ "servethecity-karlsruhe.de", true },

View File

@ -7,16 +7,13 @@
* Test that OS.File can be loaded using the CommonJS loader.
*/
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
let { Loader } = Components.utils.import('resource://gre/modules/commonjs/toolkit/loader.js', {});
function run_test() {
run_next_test();
}
add_task(function*() {
let dataDir = Services.io.newFileURI(do_get_file("test_loader/", true)).spec + "/";
let loader = Loader.Loader({
@ -37,3 +34,4 @@ add_task(function*() {
do_print("Require has worked");
});

View File

@ -3,6 +3,8 @@
"use strict";
let {utils: Cu} = Components;
let SHARED_PATH;
let EXISTING_FILE = do_get_file("xpcshell.ini").path;

View File

@ -11,10 +11,6 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
Cu.import("resource://testing-common/httpd.js");
do_get_profile();

View File

@ -1,10 +1,5 @@
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { require } = devtools;
@ -73,4 +68,4 @@ let listener = {
};
let consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
consoleService.registerListener(listener);
consoleService.registerListener(listener);

View File

@ -7,25 +7,12 @@ const Cu = Components.utils;
const Cr = Components.results;
const CC = Components.Constructor;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
// We have to setup a profile, otherwise indexed db used by webapps
// will throw random exception when trying to get profile folder
do_get_profile();
// The webapps dir isn't registered on b2g xpcshell tests,
// we have to manually set it to the directory service.
do_get_webappsdir();
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
let gClient, gActor;
@ -79,9 +66,21 @@ function installTestApp(zipName, appId, onDone) {
};
function setup() {
// We have to setup a profile, otherwise indexed db used by webapps
// will throw random exception when trying to get profile folder
do_get_profile();
// The webapps dir isn't registered on b2g xpcshell tests,
// we have to manually set it to the directory service.
do_get_webappsdir();
// We also need a valid nsIXulAppInfo service as Webapps.jsm is querying it
Components.utils.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
// We have to toggle this flag in order to have apps being listed in getAll
// as only launchable apps are returned
Cu.import('resource://gre/modules/Webapps.jsm');
Components.utils.import('resource://gre/modules/Webapps.jsm');
DOMApplicationRegistry.allAppsLaunchable = true;
// Mock WebappOSUtils

View File

@ -1,11 +0,0 @@
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});

View File

@ -3,6 +3,8 @@
"use strict";
const Cu = Components.utils;
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
Services.prefs.setBoolPref("devtools.discovery.log", true);
@ -10,6 +12,8 @@ do_register_cleanup(() => {
Services.prefs.clearUserPref("devtools.discovery.log");
});
const { devtools } =
Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { Promise: promise } =
Cu.import("resource://gre/modules/Promise.jsm", {});
const { require } = devtools;

View File

@ -1,5 +1,5 @@
[DEFAULT]
head = head.js
head =
tail =
[test_discovery.js]

View File

@ -9,12 +9,7 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { require } = devtools;
var beautify = require("devtools/jsbeautify");

View File

@ -4,10 +4,6 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { require } = devtools;

View File

@ -1,11 +0,0 @@
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});

View File

@ -6,6 +6,8 @@
* Test encoding a simple message.
*/
const { utils: Cu } = Components;
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { require } = devtools;
const QR = require("devtools/toolkit/qrcode/index");

View File

@ -1,5 +1,5 @@
[DEFAULT]
head = head.js
head =
tail =
[test_encode.js]

View File

@ -806,8 +806,7 @@ WebappsActor.prototype = {
let deferred = promise.defer();
if (Services.appinfo.ID &&
Services.appinfo.ID != "{3c2e2abc-06d4-11e1-ac3b-374f68613e61}" &&
Services.appinfo.ID != "xpcshell@tests.mozilla.org") {
Services.appinfo.ID != "{3c2e2abc-06d4-11e1-ac3b-374f68613e61}") {
return { error: "notSupported",
message: "Not B2G. Can't launch app." };
}

View File

@ -7,10 +7,6 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { worker } = Cu.import("resource://gre/modules/devtools/worker-loader.js", {})
const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});

View File

@ -1,11 +1,4 @@
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { require } = devtools;

View File

@ -4,10 +4,6 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
Cu.import("resource://gre/modules/devtools/Loader.jsm");
Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm");
@ -45,4 +41,3 @@ let listener = {
let consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
consoleService.registerListener(listener);

View File

@ -8,10 +8,6 @@ const Cu = Components.utils;
const Cr = Components.results;
const CC = Components.Constructor;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } =
Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { Promise: promise } =

View File

@ -1,11 +0,0 @@
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});

View File

@ -3,6 +3,7 @@
// http://creativecommons.org/publicdomain/zero/1.0/
"use strict";
const { devtools } = Components.utils.import("resource://gre/modules/devtools/Loader.jsm", {});
let JSPropertyProvider = devtools.require("devtools/toolkit/webconsole/utils").JSPropertyProvider;
Components.utils.import("resource://gre/modules/jsdebugger.jsm");

View File

@ -2,6 +2,8 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const Cu = Components.utils;
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
Object.defineProperty(this, "NetworkHelper", {
get: function() {

View File

@ -1,5 +1,5 @@
[DEFAULT]
head = head.js
head =
tail =
support-files =

View File

@ -602,7 +602,7 @@ ConnectionData.prototype = Object.freeze({
deferred.resolve(result);
break;
case Ci.mozIStorageStatementCallback.REASON_CANCELLED:
case Ci.mozIStorageStatementCallback.REASON_CANCELED:
// It is not an error if the user explicitly requested cancel via
// the onRow handler.
if (userCancelled) {

View File

@ -75,19 +75,21 @@ function part3(aTestPlugin) {
}
function part4() {
ok(PopupNotifications.getNotification("click-to-play-plugins", gPluginBrowser), "part4: should have a click-to-play notification");
gPluginBrowser.removeEventListener("PluginBindingAttached", part4);
gBrowser.removeCurrentTab();
let condition = () => PopupNotifications.getNotification("click-to-play-plugins", gPluginBrowser);
waitForCondition(condition, () => {
gPluginBrowser.removeEventListener("PluginBindingAttached", part4);
gBrowser.removeCurrentTab();
let pluginEl = get_addon_element(gManagerWindow, gTestPluginId);
let menu = gManagerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "state-menulist");
let alwaysActivateItem = gManagerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "always-activate-menuitem");
menu.selectedItem = alwaysActivateItem;
alwaysActivateItem.doCommand();
gBrowser.selectedTab = gBrowser.addTab();
gPluginBrowser = gBrowser.selectedBrowser;
gPluginBrowser.addEventListener("load", part5, true);
gPluginBrowser.contentWindow.location = gHttpTestRoot + "plugin_test.html";
let pluginEl = get_addon_element(gManagerWindow, gTestPluginId);
let menu = gManagerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "state-menulist");
let alwaysActivateItem = gManagerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "always-activate-menuitem");
menu.selectedItem = alwaysActivateItem;
alwaysActivateItem.doCommand();
gBrowser.selectedTab = gBrowser.addTab();
gPluginBrowser = gBrowser.selectedBrowser;
gPluginBrowser.addEventListener("load", part5, true);
gPluginBrowser.contentWindow.location = gHttpTestRoot + "plugin_test.html";
}, "part4: should have a click-to-play notification");
}
function part5() {
@ -118,20 +120,22 @@ function part6() {
}
function part7() {
ok(PopupNotifications.getNotification("click-to-play-plugins", gPluginBrowser), "part7: disabled plugins still show a notification");
let testPlugin = gPluginBrowser.contentDocument.getElementById("test");
ok(testPlugin, "part7: should have a plugin element in the page");
let objLoadingContent = testPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "part7: plugin should not be activated");
let condition = () => PopupNotifications.getNotification("click-to-play-plugins", gPluginBrowser);
waitForCondition(condition, () => {
let testPlugin = gPluginBrowser.contentDocument.getElementById("test");
ok(testPlugin, "part7: should have a plugin element in the page");
let objLoadingContent = testPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "part7: plugin should not be activated");
gPluginBrowser.removeEventListener("PluginBindingAttached", part7);
gBrowser.removeCurrentTab();
gPluginBrowser.removeEventListener("PluginBindingAttached", part7);
gBrowser.removeCurrentTab();
let pluginEl = get_addon_element(gManagerWindow, gTestPluginId);
let details = gManagerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "details-btn");
is_element_visible(details, "part7: details link should be visible");
EventUtils.synthesizeMouseAtCenter(details, {}, gManagerWindow);
wait_for_view_load(gManagerWindow, part8);
let pluginEl = get_addon_element(gManagerWindow, gTestPluginId);
let details = gManagerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "details-btn");
is_element_visible(details, "part7: details link should be visible");
EventUtils.synthesizeMouseAtCenter(details, {}, gManagerWindow);
wait_for_view_load(gManagerWindow, part8);
}, "part7: disabled plugins still show a notification");
}
function part8() {
@ -180,19 +184,21 @@ function part10() {
}
function part11() {
ok(PopupNotifications.getNotification("click-to-play-plugins", gPluginBrowser), "part11: should have a click-to-play notification");
gPluginBrowser.removeEventListener("PluginBindingAttached", part11);
gBrowser.removeCurrentTab();
let condition = () => PopupNotifications.getNotification("click-to-play-plugins", gPluginBrowser);
waitForCondition(condition, () => {
gPluginBrowser.removeEventListener("PluginBindingAttached", part11);
gBrowser.removeCurrentTab();
let pluginTag = getTestPluginTag();
let pluginTag = getTestPluginTag();
// causes appDisabled to be set
setAndUpdateBlocklist(gHttpTestRoot + "blockPluginHard.xml",
function() {
close_manager(gManagerWindow, function() {
open_manager("addons://list/plugin", part12);
// causes appDisabled to be set
setAndUpdateBlocklist(gHttpTestRoot + "blockPluginHard.xml",
function() {
close_manager(gManagerWindow, function() {
open_manager("addons://list/plugin", part12);
});
});
});
}, "part11: should have a click-to-play notification");
}
function part12(aWindow) {