This commit is contained in:
Wes Kocher 2015-05-01 17:19:28 -07:00
Родитель fe297cf6c4 b9b0d2b3c3
Коммит 5ef0b7b6a7
76 изменённых файлов: 3487 добавлений и 2851 удалений

Просмотреть файл

@ -0,0 +1,78 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cm = Components.manager;
const kBlocklistServiceUUID = "{66354bc9-7ed1-4692-ae1d-8da97d6b205e}";
const kBlocklistServiceContractID = "@mozilla.org/extensions/blocklist;1";
const kBlocklistServiceFactory = Cm.getClassObject(Cc[kBlocklistServiceContractID], Ci.nsIFactory);
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
/*
* A lightweight blocklist proxy for the testing purposes.
*/
let BlocklistProxy = {
_uuid: null,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsIBlocklistService,
Ci.nsITimerCallback]),
init: function() {
if (!this._uuid) {
this._uuid =
Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator)
.generateUUID();
Cm.nsIComponentRegistrar.registerFactory(this._uuid, "",
"@mozilla.org/extensions/blocklist;1",
this);
}
},
uninit: function() {
if (this._uuid) {
Cm.nsIComponentRegistrar.unregisterFactory(this._uuid, this);
Cm.nsIComponentRegistrar.registerFactory(Components.ID(kBlocklistServiceUUID),
"Blocklist Service",
"@mozilla.org/extensions/blocklist;1",
kBlocklistServiceFactory);
this._uuid = null;
}
},
notify: function (aTimer) {
},
observe: function (aSubject, aTopic, aData) {
},
isAddonBlocklisted: function (aAddon, aAppVersion, aToolkitVersion) {
return false;
},
getAddonBlocklistState: function (aAddon, aAppVersion, aToolkitVersion) {
return 0; // STATE_NOT_BLOCKED
},
getPluginBlocklistState: function (aPluginTag, aAppVersion, aToolkitVersion) {
return 0; // STATE_NOT_BLOCKED
},
getAddonBlocklistURL: function (aAddon, aAppVersion, aToolkitVersion) {
return "";
},
getPluginBlocklistURL: function (aPluginTag) {
return "";
},
getPluginInfoURL: function (aPluginTag) {
return "";
},
}
BlocklistProxy.init();
addEventListener("unload", () => {
BlocklistProxy.uninit();
});

Просмотреть файл

@ -1,12 +1,7 @@
[DEFAULT]
# These tests all fail with e10s enabled.
# * Bug 899347 - no e10s click-to-play support
# * Bug 921916 - no plugin events
# * Bug XXXXX - no plugins in content processes ("Error: You cannot use the AddonManager in child processes!")
# * Bug 866413 - PageInfo doesn't work in e10s [browser_pageInfo_plugins.js]
# * Bug 921957 - remote webprogress doesn't supply originalURI attribute on the request object [browser_clearplugindata.js]
skip-if = buildapp == "mulet" || e10s
skip-if = buildapp == "mulet"
support-files =
blocklist_proxy.js
blockNoPlugins.xml
blockPluginHard.xml
blockPluginInfoURL.xml
@ -53,12 +48,14 @@ support-files =
[browser_bug818118.js]
[browser_bug820497.js]
[browser_clearplugindata.js]
skip-if = e10s # bug 1149253
[browser_CTP_context_menu.js]
skip-if = toolkit == "gtk2" || toolkit == "gtk3" # browser_CTP_context_menu.js fails intermittently on Linux (bug 909342)
skip-if = toolkit == "gtk2" || toolkit == "gtk3" # fails intermittently on Linux (bug 909342)
[browser_CTP_crashreporting.js]
skip-if = !crashreporter
[browser_CTP_data_urls.js]
[browser_CTP_drag_drop.js]
skip-if = e10s # misc. issues, bug 1156871
[browser_CTP_hide_overlay.js]
[browser_CTP_iframe.js]
skip-if = os == 'linux' || os == 'mac' # Bug 984821
@ -69,14 +66,26 @@ skip-if = os == 'linux' || os == 'mac' # Bug 984821
[browser_CTP_remove_navigate.js]
[browser_CTP_resize.js]
[browser_CTP_zoom.js]
[browser_globalplugin_crashinfobar.js]
[browser_pageInfo_plugins.js]
[browser_blocking.js]
[browser_plugins_added_dynamically.js]
[browser_pluginnotification.js]
[browser_pluginplaypreview.js]
[browser_pluginplaypreview2.js]
[browser_pluginplaypreview3.js]
[browser_plugin_infolink.js]
skip-if = e10s # bug 1160166
[browser_plugin_reloading.js]
[browser_blocklist_content.js]
skip-if = !e10s
[browser_globalplugin_crashinfobar.js]
skip-if = !crashreporter
[browser_pluginCrashCommentAndURL.js]
skip-if = !crashreporter
[browser_plugins_added_dynamically.js]
[browser_pageInfo_plugins.js]
skip-if = e10s # Bug 866413
[browser_pluginplaypreview.js]
skip-if = e10s # bug 1148827
[browser_pluginplaypreview2.js]
skip-if = e10s # bug 1148827
[browser_pluginplaypreview3.js]
skip-if = e10s # bug 1148827
[browser_pluginCrashReportNonDeterminism.js]
skip-if = !crashreporter || os == 'linux' # Bug 1152811

Просмотреть файл

@ -1,116 +1,69 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
var gTestBrowser = null;
var gNextTest = null;
var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
add_task(function* () {
registerCleanupFunction(function () {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
Services.prefs.clearUserPref("plugins.click_to_play");
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gBrowser.removeCurrentTab();
window.focus();
});
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
let newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
prepareTest(runAfterPluginBindingAttached(test1), gHttpTestRoot + "plugin_test.html");
}
function finishTest() {
clearAllPluginPermissions();
gTestBrowser.removeEventListener("load", pageLoad, true);
gBrowser.removeCurrentTab();
window.focus();
finish();
}
function pageLoad() {
// The plugin events are async dispatched and can come after the load event
// This just allows the events to fire before we then go on to test the states
executeSoon(gNextTest);
}
function prepareTest(nextTest, url) {
gNextTest = nextTest;
gTestBrowser.contentWindow.location = url;
}
// Due to layout being async, "PluginBindAttached" may trigger later.
// This wraps a function to force a layout flush, thus triggering it,
// and schedules the function execution so they're definitely executed
// afterwards.
function runAfterPluginBindingAttached(func) {
return function() {
let doc = gTestBrowser.contentDocument;
let elems = doc.getElementsByTagName('embed');
if (elems.length < 1) {
elems = doc.getElementsByTagName('object');
}
elems[0].clientTop;
executeSoon(func);
};
}
});
// Test that the activate action in content menus for CTP plugins works
function test1() {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
add_task(function* () {
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
gBrowser.selectedTab = gBrowser.addTab();
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
let bindingPromise = waitForEvent(gBrowser.selectedBrowser, "PluginBindingAttached", null, true, true);
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
yield bindingPromise;
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
ok(popupNotification, "Test 1, Should have a click-to-play notification");
let plugin = gTestBrowser.contentDocument.getElementById("test");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "Test 1, Plugin should not be activated");
// check plugin state
let pluginInfo = yield promiseForPluginInfo("test", gBrowser.selectedBrowser);
ok(!pluginInfo.activated, "plugin should not be activated");
// Display a context menu on the test plugin so we can test
// activation menu options.
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
let bounds = plugin.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
utils.sendMouseEvent("contextmenu", left, top, 2, 1, 0);
});
// When the popupshown DOM event is fired, the actual showing of the popup
// may still be pending. Clear the event loop before continuing so that
// subsequently-opened popups aren't cancelled by accident.
let goToNext = function(aEvent) {
window.document.removeEventListener("popupshown", goToNext, false);
executeSoon(function() {
test2();
aEvent.target.hidePopup();
});
};
window.document.addEventListener("popupshown", goToNext, false);
EventUtils.synthesizeMouseAtCenter(plugin,
{ type: "contextmenu", button: 2 },
gTestBrowser.contentWindow);
}
popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
ok(popupNotification, "Should have a click-to-play notification");
ok(popupNotification.dismissed, "notification should be dismissed");
function test2() {
let activate = window.document.getElementById("context-ctp-play");
ok(activate, "Test 2, Should have a context menu entry for activating the plugin");
// fixes a occasional test timeout on win7 opt
yield promiseForCondition(() => document.getElementById("context-ctp-play"));
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 2, Should have a click-to-play notification");
ok(notification.dismissed, "Test 2, notification should be dismissed");
let actMenuItem = document.getElementById("context-ctp-play");
ok(actMenuItem, "Should have a context menu entry for activating the plugin");
// Trigger the click-to-play popup
activate.doCommand();
// Activate the plugin via the context menu
EventUtils.synthesizeMouseAtCenter(actMenuItem, {});
waitForCondition(() => !notification.dismissed,
test3, "Test 2, waited too long for context activation");
}
yield promiseForCondition(() => !PopupNotifications.panel.dismissed && PopupNotifications.panel.firstChild);
function test3() {
// Activate the plugin
PopupNotifications.panel.firstChild._primaryButton.click();
let plugin = gTestBrowser.contentDocument.getElementById("test");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
waitForCondition(() => objLoadingContent.activated, test4, "Waited too long for plugin to activate");
}
function test4() {
finishTest();
}
// check plugin state
pluginInfo = yield promiseForPluginInfo("test", gBrowser.selectedBrowser);
ok(pluginInfo.activated, "plugin should not be activated");
});

Просмотреть файл

@ -1,10 +1,8 @@
/* 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/. */
let rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
const PLUGIN_PAGE = getRootDirectory(gTestPath) + "plugin_big.html";
const PLUGIN_SMALL_PAGE = getRootDirectory(gTestPath) + "plugin_small.html";
const PLUGIN_PAGE = gTestRoot + "plugin_big.html";
const PLUGIN_SMALL_PAGE = gTestRoot + "plugin_small.html";
/**
* Takes an nsIPropertyBag and converts it into a JavaScript Object. It
@ -30,14 +28,8 @@ function convertPropertyBag(aBag) {
return result;
}
function promisePopupNotificationShown(notificationID) {
return new Promise((resolve) => {
waitForNotificationShown(notificationID, resolve);
});
}
add_task(function* setup() {
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
// The test harness sets MOZ_CRASHREPORTER_NO_REPORT, which disables plugin
// crash reports. This test needs them enabled. The test also needs a mock
@ -51,9 +43,17 @@ add_task(function* setup() {
env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
env.set("MOZ_CRASHREPORTER_URL", SERVER_URL);
Services.prefs.setBoolPref("plugins.click_to_play", true);
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
registerCleanupFunction(function cleanUp() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
env.set("MOZ_CRASHREPORTER_URL", serverURL);
Services.prefs.clearUserPref("plugins.click_to_play");
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
window.focus();
});
});
@ -66,20 +66,15 @@ add_task(function*() {
gBrowser,
url: PLUGIN_PAGE,
}, function* (browser) {
let activated = yield ContentTask.spawn(browser, null, function*() {
let plugin = content.document.getElementById("test");
return plugin.QueryInterface(Ci.nsIObjectLoadingContent).activated;
});
ok(!activated, "Plugin should not be activated");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(browser);
// Open up the click-to-play notification popup...
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins",
browser);
ok(popupNotification, "Should have a click-to-play notification");
let pluginInfo = yield promiseForPluginInfo("test", browser);
ok(!pluginInfo.activated, "Plugin should not be activated");
yield promisePopupNotificationShown(popupNotification);
// The primary button in the popup should activate the plugin.
// Simulate clicking the "Allow Always" button.
let notification = PopupNotifications.getNotification("click-to-play-plugins", browser);
yield promiseForNotificationShown(notification, browser);
PopupNotifications.panel.firstChild._primaryButton.click();
// Prepare a crash report topic observer that only returns when
@ -99,8 +94,9 @@ add_task(function*() {
}, "Waited too long for plugin to activate.");
try {
plugin.crash();
} catch(e) {}
Components.utils.waiveXrays(plugin).crash();
} catch(e) {
}
let doc = plugin.ownerDocument;
@ -177,21 +173,11 @@ add_task(function*() {
gBrowser,
url: PLUGIN_SMALL_PAGE,
}, function* (browser) {
let activated = yield ContentTask.spawn(browser, null, function*() {
let plugin = content.document.getElementById("test");
return plugin.QueryInterface(Ci.nsIObjectLoadingContent).activated;
});
ok(!activated, "Plugin should not be activated");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(browser);
// Open up the click-to-play notification popup...
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins",
browser);
ok(popupNotification, "Should have a click-to-play notification");
yield promisePopupNotificationShown(popupNotification);
// The primary button in the popup should activate the plugin.
PopupNotifications.panel.firstChild._primaryButton.click();
let pluginInfo = yield promiseForPluginInfo("test", browser);
ok(pluginInfo.activated, "Plugin should be activated from previous test");
// Prepare a crash report topic observer that only returns when
// the crash report has been successfully sent.
@ -210,7 +196,7 @@ add_task(function*() {
}, "Waited too long for plugin to activate.");
try {
plugin.crash();
Components.utils.waiveXrays(plugin).crash();
} catch(e) {}
});
@ -244,4 +230,4 @@ add_task(function*() {
is(crashData.extra.PluginContentURL, undefined,
"URL should be absent from extra data when opt-in not checked");
});
});
});

Просмотреть файл

@ -1,212 +1,255 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
let gTestBrowser = null;
var gTestBrowser = null;
var gNextTest = null;
var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
add_task(function* () {
registerCleanupFunction(function () {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
Services.prefs.clearUserPref("plugins.click_to_play");
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
var newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gBrowser.selectedTab = gBrowser.addTab();
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
prepareTest(test1a, gHttpTestRoot + "plugin_data_url.html");
}
function finishTest() {
clearAllPluginPermissions();
gTestBrowser.removeEventListener("load", pageLoad, true);
gBrowser.removeCurrentTab();
window.focus();
finish();
}
function pageLoad() {
// The plugin events are async dispatched and can come after the load event
// This just allows the events to fire before we then go on to test the states
executeSoon(gNextTest);
}
function prepareTest(nextTest, url) {
gNextTest = nextTest;
gTestBrowser.contentWindow.location = url;
}
// Due to layout being async, "PluginBindAttached" may trigger later.
// This wraps a function to force a layout flush, thus triggering it,
// and schedules the function execution so they're definitely executed
// afterwards.
function runAfterPluginBindingAttached(func) {
return function() {
let doc = gTestBrowser.contentDocument;
let elems = doc.getElementsByTagName('embed');
if (elems.length < 1) {
elems = doc.getElementsByTagName('object');
}
elems[0].clientTop;
executeSoon(func);
};
}
});
// Test that the click-to-play doorhanger still works when navigating to data URLs
function test1a() {
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_data_url.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(popupNotification, "Test 1a, Should have a click-to-play notification");
let plugin = gTestBrowser.contentDocument.getElementById("test");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "Test 1a, Plugin should not be activated");
let pluginInfo = yield promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Test 1a, plugin should not be activated");
gNextTest = runAfterPluginBindingAttached(test1b);
gTestBrowser.contentDocument.getElementById("data-link-1").click();
}
let loadPromise = promiseTabLoadEvent(gBrowser.selectedTab);
yield ContentTask.spawn(gTestBrowser, {}, function* () {
// navigate forward to a page with 'test' in it
content.document.getElementById("data-link-1").click();
});
yield loadPromise;
function test1b() {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(popupNotification, "Test 1b, Should have a click-to-play notification");
let plugin = gTestBrowser.contentDocument.getElementById("test");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "Test 1b, Plugin should not be activated");
pluginInfo = yield promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Test 1b, plugin should not be activated");
let promise = promisePopupNotification("click-to-play-plugins");
yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
let bounds = plugin.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
});
yield promise;
// Simulate clicking the "Allow Always" button.
waitForNotificationShown(popupNotification, function() {
PopupNotifications.panel.firstChild._primaryButton.click();
let condition = function() !PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed &&
PopupNotifications.panel.firstChild;
yield promiseForCondition(condition);
PopupNotifications.panel.firstChild._primaryButton.click();
let condition = function() objLoadingContent.activated;
waitForCondition(condition, test1c, "Test 1b, Waited too long for plugin to activate");
});
}
// check plugin state
pluginInfo = yield promiseForPluginInfo("test");
ok(pluginInfo.activated, "Test 1b, plugin should be activated");
});
function test1c() {
// Test that the click-to-play notification doesn't break when navigating
// to data URLs with multiple plugins.
add_task(function* () {
// We click activated above
clearAllPluginPermissions();
prepareTest(runAfterPluginBindingAttached(test2a), gHttpTestRoot + "plugin_data_url.html");
}
// Test that the click-to-play notification doesn't break when navigating to data URLs with multiple plugins
function test2a() {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(popupNotification, "Test 2a, Should have a click-to-play notification");
let plugin = gTestBrowser.contentDocument.getElementById("test");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "Test 2a, Plugin should not be activated");
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_data_url.html");
gNextTest = runAfterPluginBindingAttached(test2b);
gTestBrowser.contentDocument.getElementById("data-link-2").click();
}
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
function test2b() {
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 2a, Should have a click-to-play notification");
let pluginInfo = yield promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Test 2a, plugin should not be activated");
let loadPromise = promiseTabLoadEvent(gBrowser.selectedTab);
yield ContentTask.spawn(gTestBrowser, {}, function* () {
// navigate forward to a page with 'test1' & 'test2' in it
content.document.getElementById("data-link-2").click();
});
yield loadPromise;
// Work around for delayed PluginBindingAttached
yield ContentTask.spawn(gTestBrowser, {}, function* () {
content.document.getElementById("test1").clientTop;
content.document.getElementById("test2").clientTop;
});
pluginInfo = yield promiseForPluginInfo("test1");
ok(!pluginInfo.activated, "Test 2a, test1 should not be activated");
pluginInfo = yield promiseForPluginInfo("test2");
ok(!pluginInfo.activated, "Test 2a, test2 should not be activated");
notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 2b, Should have a click-to-play notification");
yield promiseForNotificationShown(notification);
// Simulate choosing "Allow now" for the test plugin
waitForNotificationShown(notification, function() {
is(notification.options.pluginData.size, 2, "Test 2b, Should have two types of plugin in the notification");
is(notification.options.pluginData.size, 2, "Test 2b, Should have two types of plugin in the notification");
var centerAction = null;
for (var action of notification.options.pluginData.values()) {
if (action.pluginName == "Test") {
centerAction = action;
break;
}
let centerAction = null;
for (let action of notification.options.pluginData.values()) {
if (action.pluginName == "Test") {
centerAction = action;
break;
}
ok(centerAction, "Test 2b, found center action for the Test plugin");
}
ok(centerAction, "Test 2b, found center action for the Test plugin");
var centerItem = null;
for (var item of PopupNotifications.panel.firstChild.childNodes) {
is(item.value, "block", "Test 2b, all plugins should start out blocked");
if (item.action == centerAction) {
centerItem = item;
break;
}
let centerItem = null;
for (let item of PopupNotifications.panel.firstChild.childNodes) {
is(item.value, "block", "Test 2b, all plugins should start out blocked");
if (item.action == centerAction) {
centerItem = item;
break;
}
ok(centerItem, "Test 2b, found center item for the Test plugin");
}
ok(centerItem, "Test 2b, found center item for the Test plugin");
// "click" the button to activate the Test plugin
centerItem.value = "allownow";
PopupNotifications.panel.firstChild._primaryButton.click();
// "click" the button to activate the Test plugin
centerItem.value = "allownow";
PopupNotifications.panel.firstChild._primaryButton.click();
let plugin = gTestBrowser.contentDocument.getElementById("test1");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
let condition = function() objLoadingContent.activated;
waitForCondition(condition, test2c, "Test 2b, Waited too long for plugin to activate");
});
}
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
function test2c() {
let plugin = gTestBrowser.contentDocument.getElementById("test1");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 2c, Plugin should be activated");
// check plugin state
pluginInfo = yield promiseForPluginInfo("test1");
ok(pluginInfo.activated, "Test 2b, plugin should be activated");
});
add_task(function* () {
// We click activated above
clearAllPluginPermissions();
prepareTest(runAfterPluginBindingAttached(test3a), gHttpTestRoot + "plugin_data_url.html");
}
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_data_url.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
});
// Test that when navigating to a data url, the plugin permission is inherited
function test3a() {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(popupNotification, "Test 3a, Should have a click-to-play notification");
let plugin = gTestBrowser.contentDocument.getElementById("test");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "Test 3a, Plugin should not be activated");
add_task(function* () {
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 3a, Should have a click-to-play notification");
// check plugin state
let pluginInfo = yield promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Test 3a, plugin should not be activated");
let promise = promisePopupNotification("click-to-play-plugins");
yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
let bounds = plugin.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
});
yield promise;
// Simulate clicking the "Allow Always" button.
waitForNotificationShown(popupNotification, function() {
PopupNotifications.panel.firstChild._primaryButton.click();
let condition = function() !PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed &&
PopupNotifications.panel.firstChild;
yield promiseForCondition(condition);
PopupNotifications.panel.firstChild._primaryButton.click();
let condition = function() objLoadingContent.activated;
waitForCondition(condition, test3b, "Test 3a, Waited too long for plugin to activate");
// check plugin state
pluginInfo = yield promiseForPluginInfo("test");
ok(pluginInfo.activated, "Test 3a, plugin should be activated");
let loadPromise = promiseTabLoadEvent(gBrowser.selectedTab);
yield ContentTask.spawn(gTestBrowser, {}, function* () {
// navigate forward to a page with 'test' in it
content.document.getElementById("data-link-1").click();
});
}
yield loadPromise;
function test3b() {
gNextTest = test3c;
gTestBrowser.contentDocument.getElementById("data-link-1").click();
}
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
function test3c() {
let plugin = gTestBrowser.contentDocument.getElementById("test");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 3c, Plugin should be activated");
// check plugin state
pluginInfo = yield promiseForPluginInfo("test");
ok(pluginInfo.activated, "Test 3b, plugin should be activated");
clearAllPluginPermissions();
prepareTest(runAfterPluginBindingAttached(test4b),
'data:text/html,<embed id="test" style="width: 200px; height: 200px" type="application/x-test"/>');
}
});
// Test that the click-to-play doorhanger still works when directly navigating to data URLs
function test4a() {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(popupNotification, "Test 4a, Should have a click-to-play notification");
let plugin = gTestBrowser.contentDocument.getElementById("test");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "Test 4a, Plugin should not be activated");
// Test that the click-to-play doorhanger still works
// when directly navigating to data URLs.
// Fails, bug XXX. Plugins plus a data url don't fire a load event.
/*
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab,
"data:text/html,Hi!<embed id='test' style='width:200px; height:200px' type='application/x-test'/>");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 4a, Should have a click-to-play notification");
// check plugin state
let pluginInfo = yield promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Test 4a, plugin should not be activated");
let promise = promisePopupNotification("click-to-play-plugins");
yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
let bounds = plugin.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
});
yield promise;
// Simulate clicking the "Allow Always" button.
waitForNotificationShown(popupNotification, function() {
PopupNotifications.panel.firstChild._primaryButton.click();
let condition = function() !PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed &&
PopupNotifications.panel.firstChild;
yield promiseForCondition(condition);
PopupNotifications.panel.firstChild._primaryButton.click();
let condition = function() objLoadingContent.activated;
waitForCondition(condition, test4b, "Test 4a, Waited too long for plugin to activate");
});
}
function test4b() {
clearAllPluginPermissions();
finishTest();
}
// check plugin state
pluginInfo = yield promiseForPluginInfo("test");
ok(pluginInfo.activated, "Test 4a, plugin should be activated");
});
*/

Просмотреть файл

@ -1,102 +1,96 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
let gHttpTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gNextTest = null;
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gNewWindow = null;
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
add_task(function* () {
registerCleanupFunction(function () {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
Services.prefs.clearUserPref("plugins.click_to_play");
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gNewWindow.close();
gNewWindow = null;
window.focus();
});
});
add_task(function* () {
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("PluginBindingAttached", handleEvent, true, true);
gNextTest = part1;
gBrowser.selectedBrowser.contentDocument.location = gHttpTestRoot + "plugin_test.html";
}
function handleEvent() {
gNextTest();
}
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
function part1() {
gBrowser.selectedBrowser.removeEventListener("PluginBindingAttached", handleEvent);
waitForNotificationPopup("click-to-play-plugins", gBrowser.selectedBrowser, () => {
gNextTest = part2;
gNewWindow = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
gNewWindow.addEventListener("load", handleEvent, true);
});
}
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
function part2() {
gNewWindow.removeEventListener("load", handleEvent);
let condition = function() PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser);
waitForCondition(condition, part3, "Waited too long for click-to-play notification");
}
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
yield promisePopupNotification("click-to-play-plugins");
});
add_task(function* () {
gNewWindow = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
// XXX technically can't load fire before we get this call???
yield waitForEvent(gNewWindow, "load", null, true);
yield promisePopupNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser);
function part3() {
ok(PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser), "Should have a click-to-play notification in the tab in the new window");
ok(!PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser), "Should not have a click-to-play notification in the old window now");
});
add_task(function* () {
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, gNewWindow.gBrowser.selectedTab);
let condition = function() PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
waitForCondition(condition, part4, "Waited too long for click-to-play notification");
}
function part4() {
yield promisePopupNotification("click-to-play-plugins", gBrowser.selectedBrowser);
ok(PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser), "Should have a click-to-play notification in the initial tab again");
gBrowser.selectedBrowser.addEventListener("PluginBindingAttached", handleEvent, true, true);
gNextTest = part5;
gBrowser.selectedBrowser.contentDocument.location = gHttpTestRoot + "plugin_test.html";
}
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
});
function part5() {
gBrowser.selectedBrowser.removeEventListener("PluginBindingAttached", handleEvent);
waitForNotificationPopup("click-to-play-plugins", gBrowser.selectedBrowser, () => {
gNewWindow = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
waitForFocus(part6, gNewWindow);
});
}
add_task(function* () {
yield promisePopupNotification("click-to-play-plugins");
function part6() {
let condition = function() PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser);
waitForCondition(condition, part7, "Waited too long for click-to-play notification");
}
gNewWindow = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
function part7() {
yield promiseWaitForFocus(gNewWindow);
yield promisePopupNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser);
});
add_task(function* () {
ok(PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser), "Should have a click-to-play notification in the tab in the new window");
ok(!PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser), "Should not have a click-to-play notification in the old window now");
let plugin = gNewWindow.gBrowser.selectedBrowser.contentDocument.getElementById("test");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "plugin should not be activated");
let pluginInfo = yield promiseForPluginInfo("test", gNewWindow.gBrowser.selectedBrowser);
ok(!pluginInfo.activated, "plugin should not be activated");
yield ContentTask.spawn(gNewWindow.gBrowser.selectedBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
let bounds = plugin.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
});
EventUtils.synthesizeMouseAtCenter(plugin, {}, gNewWindow.gBrowser.selectedBrowser.contentWindow);
let condition = function() !PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser).dismissed && gNewWindow.PopupNotifications.panel.firstChild;
waitForCondition(condition, part8, "waited too long for plugin to activate");
}
yield promiseForCondition(condition);
});
function part8() {
add_task(function* () {
// Click the activate button on doorhanger to make sure it works
gNewWindow.PopupNotifications.panel.firstChild._primaryButton.click();
let plugin = gNewWindow.gBrowser.selectedBrowser.contentDocument.getElementById("test");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
waitForCondition(() => objLoadingContent.activated, shutdown, "plugin should be activated now");
}
function shutdown() {
gNewWindow.close();
gNewWindow = null;
finish();
}
let pluginInfo = yield promiseForPluginInfo("test", gNewWindow.gBrowser.selectedBrowser);
ok(pluginInfo.activated, "plugin should be activated");
});

Просмотреть файл

@ -1,76 +1,54 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
var gTestBrowser = null;
var gNextTest = null;
var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
add_task(function* () {
registerCleanupFunction(function () {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
Services.prefs.clearUserPref("plugins.click_to_play");
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gBrowser.removeCurrentTab();
window.focus();
});
});
add_task(function* () {
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
let newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
gBrowser.selectedTab = gBrowser.addTab();
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_DISABLED);
prepareTest(runAfterPluginBindingAttached(test1), gHttpTestRoot + "plugin_test.html");
}
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
function finishTest() {
clearAllPluginPermissions();
gTestBrowser.removeEventListener("load", pageLoad, true);
gBrowser.removeCurrentTab();
window.focus();
finish();
}
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
function pageLoad() {
// The plugin events are async dispatched and can come after the load event
// This just allows the events to fire before we then go on to test the states
executeSoon(gNextTest);
}
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
function prepareTest(nextTest, url) {
gNextTest = nextTest;
gTestBrowser.contentWindow.location = url;
}
// Tests that the overlay can be hidded for disabled plugins using the close icon.
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
let closeIcon = doc.getAnonymousElementByAttribute(plugin, "anonid", "closeIcon")
let bounds = closeIcon.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
});
// Due to layout being async, "PluginBindAttached" may trigger later.
// This wraps a function to force a layout flush, thus triggering it,
// and schedules the function execution so they're definitely executed
// afterwards.
function runAfterPluginBindingAttached(func) {
return function() {
let doc = gTestBrowser.contentDocument;
let elems = doc.getElementsByTagName('embed');
if (elems.length < 1) {
elems = doc.getElementsByTagName('object');
}
elems[0].clientTop;
executeSoon(func);
};
}
// Tests that the overlay can be hidded for disabled plugins using the close icon.
function test1() {
var doc = gTestBrowser.contentDocument;
var plugin = doc.getElementById("test");
ok(plugin, "Test 1, Found plugin in page");
var overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
ok(overlay.classList.contains("visible"), "Test 1, Plugin overlay should exist, not be hidden");
var closeIcon = doc.getAnonymousElementByAttribute(plugin, "anonid", "closeIcon")
EventUtils.synthesizeMouseAtCenter(closeIcon, {}, gTestBrowser.contentWindow);
var condition = function() !overlay.classList.contains("visible");
waitForCondition(condition, finishTest, "Test 1, Waited too long for the overlay to become invisible.");
}
let overlayIsVisible = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
return plugin && overlay.classList.contains("visible");
});
ok(!overlayIsVisible, "overlay should be hidden.");
});

Просмотреть файл

@ -1,104 +1,54 @@
let rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gTestBrowser = null;
let gNextTest = null;
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
add_task(function* () {
registerCleanupFunction(function () {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
Services.prefs.clearUserPref("plugins.click_to_play");
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gBrowser.removeCurrentTab();
window.focus();
});
});
add_task(function* () {
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
let newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
gBrowser.selectedTab = gBrowser.addTab();
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
prepareTest(delayTest(runAfterPluginBindingAttached(test1)), gHttpTestRoot + "plugin_iframe.html");
}
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_iframe.html");
function finishTest() {
clearAllPluginPermissions();
gTestBrowser.removeEventListener("load", pageLoad, true);
gBrowser.removeCurrentTab();
window.focus();
finish();
}
// Tests that the overlays are visible and actionable if the plugin is in an iframe.
function pageLoad() {
gNextTest();
}
function prepareTest(nextTest, url) {
gNextTest = nextTest;
gTestBrowser.contentWindow.location = url;
}
// Delay executing a test for one load event to wait for frame loads.
function delayTest(nextTest) {
return () => {
gNextTest = nextTest;
}
}
// Due to layout being async, "PluginBindAttached" may trigger later.
// This wraps a function to force a layout flush, thus triggering it,
// and schedules the function execution so they're definitely executed
// afterwards.
function runAfterPluginBindingAttached(func) {
return () => {
let frame = gTestBrowser.contentDocument.getElementById("frame");
let result = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let frame = content.document.getElementById("frame");
let doc = frame.contentDocument;
let elems = doc.getElementsByTagName('embed');
if (elems.length < 1) {
elems = doc.getElementsByTagName('object');
}
elems[0].clientTop;
executeSoon(func);
};
}
// Tests that the overlays are visible and actionable if the plugin is in an iframe.
function test1() {
let frame = gTestBrowser.contentDocument.getElementById("frame");
let doc = frame.contentDocument;
let plugin = doc.getElementById("test");
ok(plugin, "Test 1, Found plugin in page");
waitForNotificationPopup("click-to-play-plugins", gTestBrowser, () => {
let plugin = doc.getElementById("test");
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.");
return plugin && overlay.classList.contains("visible");
});
}
ok(result, "Test 1, Plugin overlay should exist, not be hidden");
function test2() {
prepareTest(delayTest(runAfterPluginBindingAttached(test3)), gHttpTestRoot + "plugin_iframe.html");
}
result = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let frame = content.document.getElementById("frame");
let doc = frame.contentDocument;
let plugin = doc.getElementById("test");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
let closeIcon = doc.getAnonymousElementByAttribute(plugin, "anonid", "closeIcon");
let bounds = closeIcon.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = doc.defaultView.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
return overlay.classList.contains("visible");
});
ok(!result, "Test 1, Plugin overlay should exist, be hidden");
});
function test3() {
let frame = gTestBrowser.contentDocument.getElementById("frame");
let doc = frame.contentDocument;
let plugin = doc.getElementById("test");
ok(plugin, "Test 3, Found plugin in page");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
ok(overlay.classList.contains("visible"), "Test 3, Plugin overlay should exist, not be hidden");
EventUtils.synthesizeMouseAtCenter(plugin, {}, frame.contentWindow);
let condition = () => PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
waitForCondition(condition, finishTest, "Test 3, Waited too long for the doorhanger to pop up.");
}

Просмотреть файл

@ -1,83 +1,51 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
var gTestBrowser = null;
var gNextTest = null;
var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
add_task(function* () {
registerCleanupFunction(function () {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
Services.prefs.clearUserPref("plugins.click_to_play");
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gBrowser.removeCurrentTab();
window.focus();
});
});
add_task(function* () {
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
var newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
gBrowser.selectedTab = gBrowser.addTab();
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
prepareTest(test1a, gHttpTestRoot + "plugin_two_types.html");
}
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_two_types.html");
function finishTest() {
clearAllPluginPermissions();
gTestBrowser.removeEventListener("load", pageLoad, true);
gBrowser.removeCurrentTab();
window.focus();
finish();
}
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
function pageLoad() {
// The plugin events are async dispatched and can come after the load event
// This just allows the events to fire before we then go on to test the states
executeSoon(gNextTest);
}
// Test that the click-to-play doorhanger for multiple plugins shows the correct
// state when re-opening without reloads or navigation.
function prepareTest(nextTest, url) {
gNextTest = nextTest;
gTestBrowser.contentWindow.location = url;
}
let pluginInfo = yield promiseForPluginInfo("test", gBrowser.selectedBrowser);
ok(!pluginInfo.activated, "plugin should be activated");
// Due to layout being async, "PluginBindAttached" may trigger later.
// This wraps a function to force a layout flush, thus triggering it,
// and schedules the function execution so they're definitely executed
// afterwards.
function runAfterPluginBindingAttached(func) {
return function() {
let doc = gTestBrowser.contentDocument;
let elems = doc.getElementsByTagName('embed');
if (elems.length < 1) {
elems = doc.getElementsByTagName('object');
}
elems[0].clientTop;
executeSoon(func);
};
}
// Test that the click-to-play doorhanger for multiple plugins shows the correct
// state when re-opening without reloads or navigation.
function test1a() {
let doc = gTestBrowser.contentDocument;
let plugin = doc.getElementById("test");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "Test1a, Plugin should not be activated");
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
let notification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
ok(notification, "Test 1a, Should have a click-to-play notification");
notification.reshow();
yield promiseForNotificationShown(notification);
is(notification.options.pluginData.size, 2,
"Test 1a, Should have two types of plugin in the notification");
"Test 1a, Should have two types of plugin in the notification");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
is(PopupNotifications.panel.firstChild.childNodes.length, 2, "have child nodes");
let pluginItem = null;
for (let item of PopupNotifications.panel.firstChild.childNodes) {
@ -86,21 +54,20 @@ function test1a() {
pluginItem = item;
}
}
// Choose "Allow now" for the test plugin
pluginItem.value = "allownow";
PopupNotifications.panel.firstChild._primaryButton.click();
waitForCondition(() => objLoadingContent.activated, test1b,
"Test 1a, Waited too long for plugin to activate");
}
pluginInfo = yield promiseForPluginInfo("test", gBrowser.selectedBrowser);
ok(pluginInfo.activated, "plugin should be activated");
function test1b() {
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
notification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
ok(notification, "Test 1b, Should have a click-to-play notification");
notification.reshow();
let pluginItem = null;
yield promiseForNotificationShown(notification);
pluginItem = null;
for (let item of PopupNotifications.panel.firstChild.childNodes) {
if (item.action.pluginName == "Test") {
is(item.value, "allownow", "Test 1b, Test plugin should now be set to 'Allow now'");
@ -114,17 +81,13 @@ function test1b() {
pluginItem.value = "allowalways";
PopupNotifications.panel.firstChild._primaryButton.click();
let doc = gTestBrowser.contentDocument;
let plugin = doc.getElementById("secondtestA");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
waitForCondition(() => objLoadingContent.activated, test1c,
"Test 1b, Waited too long for plugin to activate");
}
pluginInfo = yield promiseForPluginInfo("secondtestA", gBrowser.selectedBrowser);
ok(pluginInfo.activated, "plugin should be activated");
function test1c() {
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
notification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
ok(notification, "Test 1c, Should have a click-to-play notification");
notification.reshow();
yield promiseForNotificationShown(notification);
for (let item of PopupNotifications.panel.firstChild.childNodes) {
if (item.action.pluginName == "Test") {
@ -133,6 +96,4 @@ function test1c() {
is(item.value, "allowalways", "Test 1c, Second Test plugin should be set to 'Allow always'");
}
}
finishTest();
}
});

Просмотреть файл

@ -1,114 +1,58 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
var gTestBrowser = null;
var gNextTest = null;
var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
var gRunNextTestAfterPluginRemoved = false;
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
add_task(function* () {
registerCleanupFunction(function () {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
Services.prefs.clearUserPref("plugins.click_to_play");
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gTestBrowser.removeEventListener("PluginRemoved", handlePluginRemoved, true, true);
gBrowser.removeCurrentTab();
window.focus();
});
});
add_task(function* () {
Services.prefs.setBoolPref("plugins.click_to_play", true);
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
var newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
gTestBrowser.addEventListener("PluginRemoved", handlePluginRemoved, true, true);
gBrowser.selectedTab = gBrowser.addTab();
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_DISABLED, "Test Plug-in");
prepareTest(runAfterPluginBindingAttached(test1), gHttpTestRoot + "plugin_two_types.html");
}
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_two_types.html");
function finishTest() {
clearAllPluginPermissions();
gTestBrowser.removeEventListener("load", pageLoad, true);
gBrowser.removeCurrentTab();
window.focus();
finish();
}
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
function pageLoad() {
// The plugin events are async dispatched and can come after the load event
// This just allows the events to fire before we then go on to test the states
executeSoon(gNextTest);
}
function prepareTest(nextTest, url) {
gNextTest = nextTest;
gTestBrowser.contentWindow.location = url;
}
// Due to layout being async, "PluginBindAttached" may trigger later.
// This wraps a function to force a layout flush, thus triggering it,
// and schedules the function execution so they're definitely executed
// afterwards.
function runAfterPluginBindingAttached(func) {
return function() {
let doc = gTestBrowser.contentDocument;
let elems = doc.getElementsByTagName('embed');
if (elems.length < 1) {
elems = doc.getElementsByTagName('object');
}
elems[0].clientTop;
executeSoon(func);
};
}
function handlePluginRemoved() {
if (gRunNextTestAfterPluginRemoved) {
executeSoon(gNextTest);
gRunNextTestAfterPluginRemoved = false;
}
}
function runAfterPluginRemoved(func) {
gNextTest = func;
gRunNextTestAfterPluginRemoved = true;
}
// Test that the click-to-play notification is not shown for non-plugin object elements
function test1() {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
// Test that the click-to-play notification is not shown for non-plugin object elements
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
ok(popupNotification, "Test 1, Should have a click-to-play notification");
let plugin = gTestBrowser.contentDocument.getElementById("secondtestA");
plugin.parentNode.removeChild(plugin);
plugin = gTestBrowser.contentDocument.getElementById("secondtestB");
plugin.parentNode.removeChild(plugin);
let pluginRemovedPromise = waitForEvent(gBrowser.selectedBrowser, "PluginRemoved", null, true, true);
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let plugin = content.document.getElementById("secondtestA");
plugin.parentNode.removeChild(plugin);
plugin = content.document.getElementById("secondtestB");
plugin.parentNode.removeChild(plugin);
let image = gTestBrowser.contentDocument.createElement("object");
image.type = "image/png";
image.data = "moz.png";
gTestBrowser.contentDocument.body.appendChild(image);
let image = content.document.createElement("object");
image.type = "image/png";
image.data = "moz.png";
content.document.body.appendChild(image);
});
yield pluginRemovedPromise;
runAfterPluginRemoved(test2);
}
function test2() {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
ok(popupNotification, "Test 2, Should have a click-to-play notification");
let plugin = gTestBrowser.contentDocument.getElementById("test");
plugin.parentNode.removeChild(plugin);
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
plugin.parentNode.removeChild(plugin);
});
executeSoon(test3);
}
function test3() {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
ok(popupNotification, "Test 3, Should still have a click-to-play notification");
finishTest();
}
});

Просмотреть файл

@ -1,171 +1,154 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gTestBrowser = null;
var gTestBrowser = null;
var gNextTest = null;
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
add_task(function* () {
registerCleanupFunction(function () {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
Services.prefs.clearUserPref("plugins.click_to_play");
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
var newTab = gBrowser.addTab();
let newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
});
add_task(function* () {
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
prepareTest(runAfterPluginBindingAttached(test1), gHttpTestRoot + "plugin_small.html");
}
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_small.html");
function finishTest() {
gTestBrowser.removeEventListener("load", pageLoad, true);
gBrowser.removeCurrentTab();
window.focus();
finish();
}
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
function pageLoad() {
// The plugin events are async dispatched and can come after the load event
// This just allows the events to fire before we then go on to test the states
executeSoon(gNextTest);
}
yield promisePopupNotification("click-to-play-plugins");
function prepareTest(nextTest, url) {
gNextTest = nextTest;
gTestBrowser.contentWindow.location = url;
}
// Expecting a notification bar for hidden plugins
yield promiseForNotificationBar("plugin-hidden", gTestBrowser);
});
// Due to layout being async, "PluginBindAttached" may trigger later.
// This wraps a function to force a layout flush, thus triggering it,
// and schedules the function execution so they're definitely executed
// afterwards.
function runAfterPluginBindingAttached(func) {
return function() {
let doc = gTestBrowser.contentDocument;
let elems = doc.getElementsByTagName('embed');
if (elems.length < 1) {
elems = doc.getElementsByTagName('object');
}
elems[0].clientTop;
executeSoon(func);
};
}
add_task(function* () {
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
// Tests for the notification bar for hidden plugins.
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_small.html");
function test1() {
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");
});
});
}
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
function test2() {
info("Test 2 - expecting no plugin notification bar on visible plugins.");
waitForNotificationPopup("click-to-play-plugins", gTestBrowser, () => {
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
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() {
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()
{
let doc = gTestBrowser.contentDocument;
let plugin = doc.getElementById("test");
ok(plugin, "Test 3b, Found plugin in page");
plugin.QueryInterface(Ci.nsIObjectLoadingContent);
is(plugin.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
"Test 3b, plugin fallback type should be PLUGIN_CLICK_TO_PLAY");
ok(!plugin.activated, "Test 3b, Plugin should not be activated");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
ok(!overlay.classList.contains("visible"), "Test 3b, Plugin overlay should be hidden");
prepareTest(test4, gTestRoot + "plugin_positioned.html");
}
function test4() {
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() {
let doc = gTestBrowser.contentDocument;
let plugin = doc.getElementById("test");
ok(plugin, "Test 4b, Found plugin in page");
plugin.QueryInterface(Ci.nsIObjectLoadingContent);
is(plugin.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
"Test 4b, plugin fallback type should be PLUGIN_CLICK_TO_PLAY");
ok(!plugin.activated, "Test 4b, Plugin should not be activated");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
ok(!overlay.classList.contains("visible"), "Test 4b, Plugin overlay should be hidden");
prepareTest(runAfterPluginBindingAttached(test5), gHttpTestRoot + "plugin_small.html");
}
function test5() {
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
waitForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") !== null,
test6,
"Test 5, expected a notification bar for hidden plugins");
}
yield promiseForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") === null);
});
add_task(function* () {
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_overlayed.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
// Expecting a plugin notification bar when plugins are overlaid.
yield promiseForNotificationBar("plugin-hidden", gTestBrowser);
});
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_overlayed.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
plugin.QueryInterface(Ci.nsIObjectLoadingContent);
return plugin.pluginFallbackType;
});
is(result, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
"Test 3b, plugin fallback type should be PLUGIN_CLICK_TO_PLAY");
let pluginInfo = yield promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Test 1a, plugin should not be activated");
result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
return overlay && overlay.classList.contains("visible");
});
ok(!result, "Test 3b, overlay should be hidden.");
});
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_positioned.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
// Expecting a plugin notification bar when plugins are overlaid offscreen.
yield promisePopupNotification("click-to-play-plugins");
yield promiseForNotificationBar("plugin-hidden", gTestBrowser);
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
plugin.QueryInterface(Ci.nsIObjectLoadingContent);
return plugin.pluginFallbackType;
});
is(result, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
"Test 4b, plugin fallback type should be PLUGIN_CLICK_TO_PLAY");
result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
return overlay && overlay.classList.contains("visible");
});
ok(!result, "Test 4b, overlay should be hidden.");
});
// Test that the notification bar is getting dismissed when directly activating plugins
// via the doorhanger.
function test6() {
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");
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_small.html");
// simulate "always allow"
notification.reshow();
PopupNotifications.panel.firstChild._primaryButton.click();
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
waitForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") === null,
test7,
"Test 6, expected the notification bar for hidden plugins to get dismissed");
// Expecting a plugin notification bar when plugins are overlaid offscreen.
yield promisePopupNotification("click-to-play-plugins");
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
plugin.QueryInterface(Ci.nsIObjectLoadingContent);
return plugin.pluginFallbackType;
});
}
is(result, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
"Test 6, Plugin should be click-to-play");
function test7() {
let plugin = gTestBrowser.contentDocument.getElementById("test");
ok(plugin, "Test 7, Found plugin in page");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
waitForCondition(() => objLoadingContent.activated, finishTest,
"Test 7, Waited too long for plugin to activate");
}
yield promisePopupNotification("click-to-play-plugins");
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 6, Should have a click-to-play notification");
// simulate "always allow"
yield promiseForNotificationShown(notification);
PopupNotifications.panel.firstChild._primaryButton.click();
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
yield promiseForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") === null);
let pluginInfo = yield promiseForPluginInfo("test");
ok(pluginInfo.activated, "Test 7, plugin should be activated");
});

Просмотреть файл

@ -1,125 +1,120 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gTestBrowser = null;
let gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
var gTestBrowser = null;
var gNextTest = null;
var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
var gRunNextTestAfterPluginRemoved = false;
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
add_task(function* () {
registerCleanupFunction(function () {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
Services.prefs.clearUserPref("plugins.click_to_play");
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
});
add_task(function* () {
Services.prefs.setBoolPref("plugins.click_to_play", true);
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
var newTab = gBrowser.addTab();
let newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
prepareTest(test1, gHttpTestRoot + "plugin_outsideScrollArea.html");
}
function finishTest() {
clearAllPluginPermissions();
gTestBrowser.removeEventListener("load", pageLoad, true);
gBrowser.removeCurrentTab();
window.focus();
finish();
}
function pageLoad() {
// The plugin events are async dispatched and can come after the load event
// This just allows the events to fire before we then go on to test the states
executeSoon(gNextTest);
}
function prepareTest(nextTest, url) {
gNextTest = nextTest;
gTestBrowser.contentWindow.location = url;
}
// Due to layout being async, "PluginBindAttached" may trigger later.
// This wraps a function to force a layout flush, thus triggering it,
// and schedules the function execution so they're definitely executed
// afterwards.
function runAfterPluginBindingAttached(func) {
return function() {
let doc = gTestBrowser.contentDocument;
let elems = doc.getElementsByTagName('embed');
if (elems.length < 1) {
elems = doc.getElementsByTagName('object');
}
elems[0].clientTop;
executeSoon(func);
};
}
// Add plugin relative to bottom-left corner of #container.
function addPlugin(x, y) {
let doc = gTestBrowser.contentDocument;
let p = doc.createElement('embed');
p.setAttribute('id', 'test');
p.setAttribute('type', 'application/x-test');
p.style.left = x.toString() + 'px';
p.style.bottom = y.toString() + 'px';
doc.getElementById('container').appendChild(p);
}
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(!popupNotification, "Test 1, Should not have a click-to-play notification");
});
// Test that the click-to-play overlay is not hidden for elements
// partially or fully outside the viewport.
function test1() {
addPlugin(0, -200);
executeSoon(runAfterPluginBindingAttached(test2));
}
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_outsideScrollArea.html");
function test2() {
let doc = gTestBrowser.contentDocument;
let plugin = doc.getElementById("test");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
ok(overlay, "Test 2, Should have an overlay.");
ok(overlay.classList.contains("visible"), "Test 2, Overlay should be visible");
yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let p = doc.createElement('embed');
prepareTest(test3, gHttpTestRoot + "plugin_outsideScrollArea.html");
}
p.setAttribute('id', 'test');
p.setAttribute('type', 'application/x-test');
p.style.left = "0";
p.style.bottom = "200px";
function test3() {
addPlugin(0, -410);
executeSoon(runAfterPluginBindingAttached(test4));
}
doc.getElementById('container').appendChild(p);
});
function test4() {
let doc = gTestBrowser.contentDocument;
let plugin = doc.getElementById("test");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
ok(overlay, "Test 4, Should have an overlay.");
ok(overlay.classList.contains("visible"), "Test 4, Overlay should be visible");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
prepareTest(test5, gHttpTestRoot + "plugin_outsideScrollArea.html");
}
yield promisePopupNotification("click-to-play-plugins");
function test5() {
addPlugin(-600, 0);
executeSoon(runAfterPluginBindingAttached(test6));
}
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
let doc = content.document;
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
return overlay && overlay.classList.contains("visible");
});
ok(result, "Test 2, overlay should be visible.");
});
function test6() {
let doc = gTestBrowser.contentDocument;
let plugin = doc.getElementById("test");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
ok(overlay, "Test 6, Should have an overlay.");
ok(!overlay.classList.contains("visible"), "Test 6, Overlay should be hidden");
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_outsideScrollArea.html");
finishTest();
}
yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let p = doc.createElement('embed');
p.setAttribute('id', 'test');
p.setAttribute('type', 'application/x-test');
p.style.left = "0";
p.style.bottom = "-410px";
doc.getElementById('container').appendChild(p);
});
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
yield promisePopupNotification("click-to-play-plugins");
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
let doc = content.document;
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
return overlay && overlay.classList.contains("visible");
});
ok(result, "Test 3, overlay should be visible.");
});
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_outsideScrollArea.html");
yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let p = doc.createElement('embed');
p.setAttribute('id', 'test');
p.setAttribute('type', 'application/x-test');
p.style.left = "-600px";
p.style.bottom = "0";
doc.getElementById('container').appendChild(p);
});
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
yield promisePopupNotification("click-to-play-plugins");
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
let doc = content.document;
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
return overlay && overlay.classList.contains("visible");
});
ok(!result, "Test 4, overlay should be hidden.");
});

Просмотреть файл

@ -1,17 +1,23 @@
/* 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/. */
const gTestRoot = getRootDirectory(gTestPath);
const gHttpTestRoot = gTestRoot.replace("chrome://mochitests/content/",
"http://127.0.0.1:8888/");
add_task(function* () {
Services.prefs.setBoolPref("plugins.click_to_play", true);
registerCleanupFunction(() => {
registerCleanupFunction(function () {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
Services.prefs.clearUserPref("plugins.click_to_play");
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gBrowser.removeCurrentTab();
window.focus();
});
})
Services.prefs.setBoolPref("plugins.click_to_play", true);
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
});
/**
* Tests that if a plugin is removed just as we transition to
@ -19,30 +25,27 @@ add_task(function* () {
* notification bar on the new page.
*/
add_task(function* () {
let newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
let browser = gBrowser.selectedBrowser;
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
gBrowser.selectedTab = gBrowser.addTab();
// Load up a page with a plugin...
let notificationPromise =
waitForNotificationBar("plugin-hidden", gBrowser.selectedBrowser);
yield loadPage(browser, gHttpTestRoot + "plugin_small.html")
yield forcePluginBindingAttached(browser);
let notificationPromise = waitForNotificationBar("plugin-hidden", gBrowser.selectedBrowser);
yield promiseTabLoadEvent(gBrowser.selectedTab, gHttpTestRoot + "plugin_small.html");
yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
yield notificationPromise;
// Trigger the PluginRemoved event to be fired, and then immediately
// browse to a new page.
let plugin = browser.contentDocument.getElementById("test");
plugin.remove();
yield loadPage(browser, "about:mozilla");
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
plugin.remove();
});
yield promiseTabLoadEvent(gBrowser.selectedTab, "about:mozilla");
// There should be no hidden plugin notification bar at about:mozilla.
let notificationBox = gBrowser.getNotificationBox(browser);
let notificationBox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
is(notificationBox.getNotificationWithValue("plugin-hidden"), null,
"Expected no notification box");
gBrowser.removeTab(newTab);
});
/**
@ -51,32 +54,26 @@ add_task(function* () {
* for the new page.
*/
add_task(function* () {
let newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
let browser = gBrowser.selectedBrowser;
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY,
"Second Test Plug-in");
// Load up a page with a plugin...
let notificationPromise =
waitForNotificationBar("plugin-hidden", browser);
yield loadPage(browser, gHttpTestRoot + "plugin_small.html")
yield forcePluginBindingAttached(browser);
let notificationPromise = waitForNotificationBar("plugin-hidden", gBrowser.selectedBrowser);
yield promiseTabLoadEvent(gBrowser.selectedTab, gHttpTestRoot + "plugin_small.html");
yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
yield notificationPromise;
// Trigger the PluginRemoved event to be fired, and then immediately
// browse to a new page.
let plugin = browser.contentDocument.getElementById("test");
plugin.remove();
yield loadPage(browser, gTestRoot + "plugin_small_2.html");
let notification = yield waitForNotificationBar("plugin-hidden", browser);
ok(notification, "There should be a notification shown for the new page.");
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
plugin.remove();
});
});
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, gHttpTestRoot + "plugin_small_2.html");
let notification = yield waitForNotificationBar("plugin-hidden", gBrowser.selectedBrowser);
ok(notification, "There should be a notification shown for the new page.");
// Ensure that the notification is showing information about
// the x-second-test plugin.
ok(notification.label.includes("Second Test"), "Should mention the second plugin");
ok(!notification.label.includes("127.0.0.1"), "Should not refer to old principal");
ok(notification.label.includes("null"), "Should refer to the new principal");
gBrowser.removeTab(newTab);
let label = notification.label;
ok(label.includes("Second Test"), "Should mention the second plugin");
});

Просмотреть файл

@ -1,116 +1,130 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gTestBrowser = null;
var gTestBrowser = null;
var gNextTest = null;
var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
add_task(function* () {
registerCleanupFunction(function () {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
Services.prefs.clearUserPref("plugins.click_to_play");
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
});
add_task(function* () {
Services.prefs.setBoolPref("plugins.click_to_play", true);
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
var newTab = gBrowser.addTab();
let newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
prepareTest(runAfterPluginBindingAttached(test1), gHttpTestRoot + "plugin_small.html");
}
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(!popupNotification, "Test 1, Should not have a click-to-play notification");
function finishTest() {
clearAllPluginPermissions();
gTestBrowser.removeEventListener("load", pageLoad, true);
gBrowser.removeCurrentTab();
window.focus();
finish();
}
yield promiseTabLoadEvent(newTab, gTestRoot + "plugin_small.html"); // 10x10 plugin
function pageLoad() {
// The plugin events are async dispatched and can come after the load event
// This just allows the events to fire before we then go on to test the states
executeSoon(gNextTest);
}
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
function prepareTest(nextTest, url) {
gNextTest = nextTest;
gTestBrowser.contentWindow.location = url;
}
// Due to layout being async, "PluginBindAttached" may trigger later.
// This wraps a function to force a layout flush, thus triggering it,
// and schedules the function execution so they're definitely executed
// afterwards.
function runAfterPluginBindingAttached(func) {
return function() {
let doc = gTestBrowser.contentDocument;
let elems = doc.getElementsByTagName('embed');
if (elems.length < 1) {
elems = doc.getElementsByTagName('object');
}
elems[0].clientTop;
executeSoon(func);
};
}
yield promisePopupNotification("click-to-play-plugins");
});
// Test that the overlay is hidden for "small" plugin elements and is shown
// once they are resized to a size that can hold the overlay
function test1() {
add_task(function* () {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(popupNotification, "Test 1, Should have a click-to-play notification");
ok(popupNotification, "Test 2, Should have a click-to-play notification");
let plugin = gTestBrowser.contentDocument.getElementById("test");
let doc = gTestBrowser.contentDocument;
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
ok(overlay, "Test 1, Should have an overlay.");
ok(!overlay.classList.contains("visible"), "Test 1, Overlay should be hidden");
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
return overlay && overlay.classList.contains("visible");
});
ok(!result, "Test 2, overlay should be hidden.");
});
plugin.style.width = '300px';
executeSoon(test2);
}
add_task(function* () {
yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
plugin.style.width = "300px";
});
function test2() {
let plugin = gTestBrowser.contentDocument.getElementById("test");
let doc = gTestBrowser.contentDocument;
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
ok(overlay, "Test 2, Should have an overlay.");
ok(!overlay.classList.contains("visible"), "Test 2, Overlay should be hidden");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
plugin.style.height = '300px';
let condition = () => overlay.classList.contains("visible");
waitForCondition(condition, test3, "Test 2, Waited too long for overlay to become visible");
}
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
return overlay && overlay.classList.contains("visible");
});
ok(!result, "Test 3, overlay should be hidden.");
});
function test3() {
let plugin = gTestBrowser.contentDocument.getElementById("test");
let doc = gTestBrowser.contentDocument;
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
ok(overlay, "Test 3, Should have an overlay.");
ok(overlay.classList.contains("visible"), "Test 3, Overlay should be visible");
plugin.style.width = '10px';
plugin.style.height = '10px';
let condition = () => !overlay.classList.contains("visible");
waitForCondition(condition, test4, "Test 3, Waited too long for overlay to become hidden");
}
add_task(function* () {
yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
plugin.style.height = "300px";
});
function test4() {
let plugin = gTestBrowser.contentDocument.getElementById("test");
let doc = gTestBrowser.contentDocument;
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
ok(overlay, "Test 4, Should have an overlay.");
ok(!overlay.classList.contains("visible"), "Test 4, Overlay should be hidden");
yield ContentTask.spawn(gTestBrowser, {}, function* () {
content.document.getElementById("test").clientTop;
});
clearAllPluginPermissions();
finishTest();
}
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
return overlay && overlay.classList.contains("visible");
});
ok(result, "Test 4, overlay should be visible.");
});
add_task(function* () {
yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
plugin.style.width = "10px";
plugin.style.height = "10px";
});
yield ContentTask.spawn(gTestBrowser, {}, function* () {
content.document.getElementById("test").clientTop;
});
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
return overlay && overlay.classList.contains("visible");
});
ok(!result, "Test 5, overlay should be hidden.");
});
add_task(function* () {
yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
plugin.style.height = "300px";
plugin.style.width = "300px";
});
yield ContentTask.spawn(gTestBrowser, {}, function* () {
content.document.getElementById("test").clientTop;
});
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
return overlay && overlay.classList.contains("visible");
});
ok(result, "Test 6, overlay should be visible.");
});

Просмотреть файл

@ -1,77 +1,62 @@
/* 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 rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/",
"http://127.0.0.1:8888/");
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gTestBrowser = null;
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(() => {
FullZoom.reset();
add_task(function* () {
registerCleanupFunction(function () {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
Services.prefs.clearUserPref("plugins.click_to_play");
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
FullZoom.reset(); // must be called before closing the tab we zoomed!
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
});
add_task(function* () {
Services.prefs.setBoolPref("plugins.click_to_play", true);
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
let newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gBrowser.selectedTab = gBrowser.addTab();
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
gTestBrowser.contentWindow.location = gHttpTestRoot + "plugin_zoom.html"
}
function finishTest() {
clearAllPluginPermissions();
gTestBrowser.removeEventListener("load", pageLoad, true);
gBrowser.removeCurrentTab();
window.focus();
finish();
}
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
function pageLoad() {
// Due to layout being async, "PluginBindAttached" may trigger later.
// This wraps a function to force a layout flush, thus triggering it,
// and schedules the function execution so they're definitely executed
// afterwards.
let doc = gTestBrowser.contentDocument;
let elems = doc.getElementsByTagName('embed');
if (elems.length < 1) {
elems = doc.getElementsByTagName('object');
}
elems[0].clientTop;
executeSoon(testOverlay);
}
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(!popupNotification, "Test 1, Should not have a click-to-play notification");
let enlargeCount = 4;
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_zoom.html");
// Enlarges the zoom level |enlargeCount| times and tests that the overlay is
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
yield promisePopupNotification("click-to-play-plugins");
});
// Enlarges the zoom level 4 times and tests that the overlay is
// visible after each enlargement.
function testOverlay() {
let plugin = gTestBrowser.contentDocument.getElementById("test");
let doc = gTestBrowser.contentDocument;
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
ok(overlay, "Overlay should exist");
ok(overlay.classList.contains("visible"), "Overlay should be visible");
add_task(function* () {
for (let count = 0; count < 4; count++) {
if (enlargeCount > 0) {
--enlargeCount;
FullZoom.enlarge();
gTestBrowser.contentWindow.location.reload();
} else {
FullZoom.reset();
clearAllPluginPermissions();
finishTest();
// Reload the page
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_zoom.html");
yield promiseUpdatePluginBindings(gTestBrowser);
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
return overlay && overlay.classList.contains("visible");
});
ok(result, "Overlay should be visible for zoom change count " + count);
}
}
});

Просмотреть файл

@ -0,0 +1,360 @@
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gTestBrowser = null;
let gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
function updateAllTestPlugins(aState) {
setTestPluginEnabledState(aState, "Test Plug-in");
setTestPluginEnabledState(aState, "Second Test Plug-in");
}
add_task(function* () {
registerCleanupFunction(Task.async(function*() {
clearAllPluginPermissions();
updateAllTestPlugins(Ci.nsIPluginTag.STATE_ENABLED);
Services.prefs.clearUserPref("plugins.click_to_play");
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
resetBlocklist();
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
}));
});
add_task(function* () {
gBrowser.selectedTab = gBrowser.addTab();
gTestBrowser = gBrowser.selectedBrowser;
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
Services.prefs.setBoolPref("plugins.click_to_play", true);
// Prime the content process
yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html>hi</html>");
// Make sure the blocklist service(s) are running
Components.classes["@mozilla.org/extensions/blocklist;1"]
.getService(Components.interfaces.nsIBlocklistService);
let exmsg = yield promiseInitContentBlocklistSvc(gBrowser.selectedBrowser);
ok(!exmsg, "exception: " + exmsg);
});
add_task(function* () {
// enable hard blocklisting for the next test
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginHard.xml", gTestBrowser);
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
yield promisePopupNotification("click-to-play-plugins");
let notification = PopupNotifications.getNotification("click-to-play-plugins");
ok(notification.dismissed, "Test 5: The plugin notification should be dismissed by default");
yield promiseForNotificationShown(notification);
let pluginInfo = yield promiseForPluginInfo("test");
is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_BLOCKLISTED, "Test 5, plugin fallback type should be PLUGIN_BLOCKLISTED");
is(notification.options.pluginData.size, 1, "Test 5: Only the blocked plugin should be present in the notification");
ok(PopupNotifications.panel.firstChild._buttonContainer.hidden, "Part 5: The blocked plugins notification should not have any buttons visible.");
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
});
// Tests a vulnerable, updatable plugin
add_task(function* () {
// enable hard blocklisting of test
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginVulnerableUpdatable.xml", gTestBrowser);
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
yield promisePopupNotification("click-to-play-plugins");
let pluginInfo = yield promiseForPluginInfo("test");
is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE,
"Test 18a, plugin fallback type should be PLUGIN_VULNERABLE_UPDATABLE");
ok(!pluginInfo.activated, "Test 18a, Plugin should not be activated");
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
let doc = content.document;
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
return overlay && overlay.classList.contains("visible");
});
ok(result, "Test 18a, Plugin overlay should exist, not be hidden");
result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
let updateLink = doc.getAnonymousElementByAttribute(plugin, "anonid", "checkForUpdatesLink");
return updateLink.style.visibility != "hidden";
});
ok(result, "Test 18a, Plugin should have an update link");
let promise = waitForEvent(gBrowser.tabContainer, "TabOpen", null, true);
let pluginUpdateURL = Services.urlFormatter.formatURLPref("plugins.update.url");
info(pluginUpdateURL);
yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
let updateLink = doc.getAnonymousElementByAttribute(plugin, "anonid", "checkForUpdatesLink");
let bounds = updateLink.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
});
yield promise;
promise = waitForEvent(gBrowser.tabContainer, "TabClose", null, true);
gBrowser.removeCurrentTab();
yield promise;
});
add_task(function* () {
// clicking the update link should not activate the plugin
let pluginInfo = yield promiseForPluginInfo("test");
is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE,
"Test 18a, plugin fallback type should be PLUGIN_VULNERABLE_UPDATABLE");
ok(!pluginInfo.activated, "Test 18b, Plugin should not be activated");
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
return overlay && overlay.classList.contains("visible");
});
ok(result, "Test 18b, Plugin overlay should exist, not be hidden");
});
// Tests a vulnerable plugin with no update
add_task(function* () {
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginVulnerableNoUpdate.xml", gTestBrowser);
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 18c, Should have a click-to-play notification");
let pluginInfo = yield promiseForPluginInfo("test");
is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE,
"Test 18c, plugin fallback type should be PLUGIN_VULNERABLE_NO_UPDATE");
ok(!pluginInfo.activated, "Test 18c, Plugin should not be activated");
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
return overlay && overlay.classList.contains("visible");
});
ok(result, "Test 18c, Plugin overlay should exist, not be hidden");
result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
let updateLink = doc.getAnonymousElementByAttribute(plugin, "anonid", "checkForUpdatesLink");
return updateLink && updateLink.style.display != "block";
});
ok(result, "Test 18c, Plugin should not have an update link");
// check that click "Always allow" works with blocked plugins
yield promiseForNotificationShown(notification);
PopupNotifications.panel.firstChild._primaryButton.click();
pluginInfo = yield promiseForPluginInfo("test");
is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE,
"Test 18c, plugin fallback type should be PLUGIN_VULNERABLE_NO_UPDATE");
ok(pluginInfo.activated, "Test 18c, Plugin should be activated");
let enabledState = getTestPluginEnabledState();
ok(enabledState, "Test 18c, Plugin enabled state should be STATE_CLICKTOPLAY");
});
// continue testing "Always allow", make sure it sticks.
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
let pluginInfo = yield promiseForPluginInfo("test");
ok(pluginInfo.activated, "Test 18d, Waited too long for plugin to activate");
clearAllPluginPermissions();
});
// clicking the in-content overlay of a vulnerable plugin should bring
// up the notification and not directly activate the plugin
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 18f, Should have a click-to-play notification");
ok(notification.dismissed, "Test 18f, notification should start dismissed");
let pluginInfo = yield promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Test 18f, Waited too long for plugin to activate");
var oldEventCallback = notification.options.eventCallback;
let promise = promiseForCondition(() => oldEventCallback == null);
notification.options.eventCallback = function() {
if (oldEventCallback) {
oldEventCallback();
}
oldEventCallback = null;
};
yield ContentTask.spawn(gTestBrowser, {}, function* () {
let doc = content.document;
let plugin = doc.getElementById("test");
let bounds = plugin.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
});
yield promise;
ok(notification, "Test 18g, Should have a click-to-play notification");
ok(!notification.dismissed, "Test 18g, notification should be open");
pluginInfo = yield promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Test 18g, Plugin should not be activated");
});
// Test that "always allow"-ing a plugin will not allow it when it becomes
// blocklisted.
add_task(function* () {
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 24a, Should have a click-to-play notification");
// Plugin should start as CTP
let pluginInfo = yield promiseForPluginInfo("test");
is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
"Test 24a, plugin fallback type should be PLUGIN_CLICK_TO_PLAY");
ok(!pluginInfo.activated, "Test 24a, Plugin should not be active.");
// simulate "always allow"
yield promiseForNotificationShown(notification);
PopupNotifications.panel.firstChild._primaryButton.click();
pluginInfo = yield promiseForPluginInfo("test");
ok(pluginInfo.activated, "Test 24a, Plugin should be active.");
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginVulnerableUpdatable.xml", gTestBrowser);
});
// the plugin is now blocklisted, so it should not automatically load
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 24b, Should have a click-to-play notification");
let pluginInfo = yield promiseForPluginInfo("test");
is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE,
"Test 24b, plugin fallback type should be PLUGIN_VULNERABLE_UPDATABLE");
ok(!pluginInfo.activated, "Test 24b, Plugin should not be active.");
// simulate "always allow"
yield promiseForNotificationShown(notification);
PopupNotifications.panel.firstChild._primaryButton.click();
pluginInfo = yield promiseForPluginInfo("test");
ok(pluginInfo.activated, "Test 24b, Plugin should be active.");
clearAllPluginPermissions();
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
});
// Plugin sync removal test. Note this test produces a notification drop down since
// the plugin we add has zero dims.
add_task(function* () {
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_syncRemoved.html");
// Maybe there some better trick here, we need to wait for the page load, then
// wait for the js to execute in the page.
yield waitForMs(500);
let notification = PopupNotifications.getNotification("click-to-play-plugins");
ok(notification, "Test 25: There should be a plugin notification even if the plugin was immediately removed");
ok(notification.dismissed, "Test 25: The notification should be dismissed by default");
yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html>hi</html>");
});
// Tests a page with a blocked plugin in it and make sure the infoURL property
// the blocklist file gets used.
add_task(function* () {
clearAllPluginPermissions();
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginInfoURL.xml", gTestBrowser);
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
let notification = PopupNotifications.getNotification("click-to-play-plugins");
// Since the plugin notification is dismissed by default, reshow it.
yield promiseForNotificationShown(notification);
let pluginInfo = yield promiseForPluginInfo("test");
is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_BLOCKLISTED,
"Test 26, plugin fallback type should be PLUGIN_BLOCKLISTED");
let result = ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
return objLoadingContent.activated;
});
ok(result, "Plugin should be activated.");
const testUrl = "http://test.url.com/";
let firstPanelChild = PopupNotifications.panel.firstChild;
let infoLink = document.getAnonymousElementByAttribute(firstPanelChild, "anonid",
"click-to-play-plugins-notification-link");
is(infoLink.href, testUrl,
"Test 26, the notification URL needs to match the infoURL from the blocklist file.");
});

Просмотреть файл

@ -0,0 +1,108 @@
let gTestBrowser = null;
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gChromeRoot = getRootDirectory(gTestPath);
add_task(function* () {
registerCleanupFunction(Task.async(function*() {
clearAllPluginPermissions();
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
Services.prefs.clearUserPref("plugins.click_to_play");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
resetBlocklist();
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
}));
});
add_task(function* () {
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
Services.prefs.setBoolPref("plugins.click_to_play", true);
gBrowser.selectedTab = gBrowser.addTab();
gTestBrowser = gBrowser.selectedBrowser;
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
// Prime the blocklist service, the remote service doesn't launch on startup.
yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html></html>");
let exmsg = yield promiseInitContentBlocklistSvc(gBrowser.selectedBrowser);
ok(!exmsg, "exception: " + exmsg);
});
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let test = content.document.getElementById("test");
return test.activated;
});
ok(result, "task 1a: test plugin should be activated!");
});
// Load a fresh page, load a new plugin blocklist, then load the same page again.
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html>GO!</html>");
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginHard.xml", gTestBrowser);
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let test = content.document.getElementById("test");
return test.activated;
});
ok(!result, "task 2a: test plugin shouldn't activate!");
});
// Unload the block list and lets do this again, only this time lets
// hack around in the content blocklist service maliciously.
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html>GO!</html>");
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
// Hack the planet! Load our blocklist shim, so we can mess with blocklist
// return results in the content process. Active until we close our tab.
let mm = gTestBrowser.messageManager;
info("test 3a: loading " + gChromeRoot + "blocklist_proxy.js" + "\n");
mm.loadFrameScript(gChromeRoot + "blocklist_proxy.js", true);
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let test = content.document.getElementById("test");
return test.activated;
});
ok(result, "task 3a: test plugin should be activated!");
});
// Load a fresh page, load a new plugin blocklist, then load the same page again.
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html>GO!</html>");
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginHard.xml", gTestBrowser);
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let test = content.document.getElementById("test");
return test.activated;
});
ok(!result, "task 4a: test plugin shouldn't activate!");
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
});

Просмотреть файл

@ -1,114 +1,127 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://mochi.test:8888/");
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gTestBrowser = null;
var gTestBrowser = null;
var gNextTest = null;
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
add_task(function* () {
registerCleanupFunction(Task.async(function*() {
clearAllPluginPermissions();
Services.prefs.clearUserPref("plugins.click_to_play");
});
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
resetBlocklist();
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
}));
});
var newTab = gBrowser.addTab();
add_task(function* () {
let newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
prepareTest(test1a, gTestRoot + "plugin_add_dynamically.html");
}
function finishTest() {
gTestBrowser.removeEventListener("load", pageLoad, true);
gBrowser.removeCurrentTab();
window.focus();
finish();
}
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
Services.prefs.setBoolPref("plugins.click_to_play", true);
function pageLoad() {
// The plugin events are async dispatched and can come after the load event
// This just allows the events to fire before we then go on to test the states
executeSoon(gNextTest);
}
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
function prepareTest(nextTest, url) {
gNextTest = nextTest;
gTestBrowser.contentWindow.location = url;
}
// Prime the blocklist service, the remote service doesn't launch on startup.
yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html></html>");
let exmsg = yield promiseInitContentBlocklistSvc(gBrowser.selectedBrowser);
ok(!exmsg, "exception: " + exmsg);
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
});
// Tests that navigation within the page and the window.history API doesn't break click-to-play state.
function test1a() {
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(!popupNotification, "Test 1a, Should not have a click-to-play notification");
var plugin = new XPCNativeWrapper(XPCNativeWrapper.unwrap(gTestBrowser.contentWindow).addPlugin());
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_add_dynamically.html");
var condition = function() PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
waitForCondition(condition, test1b, "Test 1a, Waited too long for plugin notification");
}
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(!notification, "Test 1a, Should not have a click-to-play notification");
function test1b() {
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(popupNotification, "Test 1b, Should have a click-to-play notification");
var plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[0];
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "Test 1b, Plugin should not be activated");
yield ContentTask.spawn(gTestBrowser, {}, function* () {
new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin());
});
yield promisePopupNotification("click-to-play-plugins");
});
add_task(function* () {
let isActivated = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementsByTagName("embed")[0];
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
return objLoadingContent.activated;
});
ok(!isActivated, "Test 1b, Plugin should not be activated");
// Click the activate button on doorhanger to make sure it works
popupNotification.reshow();
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
yield promiseForNotificationShown(notification);
PopupNotifications.panel.firstChild._primaryButton.click();
var condition = function() objLoadingContent.activated;
waitForCondition(condition, test1c, "Test 1b, Waited too long for plugin activation");
}
function test1c() {
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(popupNotification, "Test 1c, Should still have a click-to-play notification");
var plugin = new XPCNativeWrapper(XPCNativeWrapper.unwrap(gTestBrowser.contentWindow).addPlugin());
isActivated = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementsByTagName("embed")[0];
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
return objLoadingContent.activated;
});
ok(isActivated, "Test 1b, Plugin should be activated");
});
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
var condition = function() objLoadingContent.activated;
waitForCondition(condition, test1d, "Test 1c, Waited too long for plugin activation");
}
add_task(function* () {
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 1c, Should still have a click-to-play notification");
function test1d() {
var plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[1];
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 1d, Plugin should be activated");
let isActivated = yield ContentTask.spawn(gTestBrowser, {}, function* () {
new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin());
let plugin = content.document.getElementsByTagName("embed")[1];
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
return objLoadingContent.activated;
});
ok(isActivated, "Test 1c, Newly inserted plugin in activated page should be activated");
});
gNextTest = test1e;
gTestBrowser.contentWindow.addEventListener("hashchange", test1e, false);
add_task(function* () {
let isActivated = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementsByTagName("embed")[1];
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
return objLoadingContent.activated;
});
ok(isActivated, "Test 1d, Plugin should be activated");
let promise = waitForEvent(gTestBrowser.contentWindow, "hashchange", null);
gTestBrowser.contentWindow.location += "#anchorNavigation";
}
yield promise;
});
function test1e() {
gTestBrowser.contentWindow.removeEventListener("hashchange", test1e, false);
add_task(function* () {
let isActivated = yield ContentTask.spawn(gTestBrowser, {}, function* () {
new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin());
let plugin = content.document.getElementsByTagName("embed")[2];
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
return objLoadingContent.activated;
});
ok(isActivated, "Test 1e, Plugin should be activated");
});
var plugin = new XPCNativeWrapper(XPCNativeWrapper.unwrap(gTestBrowser.contentWindow).addPlugin());
add_task(function* () {
let isActivated = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementsByTagName("embed")[2];
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
return objLoadingContent.activated;
});
ok(isActivated, "Test 1f, Plugin should be activated");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
var condition = function() objLoadingContent.activated;
waitForCondition(condition, test1f, "Test 1e, Waited too long for plugin activation");
}
function test1f() {
var plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[2];
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 1f, Plugin should be activated");
gTestBrowser.contentWindow.history.replaceState({}, "", "replacedState");
var plugin = new XPCNativeWrapper(XPCNativeWrapper.unwrap(gTestBrowser.contentWindow).addPlugin());
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
var condition = function() objLoadingContent.activated;
waitForCondition(condition, test1g, "Test 1f, Waited too long for plugin activation");
}
function test1g() {
var plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[3];
var objLoadingContent2 = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent2.activated, "Test 1g, Plugin should be activated");
finishTest();
}
isActivated = yield ContentTask.spawn(gTestBrowser, {}, function* () {
content.history.replaceState({}, "", "replacedState");
new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin());
let plugin = content.document.getElementsByTagName("embed")[3];
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
return objLoadingContent.activated;
});
ok(isActivated, "Test 1f, Plugin should not be activated");
});

Просмотреть файл

@ -1,43 +1,51 @@
/* 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/. */
var gTestBrowser = null;
var gNumPluginBindingsAttached = 0;
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
Services.prefs.clearUserPref("plugins.click_to_play");
gTestBrowser.removeEventListener("PluginBindingAttached", pluginBindingAttached, true, true);
gBrowser.removeCurrentTab();
window.focus();
});
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
gBrowser.selectedTab = gBrowser.addTab();
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("PluginBindingAttached", pluginBindingAttached, true, true);
var gHttpTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
gTestBrowser.contentWindow.location = gHttpTestRoot + "plugin_bug744745.html";
}
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gTestBrowser = null;
let gNumPluginBindingsAttached = 0;
function pluginBindingAttached() {
gNumPluginBindingsAttached++;
if (gNumPluginBindingsAttached == 1) {
var doc = gTestBrowser.contentDocument;
var testplugin = doc.getElementById("test");
ok(testplugin, "should have test plugin");
var style = getComputedStyle(testplugin);
ok('opacity' in style, "style should have opacity set");
is(style.opacity, 1, "opacity should be 1");
finish();
} else {
if (gNumPluginBindingsAttached != 1) {
ok(false, "if we've gotten here, something is quite wrong");
}
}
add_task(function* () {
registerCleanupFunction(function () {
gTestBrowser.removeEventListener("PluginBindingAttached", pluginBindingAttached, true, true);
clearAllPluginPermissions();
Services.prefs.clearUserPref("plugins.click_to_play");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
});
add_task(function* () {
gBrowser.selectedTab = gBrowser.addTab();
gTestBrowser = gBrowser.selectedBrowser;
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
gTestBrowser.addEventListener("PluginBindingAttached", pluginBindingAttached, true, true);
let testRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
yield promiseTabLoadEvent(gBrowser.selectedTab, testRoot + "plugin_bug744745.html");
yield promiseForCondition(function () { return gNumPluginBindingsAttached == 1; });
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
if (!plugin) {
return false;
}
// We can't use MochiKit's routine
let style = content.getComputedStyle(plugin);
return 'opacity' in style && style.opacity == 1;
});
ok(result, true, "plugin style properly configured.");
});

Просмотреть файл

@ -1,49 +1,65 @@
const gHttpTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gTestBrowser = null;
let gWrapperClickCount = 0;
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
add_task(function* () {
registerCleanupFunction(function () {
clearAllPluginPermissions();
Services.prefs.clearUserPref("plugins.click_to_play");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
});
add_task(function* () {
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
gBrowser.selectedTab = gBrowser.addTab();
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
gTestBrowser.contentWindow.location = gHttpTestRoot + "plugin_bug787619.html";
}
function pageLoad() {
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
let testRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
yield promiseTabLoadEvent(gBrowser.selectedTab, testRoot + "plugin_bug787619.html");
// Due to layout being async, "PluginBindAttached" may trigger later.
// This forces a layout flush, thus triggering it, and schedules the
// test so it is definitely executed afterwards.
gTestBrowser.contentDocument.getElementById('plugin').clientTop;
executeSoon(part1);
}
yield promiseUpdatePluginBindings(gTestBrowser);
function part1() {
let wrapper = gTestBrowser.contentDocument.getElementById('wrapper');
wrapper.addEventListener('click', function() ++gWrapperClickCount, false);
// check plugin state
let pluginInfo = yield promiseForPluginInfo("plugin");
ok(!pluginInfo.activated, "1a plugin should not be activated");
let plugin = gTestBrowser.contentDocument.getElementById('plugin');
ok(plugin, 'got plugin element');
ok(!plugin.activated, 'plugin should not be activated');
ok(PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed, "Doorhanger should not be open");
// click the overlay to prompt
let promise = promisePopupNotification("click-to-play-plugins");
yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementById("plugin");
let bounds = plugin.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
});
yield promise;
EventUtils.synthesizeMouseAtCenter(plugin, {}, gTestBrowser.contentWindow);
let condition = function() !PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed;
waitForCondition(condition, part2,
'waited too long for plugin to activate');
}
// check plugin state
pluginInfo = yield promiseForPluginInfo("plugin");
ok(!pluginInfo.activated, "1b plugin should not be activated");
let condition = function() !PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed &&
PopupNotifications.panel.firstChild;
yield promiseForCondition(condition);
PopupNotifications.panel.firstChild._primaryButton.click();
// check plugin state
pluginInfo = yield promiseForPluginInfo("plugin");
ok(pluginInfo.activated, "plugin should be activated");
function part2() {
is(gWrapperClickCount, 0, 'wrapper should not have received any clicks');
gTestBrowser.removeEventListener("load", pageLoad, true);
gBrowser.removeCurrentTab();
window.focus();
finish();
}
});

Просмотреть файл

@ -1,47 +1,45 @@
/* 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/. */
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gTestBrowser = null;
let gConsoleErrors = 0;
var rootDir = getRootDirectory(gTestPath);
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
const Cc = Components.classes;
const Ci = Components.interfaces;
var gTestBrowser = null;
var gConsoleErrors = 0;
function test() {
waitForExplicitFinish();
var newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
add_task(function* () {
registerCleanupFunction(function () {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
consoleService.unregisterListener(errorListener);
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
gBrowser.selectedTab = gBrowser.addTab();
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("PluginBindingAttached", pluginBindingAttached, true, true);
var consoleService = Cc["@mozilla.org/consoleservice;1"]
let bindingPromise = waitForEvent(gTestBrowser, "PluginBindingAttached", null, true, true);
let consoleService = Cc["@mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService);
var errorListener = {
let errorListener = {
observe: function(aMessage) {
if (aMessage.message.includes("NS_ERROR"))
if (aMessage.message.includes("NS_ERROR_FAILURE"))
gConsoleErrors++;
}
};
consoleService.registerListener(errorListener);
registerCleanupFunction(function() {
gTestBrowser.removeEventListener("PluginBindingAttached", pluginBindingAttached, true);
consoleService.unregisterListener(errorListener);
gBrowser.removeCurrentTab();
window.focus();
});
gTestBrowser.contentWindow.location = gHttpTestRoot + "plugin_bug797677.html";
}
function pluginBindingAttached() {
// Let browser-plugins.js handle the PluginNotFound event, then run the test
executeSoon(runTest);
}
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_bug797677.html");
function runTest() {
var doc = gTestBrowser.contentDocument;
var plugin = doc.getElementById("plugin");
yield bindingPromise;
let pluginInfo = yield promiseForPluginInfo("plugin");
is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_UNSUPPORTED, "plugin should not have been found.");
// simple cpows
let plugin = gTestBrowser.contentDocument.getElementById("plugin");
ok(plugin, "plugin should be in the page");
is(gConsoleErrors, 0, "should have no console errors");
finish();
}
});

Просмотреть файл

@ -1,93 +1,80 @@
var gHttpTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
var gTestBrowser = null;
var gNextTest = null;
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gTestBrowser = null;
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
Services.prefs.clearUserPref("plugins.click_to_play");
});
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
var newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
setAndUpdateBlocklist(gHttpTestRoot + "blockPluginVulnerableUpdatable.xml",
function() {
prepareTest(function() {
// Due to layout being async, "PluginBindAttached" may trigger later.
// This forces a layout flush, thus triggering it, and schedules the
// test so it is definitely executed afterwards.
gTestBrowser.contentDocument.getElementById('test').clientTop;
testPart1();
},
gHttpTestRoot + "plugin_test.html");
});
}
function finishTest() {
gTestBrowser.removeEventListener("load", pageLoad, true);
gBrowser.removeCurrentTab();
window.focus();
setAndUpdateBlocklist(gHttpTestRoot + "blockNoPlugins.xml",
function() {
add_task(function* () {
registerCleanupFunction(Task.async(function*() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
resetBlocklist();
finish();
});
}
Services.prefs.clearUserPref("plugins.click_to_play");
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
}));
gBrowser.selectedTab = gBrowser.addTab();
gTestBrowser = gBrowser.selectedBrowser;
function pageLoad(aEvent) {
// The plugin events are async dispatched and can come after the load event
// This just allows the events to fire before we then go on to test the states
if (gNextTest != null)
executeSoon(gNextTest);
}
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
function prepareTest(nextTest, url) {
gNextTest = nextTest;
gTestBrowser.contentWindow.location = url;
}
// Prime the blocklist service, the remote service doesn't launch on startup.
yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html></html>");
let exmsg = yield promiseInitContentBlocklistSvc(gBrowser.selectedBrowser);
ok(!exmsg, "exception: " + exmsg);
});
// Tests that the going back will reshow the notification for click-to-play
// blocklisted plugins (part 1/4)
function testPart1() {
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
// blocklisted plugins
add_task(function* () {
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginVulnerableUpdatable.xml", gTestBrowser);
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(popupNotification, "test part 1: Should have a click-to-play notification");
var plugin = gTestBrowser.contentDocument.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE, "test part 1: plugin fallback type should be PLUGIN_VULNERABLE_UPDATABLE");
ok(!objLoadingContent.activated, "test part 1: plugin should not be activated");
prepareTest(testPart2, "about:blank");
}
let pluginInfo = yield promiseForPluginInfo("test");
is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE, "plugin should be marked as VULNERABLE");
function testPart2() {
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
let found = yield ContentTask.spawn(gTestBrowser, {}, function* () {
return !!content.document.getElementById("test");
});
ok(found, "test part 1: plugin should not be activated");
yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html></html>");
});
add_task(function* () {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(!popupNotification, "test part 2: Should not have a click-to-play notification");
var plugin = gTestBrowser.contentDocument.getElementById("test");
ok(!plugin, "test part 2: Should not have a plugin in this page");
let found = yield ContentTask.spawn(gTestBrowser, {}, function* () {
return !!content.document.getElementById("test");
});
ok(!found, "test part 2: plugin should not be activated");
Services.obs.addObserver(testPart3, "PopupNotifications-updateNotShowing", false);
let obsPromise = TestUtils.topicObserved("PopupNotifications-updateNotShowing");
let overlayPromise = promisePopupNotification("click-to-play-plugins");
gTestBrowser.contentWindow.history.back();
}
yield obsPromise;
yield overlayPromise;
});
function testPart3() {
Services.obs.removeObserver(testPart3, "PopupNotifications-updateNotShowing");
var condition = function() PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
waitForCondition(condition, testPart4, "test part 3: waited too long for click-to-play-plugin notification");
}
add_task(function* () {
yield promiseUpdatePluginBindings(gTestBrowser);
function testPart4() {
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(popupNotification, "test part 4: Should have a click-to-play notification");
var plugin = gTestBrowser.contentDocument.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE, "test part 4: plugin fallback type should be PLUGIN_VULNERABLE_UPDATABLE");
ok(!objLoadingContent.activated, "test part 4: plugin should not be activated");
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(popupNotification, "test part 3: Should have a click-to-play notification");
finishTest();
}
let pluginInfo = yield promiseForPluginInfo("test");
is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE, "plugin should be marked as VULNERABLE");
let found = yield ContentTask.spawn(gTestBrowser, {}, function* () {
return !!content.document.getElementById("test");
});
ok(found, "test part 3: plugin should not be activated");
});

Просмотреть файл

@ -1,45 +1,38 @@
var gHttpTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
var gTestBrowser = null;
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gTestBrowser = null;
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
add_task(function* () {
registerCleanupFunction(function () {
clearAllPluginPermissions();
Services.prefs.clearUserPref("plugins.click_to_play");
gTestBrowser.removeEventListener("load", pageLoad, true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
});
add_task(function* () {
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
gBrowser.selectedTab = gBrowser.addTab();
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
gTestBrowser.contentWindow.location = gHttpTestRoot + "plugin_both.html";
}
function pageLoad(aEvent) {
// Due to layout being async, "PluginBindAttached" may trigger later.
// This forces a layout flush, thus triggering it, and schedules the
// test so it is definitely executed afterwards.
gTestBrowser.contentDocument.getElementById('test').clientTop;
executeSoon(actualTest);
}
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
function actualTest() {
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_both.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(popupNotification, "should have a click-to-play notification");
var plugin = gTestBrowser.contentDocument.getElementById("test");
ok(plugin, "should have known plugin in page");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY, "plugin fallback type should be PLUGIN_CLICK_TO_PLAY");
ok(!objLoadingContent.activated, "plugin should not be activated");
var unknown = gTestBrowser.contentDocument.getElementById("unknown");
let pluginInfo = yield promiseForPluginInfo("test");
is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY, "plugin should be click to play");
ok(!pluginInfo.activated, "plugin should not be activated");
let unknown = gTestBrowser.contentDocument.getElementById("unknown");
ok(unknown, "should have unknown plugin in page");
gBrowser.removeCurrentTab();
window.focus();
finish();
}
});

Просмотреть файл

@ -1,61 +1,73 @@
/* 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/. */
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gTestBrowser = null;
let gNumPluginBindingsAttached = 0;
var gTestBrowser = null;
var gNumPluginBindingsAttached = 0;
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
add_task(function* () {
registerCleanupFunction(function () {
clearAllPluginPermissions();
Services.prefs.clearUserPref("plugins.click_to_play");
gTestBrowser.removeEventListener("PluginBindingAttached", pluginBindingAttached, true, true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
});
add_task(function* () {
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
gBrowser.selectedTab = gBrowser.addTab();
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("PluginBindingAttached", pluginBindingAttached, true, true);
var gHttpTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
gTestBrowser.contentWindow.location = gHttpTestRoot + "plugin_bug820497.html";
}
function pluginBindingAttached() {
gNumPluginBindingsAttached++;
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
if (gNumPluginBindingsAttached == 1) {
var doc = gTestBrowser.contentDocument;
var testplugin = doc.getElementById("test");
gTestBrowser.addEventListener("PluginBindingAttached", function () { gNumPluginBindingsAttached++ }, true, true);
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_bug820497.html");
yield promiseForCondition(function () { return gNumPluginBindingsAttached == 1; });
// cpows
{
// Note we add the second plugin in the code farther down, so there's
// no way we got here with anything but one plugin loaded.
let doc = gTestBrowser.contentDocument;
let testplugin = doc.getElementById("test");
ok(testplugin, "should have test plugin");
var secondtestplugin = doc.getElementById("secondtest");
let secondtestplugin = doc.getElementById("secondtest");
ok(!secondtestplugin, "should not yet have second test plugin");
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");
ok(testplugin, "should have test plugin");
var secondtestplugin = doc.getElementById("secondtest");
ok(secondtestplugin, "should have second test plugin");
var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "should have popup notification");
notification.reshow();
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");
}
}
yield promisePopupNotification("click-to-play-plugins");
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "should have a click-to-play notification");
yield promiseForNotificationShown(notification);
is(notification.options.pluginData.size, 1, "should be 1 type of plugin in the popup notification");
yield ContentTask.spawn(gTestBrowser, {}, function* () {
XPCNativeWrapper.unwrap(content).addSecondPlugin();
});
yield promiseForCondition(function () { return gNumPluginBindingsAttached == 2; });
// cpows
{
let doc = gTestBrowser.contentDocument;
let testplugin = doc.getElementById("test");
ok(testplugin, "should have test plugin");
let secondtestplugin = doc.getElementById("secondtest");
ok(secondtestplugin, "should have second test plugin");
}
notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "should have popup notification");
yield promiseForNotificationShown(notification);
is(notification.options.pluginData.size, 2, "aited too long for 2 types of plugins in popup notification");
});

Просмотреть файл

@ -21,8 +21,6 @@
"baz.com:1:5," +
"qux.com:1:100"
);
setTimeout(testFinishedCallback, 0);
}
</script>
</head>

Просмотреть файл

@ -1,50 +1,63 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var rootDir = getRootDirectory(gTestPath);
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://mochi.test:8888/");
var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
var gTestBrowser = null;
// Test clearing plugin data using sanitize.js.
const testURL1 = gHttpTestRoot + "browser_clearplugindata.html";
const testURL2 = gHttpTestRoot + "browser_clearplugindata_noage.html";
const testURL1 = gTestRoot + "browser_clearplugindata.html";
const testURL2 = gTestRoot + "browser_clearplugindata_noage.html";
let tempScope = {};
var tempScope = {};
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
.loadSubScript("chrome://browser/content/sanitize.js", tempScope);
let Sanitizer = tempScope.Sanitizer;
var Sanitizer = tempScope.Sanitizer;
const pluginHostIface = Ci.nsIPluginHost;
var pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
pluginHost.QueryInterface(pluginHostIface);
var pluginTag = getTestPlugin();
var s;
var sanitizer = null;
function stored(needles) {
var something = pluginHost.siteHasData(this.pluginTag, null);
let something = pluginHost.siteHasData(this.pluginTag, null);
if (!needles)
return something;
if (!something)
return false;
for (var i = 0; i < needles.length; ++i) {
for (let i = 0; i < needles.length; ++i) {
if (!pluginHost.siteHasData(this.pluginTag, needles[i]))
return false;
}
return true;
}
function test() {
waitForExplicitFinish();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
add_task(function* () {
registerCleanupFunction(function () {
clearAllPluginPermissions();
Services.prefs.clearUserPref("plugins.click_to_play");
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
if (gTestBrowser) {
gBrowser.removeCurrentTab();
}
window.focus();
gTestBrowser = null;
});
});
s = new Sanitizer();
s.ignoreTimespan = false;
s.prefDomain = "privacy.cpd.";
var itemPrefs = gPrefService.getBranch(s.prefDomain);
add_task(function* () {
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
sanitizer = new Sanitizer();
sanitizer.ignoreTimespan = false;
sanitizer.prefDomain = "privacy.cpd.";
let itemPrefs = gPrefService.getBranch(sanitizer.prefDomain);
itemPrefs.setBoolPref("history", false);
itemPrefs.setBoolPref("downloads", false);
itemPrefs.setBoolPref("cache", false);
@ -54,80 +67,61 @@ function test() {
itemPrefs.setBoolPref("passwords", false);
itemPrefs.setBoolPref("sessions", false);
itemPrefs.setBoolPref("siteSettings", false);
});
executeSoon(test_with_age);
}
function setFinishedCallback(callback)
{
let testPage = gBrowser.selectedBrowser.contentWindow.wrappedJSObject;
testPage.testFinishedCallback = function() {
setTimeout(function() {
info("got finished callback");
callback();
}, 0);
}
}
function test_with_age()
{
add_task(function* () {
// Load page to set data for the plugin.
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function () {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
gTestBrowser = gBrowser.selectedBrowser;
setFinishedCallback(function() {
ok(stored(["foo.com","bar.com","baz.com","qux.com"]),
"Data stored for sites");
yield promiseTabLoadEvent(gBrowser.selectedTab, testURL1);
// Clear 20 seconds ago
var now_uSec = Date.now() * 1000;
s.range = [now_uSec - 20*1000000, now_uSec];
s.sanitize();
yield promiseUpdatePluginBindings(gTestBrowser);
ok(stored(["bar.com","qux.com"]), "Data stored for sites");
ok(!stored(["foo.com"]), "Data cleared for foo.com");
ok(!stored(["baz.com"]), "Data cleared for baz.com");
ok(stored(["foo.com","bar.com","baz.com","qux.com"]),
"Data stored for sites");
// Clear everything
s.range = null;
s.sanitize();
// Clear 20 seconds ago
let now_uSec = Date.now() * 1000;
sanitizer.range = [now_uSec - 20*1000000, now_uSec];
sanitizer.sanitize();
ok(!stored(null), "All data cleared");
ok(stored(["bar.com","qux.com"]), "Data stored for sites");
ok(!stored(["foo.com"]), "Data cleared for foo.com");
ok(!stored(["baz.com"]), "Data cleared for baz.com");
gBrowser.removeCurrentTab();
// Clear everything
sanitizer.range = null;
sanitizer.sanitize();
executeSoon(test_without_age);
});
}, true);
content.location = testURL1;
}
ok(!stored(null), "All data cleared");
function test_without_age()
{
gBrowser.removeCurrentTab();
gTestBrowser = null;
});
add_task(function* () {
// Load page to set data for the plugin.
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function () {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
gTestBrowser = gBrowser.selectedBrowser;
setFinishedCallback(function() {
ok(stored(["foo.com","bar.com","baz.com","qux.com"]),
"Data stored for sites");
yield promiseTabLoadEvent(gBrowser.selectedTab, testURL2);
// Attempt to clear 20 seconds ago. The plugin will throw
// NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED, which should result in us
// clearing all data regardless of age.
var now_uSec = Date.now() * 1000;
s.range = [now_uSec - 20*1000000, now_uSec];
s.sanitize();
yield promiseUpdatePluginBindings(gTestBrowser);
ok(!stored(null), "All data cleared");
ok(stored(["foo.com","bar.com","baz.com","qux.com"]),
"Data stored for sites");
gBrowser.removeCurrentTab();
// Attempt to clear 20 seconds ago. The plugin will throw
// NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED, which should result in us
// clearing all data regardless of age.
let now_uSec = Date.now() * 1000;
sanitizer.range = [now_uSec - 20*1000000, now_uSec];
sanitizer.sanitize();
executeSoon(finish);
});
}, true);
content.location = testURL2;
}
ok(!stored(null), "All data cleared");
gBrowser.removeCurrentTab();
gTestBrowser = null;
});

Просмотреть файл

@ -21,8 +21,6 @@
"baz.com:1:5," +
"qux.com:1:100"
);
setTimeout(testFinishedCallback, 0);
}
</script>
</head>

Просмотреть файл

@ -1,7 +1,3 @@
/* 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/. */
/**
* Test that plugin crash submissions still work properly after
* click-to-play activation.

Просмотреть файл

@ -1,9 +1,4 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Cu.import("resource://gre/modules/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";

Просмотреть файл

@ -0,0 +1,77 @@
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
let gTestBrowser = null;
add_task(function* () {
registerCleanupFunction(function () {
clearAllPluginPermissions();
Services.prefs.clearUserPref("plugins.click_to_play");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
gTestBrowser = null;
gBrowser.removeCurrentTab();
window.focus();
});
});
add_task(function* () {
gBrowser.selectedTab = gBrowser.addTab();
gTestBrowser = gBrowser.selectedBrowser;
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_DISABLED, "Test Plug-in");
// Prime the blocklist service, the remote service doesn't launch on startup.
yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html></html>");
let exmsg = yield promiseInitContentBlocklistSvc(gBrowser.selectedBrowser);
ok(!exmsg, "exception: " + exmsg);
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
});
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
yield promiseUpdatePluginBindings(gTestBrowser);
let pluginInfo = yield promiseForPluginInfo("test");
is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_DISABLED,
"Test 1a, plugin fallback type should be PLUGIN_DISABLED");
// This test opens a new tab to about:addons
let promise = waitForEvent(gBrowser.tabContainer, "TabOpen", null, true);
let success = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let pluginNode = content.document.getElementById("test");
let manageLink = content.document.getAnonymousElementByAttribute(pluginNode, "anonid", "managePluginsLink");
let bounds = manageLink.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
return true;
});
ok(success, "click on manage link");
yield promise;
promise = waitForEvent(gBrowser.tabContainer, "TabClose", null, true);
// in-process page, no cpows here
let condition = function() {
let win = gBrowser.selectedBrowser.contentWindow;
if (!!win && !!win.wrappedJSObject && !!win.wrappedJSObject.gViewController) {
return win.wrappedJSObject.gViewController.currentViewId == "addons://list/plugin";
}
return false;
}
yield promiseForCondition(condition, "Waited too long for about:addons to display.", 40, 500);
// remove the tab containing about:addons
gBrowser.removeCurrentTab();
yield promise;
});

Просмотреть файл

@ -0,0 +1,85 @@
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
let gTestBrowser = null;
function updateAllTestPlugins(aState) {
setTestPluginEnabledState(aState, "Test Plug-in");
setTestPluginEnabledState(aState, "Second Test Plug-in");
}
add_task(function* () {
registerCleanupFunction(Task.async(function*() {
clearAllPluginPermissions();
Services.prefs.clearUserPref("plugins.click_to_play");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
resetBlocklist();
gTestBrowser = null;
gBrowser.removeCurrentTab();
window.focus();
}));
});
add_task(function* () {
gBrowser.selectedTab = gBrowser.addTab();
gTestBrowser = gBrowser.selectedBrowser;
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
Services.prefs.setBoolPref("plugins.click_to_play", true);
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
// Prime the blocklist service, the remote service doesn't launch on startup.
yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html></html>");
let exmsg = yield promiseInitContentBlocklistSvc(gBrowser.selectedBrowser);
ok(!exmsg, "exception: " + exmsg);
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
});
// Tests that a click-to-play plugin retains its activated state upon reloading
add_task(function* () {
clearAllPluginPermissions();
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
// Work around for delayed PluginBindingAttached
yield promiseUpdatePluginBindings(gTestBrowser);
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 1, Should have a click-to-play notification");
let pluginInfo = yield promiseForPluginInfo("test");
is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
"Test 2, plugin fallback type should be PLUGIN_CLICK_TO_PLAY");
// run the plugin
yield promisePlayObject("test");
yield promiseUpdatePluginBindings(gTestBrowser);
pluginInfo = yield promiseForPluginInfo("test");
is(pluginInfo.displayedType, Ci.nsIObjectLoadingContent.TYPE_PLUGIN, "Test 3, plugin should have started");
ok(pluginInfo.activated, "Test 4, plugin node should not be activated");
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
let plugin = content.document.getElementById("test");
let npobj1 = Components.utils.waiveXrays(plugin).getObjectValue();
plugin.src = plugin.src;
let pluginsDiffer = false;
try {
Components.utils.waiveXrays(plugin).checkObjectValue(npobj1);
} catch (e) {
pluginsDiffer = true;
}
return pluginsDiffer;
});
ok(result, "Test 5, plugins differ.");
pluginInfo = yield promiseForPluginInfo("test");
ok(pluginInfo.activated, "Test 6, Plugin should have retained activated state.");
is(pluginInfo.displayedType, Ci.nsIObjectLoadingContent.TYPE_PLUGIN, "Test 7, plugin should have started");
});

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,7 +1,3 @@
/* 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/. */
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;

Просмотреть файл

@ -1,7 +1,3 @@
/* 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/. */
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;

Просмотреть файл

@ -1,7 +1,3 @@
/* 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/. */
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;

Просмотреть файл

@ -1,178 +1,137 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://mochi.test:8888/");
let gTestBrowser = null;
let gNextTest = null;
let gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
Components.utils.import("resource://gre/modules/Services.jsm");
let gTestBrowser = null;
// Let's do the XPCNativeWrapper dance!
function addPlugin(browser, type) {
let contentWindow = XPCNativeWrapper.unwrap(browser.contentWindow);
contentWindow.addPlugin(type);
}
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
add_task(function* () {
registerCleanupFunction(Task.async(function*() {
clearAllPluginPermissions();
Services.prefs.clearUserPref("plugins.click_to_play");
});
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
let newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
prepareTest(testActivateAddSameTypePart1, gTestRoot + "plugin_add_dynamically.html");
}
function finishTest() {
gTestBrowser.removeEventListener("load", pageLoad, true);
gBrowser.removeCurrentTab();
window.focus();
finish();
}
function pageLoad() {
// The plugin events are async dispatched and can come after the load event
// This just allows the events to fire before we then go on to test the states
executeSoon(gNextTest);
}
function prepareTest(nextTest, url) {
gNextTest = nextTest;
gTestBrowser.contentWindow.location = url;
}
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
resetBlocklist();
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
}));
});
// "Activate" of a given type -> plugins of that type dynamically added should
// automatically play.
function testActivateAddSameTypePart1() {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(!popupNotification, "testActivateAddSameTypePart1: should not have a click-to-play notification");
addPlugin(gTestBrowser);
let condition = function() PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
waitForCondition(condition, testActivateAddSameTypePart2, "testActivateAddSameTypePart1: waited too long for click-to-play-plugin notification");
}
add_task(function* () {
let newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
function testActivateAddSameTypePart2() {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(popupNotification, "testActivateAddSameTypePart2: should have a click-to-play notification");
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
Services.prefs.setBoolPref("plugins.click_to_play", true);
popupNotification.reshow();
testActivateAddSameTypePart3();
}
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
});
add_task(function* () {
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_add_dynamically.html");
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(!notification, "Test 1a, Should not have a click-to-play notification");
// Add a plugin of type test
yield ContentTask.spawn(gTestBrowser, {}, function* () {
new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin("pluginone", "application/x-test"));
});
yield promisePopupNotification("click-to-play-plugins");
notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 1a, Should not have a click-to-play notification");
yield promiseForNotificationShown(notification);
function testActivateAddSameTypePart3() {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
let centerAction = null;
for (let action of popupNotification.options.pluginData.values()) {
for (let action of notification.options.pluginData.values()) {
if (action.pluginName == "Test") {
centerAction = action;
break;
}
}
ok(centerAction, "testActivateAddSameTypePart3: found center action for the Test plugin");
ok(centerAction, "Test 2, found center action for the Test plugin");
let centerItem = null;
for (let item of PopupNotifications.panel.firstChild.childNodes) {
if (item.action && item.action == centerAction) {
is(item.value, "block", "Test 3, all plugins should start out blocked");
if (item.action == centerAction) {
centerItem = item;
break;
}
}
ok(centerItem, "testActivateAddSameTypePart3: found center item for the Test plugin");
ok(centerItem, "Test 4, found center item for the Test plugin");
let plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[0];
ok(!plugin.activated, "testActivateAddSameTypePart3: plugin should not be activated");
// Change the state and click the ok button to activate the Test plugin
// Select the allow now option in the select drop down for Test Plugin
centerItem.value = "allownow";
PopupNotifications.panel.firstChild._primaryButton.click();
let condition = function() plugin.activated;
waitForCondition(condition, testActivateAddSameTypePart4, "testActivateAddSameTypePart3: waited too long for plugin to activate");
}
function testActivateAddSameTypePart4() {
let plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[0];
ok(plugin.activated, "testActivateAddSameTypePart4: plugin should be activated");
addPlugin(gTestBrowser);
let condition = function() {
let embeds = gTestBrowser.contentDocument.getElementsByTagName("embed");
let allActivated = true;
for (let embed of embeds) {
if (!embed.activated)
allActivated = false;
}
return allActivated && embeds.length == 2;
};
waitForCondition(condition, testActivateAddSameTypePart5, "testActivateAddSameTypePart4: waited too long for second plugin to activate"); }
function testActivateAddSameTypePart5() {
let embeds = gTestBrowser.contentDocument.getElementsByTagName("embed");
for (let embed of embeds) {
ok(embed.activated, "testActivateAddSameTypePart5: all plugins should be activated");
}
clearAllPluginPermissions();
prepareTest(testActivateAddDifferentTypePart1, gTestRoot + "plugin_add_dynamically.html");
}
// "Activate" of a given type -> plugins of other types dynamically added
// should not automatically play.
function testActivateAddDifferentTypePart1() {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(!popupNotification, "testActivateAddDifferentTypePart1: should not have a click-to-play notification");
addPlugin(gTestBrowser);
let condition = function() PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
waitForCondition(condition, testActivateAddDifferentTypePart2, "testActivateAddDifferentTypePart1: waited too long for click-to-play-plugin notification");
}
function testActivateAddDifferentTypePart2() {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(popupNotification, "testActivateAddDifferentTypePart2: should have a click-to-play notification");
// we have to actually show the panel to get the bindings to instantiate
popupNotification.reshow();
testActivateAddDifferentTypePart3();
}
function testActivateAddDifferentTypePart3() {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
is(popupNotification.options.pluginData.size, 1, "Should be one plugin action");
let plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[0];
ok(!plugin.activated, "testActivateAddDifferentTypePart3: plugin should not be activated");
// "click" the button to activate the Test plugin
PopupNotifications.panel.firstChild._primaryButton.click();
let condition = function() plugin.activated;
waitForCondition(condition, testActivateAddDifferentTypePart4, "testActivateAddDifferentTypePart3: waited too long for plugin to activate");
}
let pluginInfo = yield promiseForPluginInfo("pluginone");
ok(pluginInfo.activated, "Test 5, plugin should be activated");
function testActivateAddDifferentTypePart4() {
let plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[0];
ok(plugin.activated, "testActivateAddDifferentTypePart4: plugin should be activated");
// Add another plugin of type test
yield ContentTask.spawn(gTestBrowser, {}, function* () {
new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin("plugintwo", "application/x-test"));
});
addPlugin(gTestBrowser);
let condition = function() PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
waitForCondition(condition, testActivateAddDifferentTypePart5, "testActivateAddDifferentTypePart5: waited too long for popup notification");
}
pluginInfo = yield promiseForPluginInfo("plugintwo");
ok(pluginInfo.activated, "Test 6, plugins should be activated");
});
function testActivateAddDifferentTypePart5() {
ok(PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser), "testActivateAddDifferentTypePart5: should have popup notification");
let embeds = gTestBrowser.contentDocument.getElementsByTagName("embed");
for (let embed of embeds) {
if (embed.type == "application/x-test")
ok(embed.activated, "testActivateAddDifferentTypePart5: Test plugin should be activated");
else if (embed.type == "application/x-second-test")
ok(!embed.activated, "testActivateAddDifferentTypePart5: Second Test plugin should not be activated");
}
// "Activate" of a given type -> plugins of other types dynamically added
// should not automatically play.
add_task(function* () {
clearAllPluginPermissions();
finishTest();
}
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_add_dynamically.html");
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(!notification, "Test 7, Should not have a click-to-play notification");
// Add a plugin of type test
yield ContentTask.spawn(gTestBrowser, {}, function* () {
new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin("pluginone", "application/x-test"));
});
yield promisePopupNotification("click-to-play-plugins");
notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 8, Should not have a click-to-play notification");
yield promiseForNotificationShown(notification);
is(notification.options.pluginData.size, 1, "Should be one plugin action");
let pluginInfo = yield promiseForPluginInfo("pluginone");
ok(!pluginInfo.activated, "Test 8, test plugin should be activated");
let condition = function() !notification.dismissed &&
PopupNotifications.panel.firstChild;
yield promiseForCondition(condition);
// "click" the button to activate the Test plugin
PopupNotifications.panel.firstChild._primaryButton.click();
pluginInfo = yield promiseForPluginInfo("pluginone");
ok(pluginInfo.activated, "Test 9, test plugin should be activated");
yield ContentTask.spawn(gTestBrowser, {}, function* () {
new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin("plugintwo", "application/x-second-test"));
});
yield promisePopupNotification("click-to-play-plugins");
pluginInfo = yield promiseForPluginInfo("pluginone");
ok(pluginInfo.activated, "Test 10, plugins should be activated");
pluginInfo = yield promiseForPluginInfo("plugintwo");
ok(!pluginInfo.activated, "Test 11, plugins should be activated");
});

Просмотреть файл

@ -7,33 +7,122 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
function whenDelayedStartupFinished(aWindow, aCallback) {
Services.obs.addObserver(function observer(aSubject, aTopic) {
if (aWindow == aSubject) {
Services.obs.removeObserver(observer, aTopic);
executeSoon(aCallback);
// The blocklist shim running in the content process does not initialize at
// start up, so it's not active until we load content that needs to do a
// check. This helper bypasses the delay to get the svc up and running
// immediately. Note, call this after remote content has loaded.
function promiseInitContentBlocklistSvc(aBrowser)
{
return ContentTask.spawn(aBrowser, {}, function* () {
try {
let bls = Cc["@mozilla.org/extensions/blocklist;1"]
.getService(Ci.nsIBlocklistService);
} catch (ex) {
return ex.message;
}
}, "browser-delayed-startup-finished", false);
return null;
});
}
function findChromeWindowByURI(aURI) {
let windows = Services.wm.getEnumerator(null);
while (windows.hasMoreElements()) {
let win = windows.getNext();
if (win.location.href == aURI)
return win;
/**
* Waits a specified number of miliseconds.
*
* Usage:
* let wait = yield waitForMs(2000);
* ok(wait, "2 seconds should now have elapsed");
*
* @param aMs the number of miliseconds to wait for
* @returns a Promise that resolves to true after the time has elapsed
*/
function waitForMs(aMs) {
let deferred = Promise.defer();
let startTime = Date.now();
setTimeout(done, aMs);
function done() {
deferred.resolve(true);
}
return null;
return deferred.promise;
}
function waitForCondition(condition, nextTest, errorMsg) {
var tries = 0;
var interval = setInterval(function() {
if (tries >= 30) {
// DOM Promise fails for unknown reasons here, so we're using
// resource://gre/modules/Promise.jsm.
function waitForEvent(subject, eventName, checkFn, useCapture, useUntrusted) {
return new Promise((resolve, reject) => {
subject.addEventListener(eventName, function listener(event) {
try {
if (checkFn && !checkFn(event)) {
return;
}
subject.removeEventListener(eventName, listener, useCapture);
resolve(event);
} catch (ex) {
try {
subject.removeEventListener(eventName, listener, useCapture);
} catch (ex2) {
// Maybe the provided object does not support removeEventListener.
}
reject(ex);
}
}, useCapture, useUntrusted);
});
}
/**
* Waits for a load (or custom) event to finish in a given tab. If provided
* load an uri into the tab.
*
* @param tab
* The tab to load into.
* @param [optional] url
* The url to load, or the current url.
* @param [optional] event
* The load event type to wait for. Defaults to "load".
* @return {Promise} resolved when the event is handled.
* @resolves to the received event
* @rejects if a valid load event is not received within a meaningful interval
*/
function promiseTabLoadEvent(tab, url, eventType="load") {
let deferred = Promise.defer();
info("Wait tab event: " + eventType);
function handle(event) {
if (event.originalTarget != tab.linkedBrowser.contentDocument ||
event.target.location.href == "about:blank" ||
(url && event.target.location.href != url)) {
info("Skipping spurious '" + eventType + "'' event" +
" for " + event.target.location.href);
return;
}
clearTimeout(timeout);
tab.linkedBrowser.removeEventListener(eventType, handle, true);
info("Tab event received: " + eventType);
deferred.resolve(event);
}
let timeout = setTimeout(() => {
tab.linkedBrowser.removeEventListener(eventType, handle, true);
deferred.reject(new Error("Timed out while waiting for a '" + eventType + "'' event"));
}, 30000);
tab.linkedBrowser.addEventListener(eventType, handle, true, true);
if (url) {
tab.linkedBrowser.loadURI(url);
}
return deferred.promise;
}
function waitForCondition(condition, nextTest, errorMsg, aTries, aWait) {
let tries = 0;
let maxTries = aTries || 100; // 100 tries
let maxWait = aWait || 100; // 100 msec x 100 tries = ten seconds
let interval = setInterval(function() {
if (tries >= maxTries) {
ok(false, errorMsg);
moveOn();
}
var conditionPassed;
let conditionPassed;
try {
conditionPassed = condition();
} catch (e) {
@ -44,17 +133,27 @@ function waitForCondition(condition, nextTest, errorMsg) {
moveOn();
}
tries++;
}, 100);
var moveOn = function() { clearInterval(interval); nextTest(); };
}, maxWait);
let moveOn = function() { clearInterval(interval); nextTest(); };
}
// Waits for a conditional function defined by the caller to return true.
function promiseForCondition(aConditionFn, aMessage, aTries, aWait) {
let deferred = Promise.defer();
waitForCondition(aConditionFn, deferred.resolve,
(aMessage || "Condition didn't pass."),
aTries, aWait);
return deferred.promise;
}
// Returns the chrome side nsIPluginTag for this plugin
function getTestPlugin(aName) {
var pluginName = aName || "Test Plug-in";
var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
var tags = ph.getPluginTags();
let pluginName = aName || "Test Plug-in";
let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
let tags = ph.getPluginTags();
// Find the test plugin
for (var i = 0; i < tags.length; i++) {
for (let i = 0; i < tags.length; i++) {
if (tags[i].name == pluginName)
return tags[i];
}
@ -62,15 +161,73 @@ function getTestPlugin(aName) {
return null;
}
// call this to set the test plugin(s) initially expected enabled state.
// it will automatically be reset to it's previous value after the test
// ends
// Set the 'enabledState' on the nsIPluginTag stored in the main or chrome
// process.
function setTestPluginEnabledState(newEnabledState, pluginName) {
var plugin = getTestPlugin(pluginName);
var oldEnabledState = plugin.enabledState;
let name = pluginName || "Test Plug-in";
let plugin = getTestPlugin(name);
plugin.enabledState = newEnabledState;
SimpleTest.registerCleanupFunction(function() {
getTestPlugin(pluginName).enabledState = oldEnabledState;
}
// Get the 'enabledState' on the nsIPluginTag stored in the main or chrome
// process.
function getTestPluginEnabledState(pluginName) {
let name = pluginName || "Test Plug-in";
let plugin = getTestPlugin(name);
return plugin.enabledState;
}
// Returns a promise for nsIObjectLoadingContent props data.
function promiseForPluginInfo(aId, aBrowser) {
let browser = aBrowser || gTestBrowser;
return ContentTask.spawn(browser, aId, function* (aId) {
let plugin = content.document.getElementById(aId);
if (!(plugin instanceof Ci.nsIObjectLoadingContent))
throw new Error("no plugin found");
return {
pluginFallbackType: plugin.pluginFallbackType,
activated: plugin.activated,
hasRunningPlugin: plugin.hasRunningPlugin,
displayedType: plugin.displayedType,
};
});
}
// Return a promise and call the plugin's nsIObjectLoadingContent
// playPlugin() method.
function promisePlayObject(aId, aBrowser) {
let browser = aBrowser || gTestBrowser;
return ContentTask.spawn(browser, aId, function* (aId) {
let plugin = content.document.getElementById(aId);
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
objLoadingContent.playPlugin();
});
}
function promiseCrashObject(aId, aBrowser) {
let browser = aBrowser || gTestBrowser;
return ContentTask.spawn(browser, aId, function* (aId) {
let plugin = content.document.getElementById(aId);
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
Components.utils.waiveXrays(plugin).crash();
});
}
// Return a promise and call the plugin's getObjectValue() method.
function promiseObjectValueResult(aId, aBrowser) {
let browser = aBrowser || gTestBrowser;
return ContentTask.spawn(browser, aId, function* (aId) {
let plugin = content.document.getElementById(aId);
return Components.utils.waiveXrays(plugin).getObjectValue();
});
}
// Return a promise and reload the target plugin in the page
function promiseReloadPlugin(aId, aBrowser) {
let browser = aBrowser || gTestBrowser;
return ContentTask.spawn(browser, aId, function* (aId) {
let plugin = content.document.getElementById(aId);
plugin.src = plugin.src;
});
}
@ -81,15 +238,16 @@ function clearAllPluginPermissions() {
while (perms.hasMoreElements()) {
let perm = perms.getNext();
if (perm.type.startsWith('plugin')) {
info("removing permission:" + perm.host + " " + perm.type + "\n");
Services.perms.remove(perm.host, perm.type);
}
}
}
function updateBlocklist(aCallback) {
var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
let blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
.getService(Ci.nsITimerCallback);
var observer = function() {
let observer = function() {
Services.obs.removeObserver(observer, "blocklist-updated");
SimpleTest.executeSoon(aCallback);
};
@ -97,28 +255,77 @@ function updateBlocklist(aCallback) {
blocklistNotifier.notify(null);
}
var _originalTestBlocklistURL = null;
let _originalTestBlocklistURL = null;
function setAndUpdateBlocklist(aURL, aCallback) {
if (!_originalTestBlocklistURL)
if (!_originalTestBlocklistURL) {
_originalTestBlocklistURL = Services.prefs.getCharPref("extensions.blocklist.url");
}
Services.prefs.setCharPref("extensions.blocklist.url", aURL);
updateBlocklist(aCallback);
}
// A generator that insures a new blocklist is loaded (in both
// processes if applicable).
function* asyncSetAndUpdateBlocklist(aURL, aBrowser) {
info("*** loading new blocklist: " + aURL);
let doTestRemote = aBrowser ? aBrowser.isRemoteBrowser : false;
if (!_originalTestBlocklistURL) {
_originalTestBlocklistURL = Services.prefs.getCharPref("extensions.blocklist.url");
}
Services.prefs.setCharPref("extensions.blocklist.url", aURL);
let localPromise = TestUtils.topicObserved("blocklist-updated");
let remotePromise;
if (doTestRemote) {
remotePromise = TestUtils.topicObserved("content-blocklist-updated");
}
let blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
.getService(Ci.nsITimerCallback);
blocklistNotifier.notify(null);
info("*** waiting on local load");
yield localPromise;
if (doTestRemote) {
info("*** waiting on remote load");
yield remotePromise;
}
info("*** blocklist loaded.");
}
// Reset back to the blocklist we had at the start of the test run.
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`
);
// Insure there's a popup notification present. This test does not indicate
// open state. aBrowser can be undefined.
function promisePopupNotification(aName, aBrowser) {
let deferred = Promise.defer();
waitForCondition(() => PopupNotifications.getNotification(aName, aBrowser),
() => {
ok(!!PopupNotifications.getNotification(aName, aBrowser),
aName + " notification appeared");
deferred.resolve();
}, "timeout waiting for popup notification " + aName);
return deferred.promise;
}
/**
* Allows setting focus on a window, and waiting for that window to achieve
* focus.
*
* @param aWindow
* The window to focus and wait for.
*
* @return {Promise}
* @resolves When the window is focused.
* @rejects Never.
*/
function promiseWaitForFocus(aWindow) {
return new Promise((resolve) => {
waitForFocus(resolve, aWindow);
});
}
/**
@ -153,6 +360,12 @@ function waitForNotificationBar(notificationID, browser, callback) {
});
}
function promiseForNotificationBar(notificationID, browser) {
let deferred = Promise.defer();
waitForNotificationBar(notificationID, browser, deferred.resolve);
return deferred.promise;
}
/**
* Reshow a notification and call a callback when it is reshown.
* @param notification
@ -160,8 +373,7 @@ function waitForNotificationBar(notificationID, browser, callback) {
* @param callback
* A function to be called when the notification has been reshown
*/
function waitForNotificationShown(notification, callback)
{
function waitForNotificationShown(notification, callback) {
if (PopupNotifications.panel.state == "open") {
executeSoon(callback);
return;
@ -173,46 +385,30 @@ function waitForNotificationShown(notification, callback)
notification.reshow();
}
/**
* Due to layout being async, "PluginBindAttached" may trigger later.
* This returns a Promise that resolves once we've forced a layout
* flush, which triggers the PluginBindAttached event to fire.
*
* @param browser
* The browser to force plugin bindings in.
*
* @return Promise
*/
function forcePluginBindingAttached(browser) {
return new Promise((resolve, reject) => {
let doc = browser.contentDocument;
let elems = doc.getElementsByTagName('embed');
if (elems.length < 1) {
elems = doc.getElementsByTagName('object');
}
elems[0].clientTop;
executeSoon(resolve);
});
function promiseForNotificationShown(notification) {
let deferred = Promise.defer();
waitForNotificationShown(notification, deferred.resolve);
return deferred.promise;
}
/**
* Loads a page in a browser, and returns a Promise that
* resolves once the "load" event has been fired for that
* browser.
*
* Due to layout being async, "PluginBindAttached" may trigger later. This
* returns a Promise that resolves once we've forced a layout flush, which
* triggers the PluginBindAttached event to fire. This trick only works if
* there is some sort of plugin in the page.
* @param browser
* The browser to load the page in.
* @param uri
* The URI to load.
*
* The browser to force plugin bindings in.
* @return Promise
*/
function loadPage(browser, uri) {
return new Promise((resolve, reject) => {
browser.addEventListener("load", function onLoad(event) {
browser.removeEventListener("load", onLoad, true);
resolve();
}, true);
browser.loadURI(uri);
function promiseUpdatePluginBindings(browser) {
return ContentTask.spawn(browser, {}, function* () {
let doc = content.document;
let elems = doc.getElementsByTagName('embed');
if (!elems || elems.length < 1) {
elems = doc.getElementsByTagName('object');
}
if (elems && elems.length > 0) {
elems[0].clientTop;
}
});
}

Просмотреть файл

@ -1,15 +1,16 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script>
function addPlugin(type="application/x-test") {
function addPlugin(aId, aType="application/x-test") {
var embed = document.createElement("embed");
embed.setAttribute("id", aId);
embed.style.width = "200px";
embed.style.height = "200px";
embed.setAttribute("type", type);
embed.setAttribute("type", aType);
return document.body.appendChild(embed);
}
</script>

Просмотреть файл

@ -1,7 +1,7 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<head>
<meta charset="utf-8">
</head>
<body>
<embed id="unknown" style="width: 100px; height: 100px" type="application/x-unknown">

Просмотреть файл

@ -1,11 +1,11 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div id="container" style="display: none">
<object id="plugin" type="application/x-test" style="width: 200px; height: 200px;"></object>
<object id="test" type="application/x-test" style="width: 200px; height: 200px;"></object>
</div>
</body>
</html>

Просмотреть файл

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
@ -6,6 +6,7 @@
<script type="text/javascript">
// create an embed, insert it in the doc and immediately remove it
var embed = document.createElement('embed');
embed.setAttribute("id", "test");
embed.setAttribute("type", "application/x-test");
embed.setAttribute("style", "width: 0px; height: 0px;");
document.body.appendChild(embed);

Просмотреть файл

@ -1,7 +1,7 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<head>
<meta charset="utf-8">
</head>
<body>
<embed id="test" style="width: 200px; height: 200px" type="application/x-test">

Просмотреть файл

@ -1,7 +1,7 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<head>
<meta charset="utf-8">
</head>
<body>
<embed id="test" style="width: 0px; height: 0px" type="application/x-test">

Просмотреть файл

@ -1,7 +1,7 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<head>
<meta charset="utf-8">
</head>
<body>
<embed id="unknown" style="width: 100px; height: 100px" type="application/x-unknown">

Просмотреть файл

@ -428,6 +428,7 @@
@RESPATH@/components/amInstallTrigger.js
@RESPATH@/components/amWebInstallListener.js
@RESPATH@/components/nsBlocklistService.js
@RESPATH@/components/nsBlocklistServiceContent.js
#ifdef MOZ_UPDATER
@RESPATH@/components/nsUpdateService.manifest
@RESPATH@/components/nsUpdateService.js

Просмотреть файл

@ -3258,8 +3258,9 @@ nsObjectLoadingContent::ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentTyp
}
// Before we check permissions, get the blocklist state of this plugin to set
// the fallback reason correctly.
uint32_t blocklistState = nsIBlocklistService::STATE_NOT_BLOCKED;
// the fallback reason correctly. In the content process this will involve
// an ipc call to chrome.
uint32_t blocklistState = nsIBlocklistService::STATE_BLOCKED;
pluginHost->GetBlocklistStateForType(mContentType,
nsPluginHost::eExcludeNone,
&blocklistState);

86
dom/cache/Cache.cpp поставляемый
Просмотреть файл

@ -229,7 +229,10 @@ already_AddRefed<Promise>
Cache::Match(const RequestOrUSVString& aRequest,
const CacheQueryOptions& aOptions, ErrorResult& aRv)
{
MOZ_ASSERT(mActor);
if (NS_WARN_IF(!mActor)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv);
if (NS_WARN_IF(aRv.Failed())) {
@ -253,7 +256,10 @@ already_AddRefed<Promise>
Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
const CacheQueryOptions& aOptions, ErrorResult& aRv)
{
MOZ_ASSERT(mActor);
if (NS_WARN_IF(!mActor)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
CacheQueryParams params;
ToCacheQueryParams(params, aOptions);
@ -280,6 +286,11 @@ already_AddRefed<Promise>
Cache::Add(JSContext* aContext, const RequestOrUSVString& aRequest,
ErrorResult& aRv)
{
if (NS_WARN_IF(!mActor)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
if (!IsValidPutRequestMethod(aRequest, aRv)) {
return nullptr;
}
@ -290,13 +301,13 @@ Cache::Add(JSContext* aContext, const RequestOrUSVString& aRequest,
nsTArray<nsRefPtr<Request>> requestList(1);
nsRefPtr<Request> request = Request::Constructor(global, aRequest,
RequestInit(), aRv);
if (aRv.Failed()) {
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
nsAutoString url;
request->GetUrl(url);
if (!IsValidPutRequestURL(url, aRv)) {
if (NS_WARN_IF(!IsValidPutRequestURL(url, aRv))) {
return nullptr;
}
@ -309,6 +320,11 @@ Cache::AddAll(JSContext* aContext,
const Sequence<OwningRequestOrUSVString>& aRequestList,
ErrorResult& aRv)
{
if (NS_WARN_IF(!mActor)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
GlobalObject global(aContext, mGlobal->GetGlobalJSObject());
MOZ_ASSERT(!global.Failed());
@ -318,7 +334,8 @@ Cache::AddAll(JSContext* aContext,
if (aRequestList[i].IsRequest()) {
requestOrString.SetAsRequest() = aRequestList[i].GetAsRequest();
if (!IsValidPutRequestMethod(requestOrString.GetAsRequest(), aRv)) {
if (NS_WARN_IF(!IsValidPutRequestMethod(requestOrString.GetAsRequest(),
aRv))) {
return nullptr;
}
} else {
@ -329,13 +346,13 @@ Cache::AddAll(JSContext* aContext,
nsRefPtr<Request> request = Request::Constructor(global, requestOrString,
RequestInit(), aRv);
if (aRv.Failed()) {
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
nsAutoString url;
request->GetUrl(url);
if (!IsValidPutRequestURL(url, aRv)) {
if (NS_WARN_IF(!IsValidPutRequestURL(url, aRv))) {
return nullptr;
}
@ -349,14 +366,17 @@ already_AddRefed<Promise>
Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
ErrorResult& aRv)
{
MOZ_ASSERT(mActor);
if (NS_WARN_IF(!mActor)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
if (!IsValidPutRequestMethod(aRequest, aRv)) {
if (NS_WARN_IF(!IsValidPutRequestMethod(aRequest, aRv))) {
return nullptr;
}
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, ReadBody, aRv);
if (aRv.Failed()) {
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
@ -364,7 +384,7 @@ Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
args.Add(ir, ReadBody, TypeErrorOnInvalidScheme,
aResponse, aRv);
if (aRv.Failed()) {
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
@ -375,10 +395,13 @@ already_AddRefed<Promise>
Cache::Delete(const RequestOrUSVString& aRequest,
const CacheQueryOptions& aOptions, ErrorResult& aRv)
{
MOZ_ASSERT(mActor);
if (NS_WARN_IF(!mActor)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv);
if (aRv.Failed()) {
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
@ -388,7 +411,7 @@ Cache::Delete(const RequestOrUSVString& aRequest,
AutoChildOpArgs args(this, CacheDeleteArgs(CacheRequest(), params));
args.Add(ir, IgnoreBody, IgnoreInvalidScheme, aRv);
if (aRv.Failed()) {
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
@ -399,7 +422,10 @@ already_AddRefed<Promise>
Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
const CacheQueryOptions& aOptions, ErrorResult& aRv)
{
MOZ_ASSERT(mActor);
if (NS_WARN_IF(!mActor)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
CacheQueryParams params;
ToCacheQueryParams(params, aOptions);
@ -409,12 +435,12 @@ Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
if (aRequest.WasPassed()) {
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest.Value(),
IgnoreBody, aRv);
if (aRv.Failed()) {
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
args.Add(ir, IgnoreBody, IgnoreInvalidScheme, aRv);
if (aRv.Failed()) {
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
}
@ -493,9 +519,9 @@ Cache::~Cache()
{
NS_ASSERT_OWNINGTHREAD(Cache);
if (mActor) {
mActor->StartDestroy();
// DestroyInternal() is called synchronously by StartDestroy(). So we
// should have already cleared the mActor.
mActor->StartDestroyFromListener();
// DestroyInternal() is called synchronously by StartDestroyFromListener().
// So we should have already cleared the mActor.
MOZ_ASSERT(!mActor);
}
}
@ -504,11 +530,11 @@ already_AddRefed<Promise>
Cache::ExecuteOp(AutoChildOpArgs& aOpArgs, ErrorResult& aRv)
{
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
if (NS_WARN_IF(!promise)) {
return nullptr;
}
mActor->ExecuteOp(mGlobal, promise, aOpArgs.SendAsOpArgs());
mActor->ExecuteOp(mGlobal, promise, this, aOpArgs.SendAsOpArgs());
return promise.forget();
}
@ -521,7 +547,7 @@ Cache::AddAll(const GlobalObject& aGlobal,
// If there is no work to do, then resolve immediately
if (aRequestList.IsEmpty()) {
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
if (NS_WARN_IF(!promise)) {
return nullptr;
}
@ -541,7 +567,7 @@ Cache::AddAll(const GlobalObject& aGlobal,
requestOrString.SetAsRequest() = aRequestList[i];
nsRefPtr<Promise> fetch = FetchRequest(mGlobal, requestOrString,
RequestInit(), aRv);
if (aRv.Failed()) {
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
@ -549,7 +575,7 @@ Cache::AddAll(const GlobalObject& aGlobal,
}
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (aRv.Failed()) {
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
@ -557,7 +583,7 @@ Cache::AddAll(const GlobalObject& aGlobal,
Move(aRequestList), promise);
nsRefPtr<Promise> fetchPromise = Promise::All(aGlobal, fetchList, aRv);
if (aRv.Failed()) {
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
fetchPromise->AppendNativeHandler(handler);
@ -570,15 +596,19 @@ Cache::PutAll(const nsTArray<nsRefPtr<Request>>& aRequestList,
const nsTArray<nsRefPtr<Response>>& aResponseList,
ErrorResult& aRv)
{
MOZ_ASSERT(mActor);
MOZ_ASSERT(aRequestList.Length() == aResponseList.Length());
if (NS_WARN_IF(!mActor)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
AutoChildOpArgs args(this, CachePutAllArgs());
for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
nsRefPtr<InternalRequest> ir = aRequestList[i]->GetInternalRequest();
args.Add(ir, ReadBody, TypeErrorOnInvalidScheme, *aResponseList[i], aRv);
if (aRv.Failed()) {
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
}

41
dom/cache/CacheChild.cpp поставляемый
Просмотреть файл

@ -33,6 +33,7 @@ DeallocPCacheChild(PCacheChild* aActor)
CacheChild::CacheChild()
: mListener(nullptr)
, mNumChildActors(0)
, mDelayedDestroy(false)
{
MOZ_COUNT_CTOR(cache::CacheChild);
}
@ -64,11 +65,11 @@ CacheChild::ClearListener()
void
CacheChild::ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
const CacheOpArgs& aArgs)
nsISupports* aParent, const CacheOpArgs& aArgs)
{
mNumChildActors += 1;
MOZ_ALWAYS_TRUE(SendPCacheOpConstructor(
new CacheOpChild(GetFeature(), aGlobal, aPromise), aArgs));
new CacheOpChild(GetFeature(), aGlobal, aParent, aPromise), aArgs));
}
CachePushStreamChild*
@ -81,9 +82,33 @@ CacheChild::CreatePushStream(nsIAsyncInputStream* aStream)
return static_cast<CachePushStreamChild*>(actor);
}
void
CacheChild::StartDestroyFromListener()
{
NS_ASSERT_OWNINGTHREAD(CacheChild);
// The listener should be held alive by any async operations, so if it
// is going away then there must not be any child actors. This in turn
// ensures that StartDestroy() will not trigger the delayed path.
MOZ_ASSERT(!mNumChildActors);
StartDestroy();
}
void
CacheChild::StartDestroy()
{
NS_ASSERT_OWNINGTHREAD(CacheChild);
// If we have outstanding child actors, then don't destroy ourself yet.
// The child actors should be short lived and we should allow them to complete
// if possible. NoteDeletedActor() will call back into this Shutdown()
// method when the last child actor is gone.
if (mNumChildActors) {
mDelayedDestroy = true;
return;
}
nsRefPtr<Cache> listener = mListener;
// StartDestroy() can get called from either Cache or the Feature.
@ -98,14 +123,6 @@ CacheChild::StartDestroy()
// Cache listener should call ClearListener() in DestroyInternal()
MOZ_ASSERT(!mListener);
// If we have outstanding child actors, then don't destroy ourself yet.
// The child actors should be short lived and we should allow them to complete
// if possible. SendTeardown() will be called when the count drops to zero
// in NoteDeletedActor().
if (mNumChildActors) {
return;
}
// Start actor destruction from parent process
unused << SendTeardown();
}
@ -158,8 +175,8 @@ void
CacheChild::NoteDeletedActor()
{
mNumChildActors -= 1;
if (!mNumChildActors && !mListener) {
unused << SendTeardown();
if (!mNumChildActors && mDelayedDestroy) {
StartDestroy();
}
}

21
dom/cache/CacheChild.h поставляемый
Просмотреть файл

@ -33,25 +33,27 @@ public:
void SetListener(Cache* aListener);
// Must be called by the associated Cache listener in its ActorDestroy()
// method. Also, Cache must Send__delete__() the actor in its destructor to
// trigger ActorDestroy() if it has not been called yet.
// Must be called by the associated Cache listener in its DestroyInternal()
// method. Also, Cache must call StartDestroyFromListener() on the actor in
// its destructor to trigger ActorDestroy() if it has not been called yet.
void ClearListener();
void
ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
const CacheOpArgs& aArgs);
nsISupports* aParent, const CacheOpArgs& aArgs);
CachePushStreamChild*
CreatePushStream(nsIAsyncInputStream* aStream);
// ActorChild methods
// Synchronously call ActorDestroy on our Cache listener and then start the
// actor destruction asynchronously from the parent-side.
virtual void StartDestroy() override;
// Our parent Listener object has gone out of scope and is being destroyed.
void StartDestroyFromListener();
private:
// ActorChild methods
// Feature is trying to destroy due to worker shutdown.
virtual void StartDestroy() override;
// PCacheChild methods
virtual void
ActorDestroy(ActorDestroyReason aReason) override;
@ -77,6 +79,7 @@ private:
// destroyed.
Cache* MOZ_NON_OWNING_REF mListener;
uint32_t mNumChildActors;
bool mDelayedDestroy;
NS_DECL_OWNINGTHREAD
};

6
dom/cache/CacheOpChild.cpp поставляемый
Просмотреть файл

@ -57,11 +57,13 @@ AddFeatureToStreamChild(const CacheRequest& aRequest, Feature* aFeature)
} // anonymous namespace
CacheOpChild::CacheOpChild(Feature* aFeature, nsIGlobalObject* aGlobal,
Promise* aPromise)
nsISupports* aParent, Promise* aPromise)
: mGlobal(aGlobal)
, mParent(aParent)
, mPromise(aPromise)
{
MOZ_ASSERT(mGlobal);
MOZ_ASSERT(mParent);
MOZ_ASSERT(mPromise);
MOZ_ASSERT_IF(!NS_IsMainThread(), aFeature);
@ -95,7 +97,7 @@ CacheOpChild::Recv__delete__(const ErrorResult& aRv,
{
NS_ASSERT_OWNINGTHREAD(CacheOpChild);
if (aRv.Failed()) {
if (NS_WARN_IF(aRv.Failed())) {
MOZ_ASSERT(aResult.type() == CacheOpResult::Tvoid_t);
// TODO: Remove this const_cast (bug 1152078).
// It is safe for now since this ErrorResult is handed off to us by IPDL

6
dom/cache/CacheOpChild.h поставляемый
Просмотреть файл

@ -31,7 +31,8 @@ class CacheOpChild final : public PCacheOpChild
private:
// This class must be constructed by CacheChild or CacheStorageChild using
// their ExecuteOp() factory method.
CacheOpChild(Feature* aFeature, nsIGlobalObject* aGlobal, Promise* aPromise);
CacheOpChild(Feature* aFeature, nsIGlobalObject* aGlobal,
nsISupports* aParent, Promise* aPromise);
~CacheOpChild();
// PCacheOpChild methods
@ -68,6 +69,9 @@ private:
HandleRequestList(const nsTArray<CacheRequest>& aRequestList);
nsCOMPtr<nsIGlobalObject> mGlobal;
// Hold the parent Cache or CacheStorage object alive until this async
// operation completes.
nsCOMPtr<nsISupports> mParent;
nsRefPtr<Promise> mPromise;
NS_DECL_OWNINGTHREAD

2
dom/cache/CacheOpParent.cpp поставляемый
Просмотреть файл

@ -164,7 +164,7 @@ CacheOpParent::OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
// Never send an op-specific result if we have an error. Instead, send
// void_t() to ensure that we don't leak actors on the child side.
if (aRv.Failed()) {
if (NS_WARN_IF(aRv.Failed())) {
unused << Send__delete__(this, aRv, void_t());
aRv.SuppressException(); // We serialiazed it, as best we could.
return;

5
dom/cache/CachePushStreamChild.cpp поставляемый
Просмотреть файл

@ -118,8 +118,9 @@ CachePushStreamChild::Start()
void
CachePushStreamChild::StartDestroy()
{
// called if we are running on a Worker and the thread gets shutdown
OnEnd(NS_ERROR_ABORT);
// The worker has signaled its shutting down, but continue streaming. The
// Cache is now designed to hold the worker open until all async operations
// complete.
}
void

32
dom/cache/CacheStorage.cpp поставляемый
Просмотреть файл

@ -166,7 +166,7 @@ CacheStorage::CacheStorage(Namespace aNamespace, nsIGlobalObject* aGlobal,
// wait for the async ActorCreated() callback.
MOZ_ASSERT(NS_IsMainThread());
bool ok = BackgroundChild::GetOrCreateForCurrentThread(this);
if (!ok) {
if (NS_WARN_IF(!ok)) {
ActorFailed();
}
}
@ -177,7 +177,7 @@ CacheStorage::Match(const RequestOrUSVString& aRequest,
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
if (mFailedActor) {
if (NS_WARN_IF(mFailedActor)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
@ -189,7 +189,7 @@ CacheStorage::Match(const RequestOrUSVString& aRequest,
}
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
if (NS_WARN_IF(!promise)) {
return nullptr;
}
@ -212,13 +212,13 @@ CacheStorage::Has(const nsAString& aKey, ErrorResult& aRv)
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
if (mFailedActor) {
if (NS_WARN_IF(mFailedActor)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
if (NS_WARN_IF(!promise)) {
return nullptr;
}
@ -237,13 +237,13 @@ CacheStorage::Open(const nsAString& aKey, ErrorResult& aRv)
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
if (mFailedActor) {
if (NS_WARN_IF(mFailedActor)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
if (NS_WARN_IF(!promise)) {
return nullptr;
}
@ -262,13 +262,13 @@ CacheStorage::Delete(const nsAString& aKey, ErrorResult& aRv)
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
if (mFailedActor) {
if (NS_WARN_IF(mFailedActor)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
if (NS_WARN_IF(!promise)) {
return nullptr;
}
@ -287,13 +287,13 @@ CacheStorage::Keys(ErrorResult& aRv)
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
if (mFailedActor) {
if (NS_WARN_IF(mFailedActor)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
if (NS_WARN_IF(!promise)) {
return nullptr;
}
@ -413,9 +413,9 @@ CacheStorage::~CacheStorage()
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
if (mActor) {
mActor->StartDestroy();
// DestroyInternal() is called synchronously by StartDestroy(). So we
// should have already cleared the mActor.
mActor->StartDestroyFromListener();
// DestroyInternal() is called synchronously by StartDestroyFromListener().
// So we should have already cleared the mActor.
MOZ_ASSERT(!mActor);
}
}
@ -434,11 +434,11 @@ CacheStorage::MaybeRunPendingRequests()
if (entry->mRequest) {
args.Add(entry->mRequest, IgnoreBody, IgnoreInvalidScheme, rv);
}
if (rv.Failed()) {
if (NS_WARN_IF(rv.Failed())) {
entry->mPromise->MaybeReject(rv);
continue;
}
mActor->ExecuteOp(mGlobal, entry->mPromise, args.SendAsOpArgs());
mActor->ExecuteOp(mGlobal, entry->mPromise, this, args.SendAsOpArgs());
}
mPendingRequests.Clear();
}

39
dom/cache/CacheStorageChild.cpp поставляемый
Просмотреть файл

@ -25,6 +25,7 @@ DeallocPCacheStorageChild(PCacheStorageChild* aActor)
CacheStorageChild::CacheStorageChild(CacheStorage* aListener, Feature* aFeature)
: mListener(aListener)
, mNumChildActors(0)
, mDelayedDestroy(false)
{
MOZ_COUNT_CTOR(cache::CacheStorageChild);
MOZ_ASSERT(mListener);
@ -49,11 +50,24 @@ CacheStorageChild::ClearListener()
void
CacheStorageChild::ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
const CacheOpArgs& aArgs)
nsISupports* aParent, const CacheOpArgs& aArgs)
{
mNumChildActors += 1;
unused << SendPCacheOpConstructor(
new CacheOpChild(GetFeature(), aGlobal, aPromise), aArgs);
new CacheOpChild(GetFeature(), aGlobal, aParent, aPromise), aArgs);
}
void
CacheStorageChild::StartDestroyFromListener()
{
NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
// The listener should be held alive by any async operations, so if it
// is going away then there must not be any child actors. This in turn
// ensures that StartDestroy() will not trigger the delayed path.
MOZ_ASSERT(!mNumChildActors);
StartDestroy();
}
void
@ -61,6 +75,15 @@ CacheStorageChild::StartDestroy()
{
NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
// If we have outstanding child actors, then don't destroy ourself yet.
// The child actors should be short lived and we should allow them to complete
// if possible. NoteDeletedActor() will call back into this Shutdown()
// method when the last child actor is gone.
if (mNumChildActors) {
mDelayedDestroy = true;
return;
}
nsRefPtr<CacheStorage> listener = mListener;
// StartDestroy() can get called from either CacheStorage or the Feature.
@ -75,14 +98,6 @@ CacheStorageChild::StartDestroy()
// CacheStorage listener should call ClearListener() in DestroyInternal()
MOZ_ASSERT(!mListener);
// If we have outstanding child actors, then don't destroy ourself yet.
// The child actors should be short lived and we should allow them to complete
// if possible. SendTeardown() will be called when the count drops to zero
// in NoteDeletedActor().
if (mNumChildActors) {
return;
}
// Start actor destruction from parent process
unused << SendTeardown();
}
@ -121,8 +136,8 @@ CacheStorageChild::NoteDeletedActor()
{
MOZ_ASSERT(mNumChildActors);
mNumChildActors -= 1;
if (!mNumChildActors && !mListener) {
unused << SendTeardown();
if (!mNumChildActors && mDelayedDestroy) {
StartDestroy();
}
}

21
dom/cache/CacheStorageChild.h поставляемый
Просмотреть файл

@ -33,22 +33,24 @@ public:
~CacheStorageChild();
// Must be called by the associated CacheStorage listener in its
// ActorDestroy() method. Also, CacheStorage must call SendDestroy() on the
// actor in its destructor to trigger ActorDestroy() if it has not been
// called yet.
// DestroyInternal() method. Also, CacheStorage must call
// SendDestroyFromListener() on the actor in its destructor to trigger
// ActorDestroy() if it has not been called yet.
void ClearListener();
void
ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
const CacheOpArgs& aArgs);
nsISupports* aParent, const CacheOpArgs& aArgs);
// ActorChild methods
// Synchronously call ActorDestroy on our CacheStorage listener and then start
// the actor destruction asynchronously from the parent-side.
virtual void StartDestroy() override;
// Our parent Listener object has gone out of scope and is being destroyed.
void StartDestroyFromListener();
private:
// ActorChild methods
// Feature is trying to destroy due to worker shutdown.
virtual void StartDestroy() override;
// PCacheStorageChild methods
virtual void ActorDestroy(ActorDestroyReason aReason) override;
@ -67,6 +69,7 @@ private:
// destroyed.
CacheStorage* MOZ_NON_OWNING_REF mListener;
uint32_t mNumChildActors;
bool mDelayedDestroy;
NS_DECL_OWNINGTHREAD
};

2
dom/cache/CacheStorageParent.cpp поставляемый
Просмотреть файл

@ -100,7 +100,7 @@ CacheStorageParent::RecvPCacheOpConstructor(PCacheOpParent* aActor,
return true;
}
if (NS_FAILED(mVerifiedStatus)) {
if (NS_WARN_IF(NS_FAILED(mVerifiedStatus))) {
unused << CacheOpParent::Send__delete__(actor, ErrorResult(mVerifiedStatus),
void_t());
return true;

4
dom/cache/Feature.cpp поставляемый
Просмотреть файл

@ -13,7 +13,7 @@ namespace mozilla {
namespace dom {
namespace cache {
using mozilla::dom::workers::Running;
using mozilla::dom::workers::Canceling;
using mozilla::dom::workers::Status;
using mozilla::dom::workers::WorkerPrivate;
@ -73,7 +73,7 @@ Feature::Notify(JSContext* aCx, Status aStatus)
{
NS_ASSERT_OWNINGTHREAD(Feature);
if (aStatus <= Running || mNotified) {
if (aStatus < Canceling || mNotified) {
return true;
}

6
dom/cache/Manager.cpp поставляемый
Просмотреть файл

@ -1623,7 +1623,7 @@ Manager::ExecuteCacheOp(Listener* aListener, CacheId aCacheId,
MOZ_ASSERT(aListener);
MOZ_ASSERT(aOpArgs.type() != CacheOpArgs::TCachePutAllArgs);
if (mState == Closing) {
if (NS_WARN_IF(mState == Closing)) {
aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), void_t());
return;
}
@ -1667,7 +1667,7 @@ Manager::ExecuteStorageOp(Listener* aListener, Namespace aNamespace,
NS_ASSERT_OWNINGTHREAD(Manager);
MOZ_ASSERT(aListener);
if (mState == Closing) {
if (NS_WARN_IF(mState == Closing)) {
aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), void_t());
return;
}
@ -1716,7 +1716,7 @@ Manager::ExecutePutAll(Listener* aListener, CacheId aCacheId,
NS_ASSERT_OWNINGTHREAD(Manager);
MOZ_ASSERT(aListener);
if (mState == Closing) {
if (NS_WARN_IF(mState == Closing)) {
aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), CachePutAllResult());
return;
}

Просмотреть файл

@ -161,6 +161,9 @@
#include "private/pprio.h"
#include "ContentProcessManager.h"
#include "mozilla/psm/PSMContentListener.h"
#include "nsPluginHost.h"
#include "nsPluginTags.h"
#include "nsIBlocklistService.h"
#include "nsIBidiKeyboard.h"
@ -1083,6 +1086,25 @@ ContentParent::RecvConnectPluginBridge(const uint32_t& aPluginId, nsresult* aRv)
return mozilla::plugins::SetupBridge(aPluginId, this, true, aRv, &dummy);
}
bool
ContentParent::RecvGetBlocklistState(const uint32_t& aPluginId,
uint32_t* aState)
{
*aState = nsIBlocklistService::STATE_BLOCKED;
nsRefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
if (!pluginHost) {
return false;
}
nsPluginTag* tag = pluginHost->PluginWithId(aPluginId);
if (!tag) {
return false;
}
return NS_SUCCEEDED(tag->GetBlocklistState(aState));
}
bool
ContentParent::RecvFindPlugins(const uint32_t& aPluginEpoch,
nsTArray<PluginTag>* aPlugins,

Просмотреть файл

@ -173,6 +173,7 @@ public:
virtual bool RecvLoadPlugin(const uint32_t& aPluginId, nsresult* aRv, uint32_t* aRunID) override;
virtual bool RecvConnectPluginBridge(const uint32_t& aPluginId, nsresult* aRv) override;
virtual bool RecvGetBlocklistState(const uint32_t& aPluginId, uint32_t* aIsBlocklisted) override;
virtual bool RecvFindPlugins(const uint32_t& aPluginEpoch,
nsTArray<PluginTag>* aPlugins,
uint32_t* aNewPluginEpoch) override;

Просмотреть файл

@ -699,6 +699,11 @@ parent:
*/
sync ConnectPluginBridge(uint32_t aPluginId) returns (nsresult rv);
/**
* Return the current blocklist state for a particular plugin.
*/
sync GetBlocklistState(uint32_t aPluginId) returns (uint32_t aState);
/**
* This call returns the set of plugins loaded in the chrome
* process. However, in many cases this set will not have changed since the

Просмотреть файл

@ -110,6 +110,8 @@
#include "nsExceptionHandler.h"
#endif
#include "npapi.h"
using namespace mozilla;
using mozilla::TimeStamp;
using mozilla::plugins::PluginTag;
@ -1054,7 +1056,6 @@ nsPluginHost::GetBlocklistStateForType(const nsACString &aMimeType,
aExcludeFlags,
getter_AddRefs(tag));
NS_ENSURE_SUCCESS(rv, rv);
return tag->GetBlocklistState(aState);
}
@ -1275,6 +1276,13 @@ nsPluginHost::GetPluginForContentProcess(uint32_t aPluginId, nsNPAPIPlugin** aPl
nsPluginTag* pluginTag = PluginWithId(aPluginId);
if (pluginTag) {
// When setting up a bridge, double check with chrome to see if this plugin
// is blocked hard. Note this does not protect against vulnerable plugins
// that the user has explicitly allowed. :(
if (pluginTag->IsBlocklisted()) {
return NS_ERROR_PLUGIN_BLOCKLISTED;
}
nsresult rv = EnsurePluginLoaded(pluginTag);
if (NS_FAILED(rv)) {
return rv;

Просмотреть файл

@ -11,7 +11,6 @@
#include "nsCOMPtr.h"
#include "prlink.h"
#include "prclist.h"
#include "npapi.h"
#include "nsIPluginTag.h"
#include "nsPluginsDir.h"
#include "nsPluginDirServiceProvider.h"
@ -30,6 +29,7 @@
#include "nsCRT.h"
#ifdef XP_WIN
#include <minwindef.h>
#include "nsIWindowsRegKey.h"
#endif
@ -52,6 +52,10 @@ class nsNPAPIPluginStreamListener;
class nsIPluginInstanceOwner;
class nsIInputStream;
class nsIStreamListener;
#ifndef npapi_h_
struct _NPP;
typedef _NPP* NPP;
#endif
class nsInvalidPluginTag : public nsISupports
{

Просмотреть файл

@ -20,6 +20,7 @@
#include "mozilla/unused.h"
#include <cctype>
#include "mozilla/dom/EncodingUtils.h"
#include "mozilla/dom/ContentChild.h"
using mozilla::dom::EncodingUtils;
using namespace mozilla;
@ -645,27 +646,33 @@ nsPluginTag::GetBlocklistState(uint32_t *aResult)
return NS_OK;
}
nsCOMPtr<nsIBlocklistService> blocklist =
do_GetService("@mozilla.org/extensions/blocklist;1");
if (XRE_GetProcessType() != GeckoProcessType_Default) {
*aResult = nsIBlocklistService::STATE_BLOCKED;
dom::ContentChild* cp = dom::ContentChild::GetSingleton();
if (!cp->SendGetBlocklistState(mId, aResult)) {
return NS_OK;
}
} else {
nsCOMPtr<nsIBlocklistService> blocklist =
do_GetService("@mozilla.org/extensions/blocklist;1");
if (!blocklist) {
*aResult = nsIBlocklistService::STATE_NOT_BLOCKED;
return NS_OK;
if (!blocklist) {
*aResult = nsIBlocklistService::STATE_NOT_BLOCKED;
return NS_OK;
}
// The EmptyString()s are so we use the currently running application
// and toolkit versions
if (NS_FAILED(blocklist->GetPluginBlocklistState(this, EmptyString(),
EmptyString(), aResult))) {
*aResult = nsIBlocklistService::STATE_NOT_BLOCKED;
return NS_OK;
}
}
// The EmptyString()s are so we use the currently running application
// and toolkit versions
uint32_t state;
if (NS_FAILED(blocklist->GetPluginBlocklistState(this, EmptyString(),
EmptyString(), &state))) {
*aResult = nsIBlocklistService::STATE_NOT_BLOCKED;
return NS_OK;
}
MOZ_ASSERT(state <= UINT16_MAX);
mCachedBlocklistState = (uint16_t) state;
MOZ_ASSERT(*aResult <= UINT16_MAX);
mCachedBlocklistState = (uint16_t) *aResult;
mCachedBlocklistStateValid = true;
*aResult = state;
return NS_OK;
}

Просмотреть файл

@ -1043,6 +1043,7 @@ ServiceWorkerManager::AppendPendingOperation(nsIRunnable* aRunnable)
class LifecycleEventPromiseHandler final : public PromiseNativeHandler
{
nsMainThreadPtrHandle<ContinueLifecycleTask> mTask;
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
bool mActivateImmediately;
virtual
@ -1051,8 +1052,10 @@ class LifecycleEventPromiseHandler final : public PromiseNativeHandler
public:
LifecycleEventPromiseHandler(const nsMainThreadPtrHandle<ContinueLifecycleTask>& aTask,
const nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
bool aActivateImmediately)
: mTask(aTask)
, mServiceWorker(aServiceWorker)
, mActivateImmediately(aActivateImmediately)
{
MOZ_ASSERT(!NS_IsMainThread());
@ -1135,7 +1138,7 @@ LifecycleEventWorkerRunnable::DispatchLifecycleEvent(JSContext* aCx, WorkerPriva
}
nsRefPtr<LifecycleEventPromiseHandler> handler =
new LifecycleEventPromiseHandler(mTask, false /* activateImmediately */);
new LifecycleEventPromiseHandler(mTask, mServiceWorker, false /* activateImmediately */);
waitUntilPromise->AppendNativeHandler(handler);
return true;
}

Просмотреть файл

@ -83,6 +83,7 @@ using namespace mozilla::layout;
using namespace mozilla::gfx;
typedef FrameMetrics::ViewID ViewID;
typedef nsStyleTransformMatrix::TransformReferenceBox TransformReferenceBox;
#ifdef DEBUG
static bool
@ -115,7 +116,7 @@ MakeCSSAngle(const nsCSSValue& aValue)
static void AddTransformFunctions(nsCSSValueList* aList,
nsStyleContext* aContext,
nsPresContext* aPresContext,
nsRect& aBounds,
TransformReferenceBox& aRefBox,
InfallibleTArray<TransformFunction>& aFunctions)
{
if (aList->mValue.GetUnit() == eCSSUnit_None) {
@ -200,7 +201,7 @@ static void AddTransformFunctions(nsCSSValueList* aList,
{
double x = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
aBounds.Width());
&aRefBox, &TransformReferenceBox::Width);
aFunctions.AppendElement(Translation(x, 0, 0));
break;
}
@ -208,7 +209,7 @@ static void AddTransformFunctions(nsCSSValueList* aList,
{
double y = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
aBounds.Height());
&aRefBox, &TransformReferenceBox::Height);
aFunctions.AppendElement(Translation(0, y, 0));
break;
}
@ -216,7 +217,7 @@ static void AddTransformFunctions(nsCSSValueList* aList,
{
double z = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
0);
nullptr);
aFunctions.AppendElement(Translation(0, 0, z));
break;
}
@ -224,13 +225,13 @@ static void AddTransformFunctions(nsCSSValueList* aList,
{
double x = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
aBounds.Width());
&aRefBox, &TransformReferenceBox::Width);
// translate(x) is shorthand for translate(x, 0)
double y = 0;
if (array->Count() == 3) {
y = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(2), aContext, aPresContext, canStoreInRuleTree,
aBounds.Height());
&aRefBox, &TransformReferenceBox::Height);
}
aFunctions.AppendElement(Translation(x, y, 0));
break;
@ -239,13 +240,13 @@ static void AddTransformFunctions(nsCSSValueList* aList,
{
double x = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
aBounds.Width());
&aRefBox, &TransformReferenceBox::Width);
double y = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(2), aContext, aPresContext, canStoreInRuleTree,
aBounds.Height());
&aRefBox, &TransformReferenceBox::Height);
double z = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(3), aContext, aPresContext, canStoreInRuleTree,
0);
nullptr);
aFunctions.AppendElement(Translation(x, y, z));
break;
@ -324,7 +325,7 @@ static void AddTransformFunctions(nsCSSValueList* aList,
aContext,
aPresContext,
canStoreInRuleTree,
aBounds);
aRefBox);
aFunctions.AppendElement(TransformMatrix(gfx::ToMatrix4x4(matrix)));
break;
}
@ -362,7 +363,7 @@ AddAnimationForProperty(nsIFrame* aFrame, const AnimationProperty& aProperty,
"Should not be adding an animation without an effect");
nsStyleContext* styleContext = aFrame->StyleContext();
nsPresContext* presContext = aFrame->PresContext();
nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(aFrame);
TransformReferenceBox refBox(aFrame);
layers::Animation* animation =
aPending ?
@ -393,11 +394,11 @@ AddAnimationForProperty(nsIFrame* aFrame, const AnimationProperty& aProperty,
nsCSSValueSharedList* list =
segment.mFromValue.GetCSSValueSharedListValue();
AddTransformFunctions(list->mHead, styleContext, presContext, bounds,
AddTransformFunctions(list->mHead, styleContext, presContext, refBox,
animSegment->startState().get_ArrayOfTransformFunction());
list = segment.mToValue.GetCSSValueSharedListValue();
AddTransformFunctions(list->mHead, styleContext, presContext, bounds,
AddTransformFunctions(list->mHead, styleContext, presContext, refBox,
animSegment->endState().get_ArrayOfTransformFunction());
} else if (aProperty.mProperty == eCSSProperty_opacity) {
animSegment->startState() = segment.mFromValue.GetFloatValue();
@ -535,7 +536,13 @@ nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer,
AnimationData data;
if (aProperty == eCSSProperty_transform) {
nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(aFrame);
// XXX Performance here isn't ideal for SVG. We'd prefer to avoid resolving
// the dimensions of refBox. That said, we only get here if there are CSS
// animations or transitions on this element, and that is likely to be a
// lot rarer that transforms on SVG (the frequency of which drives the need
// for TransformReferenceBox).
TransformReferenceBox refBox(aFrame);
nsRect bounds(0, 0, refBox.Width(), refBox.Height());
// all data passed directly to the compositor should be in dev pixels
int32_t devPixelsToAppUnits = aFrame->PresContext()->AppUnitsPerDevPixel();
float scale = devPixelsToAppUnits;
@ -4465,7 +4472,8 @@ bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder,
// nsDisplayTransform Implementation
//
// Write #define UNIFIED_CONTINUATIONS here to have the transform property try
// Write #define UNIFIED_CONTINUATIONS here and in
// TransformReferenceBox::Initialize to have the transform property try
// to transform content with continuations as one unified block instead of
// several smaller ones. This is currently disabled because it doesn't work
// correctly, since when the frames are initially being reflowed, their
@ -4476,63 +4484,6 @@ bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder,
#undef UNIFIED_CONTINUATIONS
#undef DEBUG_HIT
/* Returns the bounds of a frame as defined for transforms. If
* UNIFIED_CONTINUATIONS is not defined, this is simply the frame's bounding
* rectangle, translated to the origin. Otherwise, returns the smallest
* rectangle containing a frame and all of its continuations. For example, if
* there is a <span> element with several continuations split over several
* lines, this function will return the rectangle containing all of those
* continuations. This rectangle is relative to the origin of the frame's local
* coordinate space.
*/
#ifndef UNIFIED_CONTINUATIONS
nsRect
nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
{
NS_PRECONDITION(aFrame, "Can't get the bounds of a nonexistent frame!");
if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
// TODO: SVG needs to define what percentage translations resolve against.
return nsRect();
}
return nsRect(nsPoint(0, 0), aFrame->GetSize());
}
#else
nsRect
nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
{
NS_PRECONDITION(aFrame, "Can't get the bounds of a nonexistent frame!");
nsRect result;
if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
// TODO: SVG needs to define what percentage translations resolve against.
return result;
}
/* Iterate through the continuation list, unioning together all the
* bounding rects.
*/
for (const nsIFrame *currFrame = aFrame->FirstContinuation();
currFrame != nullptr;
currFrame = currFrame->GetNextContinuation())
{
/* Get the frame rect in local coordinates, then translate back to the
* original coordinates.
*/
result.UnionRect(result, nsRect(currFrame->GetOffsetTo(aFrame),
currFrame->GetSize()));
}
return result;
}
#endif
nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
nsIFrame *aFrame, nsDisplayList *aList,
const nsRect& aChildrenVisibleRect,
@ -4633,13 +4584,17 @@ nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame,
* a distance, it's already computed for us!
*/
const nsStyleDisplay* display = aFrame->StyleDisplay();
nsRect boundingRect = (aBoundsOverride ? *aBoundsOverride :
nsDisplayTransform::GetFrameBoundsForTransform(aFrame));
TransformReferenceBox refBox;
if (aBoundsOverride) {
refBox.Init(aBoundsOverride->Size());
} else {
refBox.Init(aFrame);
}
/* Allows us to access named variables by index. */
/* Allows us to access dimension getters by index. */
float coords[3];
const nscoord* dimensions[2] =
{&boundingRect.width, &boundingRect.height};
TransformReferenceBox::DimensionGetter dimensionGetter[] =
{ &TransformReferenceBox::Width, &TransformReferenceBox::Height };
for (uint8_t index = 0; index < 2; ++index) {
/* If the -moz-transform-origin specifies a percentage, take the percentage
@ -4649,12 +4604,12 @@ nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame,
if (coord.GetUnit() == eStyleUnit_Calc) {
const nsStyleCoord::Calc *calc = coord.GetCalcValue();
coords[index] =
NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) *
calc->mPercent +
NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
} else if (coord.GetUnit() == eStyleUnit_Percent) {
coords[index] =
NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) *
coord.GetPercentValue();
} else {
MOZ_ASSERT(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
@ -4673,9 +4628,11 @@ nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame,
coords[2] = NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(),
aAppUnitsPerPixel);
/* Adjust based on the origin of the rectangle. */
coords[0] += NSAppUnitsToFloatPixels(boundingRect.x, aAppUnitsPerPixel);
coords[1] += NSAppUnitsToFloatPixels(boundingRect.y, aAppUnitsPerPixel);
if (aBoundsOverride) {
// Adjust based on the origin of the override:
coords[0] += NSAppUnitsToFloatPixels(aBoundsOverride->x, aAppUnitsPerPixel);
coords[1] += NSAppUnitsToFloatPixels(aBoundsOverride->y, aAppUnitsPerPixel);
}
return Point3D(coords[0], coords[1], coords[2]);
}
@ -4716,14 +4673,14 @@ nsDisplayTransform::GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame,
}
}
const nsStyleDisplay* display = psc->StyleDisplay();
nsRect boundingRect = nsDisplayTransform::GetFrameBoundsForTransform(parent);
TransformReferenceBox refBox(parent);
/* Allows us to access named variables by index. */
Point3D result;
result.z = 0.0f;
gfx::Float* coords[2] = {&result.x, &result.y};
const nscoord* dimensions[2] =
{&boundingRect.width, &boundingRect.height};
TransformReferenceBox::DimensionGetter dimensionGetter[] =
{ &TransformReferenceBox::Width, &TransformReferenceBox::Height };
for (uint8_t index = 0; index < 2; ++index) {
/* If the -moz-transform-origin specifies a percentage, take the percentage
@ -4733,12 +4690,12 @@ nsDisplayTransform::GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame,
if (coord.GetUnit() == eStyleUnit_Calc) {
const nsStyleCoord::Calc *calc = coord.GetCalcValue();
*coords[index] =
NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) *
calc->mPercent +
NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
} else if (coord.GetUnit() == eStyleUnit_Percent) {
*coords[index] =
NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) *
coord.GetPercentValue();
} else {
MOZ_ASSERT(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
@ -4821,11 +4778,14 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
*aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(frame);
}
/* Get the underlying transform matrix. This requires us to get the
* bounds of the frame.
*/
nsRect bounds = (aBoundsOverride ? *aBoundsOverride :
nsDisplayTransform::GetFrameBoundsForTransform(frame));
// Get the underlying transform matrix:
TransformReferenceBox refBox;
if (aBoundsOverride) {
refBox.Init(aBoundsOverride->Size());
} else {
refBox.Init(frame);
}
/* Get the matrix, then change its basis to factor in the origin. */
bool dummy;
@ -4840,7 +4800,7 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
result = nsStyleTransformMatrix::ReadTransforms(aProperties.mTransformList->mHead,
frame ? frame->StyleContext() : nullptr,
frame ? frame->PresContext() : nullptr,
dummy, bounds, aAppUnitsPerPixel);
dummy, refBox, aAppUnitsPerPixel);
} else if (hasSVGTransforms) {
// Correct the translation components for zoom:
float pixelsPerCSSPx = frame->PresContext()->AppUnitsPerCSSPixel() /

Просмотреть файл

@ -3486,22 +3486,6 @@ public:
static Point3D GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame,
float aAppUnitsPerPixel);
/**
* Returns the bounds of a frame as defined for resolving percentage
* <translation-value>s in CSS transforms. If
* UNIFIED_CONTINUATIONS is not defined, this is simply the frame's bounding
* rectangle, translated to the origin. Otherwise, returns the smallest
* rectangle containing a frame and all of its continuations. For example,
* if there is a <span> element with several continuations split over
* several lines, this function will return the rectangle containing all of
* those continuations. This rectangle is relative to the origin of the
* frame's local coordinate space.
*
* @param aFrame The frame to get the bounding rect for.
* @return The frame's bounding rect, as described above.
*/
static nsRect GetFrameBoundsForTransform(const nsIFrame* aFrame);
struct FrameTransformProperties
{
FrameTransformProperties(const nsIFrame* aFrame,
@ -3533,10 +3517,10 @@ public:
* @param aOrigin Relative to which point this transform should be applied.
* @param aAppUnitsPerPixel The number of app units per graphics unit.
* @param aBoundsOverride [optional] If this is nullptr (the default), the
* computation will use the value of GetFrameBoundsForTransform(aFrame)
* for the frame's bounding rectangle. Otherwise, it will use the
* value of aBoundsOverride. This is mostly for internal use and in
* most cases you will not need to specify a value.
* computation will use the value of TransformReferenceBox(aFrame).
* Otherwise, it will use the value of aBoundsOverride. This is
* mostly for internal use and in most cases you will not need to
* specify a value.
* @param aOffsetByOrigin If true, the resulting matrix will be translated
* by aOrigin. This translation is applied *before* the CSS transform.
*/

Просмотреть файл

@ -128,6 +128,7 @@ bool nsLayoutUtils::gPreventAssertInCompareTreePosition = false;
#endif // DEBUG
typedef FrameMetrics::ViewID ViewID;
typedef nsStyleTransformMatrix::TransformReferenceBox TransformReferenceBox;
/* static */ uint32_t nsLayoutUtils::sFontSizeInflationEmPerLine;
/* static */ uint32_t nsLayoutUtils::sFontSizeInflationMinTwips;
@ -462,12 +463,12 @@ GetScaleForValue(const StyleAnimationValue& aValue, nsIFrame* aFrame)
return gfxSize();
}
nsRect frameBounds = aFrame->GetRect();
bool dontCare;
TransformReferenceBox refBox(aFrame);
gfx3DMatrix transform = nsStyleTransformMatrix::ReadTransforms(
list->mHead,
aFrame->StyleContext(),
aFrame->PresContext(), dontCare, frameBounds,
aFrame->PresContext(), dontCare, refBox,
aFrame->PresContext()->AppUnitsPerDevPixel());
gfxMatrix transform2d;

Просмотреть файл

@ -53,6 +53,7 @@ using namespace mozilla;
using namespace mozilla::dom;
typedef const nsStyleBackground::Position Position;
typedef const nsStyleBackground::Position::PositionCoord PositionCoord;
typedef nsStyleTransformMatrix::TransformReferenceBox TransformReferenceBox;
#if defined(DEBUG_bzbarsky) || defined(DEBUG_caillon)
#define DEBUG_ComputedDOMStyle
@ -1253,7 +1254,9 @@ nsComputedDOMStyle::DoGetTransform()
* store it in a string, and hand it back to the caller.
*/
/* Use the inner frame for width and height. If we fail, assume zero.
/* Use the inner frame for the reference box. If we don't have an inner
* frame we use empty dimensions to allow us to continue (and percentage
* values in the transform will simply give broken results).
* TODO: There is no good way for us to represent the case where there's no
* frame, which is problematic. The reason is that when we have percentage
* transforms, there are a total of four stored matrix entries that influence
@ -1262,9 +1265,7 @@ nsComputedDOMStyle::DoGetTransform()
* using the named transforms. Until a real solution is found, we'll just
* use this approach.
*/
nsRect bounds =
(mInnerFrame ? nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame) :
nsRect(0, 0, 0, 0));
TransformReferenceBox refBox(mInnerFrame, nsSize(0, 0));
bool dummy;
gfx3DMatrix matrix =
@ -1272,7 +1273,7 @@ nsComputedDOMStyle::DoGetTransform()
mStyleContextHolder,
mStyleContextHolder->PresContext(),
dummy,
bounds,
refBox,
float(mozilla::AppUnitsPerCSSPixel()));
return MatrixToCSSValue(matrix);
@ -4958,7 +4959,7 @@ nsComputedDOMStyle::GetFrameBoundsWidthForTransform(nscoord& aWidth)
AssertFlushedPendingReflows();
aWidth = nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame).width;
aWidth = TransformReferenceBox(mInnerFrame).Width();
return true;
}
@ -4972,7 +4973,7 @@ nsComputedDOMStyle::GetFrameBoundsHeightForTransform(nscoord& aHeight)
AssertFlushedPendingReflows();
aHeight = nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame).height;
aHeight = TransformReferenceBox(mInnerFrame).Height();
return true;
}

Просмотреть файл

@ -26,6 +26,72 @@ namespace nsStyleTransformMatrix {
* involving angles need to be done in 'double'.
*/
// Define UNIFIED_CONTINUATIONS here and in nsDisplayList.cpp
// to have the transform property try
// to transform content with continuations as one unified block instead of
// several smaller ones. This is currently disabled because it doesn't work
// correctly, since when the frames are initially being reflowed, their
// continuations all compute their bounding rects independently of each other
// and consequently get the wrong value.
//#define UNIFIED_CONTINUATIONS
void
TransformReferenceBox::EnsureDimensionsAreCached()
{
if (mIsCached) {
return;
}
MOZ_ASSERT(mFrame);
mIsCached = true;
if (mFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
// TODO: SVG needs to define what percentage translations resolve against.
mWidth = 0;
mHeight = 0;
return;
}
// If UNIFIED_CONTINUATIONS is not defined, this is simply the frame's
// bounding rectangle, translated to the origin. Otherwise, it is the
// smallest rectangle containing a frame and all of its continuations. For
// example, if there is a <span> element with several continuations split
// over several lines, this function will return the rectangle containing all
// of those continuations.
nsRect rect;
#ifndef UNIFIED_CONTINUATIONS
rect = mFrame->GetRect();
#else
// Iterate the continuation list, unioning together the bounding rects:
for (const nsIFrame *currFrame = mFrame->FirstContinuation();
currFrame != nullptr;
currFrame = currFrame->GetNextContinuation())
{
// Get the frame rect in local coordinates, then translate back to the
// original coordinates:
rect.UnionRect(result, nsRect(currFrame->GetOffsetTo(mFrame),
currFrame->GetSize()));
}
#endif
mWidth = rect.Width();
mHeight = rect.Height();
}
void
TransformReferenceBox::Init(const nsSize& aDimensions)
{
MOZ_ASSERT(!mFrame && !mIsCached);
mWidth = aDimensions.width;
mHeight = aDimensions.height;
mIsCached = true;
}
/* Force small values to zero. We do this to avoid having sin(360deg)
* evaluate to a tiny but nonzero value.
*/
@ -42,7 +108,8 @@ ProcessTranslatePart(const nsCSSValue& aValue,
nsStyleContext* aContext,
nsPresContext* aPresContext,
bool& aCanStoreInRuleTree,
nscoord aSize)
TransformReferenceBox* aRefBox,
TransformReferenceBox::DimensionGetter aDimensionGetter)
{
nscoord offset = 0;
float percent = 0.0f;
@ -72,8 +139,16 @@ ProcessTranslatePart(const nsCSSValue& aValue,
aCanStoreInRuleTree);
}
return (percent * NSAppUnitsToFloatPixels(aSize, nsPresContext::AppUnitsPerCSSPixel())) +
NSAppUnitsToFloatPixels(offset, nsPresContext::AppUnitsPerCSSPixel());
float translation = NSAppUnitsToFloatPixels(offset,
nsPresContext::AppUnitsPerCSSPixel());
// We want to avoid calling aDimensionGetter if there's no percentage to be
// resolved (for performance reasons - see TransformReferenceBox).
if (percent != 0.0f && aRefBox) {
translation += percent *
NSAppUnitsToFloatPixels((aRefBox->*aDimensionGetter)(),
nsPresContext::AppUnitsPerCSSPixel());
}
return translation;
}
/**
@ -89,7 +164,7 @@ ProcessMatrix(gfx3DMatrix& aMatrix,
nsStyleContext* aContext,
nsPresContext* aPresContext,
bool& aCanStoreInRuleTree,
nsRect& aBounds)
TransformReferenceBox& aRefBox)
{
NS_PRECONDITION(aData->Count() == 7, "Invalid array!");
@ -108,10 +183,10 @@ ProcessMatrix(gfx3DMatrix& aMatrix,
*/
result._31 = ProcessTranslatePart(aData->Item(5),
aContext, aPresContext, aCanStoreInRuleTree,
aBounds.Width());
&aRefBox, &TransformReferenceBox::Width);
result._32 = ProcessTranslatePart(aData->Item(6),
aContext, aPresContext, aCanStoreInRuleTree,
aBounds.Height());
&aRefBox, &TransformReferenceBox::Height);
aMatrix.PreMultiply(result);
}
@ -122,7 +197,7 @@ ProcessMatrix3D(gfx3DMatrix& aMatrix,
nsStyleContext* aContext,
nsPresContext* aPresContext,
bool& aCanStoreInRuleTree,
nsRect& aBounds)
TransformReferenceBox& aRefBox)
{
NS_PRECONDITION(aData->Count() == 17, "Invalid array!");
@ -144,13 +219,14 @@ ProcessMatrix3D(gfx3DMatrix& aMatrix,
temp._41 = ProcessTranslatePart(aData->Item(13),
aContext, aPresContext, aCanStoreInRuleTree,
aBounds.Width());
&aRefBox, &TransformReferenceBox::Width);
temp._42 = ProcessTranslatePart(aData->Item(14),
aContext, aPresContext, aCanStoreInRuleTree,
aBounds.Height());
&aRefBox, &TransformReferenceBox::Height);
temp._43 = ProcessTranslatePart(aData->Item(15),
aContext, aPresContext, aCanStoreInRuleTree,
aBounds.Height());
&aRefBox, &TransformReferenceBox::Height);
// XXXjwatt why are we using TransformReferenceBox::Height for the z compontent?!
aMatrix.PreMultiply(temp);
}
@ -162,7 +238,7 @@ ProcessInterpolateMatrix(gfx3DMatrix& aMatrix,
nsStyleContext* aContext,
nsPresContext* aPresContext,
bool& aCanStoreInRuleTree,
nsRect& aBounds)
TransformReferenceBox& aRefBox)
{
NS_PRECONDITION(aData->Count() == 4, "Invalid array!");
@ -171,13 +247,13 @@ ProcessInterpolateMatrix(gfx3DMatrix& aMatrix,
matrix1 = nsStyleTransformMatrix::ReadTransforms(aData->Item(1).GetListValue(),
aContext, aPresContext,
aCanStoreInRuleTree,
aBounds, nsPresContext::AppUnitsPerCSSPixel());
aRefBox, nsPresContext::AppUnitsPerCSSPixel());
}
if (aData->Item(2).GetUnit() == eCSSUnit_List) {
matrix2 = ReadTransforms(aData->Item(2).GetListValue(),
aContext, aPresContext,
aCanStoreInRuleTree,
aBounds, nsPresContext::AppUnitsPerCSSPixel());
aRefBox, nsPresContext::AppUnitsPerCSSPixel());
}
double progress = aData->Item(3).GetPercentValue();
@ -193,7 +269,7 @@ ProcessTranslateX(gfx3DMatrix& aMatrix,
nsStyleContext* aContext,
nsPresContext* aPresContext,
bool& aCanStoreInRuleTree,
nsRect& aBounds)
TransformReferenceBox& aRefBox)
{
NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
@ -201,7 +277,7 @@ ProcessTranslateX(gfx3DMatrix& aMatrix,
temp.x = ProcessTranslatePart(aData->Item(1),
aContext, aPresContext, aCanStoreInRuleTree,
aBounds.Width());
&aRefBox, &TransformReferenceBox::Width);
aMatrix.Translate(temp);
}
@ -212,7 +288,7 @@ ProcessTranslateY(gfx3DMatrix& aMatrix,
nsStyleContext* aContext,
nsPresContext* aPresContext,
bool& aCanStoreInRuleTree,
nsRect& aBounds)
TransformReferenceBox& aRefBox)
{
NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
@ -220,7 +296,7 @@ ProcessTranslateY(gfx3DMatrix& aMatrix,
temp.y = ProcessTranslatePart(aData->Item(1),
aContext, aPresContext, aCanStoreInRuleTree,
aBounds.Height());
&aRefBox, &TransformReferenceBox::Height);
aMatrix.Translate(temp);
}
@ -236,7 +312,8 @@ ProcessTranslateZ(gfx3DMatrix& aMatrix,
Point3D temp;
temp.z = ProcessTranslatePart(aData->Item(1), aContext,
aPresContext, aCanStoreInRuleTree, 0);
aPresContext, aCanStoreInRuleTree,
nullptr);
aMatrix.Translate(temp);
}
@ -247,7 +324,7 @@ ProcessTranslate(gfx3DMatrix& aMatrix,
nsStyleContext* aContext,
nsPresContext* aPresContext,
bool& aCanStoreInRuleTree,
nsRect& aBounds)
TransformReferenceBox& aRefBox)
{
NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Invalid array!");
@ -255,13 +332,13 @@ ProcessTranslate(gfx3DMatrix& aMatrix,
temp.x = ProcessTranslatePart(aData->Item(1),
aContext, aPresContext, aCanStoreInRuleTree,
aBounds.Width());
&aRefBox, &TransformReferenceBox::Width);
/* If we read in a Y component, set it appropriately */
if (aData->Count() == 3) {
temp.y = ProcessTranslatePart(aData->Item(2),
aContext, aPresContext, aCanStoreInRuleTree,
aBounds.Height());
&aRefBox, &TransformReferenceBox::Height);
}
aMatrix.Translate(temp);
}
@ -272,7 +349,7 @@ ProcessTranslate3D(gfx3DMatrix& aMatrix,
nsStyleContext* aContext,
nsPresContext* aPresContext,
bool& aCanStoreInRuleTree,
nsRect& aBounds)
TransformReferenceBox& aRefBox)
{
NS_PRECONDITION(aData->Count() == 4, "Invalid array!");
@ -280,15 +357,15 @@ ProcessTranslate3D(gfx3DMatrix& aMatrix,
temp.x = ProcessTranslatePart(aData->Item(1),
aContext, aPresContext, aCanStoreInRuleTree,
aBounds.Width());
&aRefBox, &TransformReferenceBox::Width);
temp.y = ProcessTranslatePart(aData->Item(2),
aContext, aPresContext, aCanStoreInRuleTree,
aBounds.Height());
&aRefBox, &TransformReferenceBox::Height);
temp.z = ProcessTranslatePart(aData->Item(3),
aContext, aPresContext, aCanStoreInRuleTree,
0);
nullptr);
aMatrix.Translate(temp);
}
@ -481,7 +558,7 @@ ProcessPerspective(gfx3DMatrix& aMatrix,
float depth = ProcessTranslatePart(aData->Item(1), aContext,
aPresContext, aCanStoreInRuleTree,
0);
nullptr);
aMatrix.Perspective(depth);
}
@ -496,7 +573,7 @@ MatrixForTransformFunction(gfx3DMatrix& aMatrix,
nsStyleContext* aContext,
nsPresContext* aPresContext,
bool& aCanStoreInRuleTree,
nsRect& aBounds)
TransformReferenceBox& aRefBox)
{
NS_PRECONDITION(aData, "Why did you want to get data from a null array?");
// It's OK if aContext and aPresContext are null if the caller already
@ -508,11 +585,11 @@ MatrixForTransformFunction(gfx3DMatrix& aMatrix,
switch (TransformFunctionOf(aData)) {
case eCSSKeyword_translatex:
ProcessTranslateX(aMatrix, aData, aContext, aPresContext,
aCanStoreInRuleTree, aBounds);
aCanStoreInRuleTree, aRefBox);
break;
case eCSSKeyword_translatey:
ProcessTranslateY(aMatrix, aData, aContext, aPresContext,
aCanStoreInRuleTree, aBounds);
aCanStoreInRuleTree, aRefBox);
break;
case eCSSKeyword_translatez:
ProcessTranslateZ(aMatrix, aData, aContext, aPresContext,
@ -520,11 +597,11 @@ MatrixForTransformFunction(gfx3DMatrix& aMatrix,
break;
case eCSSKeyword_translate:
ProcessTranslate(aMatrix, aData, aContext, aPresContext,
aCanStoreInRuleTree, aBounds);
aCanStoreInRuleTree, aRefBox);
break;
case eCSSKeyword_translate3d:
ProcessTranslate3D(aMatrix, aData, aContext, aPresContext,
aCanStoreInRuleTree, aBounds);
aCanStoreInRuleTree, aRefBox);
break;
case eCSSKeyword_scalex:
ProcessScaleX(aMatrix, aData);
@ -565,15 +642,15 @@ MatrixForTransformFunction(gfx3DMatrix& aMatrix,
break;
case eCSSKeyword_matrix:
ProcessMatrix(aMatrix, aData, aContext, aPresContext,
aCanStoreInRuleTree, aBounds);
aCanStoreInRuleTree, aRefBox);
break;
case eCSSKeyword_matrix3d:
ProcessMatrix3D(aMatrix, aData, aContext, aPresContext,
aCanStoreInRuleTree, aBounds);
aCanStoreInRuleTree, aRefBox);
break;
case eCSSKeyword_interpolatematrix:
ProcessInterpolateMatrix(aMatrix, aData, aContext, aPresContext,
aCanStoreInRuleTree, aBounds);
aCanStoreInRuleTree, aRefBox);
break;
case eCSSKeyword_perspective:
ProcessPerspective(aMatrix, aData, aContext, aPresContext,
@ -600,7 +677,7 @@ ReadTransforms(const nsCSSValueList* aList,
nsStyleContext* aContext,
nsPresContext* aPresContext,
bool &aCanStoreInRuleTree,
nsRect& aBounds,
TransformReferenceBox& aRefBox,
float aAppUnitsPerMatrixUnit)
{
gfx3DMatrix result;
@ -619,7 +696,7 @@ ReadTransforms(const nsCSSValueList* aList,
/* Read in a single transform matrix. */
MatrixForTransformFunction(result, currElem.GetArrayValue(), aContext,
aPresContext, aCanStoreInRuleTree, aBounds);
aPresContext, aCanStoreInRuleTree, aRefBox);
}
float scale = float(nsPresContext::AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit;

Просмотреть файл

@ -13,6 +13,7 @@
#include "nsCSSValue.h"
#include "gfx3DMatrix.h"
class nsIFrame;
class nsStyleContext;
class nsPresContext;
struct nsRect;
@ -21,7 +22,86 @@ struct nsRect;
* A helper to generate gfxMatrixes from css transform functions.
*/
namespace nsStyleTransformMatrix {
/**
* This class provides on-demand access to the 'reference box' for CSS
* transforms (needed to resolve percentage values in 'transform',
* 'transform-origin', etc.):
*
* http://dev.w3.org/csswg/css-transforms/#reference-box
*
* This class helps us to avoid calculating the reference box unless and
* until it is actually needed. This is important for performance when
* transforms are applied to SVG elements since the reference box for SVG is
* much more expensive to calculate (than for elements with a CSS layout box
* where we can use the nsIFrame's cached mRect), much more common (than on
* HTML), and yet very rarely have percentage values that require the
* reference box to be resolved. We also don't want to cause SVG frames to
* cache lots of ObjectBoundingBoxProperty objects that aren't needed.
*
* If UNIFIED_CONTINUATIONS (experimental, and currently broke) is defined,
* we consider the reference box for non-SVG frames to be the smallest
* rectangle containing a frame and all of its continuations. For example,
* if there is a <span> element with several continuations split over
* several lines, this function will return the rectangle containing all of
* those continuations. (This behavior is not currently in a spec.)
*/
class MOZ_STACK_CLASS TransformReferenceBox final {
public:
typedef nscoord (TransformReferenceBox::*DimensionGetter)();
explicit TransformReferenceBox()
: mFrame(nullptr)
, mIsCached(false)
{}
explicit TransformReferenceBox(const nsIFrame* aFrame)
: mFrame(aFrame)
, mIsCached(false)
{
MOZ_ASSERT(mFrame);
}
explicit TransformReferenceBox(const nsIFrame* aFrame,
const nsSize& aFallbackDimensions)
{
mFrame = aFrame;
mIsCached = false;
if (!mFrame) {
Init(aFallbackDimensions);
}
}
void Init(const nsIFrame* aFrame) {
MOZ_ASSERT(!mFrame && !mIsCached);
mFrame = aFrame;
}
void Init(const nsSize& aDimensions);
nscoord Width() {
EnsureDimensionsAreCached();
return mWidth;
}
nscoord Height() {
EnsureDimensionsAreCached();
return mHeight;
}
private:
// We don't really need to prevent copying, but since none of our consumers
// currently need to copy, preventing copying may allow us to catch some
// cases where we use pass-by-value instead of pass-by-reference.
TransformReferenceBox(const TransformReferenceBox&) = delete;
void EnsureDimensionsAreCached();
const nsIFrame* mFrame;
nscoord mWidth, mHeight;
bool mIsCached;
};
/**
* Return the transform function, as an nsCSSKeyword, for the given
* nsCSSValue::Array from a transform list.
@ -32,7 +112,8 @@ namespace nsStyleTransformMatrix {
nsStyleContext* aContext,
nsPresContext* aPresContext,
bool& aCanStoreInRuleTree,
nscoord aSize);
TransformReferenceBox* aRefBox,
TransformReferenceBox::DimensionGetter aDimensionGetter = nullptr);
void
ProcessInterpolateMatrix(gfx3DMatrix& aMatrix,
@ -40,7 +121,7 @@ namespace nsStyleTransformMatrix {
nsStyleContext* aContext,
nsPresContext* aPresContext,
bool& aCanStoreInRuleTree,
nsRect& aBounds);
TransformReferenceBox& aBounds);
/**
* Given an nsCSSValueList containing -moz-transform functions,
@ -62,7 +143,7 @@ namespace nsStyleTransformMatrix {
nsStyleContext* aContext,
nsPresContext* aPresContext,
bool &aCanStoreInRuleTree,
nsRect& aBounds,
TransformReferenceBox& aBounds,
float aAppUnitsPerMatrixUnit);
} // namespace nsStyleTransformMatrix

Просмотреть файл

@ -298,7 +298,8 @@ function Blocklist() {
gPref.addObserver(PREF_EM_LOGGING_ENABLED, this, false);
this.wrappedJSObject = this;
// requests from child processes come in here, see receiveMessage.
Services.ppmm.addMessageListener("Blocklist::getPluginBlocklistState", this);
Services.ppmm.addMessageListener("Blocklist:getPluginBlocklistState", this);
Services.ppmm.addMessageListener("Blocklist:content-blocklist-updated", this);
}
Blocklist.prototype = {
@ -322,7 +323,8 @@ Blocklist.prototype = {
shutdown: function () {
Services.obs.removeObserver(this, "xpcom-shutdown");
Services.ppmm.removeMessageListener("Blocklist::getPluginBlocklistState", this);
Services.ppmm.removeMessageListener("Blocklist:getPluginBlocklistState", this);
Services.ppmm.removeMessageListener("Blocklist:content-blocklist-updated", this);
gPref.removeObserver("extensions.blocklist.", this);
gPref.removeObserver(PREF_EM_LOGGING_ENABLED, this);
},
@ -359,10 +361,13 @@ Blocklist.prototype = {
// Message manager message handlers
receiveMessage: function (aMsg) {
switch (aMsg.name) {
case "Blocklist::getPluginBlocklistState":
case "Blocklist:getPluginBlocklistState":
return this.getPluginBlocklistState(aMsg.data.addonData,
aMsg.data.appVersion,
aMsg.data.toolkitVersion);
case "Blocklist:content-blocklist-updated":
Services.obs.notifyObservers(null, "content-blocklist-updated", null);
break;
default:
throw new Error("Unknown blocklist message received from content: " + aMsg.name);
}
@ -1192,6 +1197,11 @@ Blocklist.prototype = {
return blockEntry.infoURL;
},
_notifyObserversBlocklistUpdated: function () {
Services.obs.notifyObservers(this, "blocklist-updated", "");
Services.ppmm.broadcastAsyncMessage("Blocklist:blocklistInvalidated", {});
},
_blocklistUpdated: function Blocklist_blocklistUpdated(oldAddonEntries, oldPluginEntries) {
var addonList = [];
@ -1296,7 +1306,7 @@ Blocklist.prototype = {
}
if (addonList.length == 0) {
Services.obs.notifyObservers(self, "blocklist-updated", "");
self._notifyObserversBlocklistUpdated();
return;
}
@ -1308,7 +1318,7 @@ Blocklist.prototype = {
} catch (e) {
LOG(e);
}
Services.obs.notifyObservers(self, "blocklist-updated", "");
self._notifyObserversBlocklistUpdated();
return;
}
@ -1342,7 +1352,7 @@ Blocklist.prototype = {
if (args.restart)
restartApp();
Services.obs.notifyObservers(self, "blocklist-updated", "");
self._notifyObserversBlocklistUpdated();
Services.obs.removeObserver(applyBlocklistChanges, "addon-blocklist-closed");
}

Просмотреть файл

@ -21,19 +21,51 @@ const kMissingAPIMessage = "Unsupported blocklist call in the child process."
*/
function Blocklist() {
this.init();
}
Blocklist.prototype = {
classID: Components.ID("{e0a106ed-6ad4-47a4-b6af-2f1c8aa4712d}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIBlocklistService]),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsIBlocklistService]),
init: function () {
Services.cpmm.addMessageListener("Blocklist:blocklistInvalidated", this);
Services.obs.addObserver(this, "xpcom-shutdown", false);
},
uninit: function () {
Services.cpmm.removeMessageListener("Blocklist:blocklistInvalidated", this);
Services.obs.removeObserver(this, "xpcom-shutdown", false);
},
observe: function (aSubject, aTopic, aData) {
switch (aTopic) {
case "xpcom-shutdown":
this.uninit();
break;
}
},
// Message manager message handlers
receiveMessage: function (aMsg) {
switch (aMsg.name) {
case "Blocklist:blocklistInvalidated":
Services.obs.notifyObservers(null, "blocklist-updated", null);
Services.cpmm.sendAsyncMessage("Blocklist:content-blocklist-updated");
break;
default:
throw new Error("Unknown blocklist message received from content: " + aMsg.name);
}
},
/*
* A helper that queries key data from a plugin or addon object
* and generates a simple data wrapper suitable for ipc. We hand
* these directly to the nsBlockListService in the parent which
* doesn't query for much.. allowing us to get away with this.
*/
* A helper that queries key data from a plugin or addon object
* and generates a simple data wrapper suitable for ipc. We hand
* these directly to the nsBlockListService in the parent which
* doesn't query for much.. allowing us to get away with this.
*/
flattenObject: function (aTag) {
// Based on debugging the nsBlocklistService, these are the props the
// parent side will check on our objects.
@ -49,15 +81,16 @@ Blocklist.prototype = {
// only calls getPluginBlocklistState.
isAddonBlocklisted: function (aAddon, aAppVersion, aToolkitVersion) {
throw new Error(kMissingAPIMessage);
return true;
},
getAddonBlocklistState: function (aAddon, aAppVersion, aToolkitVersion) {
throw new Error(kMissingAPIMessage);
return Components.interfaces.nsIBlocklistService.STATE_BLOCKED;
},
// There are a few callers in layout that rely on this.
getPluginBlocklistState: function (aPluginTag, aAppVersion, aToolkitVersion) {
return Services.cpmm.sendSyncMessage("Blocklist::getPluginBlocklistState", {
return Services.cpmm.sendSyncMessage("Blocklist:getPluginBlocklistState", {
addonData: this.flattenObject(aPluginTag),
appVersion: aAppVersion,
toolkitVersion: aToolkitVersion

Просмотреть файл

@ -231,7 +231,7 @@ nsPrimitiveHelpers :: ConvertPlatformPlainTextToUnicode ( const char* inText, in
// be reallocated regardless (disposing the old buffer is taken care of internally, see
// the note below).
//
// NOTE: this assumes that it can use nsMemory to dispose of the old buffer.
// NOTE: this assumes that it can use 'free' to dispose of the old buffer.
//
nsresult
nsLinebreakHelpers :: ConvertPlatformToDOMLinebreaks ( const char* inFlavor, void** ioData,

Просмотреть файл

@ -56,7 +56,7 @@ public:
// be reallocated regardless (disposing the old buffer is taken care of internally, see
// the note below).
//
// NOTE: this assumes that it can use nsMemory to dispose of the old buffer.
// NOTE: this assumes that it can use 'free' to dispose of the old buffer.
static nsresult ConvertPlatformToDOMLinebreaks ( const char* inFlavor, void** ioData, int32_t* ioLengthInBytes ) ;
}; // class nsLinebreakHelpers