зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to m-c a=merge
This commit is contained in:
Коммит
5ef0b7b6a7
|
@ -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]
|
[DEFAULT]
|
||||||
# These tests all fail with e10s enabled.
|
skip-if = buildapp == "mulet"
|
||||||
# * 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
|
|
||||||
support-files =
|
support-files =
|
||||||
|
blocklist_proxy.js
|
||||||
blockNoPlugins.xml
|
blockNoPlugins.xml
|
||||||
blockPluginHard.xml
|
blockPluginHard.xml
|
||||||
blockPluginInfoURL.xml
|
blockPluginInfoURL.xml
|
||||||
|
@ -53,12 +48,14 @@ support-files =
|
||||||
[browser_bug818118.js]
|
[browser_bug818118.js]
|
||||||
[browser_bug820497.js]
|
[browser_bug820497.js]
|
||||||
[browser_clearplugindata.js]
|
[browser_clearplugindata.js]
|
||||||
|
skip-if = e10s # bug 1149253
|
||||||
[browser_CTP_context_menu.js]
|
[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]
|
[browser_CTP_crashreporting.js]
|
||||||
skip-if = !crashreporter
|
skip-if = !crashreporter
|
||||||
[browser_CTP_data_urls.js]
|
[browser_CTP_data_urls.js]
|
||||||
[browser_CTP_drag_drop.js]
|
[browser_CTP_drag_drop.js]
|
||||||
|
skip-if = e10s # misc. issues, bug 1156871
|
||||||
[browser_CTP_hide_overlay.js]
|
[browser_CTP_hide_overlay.js]
|
||||||
[browser_CTP_iframe.js]
|
[browser_CTP_iframe.js]
|
||||||
skip-if = os == 'linux' || os == 'mac' # Bug 984821
|
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_remove_navigate.js]
|
||||||
[browser_CTP_resize.js]
|
[browser_CTP_resize.js]
|
||||||
[browser_CTP_zoom.js]
|
[browser_CTP_zoom.js]
|
||||||
[browser_globalplugin_crashinfobar.js]
|
[browser_blocking.js]
|
||||||
[browser_pageInfo_plugins.js]
|
[browser_plugins_added_dynamically.js]
|
||||||
[browser_pluginnotification.js]
|
[browser_pluginnotification.js]
|
||||||
[browser_pluginplaypreview.js]
|
[browser_plugin_infolink.js]
|
||||||
[browser_pluginplaypreview2.js]
|
skip-if = e10s # bug 1160166
|
||||||
[browser_pluginplaypreview3.js]
|
[browser_plugin_reloading.js]
|
||||||
|
[browser_blocklist_content.js]
|
||||||
|
skip-if = !e10s
|
||||||
|
[browser_globalplugin_crashinfobar.js]
|
||||||
|
skip-if = !crashreporter
|
||||||
[browser_pluginCrashCommentAndURL.js]
|
[browser_pluginCrashCommentAndURL.js]
|
||||||
skip-if = !crashreporter
|
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]
|
[browser_pluginCrashReportNonDeterminism.js]
|
||||||
skip-if = !crashreporter || os == 'linux' # Bug 1152811
|
skip-if = !crashreporter || os == 'linux' # Bug 1152811
|
||||||
|
|
||||||
|
|
|
@ -1,116 +1,69 @@
|
||||||
var rootDir = getRootDirectory(gTestPath);
|
let rootDir = getRootDirectory(gTestPath);
|
||||||
const gTestRoot = rootDir;
|
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
|
||||||
|
|
||||||
var gTestBrowser = null;
|
add_task(function* () {
|
||||||
var gNextTest = null;
|
registerCleanupFunction(function () {
|
||||||
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() {
|
|
||||||
clearAllPluginPermissions();
|
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");
|
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
|
// Test that the activate action in content menus for CTP plugins works
|
||||||
function test1() {
|
add_task(function* () {
|
||||||
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
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");
|
ok(popupNotification, "Test 1, Should have a click-to-play notification");
|
||||||
|
|
||||||
let plugin = gTestBrowser.contentDocument.getElementById("test");
|
// check plugin state
|
||||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
let pluginInfo = yield promiseForPluginInfo("test", gBrowser.selectedBrowser);
|
||||||
ok(!objLoadingContent.activated, "Test 1, Plugin should not be activated");
|
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
|
popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
|
||||||
// may still be pending. Clear the event loop before continuing so that
|
ok(popupNotification, "Should have a click-to-play notification");
|
||||||
// subsequently-opened popups aren't cancelled by accident.
|
ok(popupNotification.dismissed, "notification should be dismissed");
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
function test2() {
|
// fixes a occasional test timeout on win7 opt
|
||||||
let activate = window.document.getElementById("context-ctp-play");
|
yield promiseForCondition(() => document.getElementById("context-ctp-play"));
|
||||||
ok(activate, "Test 2, Should have a context menu entry for activating the plugin");
|
|
||||||
|
|
||||||
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
let actMenuItem = document.getElementById("context-ctp-play");
|
||||||
ok(notification, "Test 2, Should have a click-to-play notification");
|
ok(actMenuItem, "Should have a context menu entry for activating the plugin");
|
||||||
ok(notification.dismissed, "Test 2, notification should be dismissed");
|
|
||||||
|
|
||||||
// Trigger the click-to-play popup
|
// Activate the plugin via the context menu
|
||||||
activate.doCommand();
|
EventUtils.synthesizeMouseAtCenter(actMenuItem, {});
|
||||||
|
|
||||||
waitForCondition(() => !notification.dismissed,
|
yield promiseForCondition(() => !PopupNotifications.panel.dismissed && PopupNotifications.panel.firstChild);
|
||||||
test3, "Test 2, waited too long for context activation");
|
|
||||||
}
|
|
||||||
|
|
||||||
function test3() {
|
|
||||||
// Activate the plugin
|
// Activate the plugin
|
||||||
PopupNotifications.panel.firstChild._primaryButton.click();
|
PopupNotifications.panel.firstChild._primaryButton.click();
|
||||||
|
|
||||||
let plugin = gTestBrowser.contentDocument.getElementById("test");
|
// check plugin state
|
||||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
pluginInfo = yield promiseForPluginInfo("test", gBrowser.selectedBrowser);
|
||||||
waitForCondition(() => objLoadingContent.activated, test4, "Waited too long for plugin to activate");
|
ok(pluginInfo.activated, "plugin should not be activated");
|
||||||
}
|
});
|
||||||
|
|
||||||
function test4() {
|
|
||||||
finishTest();
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
let rootDir = getRootDirectory(gTestPath);
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
|
const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
|
||||||
const PLUGIN_PAGE = getRootDirectory(gTestPath) + "plugin_big.html";
|
const PLUGIN_PAGE = gTestRoot + "plugin_big.html";
|
||||||
const PLUGIN_SMALL_PAGE = getRootDirectory(gTestPath) + "plugin_small.html";
|
const PLUGIN_SMALL_PAGE = gTestRoot + "plugin_small.html";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes an nsIPropertyBag and converts it into a JavaScript Object. It
|
* Takes an nsIPropertyBag and converts it into a JavaScript Object. It
|
||||||
|
@ -30,14 +28,8 @@ function convertPropertyBag(aBag) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function promisePopupNotificationShown(notificationID) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
waitForNotificationShown(notificationID, resolve);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
add_task(function* setup() {
|
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
|
// The test harness sets MOZ_CRASHREPORTER_NO_REPORT, which disables plugin
|
||||||
// crash reports. This test needs them enabled. The test also needs a mock
|
// 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_NO_REPORT", "");
|
||||||
env.set("MOZ_CRASHREPORTER_URL", SERVER_URL);
|
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() {
|
registerCleanupFunction(function cleanUp() {
|
||||||
|
clearAllPluginPermissions();
|
||||||
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
|
||||||
env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
|
env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
|
||||||
env.set("MOZ_CRASHREPORTER_URL", serverURL);
|
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,
|
gBrowser,
|
||||||
url: PLUGIN_PAGE,
|
url: PLUGIN_PAGE,
|
||||||
}, function* (browser) {
|
}, function* (browser) {
|
||||||
let activated = yield ContentTask.spawn(browser, null, function*() {
|
// Work around for delayed PluginBindingAttached
|
||||||
let plugin = content.document.getElementById("test");
|
yield promiseUpdatePluginBindings(browser);
|
||||||
return plugin.QueryInterface(Ci.nsIObjectLoadingContent).activated;
|
|
||||||
});
|
|
||||||
ok(!activated, "Plugin should not be activated");
|
|
||||||
|
|
||||||
// Open up the click-to-play notification popup...
|
let pluginInfo = yield promiseForPluginInfo("test", browser);
|
||||||
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins",
|
ok(!pluginInfo.activated, "Plugin should not be activated");
|
||||||
browser);
|
|
||||||
ok(popupNotification, "Should have a click-to-play notification");
|
|
||||||
|
|
||||||
yield promisePopupNotificationShown(popupNotification);
|
// Simulate clicking the "Allow Always" button.
|
||||||
|
let notification = PopupNotifications.getNotification("click-to-play-plugins", browser);
|
||||||
// The primary button in the popup should activate the plugin.
|
yield promiseForNotificationShown(notification, browser);
|
||||||
PopupNotifications.panel.firstChild._primaryButton.click();
|
PopupNotifications.panel.firstChild._primaryButton.click();
|
||||||
|
|
||||||
// Prepare a crash report topic observer that only returns when
|
// Prepare a crash report topic observer that only returns when
|
||||||
|
@ -99,8 +94,9 @@ add_task(function*() {
|
||||||
}, "Waited too long for plugin to activate.");
|
}, "Waited too long for plugin to activate.");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
plugin.crash();
|
Components.utils.waiveXrays(plugin).crash();
|
||||||
} catch(e) {}
|
} catch(e) {
|
||||||
|
}
|
||||||
|
|
||||||
let doc = plugin.ownerDocument;
|
let doc = plugin.ownerDocument;
|
||||||
|
|
||||||
|
@ -177,21 +173,11 @@ add_task(function*() {
|
||||||
gBrowser,
|
gBrowser,
|
||||||
url: PLUGIN_SMALL_PAGE,
|
url: PLUGIN_SMALL_PAGE,
|
||||||
}, function* (browser) {
|
}, function* (browser) {
|
||||||
let activated = yield ContentTask.spawn(browser, null, function*() {
|
// Work around for delayed PluginBindingAttached
|
||||||
let plugin = content.document.getElementById("test");
|
yield promiseUpdatePluginBindings(browser);
|
||||||
return plugin.QueryInterface(Ci.nsIObjectLoadingContent).activated;
|
|
||||||
});
|
|
||||||
ok(!activated, "Plugin should not be activated");
|
|
||||||
|
|
||||||
// Open up the click-to-play notification popup...
|
let pluginInfo = yield promiseForPluginInfo("test", browser);
|
||||||
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins",
|
ok(pluginInfo.activated, "Plugin should be activated from previous test");
|
||||||
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();
|
|
||||||
|
|
||||||
// Prepare a crash report topic observer that only returns when
|
// Prepare a crash report topic observer that only returns when
|
||||||
// the crash report has been successfully sent.
|
// the crash report has been successfully sent.
|
||||||
|
@ -210,7 +196,7 @@ add_task(function*() {
|
||||||
}, "Waited too long for plugin to activate.");
|
}, "Waited too long for plugin to activate.");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
plugin.crash();
|
Components.utils.waiveXrays(plugin).crash();
|
||||||
} catch(e) {}
|
} catch(e) {}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -244,4 +230,4 @@ add_task(function*() {
|
||||||
is(crashData.extra.PluginContentURL, undefined,
|
is(crashData.extra.PluginContentURL, undefined,
|
||||||
"URL should be absent from extra data when opt-in not checked");
|
"URL should be absent from extra data when opt-in not checked");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,212 +1,255 @@
|
||||||
var rootDir = getRootDirectory(gTestPath);
|
let rootDir = getRootDirectory(gTestPath);
|
||||||
const gTestRoot = rootDir;
|
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
const gHttpTestRoot = 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;
|
add_task(function* () {
|
||||||
var gNextTest = null;
|
registerCleanupFunction(function () {
|
||||||
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() {
|
|
||||||
clearAllPluginPermissions();
|
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");
|
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 = gBrowser.addTab();
|
||||||
gBrowser.selectedTab = newTab;
|
|
||||||
gTestBrowser = gBrowser.selectedBrowser;
|
gTestBrowser = gBrowser.selectedBrowser;
|
||||||
gTestBrowser.addEventListener("load", pageLoad, true);
|
|
||||||
|
|
||||||
Services.prefs.setBoolPref("plugins.click_to_play", 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");
|
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
|
// 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);
|
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
||||||
ok(popupNotification, "Test 1a, Should have a click-to-play notification");
|
ok(popupNotification, "Test 1a, Should have a click-to-play notification");
|
||||||
|
|
||||||
let plugin = gTestBrowser.contentDocument.getElementById("test");
|
let pluginInfo = yield promiseForPluginInfo("test");
|
||||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
ok(!pluginInfo.activated, "Test 1a, plugin should not be activated");
|
||||||
ok(!objLoadingContent.activated, "Test 1a, Plugin should not be activated");
|
|
||||||
|
|
||||||
gNextTest = runAfterPluginBindingAttached(test1b);
|
let loadPromise = promiseTabLoadEvent(gBrowser.selectedTab);
|
||||||
gTestBrowser.contentDocument.getElementById("data-link-1").click();
|
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() {
|
// Work around for delayed PluginBindingAttached
|
||||||
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||||
|
|
||||||
|
popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
||||||
ok(popupNotification, "Test 1b, Should have a click-to-play notification");
|
ok(popupNotification, "Test 1b, Should have a click-to-play notification");
|
||||||
|
|
||||||
let plugin = gTestBrowser.contentDocument.getElementById("test");
|
pluginInfo = yield promiseForPluginInfo("test");
|
||||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
ok(!pluginInfo.activated, "Test 1b, plugin should not be activated");
|
||||||
ok(!objLoadingContent.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.
|
// Simulate clicking the "Allow Always" button.
|
||||||
waitForNotificationShown(popupNotification, function() {
|
let condition = function() !PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed &&
|
||||||
PopupNotifications.panel.firstChild._primaryButton.click();
|
PopupNotifications.panel.firstChild;
|
||||||
|
yield promiseForCondition(condition);
|
||||||
|
PopupNotifications.panel.firstChild._primaryButton.click();
|
||||||
|
|
||||||
let condition = function() objLoadingContent.activated;
|
// check plugin state
|
||||||
waitForCondition(condition, test1c, "Test 1b, Waited too long for plugin to activate");
|
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();
|
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
|
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_data_url.html");
|
||||||
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");
|
|
||||||
|
|
||||||
gNextTest = runAfterPluginBindingAttached(test2b);
|
// Work around for delayed PluginBindingAttached
|
||||||
gTestBrowser.contentDocument.getElementById("data-link-2").click();
|
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||||
}
|
|
||||||
|
|
||||||
function test2b() {
|
|
||||||
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
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");
|
ok(notification, "Test 2b, Should have a click-to-play notification");
|
||||||
|
|
||||||
|
yield promiseForNotificationShown(notification);
|
||||||
|
|
||||||
// Simulate choosing "Allow now" for the test plugin
|
// 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;
|
let centerAction = null;
|
||||||
for (var action of notification.options.pluginData.values()) {
|
for (let action of notification.options.pluginData.values()) {
|
||||||
if (action.pluginName == "Test") {
|
if (action.pluginName == "Test") {
|
||||||
centerAction = action;
|
centerAction = action;
|
||||||
break;
|
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;
|
let centerItem = null;
|
||||||
for (var item of PopupNotifications.panel.firstChild.childNodes) {
|
for (let item of PopupNotifications.panel.firstChild.childNodes) {
|
||||||
is(item.value, "block", "Test 2b, all plugins should start out blocked");
|
is(item.value, "block", "Test 2b, all plugins should start out blocked");
|
||||||
if (item.action == centerAction) {
|
if (item.action == centerAction) {
|
||||||
centerItem = item;
|
centerItem = item;
|
||||||
break;
|
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
|
// "click" the button to activate the Test plugin
|
||||||
centerItem.value = "allownow";
|
centerItem.value = "allownow";
|
||||||
PopupNotifications.panel.firstChild._primaryButton.click();
|
PopupNotifications.panel.firstChild._primaryButton.click();
|
||||||
|
|
||||||
let plugin = gTestBrowser.contentDocument.getElementById("test1");
|
// Work around for delayed PluginBindingAttached
|
||||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||||
let condition = function() objLoadingContent.activated;
|
|
||||||
waitForCondition(condition, test2c, "Test 2b, Waited too long for plugin to activate");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function test2c() {
|
// check plugin state
|
||||||
let plugin = gTestBrowser.contentDocument.getElementById("test1");
|
pluginInfo = yield promiseForPluginInfo("test1");
|
||||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
ok(pluginInfo.activated, "Test 2b, plugin should be activated");
|
||||||
ok(objLoadingContent.activated, "Test 2c, Plugin should be activated");
|
});
|
||||||
|
|
||||||
|
add_task(function* () {
|
||||||
|
// We click activated above
|
||||||
clearAllPluginPermissions();
|
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
|
// Test that when navigating to a data url, the plugin permission is inherited
|
||||||
function test3a() {
|
add_task(function* () {
|
||||||
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
||||||
ok(popupNotification, "Test 3a, Should have a click-to-play notification");
|
ok(notification, "Test 3a, Should have a click-to-play notification");
|
||||||
let plugin = gTestBrowser.contentDocument.getElementById("test");
|
|
||||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
// check plugin state
|
||||||
ok(!objLoadingContent.activated, "Test 3a, Plugin should not be activated");
|
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.
|
// Simulate clicking the "Allow Always" button.
|
||||||
waitForNotificationShown(popupNotification, function() {
|
let condition = function() !PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed &&
|
||||||
PopupNotifications.panel.firstChild._primaryButton.click();
|
PopupNotifications.panel.firstChild;
|
||||||
|
yield promiseForCondition(condition);
|
||||||
|
PopupNotifications.panel.firstChild._primaryButton.click();
|
||||||
|
|
||||||
let condition = function() objLoadingContent.activated;
|
// check plugin state
|
||||||
waitForCondition(condition, test3b, "Test 3a, Waited too long for plugin to activate");
|
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() {
|
// Work around for delayed PluginBindingAttached
|
||||||
gNextTest = test3c;
|
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||||
gTestBrowser.contentDocument.getElementById("data-link-1").click();
|
|
||||||
}
|
|
||||||
|
|
||||||
function test3c() {
|
// check plugin state
|
||||||
let plugin = gTestBrowser.contentDocument.getElementById("test");
|
pluginInfo = yield promiseForPluginInfo("test");
|
||||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
ok(pluginInfo.activated, "Test 3b, plugin should be activated");
|
||||||
ok(objLoadingContent.activated, "Test 3c, Plugin should be activated");
|
|
||||||
|
|
||||||
clearAllPluginPermissions();
|
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
|
// Test that the click-to-play doorhanger still works
|
||||||
function test4a() {
|
// when directly navigating to data URLs.
|
||||||
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
// Fails, bug XXX. Plugins plus a data url don't fire a load event.
|
||||||
ok(popupNotification, "Test 4a, Should have a click-to-play notification");
|
/*
|
||||||
let plugin = gTestBrowser.contentDocument.getElementById("test");
|
add_task(function* () {
|
||||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
yield promiseTabLoadEvent(gBrowser.selectedTab,
|
||||||
ok(!objLoadingContent.activated, "Test 4a, Plugin should not be activated");
|
"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.
|
// Simulate clicking the "Allow Always" button.
|
||||||
waitForNotificationShown(popupNotification, function() {
|
let condition = function() !PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed &&
|
||||||
PopupNotifications.panel.firstChild._primaryButton.click();
|
PopupNotifications.panel.firstChild;
|
||||||
|
yield promiseForCondition(condition);
|
||||||
|
PopupNotifications.panel.firstChild._primaryButton.click();
|
||||||
|
|
||||||
let condition = function() objLoadingContent.activated;
|
// check plugin state
|
||||||
waitForCondition(condition, test4b, "Test 4a, Waited too long for plugin to activate");
|
pluginInfo = yield promiseForPluginInfo("test");
|
||||||
});
|
ok(pluginInfo.activated, "Test 4a, plugin should be activated");
|
||||||
}
|
});
|
||||||
|
*/
|
||||||
function test4b() {
|
|
||||||
clearAllPluginPermissions();
|
|
||||||
finishTest();
|
|
||||||
}
|
|
|
@ -1,102 +1,96 @@
|
||||||
/* Any copyright is dedicated to the Public Domain.
|
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
* 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 gNewWindow = null;
|
let gNewWindow = null;
|
||||||
|
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
add_task(function* () {
|
||||||
|
registerCleanupFunction(function () {
|
||||||
function test() {
|
|
||||||
waitForExplicitFinish();
|
|
||||||
registerCleanupFunction(function() {
|
|
||||||
clearAllPluginPermissions();
|
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("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);
|
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.selectedTab = gBrowser.addTab();
|
||||||
gBrowser.selectedBrowser.addEventListener("PluginBindingAttached", handleEvent, true, true);
|
|
||||||
gNextTest = part1;
|
|
||||||
gBrowser.selectedBrowser.contentDocument.location = gHttpTestRoot + "plugin_test.html";
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleEvent() {
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
|
||||||
gNextTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
function part1() {
|
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
|
||||||
gBrowser.selectedBrowser.removeEventListener("PluginBindingAttached", handleEvent);
|
|
||||||
waitForNotificationPopup("click-to-play-plugins", gBrowser.selectedBrowser, () => {
|
|
||||||
gNextTest = part2;
|
|
||||||
gNewWindow = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
|
|
||||||
gNewWindow.addEventListener("load", handleEvent, true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function part2() {
|
// Work around for delayed PluginBindingAttached
|
||||||
gNewWindow.removeEventListener("load", handleEvent);
|
yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
|
||||||
let condition = function() PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser);
|
|
||||||
waitForCondition(condition, part3, "Waited too long for click-to-play notification");
|
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", 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");
|
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.selectedTab = gBrowser.addTab();
|
||||||
gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, gNewWindow.gBrowser.selectedTab);
|
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");
|
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);
|
// Work around for delayed PluginBindingAttached
|
||||||
gNextTest = part5;
|
yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
|
||||||
gBrowser.selectedBrowser.contentDocument.location = gHttpTestRoot + "plugin_test.html";
|
});
|
||||||
}
|
|
||||||
|
|
||||||
function part5() {
|
add_task(function* () {
|
||||||
gBrowser.selectedBrowser.removeEventListener("PluginBindingAttached", handleEvent);
|
yield promisePopupNotification("click-to-play-plugins");
|
||||||
waitForNotificationPopup("click-to-play-plugins", gBrowser.selectedBrowser, () => {
|
|
||||||
gNewWindow = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
|
|
||||||
waitForFocus(part6, gNewWindow);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function part6() {
|
gNewWindow = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
|
||||||
let condition = function() PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser);
|
|
||||||
waitForCondition(condition, part7, "Waited too long for click-to-play notification");
|
|
||||||
}
|
|
||||||
|
|
||||||
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", 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");
|
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 pluginInfo = yield promiseForPluginInfo("test", gNewWindow.gBrowser.selectedBrowser);
|
||||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
ok(!pluginInfo.activated, "plugin should not be activated");
|
||||||
ok(!objLoadingContent.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;
|
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
|
// Click the activate button on doorhanger to make sure it works
|
||||||
gNewWindow.PopupNotifications.panel.firstChild._primaryButton.click();
|
gNewWindow.PopupNotifications.panel.firstChild._primaryButton.click();
|
||||||
|
|
||||||
let plugin = gNewWindow.gBrowser.selectedBrowser.contentDocument.getElementById("test");
|
let pluginInfo = yield promiseForPluginInfo("test", gNewWindow.gBrowser.selectedBrowser);
|
||||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
ok(pluginInfo.activated, "plugin should be activated");
|
||||||
waitForCondition(() => objLoadingContent.activated, shutdown, "plugin should be activated now");
|
});
|
||||||
}
|
|
||||||
|
|
||||||
function shutdown() {
|
|
||||||
gNewWindow.close();
|
|
||||||
gNewWindow = null;
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,76 +1,54 @@
|
||||||
var rootDir = getRootDirectory(gTestPath);
|
let rootDir = getRootDirectory(gTestPath);
|
||||||
const gTestRoot = rootDir;
|
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
const gHttpTestRoot = 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;
|
add_task(function* () {
|
||||||
var gNextTest = null;
|
registerCleanupFunction(function () {
|
||||||
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() {
|
|
||||||
clearAllPluginPermissions();
|
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");
|
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
|
||||||
|
gBrowser.removeCurrentTab();
|
||||||
|
window.focus();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(function* () {
|
||||||
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
|
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
|
||||||
|
|
||||||
let newTab = gBrowser.addTab();
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
gBrowser.selectedTab = newTab;
|
|
||||||
gTestBrowser = gBrowser.selectedBrowser;
|
|
||||||
gTestBrowser.addEventListener("load", pageLoad, true);
|
|
||||||
|
|
||||||
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
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() {
|
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
|
||||||
clearAllPluginPermissions();
|
|
||||||
gTestBrowser.removeEventListener("load", pageLoad, true);
|
|
||||||
gBrowser.removeCurrentTab();
|
|
||||||
window.focus();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
function pageLoad() {
|
// Work around for delayed PluginBindingAttached
|
||||||
// The plugin events are async dispatched and can come after the load event
|
yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
|
||||||
// This just allows the events to fire before we then go on to test the states
|
|
||||||
executeSoon(gNextTest);
|
|
||||||
}
|
|
||||||
|
|
||||||
function prepareTest(nextTest, url) {
|
// Tests that the overlay can be hidded for disabled plugins using the close icon.
|
||||||
gNextTest = nextTest;
|
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
|
||||||
gTestBrowser.contentWindow.location = url;
|
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.
|
let overlayIsVisible = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
|
||||||
// This wraps a function to force a layout flush, thus triggering it,
|
let doc = content.document;
|
||||||
// and schedules the function execution so they're definitely executed
|
let plugin = doc.getElementById("test");
|
||||||
// afterwards.
|
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
|
||||||
function runAfterPluginBindingAttached(func) {
|
return plugin && overlay.classList.contains("visible");
|
||||||
return function() {
|
});
|
||||||
let doc = gTestBrowser.contentDocument;
|
ok(!overlayIsVisible, "overlay should be hidden.");
|
||||||
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.");
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,104 +1,54 @@
|
||||||
let rootDir = getRootDirectory(gTestPath);
|
let rootDir = getRootDirectory(gTestPath);
|
||||||
const gTestRoot = rootDir;
|
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
|
||||||
|
|
||||||
let gTestBrowser = null;
|
add_task(function* () {
|
||||||
let gNextTest = null;
|
registerCleanupFunction(function () {
|
||||||
|
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
|
||||||
|
|
||||||
function test() {
|
|
||||||
waitForExplicitFinish();
|
|
||||||
registerCleanupFunction(function() {
|
|
||||||
clearAllPluginPermissions();
|
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");
|
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
|
||||||
|
gBrowser.removeCurrentTab();
|
||||||
|
window.focus();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(function* () {
|
||||||
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
|
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
|
||||||
|
|
||||||
let newTab = gBrowser.addTab();
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
gBrowser.selectedTab = newTab;
|
|
||||||
gTestBrowser = gBrowser.selectedBrowser;
|
|
||||||
gTestBrowser.addEventListener("load", pageLoad, true);
|
|
||||||
|
|
||||||
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
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() {
|
// Tests that the overlays are visible and actionable if the plugin is in an iframe.
|
||||||
clearAllPluginPermissions();
|
|
||||||
gTestBrowser.removeEventListener("load", pageLoad, true);
|
|
||||||
gBrowser.removeCurrentTab();
|
|
||||||
window.focus();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
function pageLoad() {
|
let result = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
|
||||||
gNextTest();
|
let frame = content.document.getElementById("frame");
|
||||||
}
|
|
||||||
|
|
||||||
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 doc = frame.contentDocument;
|
let doc = frame.contentDocument;
|
||||||
let elems = doc.getElementsByTagName('embed');
|
let plugin = doc.getElementById("test");
|
||||||
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 overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
|
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
|
||||||
ok(overlay.classList.contains("visible"), "Test 1, Plugin overlay should exist, not be hidden");
|
return plugin && overlay.classList.contains("visible");
|
||||||
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.");
|
|
||||||
});
|
});
|
||||||
}
|
ok(result, "Test 1, Plugin overlay should exist, not be hidden");
|
||||||
|
|
||||||
function test2() {
|
result = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
|
||||||
prepareTest(delayTest(runAfterPluginBindingAttached(test3)), gHttpTestRoot + "plugin_iframe.html");
|
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);
|
let rootDir = getRootDirectory(gTestPath);
|
||||||
const gTestRoot = rootDir;
|
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
const gHttpTestRoot = 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;
|
add_task(function* () {
|
||||||
var gNextTest = null;
|
registerCleanupFunction(function () {
|
||||||
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() {
|
|
||||||
clearAllPluginPermissions();
|
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");
|
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
|
||||||
|
gBrowser.removeCurrentTab();
|
||||||
|
window.focus();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(function* () {
|
||||||
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
|
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
|
||||||
|
|
||||||
var newTab = gBrowser.addTab();
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
gBrowser.selectedTab = newTab;
|
|
||||||
gTestBrowser = gBrowser.selectedBrowser;
|
|
||||||
gTestBrowser.addEventListener("load", pageLoad, true);
|
|
||||||
|
|
||||||
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
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");
|
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() {
|
// Work around for delayed PluginBindingAttached
|
||||||
clearAllPluginPermissions();
|
yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
|
||||||
gTestBrowser.removeEventListener("load", pageLoad, true);
|
|
||||||
gBrowser.removeCurrentTab();
|
|
||||||
window.focus();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
function pageLoad() {
|
// Test that the click-to-play doorhanger for multiple plugins shows the correct
|
||||||
// The plugin events are async dispatched and can come after the load event
|
// state when re-opening without reloads or navigation.
|
||||||
// This just allows the events to fire before we then go on to test the states
|
|
||||||
executeSoon(gNextTest);
|
|
||||||
}
|
|
||||||
|
|
||||||
function prepareTest(nextTest, url) {
|
let pluginInfo = yield promiseForPluginInfo("test", gBrowser.selectedBrowser);
|
||||||
gNextTest = nextTest;
|
ok(!pluginInfo.activated, "plugin should be activated");
|
||||||
gTestBrowser.contentWindow.location = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Due to layout being async, "PluginBindAttached" may trigger later.
|
let notification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
|
||||||
// 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);
|
|
||||||
ok(notification, "Test 1a, Should have a click-to-play notification");
|
ok(notification, "Test 1a, Should have a click-to-play notification");
|
||||||
notification.reshow();
|
|
||||||
|
yield promiseForNotificationShown(notification);
|
||||||
|
|
||||||
is(notification.options.pluginData.size, 2,
|
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;
|
let pluginItem = null;
|
||||||
for (let item of PopupNotifications.panel.firstChild.childNodes) {
|
for (let item of PopupNotifications.panel.firstChild.childNodes) {
|
||||||
|
@ -86,21 +54,20 @@ function test1a() {
|
||||||
pluginItem = item;
|
pluginItem = item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Choose "Allow now" for the test plugin
|
// Choose "Allow now" for the test plugin
|
||||||
pluginItem.value = "allownow";
|
pluginItem.value = "allownow";
|
||||||
PopupNotifications.panel.firstChild._primaryButton.click();
|
PopupNotifications.panel.firstChild._primaryButton.click();
|
||||||
|
|
||||||
waitForCondition(() => objLoadingContent.activated, test1b,
|
pluginInfo = yield promiseForPluginInfo("test", gBrowser.selectedBrowser);
|
||||||
"Test 1a, Waited too long for plugin to activate");
|
ok(pluginInfo.activated, "plugin should be activated");
|
||||||
}
|
|
||||||
|
|
||||||
function test1b() {
|
notification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
|
||||||
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
|
||||||
ok(notification, "Test 1b, Should have a click-to-play notification");
|
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) {
|
for (let item of PopupNotifications.panel.firstChild.childNodes) {
|
||||||
if (item.action.pluginName == "Test") {
|
if (item.action.pluginName == "Test") {
|
||||||
is(item.value, "allownow", "Test 1b, Test plugin should now be set to 'Allow now'");
|
is(item.value, "allownow", "Test 1b, Test plugin should now be set to 'Allow now'");
|
||||||
|
@ -114,17 +81,13 @@ function test1b() {
|
||||||
pluginItem.value = "allowalways";
|
pluginItem.value = "allowalways";
|
||||||
PopupNotifications.panel.firstChild._primaryButton.click();
|
PopupNotifications.panel.firstChild._primaryButton.click();
|
||||||
|
|
||||||
let doc = gTestBrowser.contentDocument;
|
pluginInfo = yield promiseForPluginInfo("secondtestA", gBrowser.selectedBrowser);
|
||||||
let plugin = doc.getElementById("secondtestA");
|
ok(pluginInfo.activated, "plugin should be activated");
|
||||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
|
||||||
waitForCondition(() => objLoadingContent.activated, test1c,
|
|
||||||
"Test 1b, Waited too long for plugin to activate");
|
|
||||||
}
|
|
||||||
|
|
||||||
function test1c() {
|
notification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
|
||||||
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
|
||||||
ok(notification, "Test 1c, Should have a click-to-play notification");
|
ok(notification, "Test 1c, Should have a click-to-play notification");
|
||||||
notification.reshow();
|
|
||||||
|
yield promiseForNotificationShown(notification);
|
||||||
|
|
||||||
for (let item of PopupNotifications.panel.firstChild.childNodes) {
|
for (let item of PopupNotifications.panel.firstChild.childNodes) {
|
||||||
if (item.action.pluginName == "Test") {
|
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'");
|
is(item.value, "allowalways", "Test 1c, Second Test plugin should be set to 'Allow always'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
finishTest();
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,114 +1,58 @@
|
||||||
var rootDir = getRootDirectory(gTestPath);
|
let rootDir = getRootDirectory(gTestPath);
|
||||||
const gTestRoot = rootDir;
|
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
const gHttpTestRoot = 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;
|
add_task(function* () {
|
||||||
var gNextTest = null;
|
registerCleanupFunction(function () {
|
||||||
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() {
|
|
||||||
clearAllPluginPermissions();
|
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");
|
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);
|
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
|
||||||
|
|
||||||
var newTab = gBrowser.addTab();
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
gBrowser.selectedTab = newTab;
|
|
||||||
gTestBrowser = gBrowser.selectedBrowser;
|
|
||||||
gTestBrowser.addEventListener("load", pageLoad, true);
|
|
||||||
gTestBrowser.addEventListener("PluginRemoved", handlePluginRemoved, true, true);
|
|
||||||
|
|
||||||
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_DISABLED, "Test Plug-in");
|
||||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
|
|
||||||
|
|
||||||
prepareTest(runAfterPluginBindingAttached(test1), gHttpTestRoot + "plugin_two_types.html");
|
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_two_types.html");
|
||||||
}
|
|
||||||
|
|
||||||
function finishTest() {
|
// Work around for delayed PluginBindingAttached
|
||||||
clearAllPluginPermissions();
|
yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
|
||||||
gTestBrowser.removeEventListener("load", pageLoad, true);
|
|
||||||
gBrowser.removeCurrentTab();
|
|
||||||
window.focus();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
function pageLoad() {
|
// Test that the click-to-play notification is not shown for non-plugin object elements
|
||||||
// The plugin events are async dispatched and can come after the load event
|
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
|
||||||
// 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);
|
|
||||||
ok(popupNotification, "Test 1, Should have a click-to-play notification");
|
ok(popupNotification, "Test 1, Should have a click-to-play notification");
|
||||||
|
|
||||||
let plugin = gTestBrowser.contentDocument.getElementById("secondtestA");
|
let pluginRemovedPromise = waitForEvent(gBrowser.selectedBrowser, "PluginRemoved", null, true, true);
|
||||||
plugin.parentNode.removeChild(plugin);
|
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
|
||||||
plugin = gTestBrowser.contentDocument.getElementById("secondtestB");
|
let plugin = content.document.getElementById("secondtestA");
|
||||||
plugin.parentNode.removeChild(plugin);
|
plugin.parentNode.removeChild(plugin);
|
||||||
|
plugin = content.document.getElementById("secondtestB");
|
||||||
|
plugin.parentNode.removeChild(plugin);
|
||||||
|
|
||||||
let image = gTestBrowser.contentDocument.createElement("object");
|
let image = content.document.createElement("object");
|
||||||
image.type = "image/png";
|
image.type = "image/png";
|
||||||
image.data = "moz.png";
|
image.data = "moz.png";
|
||||||
gTestBrowser.contentDocument.body.appendChild(image);
|
content.document.body.appendChild(image);
|
||||||
|
});
|
||||||
|
yield pluginRemovedPromise;
|
||||||
|
|
||||||
runAfterPluginRemoved(test2);
|
popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
|
||||||
}
|
|
||||||
|
|
||||||
function test2() {
|
|
||||||
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
|
||||||
ok(popupNotification, "Test 2, Should have a click-to-play notification");
|
ok(popupNotification, "Test 2, Should have a click-to-play notification");
|
||||||
|
|
||||||
let plugin = gTestBrowser.contentDocument.getElementById("test");
|
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
|
||||||
plugin.parentNode.removeChild(plugin);
|
let plugin = content.document.getElementById("test");
|
||||||
|
plugin.parentNode.removeChild(plugin);
|
||||||
|
});
|
||||||
|
|
||||||
executeSoon(test3);
|
popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gBrowser.selectedBrowser);
|
||||||
}
|
|
||||||
|
|
||||||
function test3() {
|
|
||||||
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
|
||||||
ok(popupNotification, "Test 3, Should still have a click-to-play notification");
|
ok(popupNotification, "Test 3, Should still have a click-to-play notification");
|
||||||
|
});
|
||||||
finishTest();
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,171 +1,154 @@
|
||||||
var rootDir = getRootDirectory(gTestPath);
|
let rootDir = getRootDirectory(gTestPath);
|
||||||
const gTestRoot = rootDir;
|
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
let gTestBrowser = null;
|
||||||
|
|
||||||
var gTestBrowser = null;
|
add_task(function* () {
|
||||||
var gNextTest = null;
|
registerCleanupFunction(function () {
|
||||||
|
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
|
||||||
|
|
||||||
function test() {
|
|
||||||
waitForExplicitFinish();
|
|
||||||
registerCleanupFunction(function() {
|
|
||||||
clearAllPluginPermissions();
|
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");
|
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
|
||||||
|
gBrowser.removeCurrentTab();
|
||||||
|
window.focus();
|
||||||
|
gTestBrowser = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
|
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
|
||||||
|
|
||||||
var newTab = gBrowser.addTab();
|
let newTab = gBrowser.addTab();
|
||||||
gBrowser.selectedTab = newTab;
|
gBrowser.selectedTab = newTab;
|
||||||
gTestBrowser = gBrowser.selectedBrowser;
|
gTestBrowser = gBrowser.selectedBrowser;
|
||||||
gTestBrowser.addEventListener("load", pageLoad, true);
|
});
|
||||||
|
|
||||||
|
add_task(function* () {
|
||||||
Services.prefs.setBoolPref("plugins.click_to_play", 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");
|
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_small.html");
|
||||||
}
|
|
||||||
|
|
||||||
function finishTest() {
|
// Work around for delayed PluginBindingAttached
|
||||||
gTestBrowser.removeEventListener("load", pageLoad, true);
|
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||||
gBrowser.removeCurrentTab();
|
|
||||||
window.focus();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
function pageLoad() {
|
yield promisePopupNotification("click-to-play-plugins");
|
||||||
// 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) {
|
// Expecting a notification bar for hidden plugins
|
||||||
gNextTest = nextTest;
|
yield promiseForNotificationBar("plugin-hidden", gTestBrowser);
|
||||||
gTestBrowser.contentWindow.location = url;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// Due to layout being async, "PluginBindAttached" may trigger later.
|
add_task(function* () {
|
||||||
// This wraps a function to force a layout flush, thus triggering it,
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
|
||||||
// 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 for the notification bar for hidden plugins.
|
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_small.html");
|
||||||
|
|
||||||
function test1() {
|
// Work around for delayed PluginBindingAttached
|
||||||
info("Test 1 - expecting a notification bar for hidden plugins.");
|
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||||
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");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
|
||||||
waitForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") !== null,
|
yield promiseForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") === null);
|
||||||
test6,
|
});
|
||||||
"Test 5, expected a notification bar for hidden plugins");
|
|
||||||
}
|
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
|
// Test that the notification bar is getting dismissed when directly activating plugins
|
||||||
// via the doorhanger.
|
// via the doorhanger.
|
||||||
|
|
||||||
function test6() {
|
add_task(function* () {
|
||||||
info("Test 6 - expecting the doorhanger to be dismissed when directly activating plugins.");
|
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_small.html");
|
||||||
waitForNotificationPopup("click-to-play-plugins", gTestBrowser, (notification) => {
|
|
||||||
let plugin = gTestBrowser.contentDocument.getElementById("test");
|
|
||||||
ok(plugin, "Test 6, Found plugin in page");
|
|
||||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
|
||||||
is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
|
|
||||||
"Test 6, Plugin should be click-to-play");
|
|
||||||
|
|
||||||
// simulate "always allow"
|
// Work around for delayed PluginBindingAttached
|
||||||
notification.reshow();
|
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||||
PopupNotifications.panel.firstChild._primaryButton.click();
|
|
||||||
|
|
||||||
let notificationBox = gBrowser.getNotificationBox(gTestBrowser);
|
// Expecting a plugin notification bar when plugins are overlaid offscreen.
|
||||||
waitForCondition(() => notificationBox.getNotificationWithValue("plugin-hidden") === null,
|
yield promisePopupNotification("click-to-play-plugins");
|
||||||
test7,
|
|
||||||
"Test 6, expected the notification bar for hidden plugins to get dismissed");
|
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() {
|
yield promisePopupNotification("click-to-play-plugins");
|
||||||
let plugin = gTestBrowser.contentDocument.getElementById("test");
|
|
||||||
ok(plugin, "Test 7, Found plugin in page");
|
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
||||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
ok(notification, "Test 6, Should have a click-to-play notification");
|
||||||
waitForCondition(() => objLoadingContent.activated, finishTest,
|
|
||||||
"Test 7, Waited too long for plugin to activate");
|
// 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);
|
let rootDir = getRootDirectory(gTestPath);
|
||||||
const gTestRoot = rootDir;
|
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
const gHttpTestRoot = 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;
|
add_task(function* () {
|
||||||
var gNextTest = null;
|
registerCleanupFunction(function () {
|
||||||
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() {
|
|
||||||
clearAllPluginPermissions();
|
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");
|
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);
|
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
|
||||||
|
|
||||||
var newTab = gBrowser.addTab();
|
let newTab = gBrowser.addTab();
|
||||||
gBrowser.selectedTab = newTab;
|
gBrowser.selectedTab = newTab;
|
||||||
gTestBrowser = gBrowser.selectedBrowser;
|
gTestBrowser = gBrowser.selectedBrowser;
|
||||||
gTestBrowser.addEventListener("load", pageLoad, true);
|
|
||||||
|
|
||||||
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
|
||||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
|
|
||||||
|
|
||||||
prepareTest(test1, gHttpTestRoot + "plugin_outsideScrollArea.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();
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that the click-to-play overlay is not hidden for elements
|
// Test that the click-to-play overlay is not hidden for elements
|
||||||
// partially or fully outside the viewport.
|
// partially or fully outside the viewport.
|
||||||
|
|
||||||
function test1() {
|
add_task(function* () {
|
||||||
addPlugin(0, -200);
|
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_outsideScrollArea.html");
|
||||||
executeSoon(runAfterPluginBindingAttached(test2));
|
|
||||||
}
|
|
||||||
|
|
||||||
function test2() {
|
yield ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||||
let doc = gTestBrowser.contentDocument;
|
let doc = content.document;
|
||||||
let plugin = doc.getElementById("test");
|
let p = doc.createElement('embed');
|
||||||
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");
|
|
||||||
|
|
||||||
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() {
|
doc.getElementById('container').appendChild(p);
|
||||||
addPlugin(0, -410);
|
});
|
||||||
executeSoon(runAfterPluginBindingAttached(test4));
|
|
||||||
}
|
|
||||||
|
|
||||||
function test4() {
|
// Work around for delayed PluginBindingAttached
|
||||||
let doc = gTestBrowser.contentDocument;
|
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||||
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");
|
|
||||||
|
|
||||||
prepareTest(test5, gHttpTestRoot + "plugin_outsideScrollArea.html");
|
yield promisePopupNotification("click-to-play-plugins");
|
||||||
}
|
|
||||||
|
|
||||||
function test5() {
|
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||||
addPlugin(-600, 0);
|
let plugin = content.document.getElementById("test");
|
||||||
executeSoon(runAfterPluginBindingAttached(test6));
|
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() {
|
add_task(function* () {
|
||||||
let doc = gTestBrowser.contentDocument;
|
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_outsideScrollArea.html");
|
||||||
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");
|
|
||||||
|
|
||||||
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 gTestRoot = getRootDirectory(gTestPath);
|
||||||
const gHttpTestRoot = gTestRoot.replace("chrome://mochitests/content/",
|
const gHttpTestRoot = gTestRoot.replace("chrome://mochitests/content/",
|
||||||
"http://127.0.0.1:8888/");
|
"http://127.0.0.1:8888/");
|
||||||
|
|
||||||
add_task(function* () {
|
add_task(function* () {
|
||||||
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
registerCleanupFunction(function () {
|
||||||
registerCleanupFunction(() => {
|
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("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
|
* 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.
|
* notification bar on the new page.
|
||||||
*/
|
*/
|
||||||
add_task(function* () {
|
add_task(function* () {
|
||||||
let newTab = gBrowser.addTab();
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
gBrowser.selectedTab = newTab;
|
|
||||||
let browser = gBrowser.selectedBrowser;
|
|
||||||
|
|
||||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
|
|
||||||
|
|
||||||
// Load up a page with a plugin...
|
// Load up a page with a plugin...
|
||||||
let notificationPromise =
|
let notificationPromise = waitForNotificationBar("plugin-hidden", gBrowser.selectedBrowser);
|
||||||
waitForNotificationBar("plugin-hidden", gBrowser.selectedBrowser);
|
yield promiseTabLoadEvent(gBrowser.selectedTab, gHttpTestRoot + "plugin_small.html");
|
||||||
yield loadPage(browser, gHttpTestRoot + "plugin_small.html")
|
yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
|
||||||
yield forcePluginBindingAttached(browser);
|
|
||||||
yield notificationPromise;
|
yield notificationPromise;
|
||||||
|
|
||||||
// Trigger the PluginRemoved event to be fired, and then immediately
|
// Trigger the PluginRemoved event to be fired, and then immediately
|
||||||
// browse to a new page.
|
// browse to a new page.
|
||||||
let plugin = browser.contentDocument.getElementById("test");
|
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
|
||||||
plugin.remove();
|
let plugin = content.document.getElementById("test");
|
||||||
yield loadPage(browser, "about:mozilla");
|
plugin.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
yield promiseTabLoadEvent(gBrowser.selectedTab, "about:mozilla");
|
||||||
|
|
||||||
// There should be no hidden plugin notification bar at 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,
|
is(notificationBox.getNotificationWithValue("plugin-hidden"), null,
|
||||||
"Expected no notification box");
|
"Expected no notification box");
|
||||||
gBrowser.removeTab(newTab);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,32 +54,26 @@ add_task(function* () {
|
||||||
* for the new page.
|
* for the new page.
|
||||||
*/
|
*/
|
||||||
add_task(function* () {
|
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...
|
// Load up a page with a plugin...
|
||||||
let notificationPromise =
|
let notificationPromise = waitForNotificationBar("plugin-hidden", gBrowser.selectedBrowser);
|
||||||
waitForNotificationBar("plugin-hidden", browser);
|
yield promiseTabLoadEvent(gBrowser.selectedTab, gHttpTestRoot + "plugin_small.html");
|
||||||
yield loadPage(browser, gHttpTestRoot + "plugin_small.html")
|
yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
|
||||||
yield forcePluginBindingAttached(browser);
|
|
||||||
yield notificationPromise;
|
yield notificationPromise;
|
||||||
|
|
||||||
// Trigger the PluginRemoved event to be fired, and then immediately
|
// Trigger the PluginRemoved event to be fired, and then immediately
|
||||||
// browse to a new page.
|
// browse to a new page.
|
||||||
let plugin = browser.contentDocument.getElementById("test");
|
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
|
||||||
plugin.remove();
|
let plugin = content.document.getElementById("test");
|
||||||
yield loadPage(browser, gTestRoot + "plugin_small_2.html");
|
plugin.remove();
|
||||||
let notification = yield waitForNotificationBar("plugin-hidden", browser);
|
});
|
||||||
ok(notification, "There should be a notification shown for the new page.");
|
});
|
||||||
|
|
||||||
|
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
|
// Ensure that the notification is showing information about
|
||||||
// the x-second-test plugin.
|
// the x-second-test plugin.
|
||||||
ok(notification.label.includes("Second Test"), "Should mention the second plugin");
|
let label = notification.label;
|
||||||
ok(!notification.label.includes("127.0.0.1"), "Should not refer to old principal");
|
ok(label.includes("Second Test"), "Should mention the second plugin");
|
||||||
ok(notification.label.includes("null"), "Should refer to the new principal");
|
|
||||||
gBrowser.removeTab(newTab);
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,116 +1,130 @@
|
||||||
var rootDir = getRootDirectory(gTestPath);
|
let rootDir = getRootDirectory(gTestPath);
|
||||||
const gTestRoot = rootDir;
|
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
let gTestBrowser = null;
|
||||||
|
|
||||||
var gTestBrowser = null;
|
add_task(function* () {
|
||||||
var gNextTest = null;
|
registerCleanupFunction(function () {
|
||||||
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() {
|
|
||||||
clearAllPluginPermissions();
|
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");
|
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);
|
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
|
||||||
|
|
||||||
var newTab = gBrowser.addTab();
|
let newTab = gBrowser.addTab();
|
||||||
gBrowser.selectedTab = newTab;
|
gBrowser.selectedTab = newTab;
|
||||||
gTestBrowser = gBrowser.selectedBrowser;
|
gTestBrowser = gBrowser.selectedBrowser;
|
||||||
gTestBrowser.addEventListener("load", pageLoad, true);
|
|
||||||
|
|
||||||
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
|
||||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
|
|
||||||
|
|
||||||
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() {
|
yield promiseTabLoadEvent(newTab, gTestRoot + "plugin_small.html"); // 10x10 plugin
|
||||||
clearAllPluginPermissions();
|
|
||||||
gTestBrowser.removeEventListener("load", pageLoad, true);
|
|
||||||
gBrowser.removeCurrentTab();
|
|
||||||
window.focus();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
function pageLoad() {
|
// Work around for delayed PluginBindingAttached
|
||||||
// The plugin events are async dispatched and can come after the load event
|
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||||
// This just allows the events to fire before we then go on to test the states
|
|
||||||
executeSoon(gNextTest);
|
|
||||||
}
|
|
||||||
|
|
||||||
function prepareTest(nextTest, url) {
|
yield promisePopupNotification("click-to-play-plugins");
|
||||||
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 overlay is hidden for "small" plugin elements and is shown
|
// 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
|
// once they are resized to a size that can hold the overlay
|
||||||
|
add_task(function* () {
|
||||||
function test1() {
|
|
||||||
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
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 result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||||
let doc = gTestBrowser.contentDocument;
|
let doc = content.document;
|
||||||
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
|
let plugin = doc.getElementById("test");
|
||||||
ok(overlay, "Test 1, Should have an overlay.");
|
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
|
||||||
ok(!overlay.classList.contains("visible"), "Test 1, Overlay should be hidden");
|
return overlay && overlay.classList.contains("visible");
|
||||||
|
});
|
||||||
|
ok(!result, "Test 2, overlay should be hidden.");
|
||||||
|
});
|
||||||
|
|
||||||
plugin.style.width = '300px';
|
add_task(function* () {
|
||||||
executeSoon(test2);
|
yield ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||||
}
|
let plugin = content.document.getElementById("test");
|
||||||
|
plugin.style.width = "300px";
|
||||||
|
});
|
||||||
|
|
||||||
function test2() {
|
// Work around for delayed PluginBindingAttached
|
||||||
let plugin = gTestBrowser.contentDocument.getElementById("test");
|
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||||
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");
|
|
||||||
|
|
||||||
plugin.style.height = '300px';
|
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||||
let condition = () => overlay.classList.contains("visible");
|
let doc = content.document;
|
||||||
waitForCondition(condition, test3, "Test 2, Waited too long for overlay to become visible");
|
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';
|
add_task(function* () {
|
||||||
plugin.style.height = '10px';
|
yield ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||||
let condition = () => !overlay.classList.contains("visible");
|
let plugin = content.document.getElementById("test");
|
||||||
waitForCondition(condition, test4, "Test 3, Waited too long for overlay to become hidden");
|
plugin.style.height = "300px";
|
||||||
}
|
});
|
||||||
|
|
||||||
function test4() {
|
yield ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||||
let plugin = gTestBrowser.contentDocument.getElementById("test");
|
content.document.getElementById("test").clientTop;
|
||||||
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");
|
|
||||||
|
|
||||||
clearAllPluginPermissions();
|
let result = yield ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||||
finishTest();
|
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";
|
"use strict";
|
||||||
|
|
||||||
let rootDir = getRootDirectory(gTestPath);
|
let rootDir = getRootDirectory(gTestPath);
|
||||||
const gTestRoot = rootDir;
|
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/",
|
|
||||||
"http://127.0.0.1:8888/");
|
|
||||||
|
|
||||||
let gTestBrowser = null;
|
let gTestBrowser = null;
|
||||||
|
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
add_task(function* () {
|
||||||
|
registerCleanupFunction(function () {
|
||||||
function test() {
|
|
||||||
waitForExplicitFinish();
|
|
||||||
registerCleanupFunction(() => {
|
|
||||||
FullZoom.reset();
|
|
||||||
clearAllPluginPermissions();
|
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");
|
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("extensions.blocklist.suppressUI", true);
|
||||||
|
|
||||||
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
|
|
||||||
|
|
||||||
let newTab = gBrowser.addTab();
|
|
||||||
gBrowser.selectedTab = newTab;
|
|
||||||
gTestBrowser = gBrowser.selectedBrowser;
|
gTestBrowser = gBrowser.selectedBrowser;
|
||||||
gTestBrowser.addEventListener("load", pageLoad, true);
|
|
||||||
gTestBrowser.contentWindow.location = gHttpTestRoot + "plugin_zoom.html"
|
|
||||||
}
|
|
||||||
|
|
||||||
function finishTest() {
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
|
||||||
clearAllPluginPermissions();
|
|
||||||
gTestBrowser.removeEventListener("load", pageLoad, true);
|
|
||||||
gBrowser.removeCurrentTab();
|
|
||||||
window.focus();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
function pageLoad() {
|
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
||||||
// Due to layout being async, "PluginBindAttached" may trigger later.
|
ok(!popupNotification, "Test 1, Should not have a click-to-play notification");
|
||||||
// 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 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.
|
// visible after each enlargement.
|
||||||
function testOverlay() {
|
add_task(function* () {
|
||||||
let plugin = gTestBrowser.contentDocument.getElementById("test");
|
for (let count = 0; count < 4; count++) {
|
||||||
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");
|
|
||||||
|
|
||||||
if (enlargeCount > 0) {
|
|
||||||
--enlargeCount;
|
|
||||||
FullZoom.enlarge();
|
FullZoom.enlarge();
|
||||||
gTestBrowser.contentWindow.location.reload();
|
|
||||||
} else {
|
// Reload the page
|
||||||
FullZoom.reset();
|
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_zoom.html");
|
||||||
clearAllPluginPermissions();
|
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||||
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, "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);
|
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://mochi.test:8888/");
|
let gTestBrowser = null;
|
||||||
|
|
||||||
var gTestBrowser = null;
|
add_task(function* () {
|
||||||
var gNextTest = null;
|
registerCleanupFunction(Task.async(function*() {
|
||||||
|
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
|
||||||
|
|
||||||
function test() {
|
|
||||||
waitForExplicitFinish();
|
|
||||||
registerCleanupFunction(function() {
|
|
||||||
clearAllPluginPermissions();
|
clearAllPluginPermissions();
|
||||||
Services.prefs.clearUserPref("plugins.click_to_play");
|
Services.prefs.clearUserPref("plugins.click_to_play");
|
||||||
});
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
|
||||||
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
|
||||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
|
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;
|
gBrowser.selectedTab = newTab;
|
||||||
gTestBrowser = gBrowser.selectedBrowser;
|
gTestBrowser = gBrowser.selectedBrowser;
|
||||||
gTestBrowser.addEventListener("load", pageLoad, true);
|
|
||||||
prepareTest(test1a, gTestRoot + "plugin_add_dynamically.html");
|
|
||||||
}
|
|
||||||
|
|
||||||
function finishTest() {
|
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
|
||||||
gTestBrowser.removeEventListener("load", pageLoad, true);
|
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
||||||
gBrowser.removeCurrentTab();
|
|
||||||
window.focus();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
function pageLoad() {
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
|
||||||
// The plugin events are async dispatched and can come after the load event
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
|
||||||
// This just allows the events to fire before we then go on to test the states
|
|
||||||
executeSoon(gNextTest);
|
|
||||||
}
|
|
||||||
|
|
||||||
function prepareTest(nextTest, url) {
|
// Prime the blocklist service, the remote service doesn't launch on startup.
|
||||||
gNextTest = nextTest;
|
yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html></html>");
|
||||||
gTestBrowser.contentWindow.location = url;
|
|
||||||
}
|
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.
|
// Tests that navigation within the page and the window.history API doesn't break click-to-play state.
|
||||||
function test1a() {
|
add_task(function* () {
|
||||||
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_add_dynamically.html");
|
||||||
ok(!popupNotification, "Test 1a, Should not have a click-to-play notification");
|
|
||||||
var plugin = new XPCNativeWrapper(XPCNativeWrapper.unwrap(gTestBrowser.contentWindow).addPlugin());
|
|
||||||
|
|
||||||
var condition = function() PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
||||||
waitForCondition(condition, test1b, "Test 1a, Waited too long for plugin notification");
|
ok(!notification, "Test 1a, Should not have a click-to-play notification");
|
||||||
}
|
|
||||||
|
|
||||||
function test1b() {
|
yield ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||||
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin());
|
||||||
ok(popupNotification, "Test 1b, Should have a click-to-play notification");
|
});
|
||||||
var plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[0];
|
|
||||||
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
yield promisePopupNotification("click-to-play-plugins");
|
||||||
ok(!objLoadingContent.activated, "Test 1b, Plugin should not be activated");
|
});
|
||||||
|
|
||||||
|
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
|
// 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();
|
PopupNotifications.panel.firstChild._primaryButton.click();
|
||||||
var condition = function() objLoadingContent.activated;
|
|
||||||
waitForCondition(condition, test1c, "Test 1b, Waited too long for plugin activation");
|
|
||||||
}
|
|
||||||
|
|
||||||
function test1c() {
|
isActivated = yield ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||||
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
let plugin = content.document.getElementsByTagName("embed")[0];
|
||||||
ok(popupNotification, "Test 1c, Should still have a click-to-play notification");
|
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
||||||
var plugin = new XPCNativeWrapper(XPCNativeWrapper.unwrap(gTestBrowser.contentWindow).addPlugin());
|
return objLoadingContent.activated;
|
||||||
|
});
|
||||||
|
ok(isActivated, "Test 1b, Plugin should be activated");
|
||||||
|
});
|
||||||
|
|
||||||
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
add_task(function* () {
|
||||||
var condition = function() objLoadingContent.activated;
|
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
||||||
waitForCondition(condition, test1d, "Test 1c, Waited too long for plugin activation");
|
ok(notification, "Test 1c, Should still have a click-to-play notification");
|
||||||
}
|
|
||||||
|
|
||||||
function test1d() {
|
let isActivated = yield ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||||
var plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[1];
|
new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin());
|
||||||
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
let plugin = content.document.getElementsByTagName("embed")[1];
|
||||||
ok(objLoadingContent.activated, "Test 1d, Plugin should be activated");
|
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
||||||
|
return objLoadingContent.activated;
|
||||||
|
});
|
||||||
|
ok(isActivated, "Test 1c, Newly inserted plugin in activated page should be activated");
|
||||||
|
});
|
||||||
|
|
||||||
gNextTest = test1e;
|
add_task(function* () {
|
||||||
gTestBrowser.contentWindow.addEventListener("hashchange", test1e, false);
|
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";
|
gTestBrowser.contentWindow.location += "#anchorNavigation";
|
||||||
}
|
yield promise;
|
||||||
|
});
|
||||||
|
|
||||||
function test1e() {
|
add_task(function* () {
|
||||||
gTestBrowser.contentWindow.removeEventListener("hashchange", test1e, false);
|
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);
|
isActivated = yield ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||||
var condition = function() objLoadingContent.activated;
|
content.history.replaceState({}, "", "replacedState");
|
||||||
waitForCondition(condition, test1f, "Test 1e, Waited too long for plugin activation");
|
new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin());
|
||||||
}
|
let plugin = content.document.getElementsByTagName("embed")[3];
|
||||||
|
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
||||||
function test1f() {
|
return objLoadingContent.activated;
|
||||||
var plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[2];
|
});
|
||||||
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
ok(isActivated, "Test 1f, Plugin should not be activated");
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,43 +1,51 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
let gTestBrowser = null;
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
let gNumPluginBindingsAttached = 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";
|
|
||||||
}
|
|
||||||
|
|
||||||
function pluginBindingAttached() {
|
function pluginBindingAttached() {
|
||||||
gNumPluginBindingsAttached++;
|
gNumPluginBindingsAttached++;
|
||||||
|
if (gNumPluginBindingsAttached != 1) {
|
||||||
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 {
|
|
||||||
ok(false, "if we've gotten here, something is quite wrong");
|
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 gTestBrowser = null;
|
||||||
let gWrapperClickCount = 0;
|
let gWrapperClickCount = 0;
|
||||||
|
|
||||||
function test() {
|
add_task(function* () {
|
||||||
waitForExplicitFinish();
|
registerCleanupFunction(function () {
|
||||||
registerCleanupFunction(function() {
|
clearAllPluginPermissions();
|
||||||
Services.prefs.clearUserPref("plugins.click_to_play");
|
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);
|
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
||||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
|
|
||||||
|
|
||||||
gBrowser.selectedTab = gBrowser.addTab();
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
gTestBrowser = gBrowser.selectedBrowser;
|
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.
|
// Due to layout being async, "PluginBindAttached" may trigger later.
|
||||||
// This forces a layout flush, thus triggering it, and schedules the
|
// This forces a layout flush, thus triggering it, and schedules the
|
||||||
// test so it is definitely executed afterwards.
|
// test so it is definitely executed afterwards.
|
||||||
gTestBrowser.contentDocument.getElementById('plugin').clientTop;
|
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||||
executeSoon(part1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function part1() {
|
// check plugin state
|
||||||
let wrapper = gTestBrowser.contentDocument.getElementById('wrapper');
|
let pluginInfo = yield promiseForPluginInfo("plugin");
|
||||||
wrapper.addEventListener('click', function() ++gWrapperClickCount, false);
|
ok(!pluginInfo.activated, "1a plugin should not be activated");
|
||||||
|
|
||||||
let plugin = gTestBrowser.contentDocument.getElementById('plugin');
|
// click the overlay to prompt
|
||||||
ok(plugin, 'got plugin element');
|
let promise = promisePopupNotification("click-to-play-plugins");
|
||||||
ok(!plugin.activated, 'plugin should not be activated');
|
yield ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||||
ok(PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed, "Doorhanger should not be open");
|
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);
|
// check plugin state
|
||||||
let condition = function() !PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser).dismissed;
|
pluginInfo = yield promiseForPluginInfo("plugin");
|
||||||
waitForCondition(condition, part2,
|
ok(!pluginInfo.activated, "1b plugin should not be activated");
|
||||||
'waited too long for plugin to activate');
|
|
||||||
}
|
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');
|
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
|
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
let gTestBrowser = null;
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
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 Cc = Components.classes;
|
||||||
const Ci = Components.interfaces;
|
const Ci = Components.interfaces;
|
||||||
var gTestBrowser = null;
|
|
||||||
var gConsoleErrors = 0;
|
|
||||||
|
|
||||||
function test() {
|
add_task(function* () {
|
||||||
waitForExplicitFinish();
|
registerCleanupFunction(function () {
|
||||||
var newTab = gBrowser.addTab();
|
clearAllPluginPermissions();
|
||||||
gBrowser.selectedTab = newTab;
|
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 = 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);
|
.getService(Ci.nsIConsoleService);
|
||||||
var errorListener = {
|
let errorListener = {
|
||||||
observe: function(aMessage) {
|
observe: function(aMessage) {
|
||||||
if (aMessage.message.includes("NS_ERROR"))
|
if (aMessage.message.includes("NS_ERROR_FAILURE"))
|
||||||
gConsoleErrors++;
|
gConsoleErrors++;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
consoleService.registerListener(errorListener);
|
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() {
|
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_bug797677.html");
|
||||||
// Let browser-plugins.js handle the PluginNotFound event, then run the test
|
|
||||||
executeSoon(runTest);
|
|
||||||
}
|
|
||||||
|
|
||||||
function runTest() {
|
yield bindingPromise;
|
||||||
var doc = gTestBrowser.contentDocument;
|
|
||||||
var plugin = doc.getElementById("plugin");
|
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");
|
ok(plugin, "plugin should be in the page");
|
||||||
is(gConsoleErrors, 0, "should have no console errors");
|
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/");
|
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
var gTestBrowser = null;
|
let gTestBrowser = null;
|
||||||
var gNextTest = null;
|
|
||||||
|
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
add_task(function* () {
|
||||||
|
registerCleanupFunction(Task.async(function*() {
|
||||||
function test() {
|
clearAllPluginPermissions();
|
||||||
waitForExplicitFinish();
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
|
||||||
registerCleanupFunction(function() {
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
|
||||||
Services.prefs.clearUserPref("plugins.click_to_play");
|
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
|
||||||
});
|
|
||||||
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() {
|
|
||||||
resetBlocklist();
|
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) {
|
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
||||||
// The plugin events are async dispatched and can come after the load event
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
|
||||||
// This just allows the events to fire before we then go on to test the states
|
|
||||||
if (gNextTest != null)
|
|
||||||
executeSoon(gNextTest);
|
|
||||||
}
|
|
||||||
|
|
||||||
function prepareTest(nextTest, url) {
|
// Prime the blocklist service, the remote service doesn't launch on startup.
|
||||||
gNextTest = nextTest;
|
yield promiseTabLoadEvent(gBrowser.selectedTab, "data:text/html,<html></html>");
|
||||||
gTestBrowser.contentWindow.location = url;
|
let exmsg = yield promiseInitContentBlocklistSvc(gBrowser.selectedBrowser);
|
||||||
}
|
ok(!exmsg, "exception: " + exmsg);
|
||||||
|
});
|
||||||
|
|
||||||
// Tests that the going back will reshow the notification for click-to-play
|
// Tests that the going back will reshow the notification for click-to-play
|
||||||
// blocklisted plugins (part 1/4)
|
// blocklisted plugins
|
||||||
function testPart1() {
|
add_task(function* () {
|
||||||
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
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");
|
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() {
|
let found = yield ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||||
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
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");
|
ok(!popupNotification, "test part 2: Should not have a click-to-play notification");
|
||||||
var plugin = gTestBrowser.contentDocument.getElementById("test");
|
let found = yield ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||||
ok(!plugin, "test part 2: Should not have a plugin in this page");
|
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();
|
gTestBrowser.contentWindow.history.back();
|
||||||
}
|
yield obsPromise;
|
||||||
|
yield overlayPromise;
|
||||||
|
});
|
||||||
|
|
||||||
function testPart3() {
|
add_task(function* () {
|
||||||
Services.obs.removeObserver(testPart3, "PopupNotifications-updateNotShowing");
|
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
function testPart4() {
|
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
||||||
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
ok(popupNotification, "test part 3: Should have a click-to-play notification");
|
||||||
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");
|
|
||||||
|
|
||||||
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/");
|
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
var gTestBrowser = null;
|
let gTestBrowser = null;
|
||||||
|
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
add_task(function* () {
|
||||||
|
registerCleanupFunction(function () {
|
||||||
function test() {
|
clearAllPluginPermissions();
|
||||||
waitForExplicitFinish();
|
|
||||||
registerCleanupFunction(function() {
|
|
||||||
Services.prefs.clearUserPref("plugins.click_to_play");
|
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);
|
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
||||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
|
|
||||||
|
|
||||||
gBrowser.selectedTab = gBrowser.addTab();
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
gTestBrowser = gBrowser.selectedBrowser;
|
gTestBrowser = gBrowser.selectedBrowser;
|
||||||
gTestBrowser.addEventListener("load", pageLoad, true);
|
|
||||||
gTestBrowser.contentWindow.location = gHttpTestRoot + "plugin_both.html";
|
|
||||||
}
|
|
||||||
|
|
||||||
function pageLoad(aEvent) {
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
function actualTest() {
|
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_both.html");
|
||||||
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
|
||||||
|
// 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");
|
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");
|
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
|
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
let gTestBrowser = null;
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
let gNumPluginBindingsAttached = 0;
|
||||||
|
|
||||||
var gTestBrowser = null;
|
add_task(function* () {
|
||||||
var gNumPluginBindingsAttached = 0;
|
registerCleanupFunction(function () {
|
||||||
|
clearAllPluginPermissions();
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
|
||||||
|
|
||||||
function test() {
|
|
||||||
waitForExplicitFinish();
|
|
||||||
registerCleanupFunction(function() {
|
|
||||||
Services.prefs.clearUserPref("plugins.click_to_play");
|
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();
|
gBrowser.removeCurrentTab();
|
||||||
window.focus();
|
window.focus();
|
||||||
|
gTestBrowser = null;
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(function* () {
|
||||||
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
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();
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
gTestBrowser = gBrowser.selectedBrowser;
|
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() {
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
|
||||||
gNumPluginBindingsAttached++;
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
|
||||||
|
|
||||||
if (gNumPluginBindingsAttached == 1) {
|
gTestBrowser.addEventListener("PluginBindingAttached", function () { gNumPluginBindingsAttached++ }, true, true);
|
||||||
var doc = gTestBrowser.contentDocument;
|
|
||||||
var testplugin = doc.getElementById("test");
|
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");
|
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");
|
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," +
|
"baz.com:1:5," +
|
||||||
"qux.com:1:100"
|
"qux.com:1:100"
|
||||||
);
|
);
|
||||||
|
|
||||||
setTimeout(testFinishedCallback, 0);
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -1,50 +1,63 @@
|
||||||
/**
|
var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
||||||
* Any copyright is dedicated to the Public Domain.
|
var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
|
||||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
var gTestBrowser = null;
|
||||||
*/
|
|
||||||
|
|
||||||
var rootDir = getRootDirectory(gTestPath);
|
|
||||||
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://mochi.test:8888/");
|
|
||||||
|
|
||||||
// Test clearing plugin data using sanitize.js.
|
// Test clearing plugin data using sanitize.js.
|
||||||
const testURL1 = gHttpTestRoot + "browser_clearplugindata.html";
|
const testURL1 = gTestRoot + "browser_clearplugindata.html";
|
||||||
const testURL2 = gHttpTestRoot + "browser_clearplugindata_noage.html";
|
const testURL2 = gTestRoot + "browser_clearplugindata_noage.html";
|
||||||
|
|
||||||
let tempScope = {};
|
var tempScope = {};
|
||||||
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
|
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
|
||||||
.loadSubScript("chrome://browser/content/sanitize.js", tempScope);
|
.loadSubScript("chrome://browser/content/sanitize.js", tempScope);
|
||||||
let Sanitizer = tempScope.Sanitizer;
|
var Sanitizer = tempScope.Sanitizer;
|
||||||
|
|
||||||
const pluginHostIface = Ci.nsIPluginHost;
|
const pluginHostIface = Ci.nsIPluginHost;
|
||||||
var pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
var pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||||
pluginHost.QueryInterface(pluginHostIface);
|
pluginHost.QueryInterface(pluginHostIface);
|
||||||
|
|
||||||
var pluginTag = getTestPlugin();
|
var pluginTag = getTestPlugin();
|
||||||
var s;
|
var sanitizer = null;
|
||||||
|
|
||||||
function stored(needles) {
|
function stored(needles) {
|
||||||
var something = pluginHost.siteHasData(this.pluginTag, null);
|
let something = pluginHost.siteHasData(this.pluginTag, null);
|
||||||
if (!needles)
|
if (!needles)
|
||||||
return something;
|
return something;
|
||||||
|
|
||||||
if (!something)
|
if (!something)
|
||||||
return false;
|
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]))
|
if (!pluginHost.siteHasData(this.pluginTag, needles[i]))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function test() {
|
add_task(function* () {
|
||||||
waitForExplicitFinish();
|
registerCleanupFunction(function () {
|
||||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
|
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();
|
add_task(function* () {
|
||||||
s.ignoreTimespan = false;
|
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
||||||
s.prefDomain = "privacy.cpd.";
|
|
||||||
var itemPrefs = gPrefService.getBranch(s.prefDomain);
|
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("history", false);
|
||||||
itemPrefs.setBoolPref("downloads", false);
|
itemPrefs.setBoolPref("downloads", false);
|
||||||
itemPrefs.setBoolPref("cache", false);
|
itemPrefs.setBoolPref("cache", false);
|
||||||
|
@ -54,80 +67,61 @@ function test() {
|
||||||
itemPrefs.setBoolPref("passwords", false);
|
itemPrefs.setBoolPref("passwords", false);
|
||||||
itemPrefs.setBoolPref("sessions", false);
|
itemPrefs.setBoolPref("sessions", false);
|
||||||
itemPrefs.setBoolPref("siteSettings", false);
|
itemPrefs.setBoolPref("siteSettings", false);
|
||||||
|
});
|
||||||
|
|
||||||
executeSoon(test_with_age);
|
add_task(function* () {
|
||||||
}
|
|
||||||
|
|
||||||
function setFinishedCallback(callback)
|
|
||||||
{
|
|
||||||
let testPage = gBrowser.selectedBrowser.contentWindow.wrappedJSObject;
|
|
||||||
testPage.testFinishedCallback = function() {
|
|
||||||
setTimeout(function() {
|
|
||||||
info("got finished callback");
|
|
||||||
callback();
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function test_with_age()
|
|
||||||
{
|
|
||||||
// Load page to set data for the plugin.
|
// Load page to set data for the plugin.
|
||||||
gBrowser.selectedTab = gBrowser.addTab();
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
gBrowser.selectedBrowser.addEventListener("load", function () {
|
gTestBrowser = gBrowser.selectedBrowser;
|
||||||
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
|
||||||
|
|
||||||
setFinishedCallback(function() {
|
yield promiseTabLoadEvent(gBrowser.selectedTab, testURL1);
|
||||||
ok(stored(["foo.com","bar.com","baz.com","qux.com"]),
|
|
||||||
"Data stored for sites");
|
|
||||||
|
|
||||||
// Clear 20 seconds ago
|
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||||
var now_uSec = Date.now() * 1000;
|
|
||||||
s.range = [now_uSec - 20*1000000, now_uSec];
|
|
||||||
s.sanitize();
|
|
||||||
|
|
||||||
ok(stored(["bar.com","qux.com"]), "Data stored for sites");
|
ok(stored(["foo.com","bar.com","baz.com","qux.com"]),
|
||||||
ok(!stored(["foo.com"]), "Data cleared for foo.com");
|
"Data stored for sites");
|
||||||
ok(!stored(["baz.com"]), "Data cleared for baz.com");
|
|
||||||
|
|
||||||
// Clear everything
|
// Clear 20 seconds ago
|
||||||
s.range = null;
|
let now_uSec = Date.now() * 1000;
|
||||||
s.sanitize();
|
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);
|
ok(!stored(null), "All data cleared");
|
||||||
});
|
|
||||||
}, true);
|
|
||||||
content.location = testURL1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function test_without_age()
|
gBrowser.removeCurrentTab();
|
||||||
{
|
gTestBrowser = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(function* () {
|
||||||
// Load page to set data for the plugin.
|
// Load page to set data for the plugin.
|
||||||
gBrowser.selectedTab = gBrowser.addTab();
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
gBrowser.selectedBrowser.addEventListener("load", function () {
|
gTestBrowser = gBrowser.selectedBrowser;
|
||||||
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
|
||||||
|
|
||||||
setFinishedCallback(function() {
|
yield promiseTabLoadEvent(gBrowser.selectedTab, testURL2);
|
||||||
ok(stored(["foo.com","bar.com","baz.com","qux.com"]),
|
|
||||||
"Data stored for sites");
|
|
||||||
|
|
||||||
// Attempt to clear 20 seconds ago. The plugin will throw
|
yield promiseUpdatePluginBindings(gTestBrowser);
|
||||||
// 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();
|
|
||||||
|
|
||||||
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);
|
ok(!stored(null), "All data cleared");
|
||||||
});
|
|
||||||
}, true);
|
gBrowser.removeCurrentTab();
|
||||||
content.location = testURL2;
|
gTestBrowser = null;
|
||||||
}
|
});
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
"baz.com:1:5," +
|
"baz.com:1:5," +
|
||||||
"qux.com:1:100"
|
"qux.com:1:100"
|
||||||
);
|
);
|
||||||
|
|
||||||
setTimeout(testFinishedCallback, 0);
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</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
|
* Test that plugin crash submissions still work properly after
|
||||||
* click-to-play activation.
|
* 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/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 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";
|
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);
|
var rootDir = getRootDirectory(gTestPath);
|
||||||
const gTestRoot = rootDir;
|
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);
|
var rootDir = getRootDirectory(gTestPath);
|
||||||
const gTestRoot = rootDir;
|
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);
|
var rootDir = getRootDirectory(gTestPath);
|
||||||
const gTestRoot = rootDir;
|
const gTestRoot = rootDir;
|
||||||
|
|
||||||
|
|
|
@ -1,178 +1,137 @@
|
||||||
var rootDir = getRootDirectory(gTestPath);
|
var rootDir = getRootDirectory(gTestPath);
|
||||||
const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://mochi.test:8888/");
|
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);
|
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!
|
add_task(function* () {
|
||||||
function addPlugin(browser, type) {
|
registerCleanupFunction(Task.async(function*() {
|
||||||
let contentWindow = XPCNativeWrapper.unwrap(browser.contentWindow);
|
|
||||||
contentWindow.addPlugin(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
function test() {
|
|
||||||
waitForExplicitFinish();
|
|
||||||
registerCleanupFunction(function() {
|
|
||||||
clearAllPluginPermissions();
|
clearAllPluginPermissions();
|
||||||
Services.prefs.clearUserPref("plugins.click_to_play");
|
Services.prefs.clearUserPref("plugins.click_to_play");
|
||||||
});
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
|
||||||
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
|
||||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
|
yield asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins.xml", gTestBrowser);
|
||||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
|
resetBlocklist();
|
||||||
|
gBrowser.removeCurrentTab();
|
||||||
let newTab = gBrowser.addTab();
|
window.focus();
|
||||||
gBrowser.selectedTab = newTab;
|
gTestBrowser = null;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// "Activate" of a given type -> plugins of that type dynamically added should
|
// "Activate" of a given type -> plugins of that type dynamically added should
|
||||||
// automatically play.
|
// automatically play.
|
||||||
function testActivateAddSameTypePart1() {
|
add_task(function* () {
|
||||||
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
let newTab = gBrowser.addTab();
|
||||||
ok(!popupNotification, "testActivateAddSameTypePart1: should not have a click-to-play notification");
|
gBrowser.selectedTab = newTab;
|
||||||
addPlugin(gTestBrowser);
|
gTestBrowser = gBrowser.selectedBrowser;
|
||||||
let condition = function() PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
|
||||||
waitForCondition(condition, testActivateAddSameTypePart2, "testActivateAddSameTypePart1: waited too long for click-to-play-plugin notification");
|
|
||||||
}
|
|
||||||
|
|
||||||
function testActivateAddSameTypePart2() {
|
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
|
||||||
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
||||||
ok(popupNotification, "testActivateAddSameTypePart2: should have a click-to-play notification");
|
|
||||||
|
|
||||||
popupNotification.reshow();
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
|
||||||
testActivateAddSameTypePart3();
|
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;
|
let centerAction = null;
|
||||||
for (let action of popupNotification.options.pluginData.values()) {
|
for (let action of notification.options.pluginData.values()) {
|
||||||
if (action.pluginName == "Test") {
|
if (action.pluginName == "Test") {
|
||||||
centerAction = action;
|
centerAction = action;
|
||||||
break;
|
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;
|
let centerItem = null;
|
||||||
for (let item of PopupNotifications.panel.firstChild.childNodes) {
|
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;
|
centerItem = item;
|
||||||
break;
|
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];
|
// Select the allow now option in the select drop down for Test Plugin
|
||||||
ok(!plugin.activated, "testActivateAddSameTypePart3: plugin should not be activated");
|
|
||||||
|
|
||||||
// Change the state and click the ok button to activate the Test plugin
|
|
||||||
centerItem.value = "allownow";
|
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
|
// "click" the button to activate the Test plugin
|
||||||
PopupNotifications.panel.firstChild._primaryButton.click();
|
PopupNotifications.panel.firstChild._primaryButton.click();
|
||||||
|
|
||||||
let condition = function() plugin.activated;
|
let pluginInfo = yield promiseForPluginInfo("pluginone");
|
||||||
waitForCondition(condition, testActivateAddDifferentTypePart4, "testActivateAddDifferentTypePart3: waited too long for plugin to activate");
|
ok(pluginInfo.activated, "Test 5, plugin should be activated");
|
||||||
}
|
|
||||||
|
|
||||||
function testActivateAddDifferentTypePart4() {
|
// Add another plugin of type test
|
||||||
let plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[0];
|
yield ContentTask.spawn(gTestBrowser, {}, function* () {
|
||||||
ok(plugin.activated, "testActivateAddDifferentTypePart4: plugin should be activated");
|
new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin("plugintwo", "application/x-test"));
|
||||||
|
});
|
||||||
|
|
||||||
addPlugin(gTestBrowser);
|
pluginInfo = yield promiseForPluginInfo("plugintwo");
|
||||||
let condition = function() PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
|
ok(pluginInfo.activated, "Test 6, plugins should be activated");
|
||||||
waitForCondition(condition, testActivateAddDifferentTypePart5, "testActivateAddDifferentTypePart5: waited too long for popup notification");
|
});
|
||||||
}
|
|
||||||
|
|
||||||
function testActivateAddDifferentTypePart5() {
|
// "Activate" of a given type -> plugins of other types dynamically added
|
||||||
ok(PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser), "testActivateAddDifferentTypePart5: should have popup notification");
|
// should not automatically play.
|
||||||
let embeds = gTestBrowser.contentDocument.getElementsByTagName("embed");
|
add_task(function* () {
|
||||||
for (let embed of embeds) {
|
clearAllPluginPermissions();
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
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",
|
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||||
"resource://gre/modules/PlacesUtils.jsm");
|
"resource://gre/modules/PlacesUtils.jsm");
|
||||||
|
|
||||||
function whenDelayedStartupFinished(aWindow, aCallback) {
|
// The blocklist shim running in the content process does not initialize at
|
||||||
Services.obs.addObserver(function observer(aSubject, aTopic) {
|
// start up, so it's not active until we load content that needs to do a
|
||||||
if (aWindow == aSubject) {
|
// check. This helper bypasses the delay to get the svc up and running
|
||||||
Services.obs.removeObserver(observer, aTopic);
|
// immediately. Note, call this after remote content has loaded.
|
||||||
executeSoon(aCallback);
|
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);
|
* Waits a specified number of miliseconds.
|
||||||
while (windows.hasMoreElements()) {
|
*
|
||||||
let win = windows.getNext();
|
* Usage:
|
||||||
if (win.location.href == aURI)
|
* let wait = yield waitForMs(2000);
|
||||||
return win;
|
* 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;
|
// DOM Promise fails for unknown reasons here, so we're using
|
||||||
var interval = setInterval(function() {
|
// resource://gre/modules/Promise.jsm.
|
||||||
if (tries >= 30) {
|
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);
|
ok(false, errorMsg);
|
||||||
moveOn();
|
moveOn();
|
||||||
}
|
}
|
||||||
var conditionPassed;
|
let conditionPassed;
|
||||||
try {
|
try {
|
||||||
conditionPassed = condition();
|
conditionPassed = condition();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -44,17 +133,27 @@ function waitForCondition(condition, nextTest, errorMsg) {
|
||||||
moveOn();
|
moveOn();
|
||||||
}
|
}
|
||||||
tries++;
|
tries++;
|
||||||
}, 100);
|
}, maxWait);
|
||||||
var moveOn = function() { clearInterval(interval); nextTest(); };
|
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) {
|
function getTestPlugin(aName) {
|
||||||
var pluginName = aName || "Test Plug-in";
|
let pluginName = aName || "Test Plug-in";
|
||||||
var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||||
var tags = ph.getPluginTags();
|
let tags = ph.getPluginTags();
|
||||||
|
|
||||||
// Find the test plugin
|
// 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)
|
if (tags[i].name == pluginName)
|
||||||
return tags[i];
|
return tags[i];
|
||||||
}
|
}
|
||||||
|
@ -62,15 +161,73 @@ function getTestPlugin(aName) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// call this to set the test plugin(s) initially expected enabled state.
|
// Set the 'enabledState' on the nsIPluginTag stored in the main or chrome
|
||||||
// it will automatically be reset to it's previous value after the test
|
// process.
|
||||||
// ends
|
|
||||||
function setTestPluginEnabledState(newEnabledState, pluginName) {
|
function setTestPluginEnabledState(newEnabledState, pluginName) {
|
||||||
var plugin = getTestPlugin(pluginName);
|
let name = pluginName || "Test Plug-in";
|
||||||
var oldEnabledState = plugin.enabledState;
|
let plugin = getTestPlugin(name);
|
||||||
plugin.enabledState = newEnabledState;
|
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()) {
|
while (perms.hasMoreElements()) {
|
||||||
let perm = perms.getNext();
|
let perm = perms.getNext();
|
||||||
if (perm.type.startsWith('plugin')) {
|
if (perm.type.startsWith('plugin')) {
|
||||||
|
info("removing permission:" + perm.host + " " + perm.type + "\n");
|
||||||
Services.perms.remove(perm.host, perm.type);
|
Services.perms.remove(perm.host, perm.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateBlocklist(aCallback) {
|
function updateBlocklist(aCallback) {
|
||||||
var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
|
let blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
|
||||||
.getService(Ci.nsITimerCallback);
|
.getService(Ci.nsITimerCallback);
|
||||||
var observer = function() {
|
let observer = function() {
|
||||||
Services.obs.removeObserver(observer, "blocklist-updated");
|
Services.obs.removeObserver(observer, "blocklist-updated");
|
||||||
SimpleTest.executeSoon(aCallback);
|
SimpleTest.executeSoon(aCallback);
|
||||||
};
|
};
|
||||||
|
@ -97,28 +255,77 @@ function updateBlocklist(aCallback) {
|
||||||
blocklistNotifier.notify(null);
|
blocklistNotifier.notify(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
var _originalTestBlocklistURL = null;
|
let _originalTestBlocklistURL = null;
|
||||||
function setAndUpdateBlocklist(aURL, aCallback) {
|
function setAndUpdateBlocklist(aURL, aCallback) {
|
||||||
if (!_originalTestBlocklistURL)
|
if (!_originalTestBlocklistURL) {
|
||||||
_originalTestBlocklistURL = Services.prefs.getCharPref("extensions.blocklist.url");
|
_originalTestBlocklistURL = Services.prefs.getCharPref("extensions.blocklist.url");
|
||||||
|
}
|
||||||
Services.prefs.setCharPref("extensions.blocklist.url", aURL);
|
Services.prefs.setCharPref("extensions.blocklist.url", aURL);
|
||||||
updateBlocklist(aCallback);
|
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() {
|
function resetBlocklist() {
|
||||||
Services.prefs.setCharPref("extensions.blocklist.url", _originalTestBlocklistURL);
|
Services.prefs.setCharPref("extensions.blocklist.url", _originalTestBlocklistURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
function waitForNotificationPopup(notificationID, browser, callback) {
|
// Insure there's a popup notification present. This test does not indicate
|
||||||
let notification;
|
// open state. aBrowser can be undefined.
|
||||||
waitForCondition(
|
function promisePopupNotification(aName, aBrowser) {
|
||||||
() => (notification = PopupNotifications.getNotification(notificationID, browser)),
|
let deferred = Promise.defer();
|
||||||
() => {
|
|
||||||
ok(notification, `Successfully got the ${notificationID} notification popup`);
|
waitForCondition(() => PopupNotifications.getNotification(aName, aBrowser),
|
||||||
callback(notification);
|
() => {
|
||||||
},
|
ok(!!PopupNotifications.getNotification(aName, aBrowser),
|
||||||
`Waited too long for the ${notificationID} notification popup`
|
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.
|
* Reshow a notification and call a callback when it is reshown.
|
||||||
* @param notification
|
* @param notification
|
||||||
|
@ -160,8 +373,7 @@ function waitForNotificationBar(notificationID, browser, callback) {
|
||||||
* @param callback
|
* @param callback
|
||||||
* A function to be called when the notification has been reshown
|
* A function to be called when the notification has been reshown
|
||||||
*/
|
*/
|
||||||
function waitForNotificationShown(notification, callback)
|
function waitForNotificationShown(notification, callback) {
|
||||||
{
|
|
||||||
if (PopupNotifications.panel.state == "open") {
|
if (PopupNotifications.panel.state == "open") {
|
||||||
executeSoon(callback);
|
executeSoon(callback);
|
||||||
return;
|
return;
|
||||||
|
@ -173,46 +385,30 @@ function waitForNotificationShown(notification, callback)
|
||||||
notification.reshow();
|
notification.reshow();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function promiseForNotificationShown(notification) {
|
||||||
* Due to layout being async, "PluginBindAttached" may trigger later.
|
let deferred = Promise.defer();
|
||||||
* This returns a Promise that resolves once we've forced a layout
|
waitForNotificationShown(notification, deferred.resolve);
|
||||||
* flush, which triggers the PluginBindAttached event to fire.
|
return deferred.promise;
|
||||||
*
|
|
||||||
* @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);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a page in a browser, and returns a Promise that
|
* Due to layout being async, "PluginBindAttached" may trigger later. This
|
||||||
* resolves once the "load" event has been fired for that
|
* returns a Promise that resolves once we've forced a layout flush, which
|
||||||
* browser.
|
* triggers the PluginBindAttached event to fire. This trick only works if
|
||||||
*
|
* there is some sort of plugin in the page.
|
||||||
* @param browser
|
* @param browser
|
||||||
* The browser to load the page in.
|
* The browser to force plugin bindings in.
|
||||||
* @param uri
|
|
||||||
* The URI to load.
|
|
||||||
*
|
|
||||||
* @return Promise
|
* @return Promise
|
||||||
*/
|
*/
|
||||||
function loadPage(browser, uri) {
|
function promiseUpdatePluginBindings(browser) {
|
||||||
return new Promise((resolve, reject) => {
|
return ContentTask.spawn(browser, {}, function* () {
|
||||||
browser.addEventListener("load", function onLoad(event) {
|
let doc = content.document;
|
||||||
browser.removeEventListener("load", onLoad, true);
|
let elems = doc.getElementsByTagName('embed');
|
||||||
resolve();
|
if (!elems || elems.length < 1) {
|
||||||
}, true);
|
elems = doc.getElementsByTagName('object');
|
||||||
browser.loadURI(uri);
|
}
|
||||||
|
if (elems && elems.length > 0) {
|
||||||
|
elems[0].clientTop;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script>
|
||||||
function addPlugin(type="application/x-test") {
|
function addPlugin(aId, aType="application/x-test") {
|
||||||
var embed = document.createElement("embed");
|
var embed = document.createElement("embed");
|
||||||
|
embed.setAttribute("id", aId);
|
||||||
embed.style.width = "200px";
|
embed.style.width = "200px";
|
||||||
embed.style.height = "200px";
|
embed.style.height = "200px";
|
||||||
embed.setAttribute("type", type);
|
embed.setAttribute("type", aType);
|
||||||
return document.body.appendChild(embed);
|
return document.body.appendChild(embed);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<embed id="unknown" style="width: 100px; height: 100px" type="application/x-unknown">
|
<embed id="unknown" style="width: 100px; height: 100px" type="application/x-unknown">
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="container" style="display: none">
|
<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>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
@ -6,6 +6,7 @@
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
// create an embed, insert it in the doc and immediately remove it
|
// create an embed, insert it in the doc and immediately remove it
|
||||||
var embed = document.createElement('embed');
|
var embed = document.createElement('embed');
|
||||||
|
embed.setAttribute("id", "test");
|
||||||
embed.setAttribute("type", "application/x-test");
|
embed.setAttribute("type", "application/x-test");
|
||||||
embed.setAttribute("style", "width: 0px; height: 0px;");
|
embed.setAttribute("style", "width: 0px; height: 0px;");
|
||||||
document.body.appendChild(embed);
|
document.body.appendChild(embed);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<embed id="test" style="width: 200px; height: 200px" type="application/x-test">
|
<embed id="test" style="width: 200px; height: 200px" type="application/x-test">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<embed id="test" style="width: 0px; height: 0px" type="application/x-test">
|
<embed id="test" style="width: 0px; height: 0px" type="application/x-test">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<embed id="unknown" style="width: 100px; height: 100px" type="application/x-unknown">
|
<embed id="unknown" style="width: 100px; height: 100px" type="application/x-unknown">
|
||||||
|
|
|
@ -428,6 +428,7 @@
|
||||||
@RESPATH@/components/amInstallTrigger.js
|
@RESPATH@/components/amInstallTrigger.js
|
||||||
@RESPATH@/components/amWebInstallListener.js
|
@RESPATH@/components/amWebInstallListener.js
|
||||||
@RESPATH@/components/nsBlocklistService.js
|
@RESPATH@/components/nsBlocklistService.js
|
||||||
|
@RESPATH@/components/nsBlocklistServiceContent.js
|
||||||
#ifdef MOZ_UPDATER
|
#ifdef MOZ_UPDATER
|
||||||
@RESPATH@/components/nsUpdateService.manifest
|
@RESPATH@/components/nsUpdateService.manifest
|
||||||
@RESPATH@/components/nsUpdateService.js
|
@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
|
// Before we check permissions, get the blocklist state of this plugin to set
|
||||||
// the fallback reason correctly.
|
// the fallback reason correctly. In the content process this will involve
|
||||||
uint32_t blocklistState = nsIBlocklistService::STATE_NOT_BLOCKED;
|
// an ipc call to chrome.
|
||||||
|
uint32_t blocklistState = nsIBlocklistService::STATE_BLOCKED;
|
||||||
pluginHost->GetBlocklistStateForType(mContentType,
|
pluginHost->GetBlocklistStateForType(mContentType,
|
||||||
nsPluginHost::eExcludeNone,
|
nsPluginHost::eExcludeNone,
|
||||||
&blocklistState);
|
&blocklistState);
|
||||||
|
|
|
@ -229,7 +229,10 @@ already_AddRefed<Promise>
|
||||||
Cache::Match(const RequestOrUSVString& aRequest,
|
Cache::Match(const RequestOrUSVString& aRequest,
|
||||||
const CacheQueryOptions& aOptions, ErrorResult& aRv)
|
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);
|
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv);
|
||||||
if (NS_WARN_IF(aRv.Failed())) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
|
@ -253,7 +256,10 @@ already_AddRefed<Promise>
|
||||||
Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
|
Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
|
||||||
const CacheQueryOptions& aOptions, ErrorResult& aRv)
|
const CacheQueryOptions& aOptions, ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mActor);
|
if (NS_WARN_IF(!mActor)) {
|
||||||
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
CacheQueryParams params;
|
CacheQueryParams params;
|
||||||
ToCacheQueryParams(params, aOptions);
|
ToCacheQueryParams(params, aOptions);
|
||||||
|
@ -280,6 +286,11 @@ already_AddRefed<Promise>
|
||||||
Cache::Add(JSContext* aContext, const RequestOrUSVString& aRequest,
|
Cache::Add(JSContext* aContext, const RequestOrUSVString& aRequest,
|
||||||
ErrorResult& aRv)
|
ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
|
if (NS_WARN_IF(!mActor)) {
|
||||||
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (!IsValidPutRequestMethod(aRequest, aRv)) {
|
if (!IsValidPutRequestMethod(aRequest, aRv)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -290,13 +301,13 @@ Cache::Add(JSContext* aContext, const RequestOrUSVString& aRequest,
|
||||||
nsTArray<nsRefPtr<Request>> requestList(1);
|
nsTArray<nsRefPtr<Request>> requestList(1);
|
||||||
nsRefPtr<Request> request = Request::Constructor(global, aRequest,
|
nsRefPtr<Request> request = Request::Constructor(global, aRequest,
|
||||||
RequestInit(), aRv);
|
RequestInit(), aRv);
|
||||||
if (aRv.Failed()) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsAutoString url;
|
nsAutoString url;
|
||||||
request->GetUrl(url);
|
request->GetUrl(url);
|
||||||
if (!IsValidPutRequestURL(url, aRv)) {
|
if (NS_WARN_IF(!IsValidPutRequestURL(url, aRv))) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,6 +320,11 @@ Cache::AddAll(JSContext* aContext,
|
||||||
const Sequence<OwningRequestOrUSVString>& aRequestList,
|
const Sequence<OwningRequestOrUSVString>& aRequestList,
|
||||||
ErrorResult& aRv)
|
ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
|
if (NS_WARN_IF(!mActor)) {
|
||||||
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
GlobalObject global(aContext, mGlobal->GetGlobalJSObject());
|
GlobalObject global(aContext, mGlobal->GetGlobalJSObject());
|
||||||
MOZ_ASSERT(!global.Failed());
|
MOZ_ASSERT(!global.Failed());
|
||||||
|
|
||||||
|
@ -318,7 +334,8 @@ Cache::AddAll(JSContext* aContext,
|
||||||
|
|
||||||
if (aRequestList[i].IsRequest()) {
|
if (aRequestList[i].IsRequest()) {
|
||||||
requestOrString.SetAsRequest() = aRequestList[i].GetAsRequest();
|
requestOrString.SetAsRequest() = aRequestList[i].GetAsRequest();
|
||||||
if (!IsValidPutRequestMethod(requestOrString.GetAsRequest(), aRv)) {
|
if (NS_WARN_IF(!IsValidPutRequestMethod(requestOrString.GetAsRequest(),
|
||||||
|
aRv))) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -329,13 +346,13 @@ Cache::AddAll(JSContext* aContext,
|
||||||
|
|
||||||
nsRefPtr<Request> request = Request::Constructor(global, requestOrString,
|
nsRefPtr<Request> request = Request::Constructor(global, requestOrString,
|
||||||
RequestInit(), aRv);
|
RequestInit(), aRv);
|
||||||
if (aRv.Failed()) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsAutoString url;
|
nsAutoString url;
|
||||||
request->GetUrl(url);
|
request->GetUrl(url);
|
||||||
if (!IsValidPutRequestURL(url, aRv)) {
|
if (NS_WARN_IF(!IsValidPutRequestURL(url, aRv))) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,14 +366,17 @@ already_AddRefed<Promise>
|
||||||
Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
|
Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
|
||||||
ErrorResult& aRv)
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, ReadBody, aRv);
|
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, ReadBody, aRv);
|
||||||
if (aRv.Failed()) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,7 +384,7 @@ Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
|
||||||
|
|
||||||
args.Add(ir, ReadBody, TypeErrorOnInvalidScheme,
|
args.Add(ir, ReadBody, TypeErrorOnInvalidScheme,
|
||||||
aResponse, aRv);
|
aResponse, aRv);
|
||||||
if (aRv.Failed()) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,10 +395,13 @@ already_AddRefed<Promise>
|
||||||
Cache::Delete(const RequestOrUSVString& aRequest,
|
Cache::Delete(const RequestOrUSVString& aRequest,
|
||||||
const CacheQueryOptions& aOptions, ErrorResult& aRv)
|
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);
|
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv);
|
||||||
if (aRv.Failed()) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,7 +411,7 @@ Cache::Delete(const RequestOrUSVString& aRequest,
|
||||||
AutoChildOpArgs args(this, CacheDeleteArgs(CacheRequest(), params));
|
AutoChildOpArgs args(this, CacheDeleteArgs(CacheRequest(), params));
|
||||||
|
|
||||||
args.Add(ir, IgnoreBody, IgnoreInvalidScheme, aRv);
|
args.Add(ir, IgnoreBody, IgnoreInvalidScheme, aRv);
|
||||||
if (aRv.Failed()) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,7 +422,10 @@ already_AddRefed<Promise>
|
||||||
Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
|
Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
|
||||||
const CacheQueryOptions& aOptions, ErrorResult& aRv)
|
const CacheQueryOptions& aOptions, ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mActor);
|
if (NS_WARN_IF(!mActor)) {
|
||||||
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
CacheQueryParams params;
|
CacheQueryParams params;
|
||||||
ToCacheQueryParams(params, aOptions);
|
ToCacheQueryParams(params, aOptions);
|
||||||
|
@ -409,12 +435,12 @@ Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
|
||||||
if (aRequest.WasPassed()) {
|
if (aRequest.WasPassed()) {
|
||||||
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest.Value(),
|
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest.Value(),
|
||||||
IgnoreBody, aRv);
|
IgnoreBody, aRv);
|
||||||
if (aRv.Failed()) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
args.Add(ir, IgnoreBody, IgnoreInvalidScheme, aRv);
|
args.Add(ir, IgnoreBody, IgnoreInvalidScheme, aRv);
|
||||||
if (aRv.Failed()) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -493,9 +519,9 @@ Cache::~Cache()
|
||||||
{
|
{
|
||||||
NS_ASSERT_OWNINGTHREAD(Cache);
|
NS_ASSERT_OWNINGTHREAD(Cache);
|
||||||
if (mActor) {
|
if (mActor) {
|
||||||
mActor->StartDestroy();
|
mActor->StartDestroyFromListener();
|
||||||
// DestroyInternal() is called synchronously by StartDestroy(). So we
|
// DestroyInternal() is called synchronously by StartDestroyFromListener().
|
||||||
// should have already cleared the mActor.
|
// So we should have already cleared the mActor.
|
||||||
MOZ_ASSERT(!mActor);
|
MOZ_ASSERT(!mActor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -504,11 +530,11 @@ already_AddRefed<Promise>
|
||||||
Cache::ExecuteOp(AutoChildOpArgs& aOpArgs, ErrorResult& aRv)
|
Cache::ExecuteOp(AutoChildOpArgs& aOpArgs, ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||||
if (!promise) {
|
if (NS_WARN_IF(!promise)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
mActor->ExecuteOp(mGlobal, promise, aOpArgs.SendAsOpArgs());
|
mActor->ExecuteOp(mGlobal, promise, this, aOpArgs.SendAsOpArgs());
|
||||||
return promise.forget();
|
return promise.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,7 +547,7 @@ Cache::AddAll(const GlobalObject& aGlobal,
|
||||||
// If there is no work to do, then resolve immediately
|
// If there is no work to do, then resolve immediately
|
||||||
if (aRequestList.IsEmpty()) {
|
if (aRequestList.IsEmpty()) {
|
||||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||||
if (!promise) {
|
if (NS_WARN_IF(!promise)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,7 +567,7 @@ Cache::AddAll(const GlobalObject& aGlobal,
|
||||||
requestOrString.SetAsRequest() = aRequestList[i];
|
requestOrString.SetAsRequest() = aRequestList[i];
|
||||||
nsRefPtr<Promise> fetch = FetchRequest(mGlobal, requestOrString,
|
nsRefPtr<Promise> fetch = FetchRequest(mGlobal, requestOrString,
|
||||||
RequestInit(), aRv);
|
RequestInit(), aRv);
|
||||||
if (aRv.Failed()) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,7 +575,7 @@ Cache::AddAll(const GlobalObject& aGlobal,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||||
if (aRv.Failed()) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,7 +583,7 @@ Cache::AddAll(const GlobalObject& aGlobal,
|
||||||
Move(aRequestList), promise);
|
Move(aRequestList), promise);
|
||||||
|
|
||||||
nsRefPtr<Promise> fetchPromise = Promise::All(aGlobal, fetchList, aRv);
|
nsRefPtr<Promise> fetchPromise = Promise::All(aGlobal, fetchList, aRv);
|
||||||
if (aRv.Failed()) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
fetchPromise->AppendNativeHandler(handler);
|
fetchPromise->AppendNativeHandler(handler);
|
||||||
|
@ -570,15 +596,19 @@ Cache::PutAll(const nsTArray<nsRefPtr<Request>>& aRequestList,
|
||||||
const nsTArray<nsRefPtr<Response>>& aResponseList,
|
const nsTArray<nsRefPtr<Response>>& aResponseList,
|
||||||
ErrorResult& aRv)
|
ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mActor);
|
|
||||||
MOZ_ASSERT(aRequestList.Length() == aResponseList.Length());
|
MOZ_ASSERT(aRequestList.Length() == aResponseList.Length());
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!mActor)) {
|
||||||
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
AutoChildOpArgs args(this, CachePutAllArgs());
|
AutoChildOpArgs args(this, CachePutAllArgs());
|
||||||
|
|
||||||
for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
|
for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
|
||||||
nsRefPtr<InternalRequest> ir = aRequestList[i]->GetInternalRequest();
|
nsRefPtr<InternalRequest> ir = aRequestList[i]->GetInternalRequest();
|
||||||
args.Add(ir, ReadBody, TypeErrorOnInvalidScheme, *aResponseList[i], aRv);
|
args.Add(ir, ReadBody, TypeErrorOnInvalidScheme, *aResponseList[i], aRv);
|
||||||
if (aRv.Failed()) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ DeallocPCacheChild(PCacheChild* aActor)
|
||||||
CacheChild::CacheChild()
|
CacheChild::CacheChild()
|
||||||
: mListener(nullptr)
|
: mListener(nullptr)
|
||||||
, mNumChildActors(0)
|
, mNumChildActors(0)
|
||||||
|
, mDelayedDestroy(false)
|
||||||
{
|
{
|
||||||
MOZ_COUNT_CTOR(cache::CacheChild);
|
MOZ_COUNT_CTOR(cache::CacheChild);
|
||||||
}
|
}
|
||||||
|
@ -64,11 +65,11 @@ CacheChild::ClearListener()
|
||||||
|
|
||||||
void
|
void
|
||||||
CacheChild::ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
|
CacheChild::ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
|
||||||
const CacheOpArgs& aArgs)
|
nsISupports* aParent, const CacheOpArgs& aArgs)
|
||||||
{
|
{
|
||||||
mNumChildActors += 1;
|
mNumChildActors += 1;
|
||||||
MOZ_ALWAYS_TRUE(SendPCacheOpConstructor(
|
MOZ_ALWAYS_TRUE(SendPCacheOpConstructor(
|
||||||
new CacheOpChild(GetFeature(), aGlobal, aPromise), aArgs));
|
new CacheOpChild(GetFeature(), aGlobal, aParent, aPromise), aArgs));
|
||||||
}
|
}
|
||||||
|
|
||||||
CachePushStreamChild*
|
CachePushStreamChild*
|
||||||
|
@ -81,9 +82,33 @@ CacheChild::CreatePushStream(nsIAsyncInputStream* aStream)
|
||||||
return static_cast<CachePushStreamChild*>(actor);
|
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
|
void
|
||||||
CacheChild::StartDestroy()
|
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;
|
nsRefPtr<Cache> listener = mListener;
|
||||||
|
|
||||||
// StartDestroy() can get called from either Cache or the Feature.
|
// StartDestroy() can get called from either Cache or the Feature.
|
||||||
|
@ -98,14 +123,6 @@ CacheChild::StartDestroy()
|
||||||
// Cache listener should call ClearListener() in DestroyInternal()
|
// Cache listener should call ClearListener() in DestroyInternal()
|
||||||
MOZ_ASSERT(!mListener);
|
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
|
// Start actor destruction from parent process
|
||||||
unused << SendTeardown();
|
unused << SendTeardown();
|
||||||
}
|
}
|
||||||
|
@ -158,8 +175,8 @@ void
|
||||||
CacheChild::NoteDeletedActor()
|
CacheChild::NoteDeletedActor()
|
||||||
{
|
{
|
||||||
mNumChildActors -= 1;
|
mNumChildActors -= 1;
|
||||||
if (!mNumChildActors && !mListener) {
|
if (!mNumChildActors && mDelayedDestroy) {
|
||||||
unused << SendTeardown();
|
StartDestroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,25 +33,27 @@ public:
|
||||||
|
|
||||||
void SetListener(Cache* aListener);
|
void SetListener(Cache* aListener);
|
||||||
|
|
||||||
// Must be called by the associated Cache listener in its ActorDestroy()
|
// Must be called by the associated Cache listener in its DestroyInternal()
|
||||||
// method. Also, Cache must Send__delete__() the actor in its destructor to
|
// method. Also, Cache must call StartDestroyFromListener() on the actor in
|
||||||
// trigger ActorDestroy() if it has not been called yet.
|
// its destructor to trigger ActorDestroy() if it has not been called yet.
|
||||||
void ClearListener();
|
void ClearListener();
|
||||||
|
|
||||||
void
|
void
|
||||||
ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
|
ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
|
||||||
const CacheOpArgs& aArgs);
|
nsISupports* aParent, const CacheOpArgs& aArgs);
|
||||||
|
|
||||||
CachePushStreamChild*
|
CachePushStreamChild*
|
||||||
CreatePushStream(nsIAsyncInputStream* aStream);
|
CreatePushStream(nsIAsyncInputStream* aStream);
|
||||||
|
|
||||||
// ActorChild methods
|
// Our parent Listener object has gone out of scope and is being destroyed.
|
||||||
|
void StartDestroyFromListener();
|
||||||
// Synchronously call ActorDestroy on our Cache listener and then start the
|
|
||||||
// actor destruction asynchronously from the parent-side.
|
|
||||||
virtual void StartDestroy() override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// ActorChild methods
|
||||||
|
|
||||||
|
// Feature is trying to destroy due to worker shutdown.
|
||||||
|
virtual void StartDestroy() override;
|
||||||
|
|
||||||
// PCacheChild methods
|
// PCacheChild methods
|
||||||
virtual void
|
virtual void
|
||||||
ActorDestroy(ActorDestroyReason aReason) override;
|
ActorDestroy(ActorDestroyReason aReason) override;
|
||||||
|
@ -77,6 +79,7 @@ private:
|
||||||
// destroyed.
|
// destroyed.
|
||||||
Cache* MOZ_NON_OWNING_REF mListener;
|
Cache* MOZ_NON_OWNING_REF mListener;
|
||||||
uint32_t mNumChildActors;
|
uint32_t mNumChildActors;
|
||||||
|
bool mDelayedDestroy;
|
||||||
|
|
||||||
NS_DECL_OWNINGTHREAD
|
NS_DECL_OWNINGTHREAD
|
||||||
};
|
};
|
||||||
|
|
|
@ -57,11 +57,13 @@ AddFeatureToStreamChild(const CacheRequest& aRequest, Feature* aFeature)
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
CacheOpChild::CacheOpChild(Feature* aFeature, nsIGlobalObject* aGlobal,
|
CacheOpChild::CacheOpChild(Feature* aFeature, nsIGlobalObject* aGlobal,
|
||||||
Promise* aPromise)
|
nsISupports* aParent, Promise* aPromise)
|
||||||
: mGlobal(aGlobal)
|
: mGlobal(aGlobal)
|
||||||
|
, mParent(aParent)
|
||||||
, mPromise(aPromise)
|
, mPromise(aPromise)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mGlobal);
|
MOZ_ASSERT(mGlobal);
|
||||||
|
MOZ_ASSERT(mParent);
|
||||||
MOZ_ASSERT(mPromise);
|
MOZ_ASSERT(mPromise);
|
||||||
|
|
||||||
MOZ_ASSERT_IF(!NS_IsMainThread(), aFeature);
|
MOZ_ASSERT_IF(!NS_IsMainThread(), aFeature);
|
||||||
|
@ -95,7 +97,7 @@ CacheOpChild::Recv__delete__(const ErrorResult& aRv,
|
||||||
{
|
{
|
||||||
NS_ASSERT_OWNINGTHREAD(CacheOpChild);
|
NS_ASSERT_OWNINGTHREAD(CacheOpChild);
|
||||||
|
|
||||||
if (aRv.Failed()) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
MOZ_ASSERT(aResult.type() == CacheOpResult::Tvoid_t);
|
MOZ_ASSERT(aResult.type() == CacheOpResult::Tvoid_t);
|
||||||
// TODO: Remove this const_cast (bug 1152078).
|
// TODO: Remove this const_cast (bug 1152078).
|
||||||
// It is safe for now since this ErrorResult is handed off to us by IPDL
|
// It is safe for now since this ErrorResult is handed off to us by IPDL
|
||||||
|
|
|
@ -31,7 +31,8 @@ class CacheOpChild final : public PCacheOpChild
|
||||||
private:
|
private:
|
||||||
// This class must be constructed by CacheChild or CacheStorageChild using
|
// This class must be constructed by CacheChild or CacheStorageChild using
|
||||||
// their ExecuteOp() factory method.
|
// their ExecuteOp() factory method.
|
||||||
CacheOpChild(Feature* aFeature, nsIGlobalObject* aGlobal, Promise* aPromise);
|
CacheOpChild(Feature* aFeature, nsIGlobalObject* aGlobal,
|
||||||
|
nsISupports* aParent, Promise* aPromise);
|
||||||
~CacheOpChild();
|
~CacheOpChild();
|
||||||
|
|
||||||
// PCacheOpChild methods
|
// PCacheOpChild methods
|
||||||
|
@ -68,6 +69,9 @@ private:
|
||||||
HandleRequestList(const nsTArray<CacheRequest>& aRequestList);
|
HandleRequestList(const nsTArray<CacheRequest>& aRequestList);
|
||||||
|
|
||||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||||
|
// Hold the parent Cache or CacheStorage object alive until this async
|
||||||
|
// operation completes.
|
||||||
|
nsCOMPtr<nsISupports> mParent;
|
||||||
nsRefPtr<Promise> mPromise;
|
nsRefPtr<Promise> mPromise;
|
||||||
|
|
||||||
NS_DECL_OWNINGTHREAD
|
NS_DECL_OWNINGTHREAD
|
||||||
|
|
|
@ -164,7 +164,7 @@ CacheOpParent::OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
||||||
|
|
||||||
// Never send an op-specific result if we have an error. Instead, send
|
// 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.
|
// 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());
|
unused << Send__delete__(this, aRv, void_t());
|
||||||
aRv.SuppressException(); // We serialiazed it, as best we could.
|
aRv.SuppressException(); // We serialiazed it, as best we could.
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -118,8 +118,9 @@ CachePushStreamChild::Start()
|
||||||
void
|
void
|
||||||
CachePushStreamChild::StartDestroy()
|
CachePushStreamChild::StartDestroy()
|
||||||
{
|
{
|
||||||
// called if we are running on a Worker and the thread gets shutdown
|
// The worker has signaled its shutting down, but continue streaming. The
|
||||||
OnEnd(NS_ERROR_ABORT);
|
// Cache is now designed to hold the worker open until all async operations
|
||||||
|
// complete.
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -166,7 +166,7 @@ CacheStorage::CacheStorage(Namespace aNamespace, nsIGlobalObject* aGlobal,
|
||||||
// wait for the async ActorCreated() callback.
|
// wait for the async ActorCreated() callback.
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
bool ok = BackgroundChild::GetOrCreateForCurrentThread(this);
|
bool ok = BackgroundChild::GetOrCreateForCurrentThread(this);
|
||||||
if (!ok) {
|
if (NS_WARN_IF(!ok)) {
|
||||||
ActorFailed();
|
ActorFailed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,7 +177,7 @@ CacheStorage::Match(const RequestOrUSVString& aRequest,
|
||||||
{
|
{
|
||||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||||
|
|
||||||
if (mFailedActor) {
|
if (NS_WARN_IF(mFailedActor)) {
|
||||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -189,7 +189,7 @@ CacheStorage::Match(const RequestOrUSVString& aRequest,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||||
if (!promise) {
|
if (NS_WARN_IF(!promise)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,13 +212,13 @@ CacheStorage::Has(const nsAString& aKey, ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||||
|
|
||||||
if (mFailedActor) {
|
if (NS_WARN_IF(mFailedActor)) {
|
||||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||||
if (!promise) {
|
if (NS_WARN_IF(!promise)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,13 +237,13 @@ CacheStorage::Open(const nsAString& aKey, ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||||
|
|
||||||
if (mFailedActor) {
|
if (NS_WARN_IF(mFailedActor)) {
|
||||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||||
if (!promise) {
|
if (NS_WARN_IF(!promise)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,13 +262,13 @@ CacheStorage::Delete(const nsAString& aKey, ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||||
|
|
||||||
if (mFailedActor) {
|
if (NS_WARN_IF(mFailedActor)) {
|
||||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||||
if (!promise) {
|
if (NS_WARN_IF(!promise)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,13 +287,13 @@ CacheStorage::Keys(ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||||
|
|
||||||
if (mFailedActor) {
|
if (NS_WARN_IF(mFailedActor)) {
|
||||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||||
if (!promise) {
|
if (NS_WARN_IF(!promise)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,9 +413,9 @@ CacheStorage::~CacheStorage()
|
||||||
{
|
{
|
||||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||||
if (mActor) {
|
if (mActor) {
|
||||||
mActor->StartDestroy();
|
mActor->StartDestroyFromListener();
|
||||||
// DestroyInternal() is called synchronously by StartDestroy(). So we
|
// DestroyInternal() is called synchronously by StartDestroyFromListener().
|
||||||
// should have already cleared the mActor.
|
// So we should have already cleared the mActor.
|
||||||
MOZ_ASSERT(!mActor);
|
MOZ_ASSERT(!mActor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -434,11 +434,11 @@ CacheStorage::MaybeRunPendingRequests()
|
||||||
if (entry->mRequest) {
|
if (entry->mRequest) {
|
||||||
args.Add(entry->mRequest, IgnoreBody, IgnoreInvalidScheme, rv);
|
args.Add(entry->mRequest, IgnoreBody, IgnoreInvalidScheme, rv);
|
||||||
}
|
}
|
||||||
if (rv.Failed()) {
|
if (NS_WARN_IF(rv.Failed())) {
|
||||||
entry->mPromise->MaybeReject(rv);
|
entry->mPromise->MaybeReject(rv);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
mActor->ExecuteOp(mGlobal, entry->mPromise, args.SendAsOpArgs());
|
mActor->ExecuteOp(mGlobal, entry->mPromise, this, args.SendAsOpArgs());
|
||||||
}
|
}
|
||||||
mPendingRequests.Clear();
|
mPendingRequests.Clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ DeallocPCacheStorageChild(PCacheStorageChild* aActor)
|
||||||
CacheStorageChild::CacheStorageChild(CacheStorage* aListener, Feature* aFeature)
|
CacheStorageChild::CacheStorageChild(CacheStorage* aListener, Feature* aFeature)
|
||||||
: mListener(aListener)
|
: mListener(aListener)
|
||||||
, mNumChildActors(0)
|
, mNumChildActors(0)
|
||||||
|
, mDelayedDestroy(false)
|
||||||
{
|
{
|
||||||
MOZ_COUNT_CTOR(cache::CacheStorageChild);
|
MOZ_COUNT_CTOR(cache::CacheStorageChild);
|
||||||
MOZ_ASSERT(mListener);
|
MOZ_ASSERT(mListener);
|
||||||
|
@ -49,11 +50,24 @@ CacheStorageChild::ClearListener()
|
||||||
|
|
||||||
void
|
void
|
||||||
CacheStorageChild::ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
|
CacheStorageChild::ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
|
||||||
const CacheOpArgs& aArgs)
|
nsISupports* aParent, const CacheOpArgs& aArgs)
|
||||||
{
|
{
|
||||||
mNumChildActors += 1;
|
mNumChildActors += 1;
|
||||||
unused << SendPCacheOpConstructor(
|
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
|
void
|
||||||
|
@ -61,6 +75,15 @@ CacheStorageChild::StartDestroy()
|
||||||
{
|
{
|
||||||
NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
|
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;
|
nsRefPtr<CacheStorage> listener = mListener;
|
||||||
|
|
||||||
// StartDestroy() can get called from either CacheStorage or the Feature.
|
// StartDestroy() can get called from either CacheStorage or the Feature.
|
||||||
|
@ -75,14 +98,6 @@ CacheStorageChild::StartDestroy()
|
||||||
// CacheStorage listener should call ClearListener() in DestroyInternal()
|
// CacheStorage listener should call ClearListener() in DestroyInternal()
|
||||||
MOZ_ASSERT(!mListener);
|
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
|
// Start actor destruction from parent process
|
||||||
unused << SendTeardown();
|
unused << SendTeardown();
|
||||||
}
|
}
|
||||||
|
@ -121,8 +136,8 @@ CacheStorageChild::NoteDeletedActor()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mNumChildActors);
|
MOZ_ASSERT(mNumChildActors);
|
||||||
mNumChildActors -= 1;
|
mNumChildActors -= 1;
|
||||||
if (!mNumChildActors && !mListener) {
|
if (!mNumChildActors && mDelayedDestroy) {
|
||||||
unused << SendTeardown();
|
StartDestroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,22 +33,24 @@ public:
|
||||||
~CacheStorageChild();
|
~CacheStorageChild();
|
||||||
|
|
||||||
// Must be called by the associated CacheStorage listener in its
|
// Must be called by the associated CacheStorage listener in its
|
||||||
// ActorDestroy() method. Also, CacheStorage must call SendDestroy() on the
|
// DestroyInternal() method. Also, CacheStorage must call
|
||||||
// actor in its destructor to trigger ActorDestroy() if it has not been
|
// SendDestroyFromListener() on the actor in its destructor to trigger
|
||||||
// called yet.
|
// ActorDestroy() if it has not been called yet.
|
||||||
void ClearListener();
|
void ClearListener();
|
||||||
|
|
||||||
void
|
void
|
||||||
ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
|
ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
|
||||||
const CacheOpArgs& aArgs);
|
nsISupports* aParent, const CacheOpArgs& aArgs);
|
||||||
|
|
||||||
// ActorChild methods
|
// Our parent Listener object has gone out of scope and is being destroyed.
|
||||||
|
void StartDestroyFromListener();
|
||||||
// Synchronously call ActorDestroy on our CacheStorage listener and then start
|
|
||||||
// the actor destruction asynchronously from the parent-side.
|
|
||||||
virtual void StartDestroy() override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// ActorChild methods
|
||||||
|
|
||||||
|
// Feature is trying to destroy due to worker shutdown.
|
||||||
|
virtual void StartDestroy() override;
|
||||||
|
|
||||||
// PCacheStorageChild methods
|
// PCacheStorageChild methods
|
||||||
virtual void ActorDestroy(ActorDestroyReason aReason) override;
|
virtual void ActorDestroy(ActorDestroyReason aReason) override;
|
||||||
|
|
||||||
|
@ -67,6 +69,7 @@ private:
|
||||||
// destroyed.
|
// destroyed.
|
||||||
CacheStorage* MOZ_NON_OWNING_REF mListener;
|
CacheStorage* MOZ_NON_OWNING_REF mListener;
|
||||||
uint32_t mNumChildActors;
|
uint32_t mNumChildActors;
|
||||||
|
bool mDelayedDestroy;
|
||||||
|
|
||||||
NS_DECL_OWNINGTHREAD
|
NS_DECL_OWNINGTHREAD
|
||||||
};
|
};
|
||||||
|
|
|
@ -100,7 +100,7 @@ CacheStorageParent::RecvPCacheOpConstructor(PCacheOpParent* aActor,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NS_FAILED(mVerifiedStatus)) {
|
if (NS_WARN_IF(NS_FAILED(mVerifiedStatus))) {
|
||||||
unused << CacheOpParent::Send__delete__(actor, ErrorResult(mVerifiedStatus),
|
unused << CacheOpParent::Send__delete__(actor, ErrorResult(mVerifiedStatus),
|
||||||
void_t());
|
void_t());
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
namespace cache {
|
namespace cache {
|
||||||
|
|
||||||
using mozilla::dom::workers::Running;
|
using mozilla::dom::workers::Canceling;
|
||||||
using mozilla::dom::workers::Status;
|
using mozilla::dom::workers::Status;
|
||||||
using mozilla::dom::workers::WorkerPrivate;
|
using mozilla::dom::workers::WorkerPrivate;
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ Feature::Notify(JSContext* aCx, Status aStatus)
|
||||||
{
|
{
|
||||||
NS_ASSERT_OWNINGTHREAD(Feature);
|
NS_ASSERT_OWNINGTHREAD(Feature);
|
||||||
|
|
||||||
if (aStatus <= Running || mNotified) {
|
if (aStatus < Canceling || mNotified) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1623,7 +1623,7 @@ Manager::ExecuteCacheOp(Listener* aListener, CacheId aCacheId,
|
||||||
MOZ_ASSERT(aListener);
|
MOZ_ASSERT(aListener);
|
||||||
MOZ_ASSERT(aOpArgs.type() != CacheOpArgs::TCachePutAllArgs);
|
MOZ_ASSERT(aOpArgs.type() != CacheOpArgs::TCachePutAllArgs);
|
||||||
|
|
||||||
if (mState == Closing) {
|
if (NS_WARN_IF(mState == Closing)) {
|
||||||
aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), void_t());
|
aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), void_t());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1667,7 +1667,7 @@ Manager::ExecuteStorageOp(Listener* aListener, Namespace aNamespace,
|
||||||
NS_ASSERT_OWNINGTHREAD(Manager);
|
NS_ASSERT_OWNINGTHREAD(Manager);
|
||||||
MOZ_ASSERT(aListener);
|
MOZ_ASSERT(aListener);
|
||||||
|
|
||||||
if (mState == Closing) {
|
if (NS_WARN_IF(mState == Closing)) {
|
||||||
aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), void_t());
|
aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), void_t());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1716,7 +1716,7 @@ Manager::ExecutePutAll(Listener* aListener, CacheId aCacheId,
|
||||||
NS_ASSERT_OWNINGTHREAD(Manager);
|
NS_ASSERT_OWNINGTHREAD(Manager);
|
||||||
MOZ_ASSERT(aListener);
|
MOZ_ASSERT(aListener);
|
||||||
|
|
||||||
if (mState == Closing) {
|
if (NS_WARN_IF(mState == Closing)) {
|
||||||
aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), CachePutAllResult());
|
aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), CachePutAllResult());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,6 +161,9 @@
|
||||||
#include "private/pprio.h"
|
#include "private/pprio.h"
|
||||||
#include "ContentProcessManager.h"
|
#include "ContentProcessManager.h"
|
||||||
#include "mozilla/psm/PSMContentListener.h"
|
#include "mozilla/psm/PSMContentListener.h"
|
||||||
|
#include "nsPluginHost.h"
|
||||||
|
#include "nsPluginTags.h"
|
||||||
|
#include "nsIBlocklistService.h"
|
||||||
|
|
||||||
#include "nsIBidiKeyboard.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);
|
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
|
bool
|
||||||
ContentParent::RecvFindPlugins(const uint32_t& aPluginEpoch,
|
ContentParent::RecvFindPlugins(const uint32_t& aPluginEpoch,
|
||||||
nsTArray<PluginTag>* aPlugins,
|
nsTArray<PluginTag>* aPlugins,
|
||||||
|
|
|
@ -173,6 +173,7 @@ public:
|
||||||
|
|
||||||
virtual bool RecvLoadPlugin(const uint32_t& aPluginId, nsresult* aRv, uint32_t* aRunID) override;
|
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 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,
|
virtual bool RecvFindPlugins(const uint32_t& aPluginEpoch,
|
||||||
nsTArray<PluginTag>* aPlugins,
|
nsTArray<PluginTag>* aPlugins,
|
||||||
uint32_t* aNewPluginEpoch) override;
|
uint32_t* aNewPluginEpoch) override;
|
||||||
|
|
|
@ -699,6 +699,11 @@ parent:
|
||||||
*/
|
*/
|
||||||
sync ConnectPluginBridge(uint32_t aPluginId) returns (nsresult rv);
|
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
|
* This call returns the set of plugins loaded in the chrome
|
||||||
* process. However, in many cases this set will not have changed since the
|
* process. However, in many cases this set will not have changed since the
|
||||||
|
|
|
@ -110,6 +110,8 @@
|
||||||
#include "nsExceptionHandler.h"
|
#include "nsExceptionHandler.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "npapi.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using mozilla::TimeStamp;
|
using mozilla::TimeStamp;
|
||||||
using mozilla::plugins::PluginTag;
|
using mozilla::plugins::PluginTag;
|
||||||
|
@ -1054,7 +1056,6 @@ nsPluginHost::GetBlocklistStateForType(const nsACString &aMimeType,
|
||||||
aExcludeFlags,
|
aExcludeFlags,
|
||||||
getter_AddRefs(tag));
|
getter_AddRefs(tag));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
return tag->GetBlocklistState(aState);
|
return tag->GetBlocklistState(aState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1275,6 +1276,13 @@ nsPluginHost::GetPluginForContentProcess(uint32_t aPluginId, nsNPAPIPlugin** aPl
|
||||||
|
|
||||||
nsPluginTag* pluginTag = PluginWithId(aPluginId);
|
nsPluginTag* pluginTag = PluginWithId(aPluginId);
|
||||||
if (pluginTag) {
|
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);
|
nsresult rv = EnsurePluginLoaded(pluginTag);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "prlink.h"
|
#include "prlink.h"
|
||||||
#include "prclist.h"
|
#include "prclist.h"
|
||||||
#include "npapi.h"
|
|
||||||
#include "nsIPluginTag.h"
|
#include "nsIPluginTag.h"
|
||||||
#include "nsPluginsDir.h"
|
#include "nsPluginsDir.h"
|
||||||
#include "nsPluginDirServiceProvider.h"
|
#include "nsPluginDirServiceProvider.h"
|
||||||
|
@ -30,6 +29,7 @@
|
||||||
#include "nsCRT.h"
|
#include "nsCRT.h"
|
||||||
|
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
|
#include <minwindef.h>
|
||||||
#include "nsIWindowsRegKey.h"
|
#include "nsIWindowsRegKey.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -52,6 +52,10 @@ class nsNPAPIPluginStreamListener;
|
||||||
class nsIPluginInstanceOwner;
|
class nsIPluginInstanceOwner;
|
||||||
class nsIInputStream;
|
class nsIInputStream;
|
||||||
class nsIStreamListener;
|
class nsIStreamListener;
|
||||||
|
#ifndef npapi_h_
|
||||||
|
struct _NPP;
|
||||||
|
typedef _NPP* NPP;
|
||||||
|
#endif
|
||||||
|
|
||||||
class nsInvalidPluginTag : public nsISupports
|
class nsInvalidPluginTag : public nsISupports
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "mozilla/unused.h"
|
#include "mozilla/unused.h"
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include "mozilla/dom/EncodingUtils.h"
|
#include "mozilla/dom/EncodingUtils.h"
|
||||||
|
#include "mozilla/dom/ContentChild.h"
|
||||||
|
|
||||||
using mozilla::dom::EncodingUtils;
|
using mozilla::dom::EncodingUtils;
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
@ -645,27 +646,33 @@ nsPluginTag::GetBlocklistState(uint32_t *aResult)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIBlocklistService> blocklist =
|
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||||
do_GetService("@mozilla.org/extensions/blocklist;1");
|
*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) {
|
if (!blocklist) {
|
||||||
*aResult = nsIBlocklistService::STATE_NOT_BLOCKED;
|
*aResult = nsIBlocklistService::STATE_NOT_BLOCKED;
|
||||||
return NS_OK;
|
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
|
MOZ_ASSERT(*aResult <= UINT16_MAX);
|
||||||
// and toolkit versions
|
mCachedBlocklistState = (uint16_t) *aResult;
|
||||||
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;
|
|
||||||
mCachedBlocklistStateValid = true;
|
mCachedBlocklistStateValid = true;
|
||||||
*aResult = state;
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1043,6 +1043,7 @@ ServiceWorkerManager::AppendPendingOperation(nsIRunnable* aRunnable)
|
||||||
class LifecycleEventPromiseHandler final : public PromiseNativeHandler
|
class LifecycleEventPromiseHandler final : public PromiseNativeHandler
|
||||||
{
|
{
|
||||||
nsMainThreadPtrHandle<ContinueLifecycleTask> mTask;
|
nsMainThreadPtrHandle<ContinueLifecycleTask> mTask;
|
||||||
|
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
|
||||||
bool mActivateImmediately;
|
bool mActivateImmediately;
|
||||||
|
|
||||||
virtual
|
virtual
|
||||||
|
@ -1051,8 +1052,10 @@ class LifecycleEventPromiseHandler final : public PromiseNativeHandler
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LifecycleEventPromiseHandler(const nsMainThreadPtrHandle<ContinueLifecycleTask>& aTask,
|
LifecycleEventPromiseHandler(const nsMainThreadPtrHandle<ContinueLifecycleTask>& aTask,
|
||||||
|
const nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
|
||||||
bool aActivateImmediately)
|
bool aActivateImmediately)
|
||||||
: mTask(aTask)
|
: mTask(aTask)
|
||||||
|
, mServiceWorker(aServiceWorker)
|
||||||
, mActivateImmediately(aActivateImmediately)
|
, mActivateImmediately(aActivateImmediately)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!NS_IsMainThread());
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
|
@ -1135,7 +1138,7 @@ LifecycleEventWorkerRunnable::DispatchLifecycleEvent(JSContext* aCx, WorkerPriva
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<LifecycleEventPromiseHandler> handler =
|
nsRefPtr<LifecycleEventPromiseHandler> handler =
|
||||||
new LifecycleEventPromiseHandler(mTask, false /* activateImmediately */);
|
new LifecycleEventPromiseHandler(mTask, mServiceWorker, false /* activateImmediately */);
|
||||||
waitUntilPromise->AppendNativeHandler(handler);
|
waitUntilPromise->AppendNativeHandler(handler);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,7 @@ using namespace mozilla::layout;
|
||||||
using namespace mozilla::gfx;
|
using namespace mozilla::gfx;
|
||||||
|
|
||||||
typedef FrameMetrics::ViewID ViewID;
|
typedef FrameMetrics::ViewID ViewID;
|
||||||
|
typedef nsStyleTransformMatrix::TransformReferenceBox TransformReferenceBox;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static bool
|
static bool
|
||||||
|
@ -115,7 +116,7 @@ MakeCSSAngle(const nsCSSValue& aValue)
|
||||||
static void AddTransformFunctions(nsCSSValueList* aList,
|
static void AddTransformFunctions(nsCSSValueList* aList,
|
||||||
nsStyleContext* aContext,
|
nsStyleContext* aContext,
|
||||||
nsPresContext* aPresContext,
|
nsPresContext* aPresContext,
|
||||||
nsRect& aBounds,
|
TransformReferenceBox& aRefBox,
|
||||||
InfallibleTArray<TransformFunction>& aFunctions)
|
InfallibleTArray<TransformFunction>& aFunctions)
|
||||||
{
|
{
|
||||||
if (aList->mValue.GetUnit() == eCSSUnit_None) {
|
if (aList->mValue.GetUnit() == eCSSUnit_None) {
|
||||||
|
@ -200,7 +201,7 @@ static void AddTransformFunctions(nsCSSValueList* aList,
|
||||||
{
|
{
|
||||||
double x = nsStyleTransformMatrix::ProcessTranslatePart(
|
double x = nsStyleTransformMatrix::ProcessTranslatePart(
|
||||||
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
|
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
|
||||||
aBounds.Width());
|
&aRefBox, &TransformReferenceBox::Width);
|
||||||
aFunctions.AppendElement(Translation(x, 0, 0));
|
aFunctions.AppendElement(Translation(x, 0, 0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -208,7 +209,7 @@ static void AddTransformFunctions(nsCSSValueList* aList,
|
||||||
{
|
{
|
||||||
double y = nsStyleTransformMatrix::ProcessTranslatePart(
|
double y = nsStyleTransformMatrix::ProcessTranslatePart(
|
||||||
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
|
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
|
||||||
aBounds.Height());
|
&aRefBox, &TransformReferenceBox::Height);
|
||||||
aFunctions.AppendElement(Translation(0, y, 0));
|
aFunctions.AppendElement(Translation(0, y, 0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -216,7 +217,7 @@ static void AddTransformFunctions(nsCSSValueList* aList,
|
||||||
{
|
{
|
||||||
double z = nsStyleTransformMatrix::ProcessTranslatePart(
|
double z = nsStyleTransformMatrix::ProcessTranslatePart(
|
||||||
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
|
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
|
||||||
0);
|
nullptr);
|
||||||
aFunctions.AppendElement(Translation(0, 0, z));
|
aFunctions.AppendElement(Translation(0, 0, z));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -224,13 +225,13 @@ static void AddTransformFunctions(nsCSSValueList* aList,
|
||||||
{
|
{
|
||||||
double x = nsStyleTransformMatrix::ProcessTranslatePart(
|
double x = nsStyleTransformMatrix::ProcessTranslatePart(
|
||||||
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
|
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
|
||||||
aBounds.Width());
|
&aRefBox, &TransformReferenceBox::Width);
|
||||||
// translate(x) is shorthand for translate(x, 0)
|
// translate(x) is shorthand for translate(x, 0)
|
||||||
double y = 0;
|
double y = 0;
|
||||||
if (array->Count() == 3) {
|
if (array->Count() == 3) {
|
||||||
y = nsStyleTransformMatrix::ProcessTranslatePart(
|
y = nsStyleTransformMatrix::ProcessTranslatePart(
|
||||||
array->Item(2), aContext, aPresContext, canStoreInRuleTree,
|
array->Item(2), aContext, aPresContext, canStoreInRuleTree,
|
||||||
aBounds.Height());
|
&aRefBox, &TransformReferenceBox::Height);
|
||||||
}
|
}
|
||||||
aFunctions.AppendElement(Translation(x, y, 0));
|
aFunctions.AppendElement(Translation(x, y, 0));
|
||||||
break;
|
break;
|
||||||
|
@ -239,13 +240,13 @@ static void AddTransformFunctions(nsCSSValueList* aList,
|
||||||
{
|
{
|
||||||
double x = nsStyleTransformMatrix::ProcessTranslatePart(
|
double x = nsStyleTransformMatrix::ProcessTranslatePart(
|
||||||
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
|
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
|
||||||
aBounds.Width());
|
&aRefBox, &TransformReferenceBox::Width);
|
||||||
double y = nsStyleTransformMatrix::ProcessTranslatePart(
|
double y = nsStyleTransformMatrix::ProcessTranslatePart(
|
||||||
array->Item(2), aContext, aPresContext, canStoreInRuleTree,
|
array->Item(2), aContext, aPresContext, canStoreInRuleTree,
|
||||||
aBounds.Height());
|
&aRefBox, &TransformReferenceBox::Height);
|
||||||
double z = nsStyleTransformMatrix::ProcessTranslatePart(
|
double z = nsStyleTransformMatrix::ProcessTranslatePart(
|
||||||
array->Item(3), aContext, aPresContext, canStoreInRuleTree,
|
array->Item(3), aContext, aPresContext, canStoreInRuleTree,
|
||||||
0);
|
nullptr);
|
||||||
|
|
||||||
aFunctions.AppendElement(Translation(x, y, z));
|
aFunctions.AppendElement(Translation(x, y, z));
|
||||||
break;
|
break;
|
||||||
|
@ -324,7 +325,7 @@ static void AddTransformFunctions(nsCSSValueList* aList,
|
||||||
aContext,
|
aContext,
|
||||||
aPresContext,
|
aPresContext,
|
||||||
canStoreInRuleTree,
|
canStoreInRuleTree,
|
||||||
aBounds);
|
aRefBox);
|
||||||
aFunctions.AppendElement(TransformMatrix(gfx::ToMatrix4x4(matrix)));
|
aFunctions.AppendElement(TransformMatrix(gfx::ToMatrix4x4(matrix)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -362,7 +363,7 @@ AddAnimationForProperty(nsIFrame* aFrame, const AnimationProperty& aProperty,
|
||||||
"Should not be adding an animation without an effect");
|
"Should not be adding an animation without an effect");
|
||||||
nsStyleContext* styleContext = aFrame->StyleContext();
|
nsStyleContext* styleContext = aFrame->StyleContext();
|
||||||
nsPresContext* presContext = aFrame->PresContext();
|
nsPresContext* presContext = aFrame->PresContext();
|
||||||
nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(aFrame);
|
TransformReferenceBox refBox(aFrame);
|
||||||
|
|
||||||
layers::Animation* animation =
|
layers::Animation* animation =
|
||||||
aPending ?
|
aPending ?
|
||||||
|
@ -393,11 +394,11 @@ AddAnimationForProperty(nsIFrame* aFrame, const AnimationProperty& aProperty,
|
||||||
|
|
||||||
nsCSSValueSharedList* list =
|
nsCSSValueSharedList* list =
|
||||||
segment.mFromValue.GetCSSValueSharedListValue();
|
segment.mFromValue.GetCSSValueSharedListValue();
|
||||||
AddTransformFunctions(list->mHead, styleContext, presContext, bounds,
|
AddTransformFunctions(list->mHead, styleContext, presContext, refBox,
|
||||||
animSegment->startState().get_ArrayOfTransformFunction());
|
animSegment->startState().get_ArrayOfTransformFunction());
|
||||||
|
|
||||||
list = segment.mToValue.GetCSSValueSharedListValue();
|
list = segment.mToValue.GetCSSValueSharedListValue();
|
||||||
AddTransformFunctions(list->mHead, styleContext, presContext, bounds,
|
AddTransformFunctions(list->mHead, styleContext, presContext, refBox,
|
||||||
animSegment->endState().get_ArrayOfTransformFunction());
|
animSegment->endState().get_ArrayOfTransformFunction());
|
||||||
} else if (aProperty.mProperty == eCSSProperty_opacity) {
|
} else if (aProperty.mProperty == eCSSProperty_opacity) {
|
||||||
animSegment->startState() = segment.mFromValue.GetFloatValue();
|
animSegment->startState() = segment.mFromValue.GetFloatValue();
|
||||||
|
@ -535,7 +536,13 @@ nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer,
|
||||||
|
|
||||||
AnimationData data;
|
AnimationData data;
|
||||||
if (aProperty == eCSSProperty_transform) {
|
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
|
// all data passed directly to the compositor should be in dev pixels
|
||||||
int32_t devPixelsToAppUnits = aFrame->PresContext()->AppUnitsPerDevPixel();
|
int32_t devPixelsToAppUnits = aFrame->PresContext()->AppUnitsPerDevPixel();
|
||||||
float scale = devPixelsToAppUnits;
|
float scale = devPixelsToAppUnits;
|
||||||
|
@ -4465,7 +4472,8 @@ bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder,
|
||||||
// nsDisplayTransform Implementation
|
// 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
|
// to transform content with continuations as one unified block instead of
|
||||||
// several smaller ones. This is currently disabled because it doesn't work
|
// several smaller ones. This is currently disabled because it doesn't work
|
||||||
// correctly, since when the frames are initially being reflowed, their
|
// correctly, since when the frames are initially being reflowed, their
|
||||||
|
@ -4476,63 +4484,6 @@ bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder,
|
||||||
#undef UNIFIED_CONTINUATIONS
|
#undef UNIFIED_CONTINUATIONS
|
||||||
#undef DEBUG_HIT
|
#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,
|
nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
|
||||||
nsIFrame *aFrame, nsDisplayList *aList,
|
nsIFrame *aFrame, nsDisplayList *aList,
|
||||||
const nsRect& aChildrenVisibleRect,
|
const nsRect& aChildrenVisibleRect,
|
||||||
|
@ -4633,13 +4584,17 @@ nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame,
|
||||||
* a distance, it's already computed for us!
|
* a distance, it's already computed for us!
|
||||||
*/
|
*/
|
||||||
const nsStyleDisplay* display = aFrame->StyleDisplay();
|
const nsStyleDisplay* display = aFrame->StyleDisplay();
|
||||||
nsRect boundingRect = (aBoundsOverride ? *aBoundsOverride :
|
TransformReferenceBox refBox;
|
||||||
nsDisplayTransform::GetFrameBoundsForTransform(aFrame));
|
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];
|
float coords[3];
|
||||||
const nscoord* dimensions[2] =
|
TransformReferenceBox::DimensionGetter dimensionGetter[] =
|
||||||
{&boundingRect.width, &boundingRect.height};
|
{ &TransformReferenceBox::Width, &TransformReferenceBox::Height };
|
||||||
|
|
||||||
for (uint8_t index = 0; index < 2; ++index) {
|
for (uint8_t index = 0; index < 2; ++index) {
|
||||||
/* If the -moz-transform-origin specifies a percentage, take the percentage
|
/* 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) {
|
if (coord.GetUnit() == eStyleUnit_Calc) {
|
||||||
const nsStyleCoord::Calc *calc = coord.GetCalcValue();
|
const nsStyleCoord::Calc *calc = coord.GetCalcValue();
|
||||||
coords[index] =
|
coords[index] =
|
||||||
NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
|
NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) *
|
||||||
calc->mPercent +
|
calc->mPercent +
|
||||||
NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
|
NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
|
||||||
} else if (coord.GetUnit() == eStyleUnit_Percent) {
|
} else if (coord.GetUnit() == eStyleUnit_Percent) {
|
||||||
coords[index] =
|
coords[index] =
|
||||||
NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
|
NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) *
|
||||||
coord.GetPercentValue();
|
coord.GetPercentValue();
|
||||||
} else {
|
} else {
|
||||||
MOZ_ASSERT(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
|
MOZ_ASSERT(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
|
||||||
|
@ -4673,9 +4628,11 @@ nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame,
|
||||||
|
|
||||||
coords[2] = NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(),
|
coords[2] = NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(),
|
||||||
aAppUnitsPerPixel);
|
aAppUnitsPerPixel);
|
||||||
/* Adjust based on the origin of the rectangle. */
|
if (aBoundsOverride) {
|
||||||
coords[0] += NSAppUnitsToFloatPixels(boundingRect.x, aAppUnitsPerPixel);
|
// Adjust based on the origin of the override:
|
||||||
coords[1] += NSAppUnitsToFloatPixels(boundingRect.y, aAppUnitsPerPixel);
|
coords[0] += NSAppUnitsToFloatPixels(aBoundsOverride->x, aAppUnitsPerPixel);
|
||||||
|
coords[1] += NSAppUnitsToFloatPixels(aBoundsOverride->y, aAppUnitsPerPixel);
|
||||||
|
}
|
||||||
|
|
||||||
return Point3D(coords[0], coords[1], coords[2]);
|
return Point3D(coords[0], coords[1], coords[2]);
|
||||||
}
|
}
|
||||||
|
@ -4716,14 +4673,14 @@ nsDisplayTransform::GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const nsStyleDisplay* display = psc->StyleDisplay();
|
const nsStyleDisplay* display = psc->StyleDisplay();
|
||||||
nsRect boundingRect = nsDisplayTransform::GetFrameBoundsForTransform(parent);
|
TransformReferenceBox refBox(parent);
|
||||||
|
|
||||||
/* Allows us to access named variables by index. */
|
/* Allows us to access named variables by index. */
|
||||||
Point3D result;
|
Point3D result;
|
||||||
result.z = 0.0f;
|
result.z = 0.0f;
|
||||||
gfx::Float* coords[2] = {&result.x, &result.y};
|
gfx::Float* coords[2] = {&result.x, &result.y};
|
||||||
const nscoord* dimensions[2] =
|
TransformReferenceBox::DimensionGetter dimensionGetter[] =
|
||||||
{&boundingRect.width, &boundingRect.height};
|
{ &TransformReferenceBox::Width, &TransformReferenceBox::Height };
|
||||||
|
|
||||||
for (uint8_t index = 0; index < 2; ++index) {
|
for (uint8_t index = 0; index < 2; ++index) {
|
||||||
/* If the -moz-transform-origin specifies a percentage, take the percentage
|
/* 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) {
|
if (coord.GetUnit() == eStyleUnit_Calc) {
|
||||||
const nsStyleCoord::Calc *calc = coord.GetCalcValue();
|
const nsStyleCoord::Calc *calc = coord.GetCalcValue();
|
||||||
*coords[index] =
|
*coords[index] =
|
||||||
NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
|
NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) *
|
||||||
calc->mPercent +
|
calc->mPercent +
|
||||||
NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
|
NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
|
||||||
} else if (coord.GetUnit() == eStyleUnit_Percent) {
|
} else if (coord.GetUnit() == eStyleUnit_Percent) {
|
||||||
*coords[index] =
|
*coords[index] =
|
||||||
NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
|
NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) *
|
||||||
coord.GetPercentValue();
|
coord.GetPercentValue();
|
||||||
} else {
|
} else {
|
||||||
MOZ_ASSERT(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
|
MOZ_ASSERT(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
|
||||||
|
@ -4821,11 +4778,14 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
|
||||||
*aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(frame);
|
*aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the underlying transform matrix. This requires us to get the
|
// Get the underlying transform matrix:
|
||||||
* bounds of the frame.
|
|
||||||
*/
|
TransformReferenceBox refBox;
|
||||||
nsRect bounds = (aBoundsOverride ? *aBoundsOverride :
|
if (aBoundsOverride) {
|
||||||
nsDisplayTransform::GetFrameBoundsForTransform(frame));
|
refBox.Init(aBoundsOverride->Size());
|
||||||
|
} else {
|
||||||
|
refBox.Init(frame);
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the matrix, then change its basis to factor in the origin. */
|
/* Get the matrix, then change its basis to factor in the origin. */
|
||||||
bool dummy;
|
bool dummy;
|
||||||
|
@ -4840,7 +4800,7 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
|
||||||
result = nsStyleTransformMatrix::ReadTransforms(aProperties.mTransformList->mHead,
|
result = nsStyleTransformMatrix::ReadTransforms(aProperties.mTransformList->mHead,
|
||||||
frame ? frame->StyleContext() : nullptr,
|
frame ? frame->StyleContext() : nullptr,
|
||||||
frame ? frame->PresContext() : nullptr,
|
frame ? frame->PresContext() : nullptr,
|
||||||
dummy, bounds, aAppUnitsPerPixel);
|
dummy, refBox, aAppUnitsPerPixel);
|
||||||
} else if (hasSVGTransforms) {
|
} else if (hasSVGTransforms) {
|
||||||
// Correct the translation components for zoom:
|
// Correct the translation components for zoom:
|
||||||
float pixelsPerCSSPx = frame->PresContext()->AppUnitsPerCSSPixel() /
|
float pixelsPerCSSPx = frame->PresContext()->AppUnitsPerCSSPixel() /
|
||||||
|
|
|
@ -3486,22 +3486,6 @@ public:
|
||||||
static Point3D GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame,
|
static Point3D GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame,
|
||||||
float aAppUnitsPerPixel);
|
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
|
struct FrameTransformProperties
|
||||||
{
|
{
|
||||||
FrameTransformProperties(const nsIFrame* aFrame,
|
FrameTransformProperties(const nsIFrame* aFrame,
|
||||||
|
@ -3533,10 +3517,10 @@ public:
|
||||||
* @param aOrigin Relative to which point this transform should be applied.
|
* @param aOrigin Relative to which point this transform should be applied.
|
||||||
* @param aAppUnitsPerPixel The number of app units per graphics unit.
|
* @param aAppUnitsPerPixel The number of app units per graphics unit.
|
||||||
* @param aBoundsOverride [optional] If this is nullptr (the default), the
|
* @param aBoundsOverride [optional] If this is nullptr (the default), the
|
||||||
* computation will use the value of GetFrameBoundsForTransform(aFrame)
|
* computation will use the value of TransformReferenceBox(aFrame).
|
||||||
* for the frame's bounding rectangle. Otherwise, it will use the
|
* Otherwise, it will use the value of aBoundsOverride. This is
|
||||||
* value of aBoundsOverride. This is mostly for internal use and in
|
* mostly for internal use and in most cases you will not need to
|
||||||
* most cases you will not need to specify a value.
|
* specify a value.
|
||||||
* @param aOffsetByOrigin If true, the resulting matrix will be translated
|
* @param aOffsetByOrigin If true, the resulting matrix will be translated
|
||||||
* by aOrigin. This translation is applied *before* the CSS transform.
|
* by aOrigin. This translation is applied *before* the CSS transform.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -128,6 +128,7 @@ bool nsLayoutUtils::gPreventAssertInCompareTreePosition = false;
|
||||||
#endif // DEBUG
|
#endif // DEBUG
|
||||||
|
|
||||||
typedef FrameMetrics::ViewID ViewID;
|
typedef FrameMetrics::ViewID ViewID;
|
||||||
|
typedef nsStyleTransformMatrix::TransformReferenceBox TransformReferenceBox;
|
||||||
|
|
||||||
/* static */ uint32_t nsLayoutUtils::sFontSizeInflationEmPerLine;
|
/* static */ uint32_t nsLayoutUtils::sFontSizeInflationEmPerLine;
|
||||||
/* static */ uint32_t nsLayoutUtils::sFontSizeInflationMinTwips;
|
/* static */ uint32_t nsLayoutUtils::sFontSizeInflationMinTwips;
|
||||||
|
@ -462,12 +463,12 @@ GetScaleForValue(const StyleAnimationValue& aValue, nsIFrame* aFrame)
|
||||||
return gfxSize();
|
return gfxSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRect frameBounds = aFrame->GetRect();
|
|
||||||
bool dontCare;
|
bool dontCare;
|
||||||
|
TransformReferenceBox refBox(aFrame);
|
||||||
gfx3DMatrix transform = nsStyleTransformMatrix::ReadTransforms(
|
gfx3DMatrix transform = nsStyleTransformMatrix::ReadTransforms(
|
||||||
list->mHead,
|
list->mHead,
|
||||||
aFrame->StyleContext(),
|
aFrame->StyleContext(),
|
||||||
aFrame->PresContext(), dontCare, frameBounds,
|
aFrame->PresContext(), dontCare, refBox,
|
||||||
aFrame->PresContext()->AppUnitsPerDevPixel());
|
aFrame->PresContext()->AppUnitsPerDevPixel());
|
||||||
|
|
||||||
gfxMatrix transform2d;
|
gfxMatrix transform2d;
|
||||||
|
|
|
@ -53,6 +53,7 @@ using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
typedef const nsStyleBackground::Position Position;
|
typedef const nsStyleBackground::Position Position;
|
||||||
typedef const nsStyleBackground::Position::PositionCoord PositionCoord;
|
typedef const nsStyleBackground::Position::PositionCoord PositionCoord;
|
||||||
|
typedef nsStyleTransformMatrix::TransformReferenceBox TransformReferenceBox;
|
||||||
|
|
||||||
#if defined(DEBUG_bzbarsky) || defined(DEBUG_caillon)
|
#if defined(DEBUG_bzbarsky) || defined(DEBUG_caillon)
|
||||||
#define DEBUG_ComputedDOMStyle
|
#define DEBUG_ComputedDOMStyle
|
||||||
|
@ -1253,7 +1254,9 @@ nsComputedDOMStyle::DoGetTransform()
|
||||||
* store it in a string, and hand it back to the caller.
|
* 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
|
* 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
|
* frame, which is problematic. The reason is that when we have percentage
|
||||||
* transforms, there are a total of four stored matrix entries that influence
|
* 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
|
* using the named transforms. Until a real solution is found, we'll just
|
||||||
* use this approach.
|
* use this approach.
|
||||||
*/
|
*/
|
||||||
nsRect bounds =
|
TransformReferenceBox refBox(mInnerFrame, nsSize(0, 0));
|
||||||
(mInnerFrame ? nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame) :
|
|
||||||
nsRect(0, 0, 0, 0));
|
|
||||||
|
|
||||||
bool dummy;
|
bool dummy;
|
||||||
gfx3DMatrix matrix =
|
gfx3DMatrix matrix =
|
||||||
|
@ -1272,7 +1273,7 @@ nsComputedDOMStyle::DoGetTransform()
|
||||||
mStyleContextHolder,
|
mStyleContextHolder,
|
||||||
mStyleContextHolder->PresContext(),
|
mStyleContextHolder->PresContext(),
|
||||||
dummy,
|
dummy,
|
||||||
bounds,
|
refBox,
|
||||||
float(mozilla::AppUnitsPerCSSPixel()));
|
float(mozilla::AppUnitsPerCSSPixel()));
|
||||||
|
|
||||||
return MatrixToCSSValue(matrix);
|
return MatrixToCSSValue(matrix);
|
||||||
|
@ -4958,7 +4959,7 @@ nsComputedDOMStyle::GetFrameBoundsWidthForTransform(nscoord& aWidth)
|
||||||
|
|
||||||
AssertFlushedPendingReflows();
|
AssertFlushedPendingReflows();
|
||||||
|
|
||||||
aWidth = nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame).width;
|
aWidth = TransformReferenceBox(mInnerFrame).Width();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4972,7 +4973,7 @@ nsComputedDOMStyle::GetFrameBoundsHeightForTransform(nscoord& aHeight)
|
||||||
|
|
||||||
AssertFlushedPendingReflows();
|
AssertFlushedPendingReflows();
|
||||||
|
|
||||||
aHeight = nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame).height;
|
aHeight = TransformReferenceBox(mInnerFrame).Height();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,72 @@ namespace nsStyleTransformMatrix {
|
||||||
* involving angles need to be done in 'double'.
|
* 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)
|
/* Force small values to zero. We do this to avoid having sin(360deg)
|
||||||
* evaluate to a tiny but nonzero value.
|
* evaluate to a tiny but nonzero value.
|
||||||
*/
|
*/
|
||||||
|
@ -42,7 +108,8 @@ ProcessTranslatePart(const nsCSSValue& aValue,
|
||||||
nsStyleContext* aContext,
|
nsStyleContext* aContext,
|
||||||
nsPresContext* aPresContext,
|
nsPresContext* aPresContext,
|
||||||
bool& aCanStoreInRuleTree,
|
bool& aCanStoreInRuleTree,
|
||||||
nscoord aSize)
|
TransformReferenceBox* aRefBox,
|
||||||
|
TransformReferenceBox::DimensionGetter aDimensionGetter)
|
||||||
{
|
{
|
||||||
nscoord offset = 0;
|
nscoord offset = 0;
|
||||||
float percent = 0.0f;
|
float percent = 0.0f;
|
||||||
|
@ -72,8 +139,16 @@ ProcessTranslatePart(const nsCSSValue& aValue,
|
||||||
aCanStoreInRuleTree);
|
aCanStoreInRuleTree);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (percent * NSAppUnitsToFloatPixels(aSize, nsPresContext::AppUnitsPerCSSPixel())) +
|
float translation = NSAppUnitsToFloatPixels(offset,
|
||||||
NSAppUnitsToFloatPixels(offset, nsPresContext::AppUnitsPerCSSPixel());
|
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,
|
nsStyleContext* aContext,
|
||||||
nsPresContext* aPresContext,
|
nsPresContext* aPresContext,
|
||||||
bool& aCanStoreInRuleTree,
|
bool& aCanStoreInRuleTree,
|
||||||
nsRect& aBounds)
|
TransformReferenceBox& aRefBox)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(aData->Count() == 7, "Invalid array!");
|
NS_PRECONDITION(aData->Count() == 7, "Invalid array!");
|
||||||
|
|
||||||
|
@ -108,10 +183,10 @@ ProcessMatrix(gfx3DMatrix& aMatrix,
|
||||||
*/
|
*/
|
||||||
result._31 = ProcessTranslatePart(aData->Item(5),
|
result._31 = ProcessTranslatePart(aData->Item(5),
|
||||||
aContext, aPresContext, aCanStoreInRuleTree,
|
aContext, aPresContext, aCanStoreInRuleTree,
|
||||||
aBounds.Width());
|
&aRefBox, &TransformReferenceBox::Width);
|
||||||
result._32 = ProcessTranslatePart(aData->Item(6),
|
result._32 = ProcessTranslatePart(aData->Item(6),
|
||||||
aContext, aPresContext, aCanStoreInRuleTree,
|
aContext, aPresContext, aCanStoreInRuleTree,
|
||||||
aBounds.Height());
|
&aRefBox, &TransformReferenceBox::Height);
|
||||||
|
|
||||||
aMatrix.PreMultiply(result);
|
aMatrix.PreMultiply(result);
|
||||||
}
|
}
|
||||||
|
@ -122,7 +197,7 @@ ProcessMatrix3D(gfx3DMatrix& aMatrix,
|
||||||
nsStyleContext* aContext,
|
nsStyleContext* aContext,
|
||||||
nsPresContext* aPresContext,
|
nsPresContext* aPresContext,
|
||||||
bool& aCanStoreInRuleTree,
|
bool& aCanStoreInRuleTree,
|
||||||
nsRect& aBounds)
|
TransformReferenceBox& aRefBox)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(aData->Count() == 17, "Invalid array!");
|
NS_PRECONDITION(aData->Count() == 17, "Invalid array!");
|
||||||
|
|
||||||
|
@ -144,13 +219,14 @@ ProcessMatrix3D(gfx3DMatrix& aMatrix,
|
||||||
|
|
||||||
temp._41 = ProcessTranslatePart(aData->Item(13),
|
temp._41 = ProcessTranslatePart(aData->Item(13),
|
||||||
aContext, aPresContext, aCanStoreInRuleTree,
|
aContext, aPresContext, aCanStoreInRuleTree,
|
||||||
aBounds.Width());
|
&aRefBox, &TransformReferenceBox::Width);
|
||||||
temp._42 = ProcessTranslatePart(aData->Item(14),
|
temp._42 = ProcessTranslatePart(aData->Item(14),
|
||||||
aContext, aPresContext, aCanStoreInRuleTree,
|
aContext, aPresContext, aCanStoreInRuleTree,
|
||||||
aBounds.Height());
|
&aRefBox, &TransformReferenceBox::Height);
|
||||||
temp._43 = ProcessTranslatePart(aData->Item(15),
|
temp._43 = ProcessTranslatePart(aData->Item(15),
|
||||||
aContext, aPresContext, aCanStoreInRuleTree,
|
aContext, aPresContext, aCanStoreInRuleTree,
|
||||||
aBounds.Height());
|
&aRefBox, &TransformReferenceBox::Height);
|
||||||
|
// XXXjwatt why are we using TransformReferenceBox::Height for the z compontent?!
|
||||||
|
|
||||||
aMatrix.PreMultiply(temp);
|
aMatrix.PreMultiply(temp);
|
||||||
}
|
}
|
||||||
|
@ -162,7 +238,7 @@ ProcessInterpolateMatrix(gfx3DMatrix& aMatrix,
|
||||||
nsStyleContext* aContext,
|
nsStyleContext* aContext,
|
||||||
nsPresContext* aPresContext,
|
nsPresContext* aPresContext,
|
||||||
bool& aCanStoreInRuleTree,
|
bool& aCanStoreInRuleTree,
|
||||||
nsRect& aBounds)
|
TransformReferenceBox& aRefBox)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(aData->Count() == 4, "Invalid array!");
|
NS_PRECONDITION(aData->Count() == 4, "Invalid array!");
|
||||||
|
|
||||||
|
@ -171,13 +247,13 @@ ProcessInterpolateMatrix(gfx3DMatrix& aMatrix,
|
||||||
matrix1 = nsStyleTransformMatrix::ReadTransforms(aData->Item(1).GetListValue(),
|
matrix1 = nsStyleTransformMatrix::ReadTransforms(aData->Item(1).GetListValue(),
|
||||||
aContext, aPresContext,
|
aContext, aPresContext,
|
||||||
aCanStoreInRuleTree,
|
aCanStoreInRuleTree,
|
||||||
aBounds, nsPresContext::AppUnitsPerCSSPixel());
|
aRefBox, nsPresContext::AppUnitsPerCSSPixel());
|
||||||
}
|
}
|
||||||
if (aData->Item(2).GetUnit() == eCSSUnit_List) {
|
if (aData->Item(2).GetUnit() == eCSSUnit_List) {
|
||||||
matrix2 = ReadTransforms(aData->Item(2).GetListValue(),
|
matrix2 = ReadTransforms(aData->Item(2).GetListValue(),
|
||||||
aContext, aPresContext,
|
aContext, aPresContext,
|
||||||
aCanStoreInRuleTree,
|
aCanStoreInRuleTree,
|
||||||
aBounds, nsPresContext::AppUnitsPerCSSPixel());
|
aRefBox, nsPresContext::AppUnitsPerCSSPixel());
|
||||||
}
|
}
|
||||||
double progress = aData->Item(3).GetPercentValue();
|
double progress = aData->Item(3).GetPercentValue();
|
||||||
|
|
||||||
|
@ -193,7 +269,7 @@ ProcessTranslateX(gfx3DMatrix& aMatrix,
|
||||||
nsStyleContext* aContext,
|
nsStyleContext* aContext,
|
||||||
nsPresContext* aPresContext,
|
nsPresContext* aPresContext,
|
||||||
bool& aCanStoreInRuleTree,
|
bool& aCanStoreInRuleTree,
|
||||||
nsRect& aBounds)
|
TransformReferenceBox& aRefBox)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
|
NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
|
||||||
|
|
||||||
|
@ -201,7 +277,7 @@ ProcessTranslateX(gfx3DMatrix& aMatrix,
|
||||||
|
|
||||||
temp.x = ProcessTranslatePart(aData->Item(1),
|
temp.x = ProcessTranslatePart(aData->Item(1),
|
||||||
aContext, aPresContext, aCanStoreInRuleTree,
|
aContext, aPresContext, aCanStoreInRuleTree,
|
||||||
aBounds.Width());
|
&aRefBox, &TransformReferenceBox::Width);
|
||||||
aMatrix.Translate(temp);
|
aMatrix.Translate(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +288,7 @@ ProcessTranslateY(gfx3DMatrix& aMatrix,
|
||||||
nsStyleContext* aContext,
|
nsStyleContext* aContext,
|
||||||
nsPresContext* aPresContext,
|
nsPresContext* aPresContext,
|
||||||
bool& aCanStoreInRuleTree,
|
bool& aCanStoreInRuleTree,
|
||||||
nsRect& aBounds)
|
TransformReferenceBox& aRefBox)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
|
NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
|
||||||
|
|
||||||
|
@ -220,7 +296,7 @@ ProcessTranslateY(gfx3DMatrix& aMatrix,
|
||||||
|
|
||||||
temp.y = ProcessTranslatePart(aData->Item(1),
|
temp.y = ProcessTranslatePart(aData->Item(1),
|
||||||
aContext, aPresContext, aCanStoreInRuleTree,
|
aContext, aPresContext, aCanStoreInRuleTree,
|
||||||
aBounds.Height());
|
&aRefBox, &TransformReferenceBox::Height);
|
||||||
aMatrix.Translate(temp);
|
aMatrix.Translate(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +312,8 @@ ProcessTranslateZ(gfx3DMatrix& aMatrix,
|
||||||
Point3D temp;
|
Point3D temp;
|
||||||
|
|
||||||
temp.z = ProcessTranslatePart(aData->Item(1), aContext,
|
temp.z = ProcessTranslatePart(aData->Item(1), aContext,
|
||||||
aPresContext, aCanStoreInRuleTree, 0);
|
aPresContext, aCanStoreInRuleTree,
|
||||||
|
nullptr);
|
||||||
aMatrix.Translate(temp);
|
aMatrix.Translate(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +324,7 @@ ProcessTranslate(gfx3DMatrix& aMatrix,
|
||||||
nsStyleContext* aContext,
|
nsStyleContext* aContext,
|
||||||
nsPresContext* aPresContext,
|
nsPresContext* aPresContext,
|
||||||
bool& aCanStoreInRuleTree,
|
bool& aCanStoreInRuleTree,
|
||||||
nsRect& aBounds)
|
TransformReferenceBox& aRefBox)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Invalid array!");
|
NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Invalid array!");
|
||||||
|
|
||||||
|
@ -255,13 +332,13 @@ ProcessTranslate(gfx3DMatrix& aMatrix,
|
||||||
|
|
||||||
temp.x = ProcessTranslatePart(aData->Item(1),
|
temp.x = ProcessTranslatePart(aData->Item(1),
|
||||||
aContext, aPresContext, aCanStoreInRuleTree,
|
aContext, aPresContext, aCanStoreInRuleTree,
|
||||||
aBounds.Width());
|
&aRefBox, &TransformReferenceBox::Width);
|
||||||
|
|
||||||
/* If we read in a Y component, set it appropriately */
|
/* If we read in a Y component, set it appropriately */
|
||||||
if (aData->Count() == 3) {
|
if (aData->Count() == 3) {
|
||||||
temp.y = ProcessTranslatePart(aData->Item(2),
|
temp.y = ProcessTranslatePart(aData->Item(2),
|
||||||
aContext, aPresContext, aCanStoreInRuleTree,
|
aContext, aPresContext, aCanStoreInRuleTree,
|
||||||
aBounds.Height());
|
&aRefBox, &TransformReferenceBox::Height);
|
||||||
}
|
}
|
||||||
aMatrix.Translate(temp);
|
aMatrix.Translate(temp);
|
||||||
}
|
}
|
||||||
|
@ -272,7 +349,7 @@ ProcessTranslate3D(gfx3DMatrix& aMatrix,
|
||||||
nsStyleContext* aContext,
|
nsStyleContext* aContext,
|
||||||
nsPresContext* aPresContext,
|
nsPresContext* aPresContext,
|
||||||
bool& aCanStoreInRuleTree,
|
bool& aCanStoreInRuleTree,
|
||||||
nsRect& aBounds)
|
TransformReferenceBox& aRefBox)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(aData->Count() == 4, "Invalid array!");
|
NS_PRECONDITION(aData->Count() == 4, "Invalid array!");
|
||||||
|
|
||||||
|
@ -280,15 +357,15 @@ ProcessTranslate3D(gfx3DMatrix& aMatrix,
|
||||||
|
|
||||||
temp.x = ProcessTranslatePart(aData->Item(1),
|
temp.x = ProcessTranslatePart(aData->Item(1),
|
||||||
aContext, aPresContext, aCanStoreInRuleTree,
|
aContext, aPresContext, aCanStoreInRuleTree,
|
||||||
aBounds.Width());
|
&aRefBox, &TransformReferenceBox::Width);
|
||||||
|
|
||||||
temp.y = ProcessTranslatePart(aData->Item(2),
|
temp.y = ProcessTranslatePart(aData->Item(2),
|
||||||
aContext, aPresContext, aCanStoreInRuleTree,
|
aContext, aPresContext, aCanStoreInRuleTree,
|
||||||
aBounds.Height());
|
&aRefBox, &TransformReferenceBox::Height);
|
||||||
|
|
||||||
temp.z = ProcessTranslatePart(aData->Item(3),
|
temp.z = ProcessTranslatePart(aData->Item(3),
|
||||||
aContext, aPresContext, aCanStoreInRuleTree,
|
aContext, aPresContext, aCanStoreInRuleTree,
|
||||||
0);
|
nullptr);
|
||||||
|
|
||||||
aMatrix.Translate(temp);
|
aMatrix.Translate(temp);
|
||||||
}
|
}
|
||||||
|
@ -481,7 +558,7 @@ ProcessPerspective(gfx3DMatrix& aMatrix,
|
||||||
|
|
||||||
float depth = ProcessTranslatePart(aData->Item(1), aContext,
|
float depth = ProcessTranslatePart(aData->Item(1), aContext,
|
||||||
aPresContext, aCanStoreInRuleTree,
|
aPresContext, aCanStoreInRuleTree,
|
||||||
0);
|
nullptr);
|
||||||
aMatrix.Perspective(depth);
|
aMatrix.Perspective(depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,7 +573,7 @@ MatrixForTransformFunction(gfx3DMatrix& aMatrix,
|
||||||
nsStyleContext* aContext,
|
nsStyleContext* aContext,
|
||||||
nsPresContext* aPresContext,
|
nsPresContext* aPresContext,
|
||||||
bool& aCanStoreInRuleTree,
|
bool& aCanStoreInRuleTree,
|
||||||
nsRect& aBounds)
|
TransformReferenceBox& aRefBox)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(aData, "Why did you want to get data from a null array?");
|
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
|
// It's OK if aContext and aPresContext are null if the caller already
|
||||||
|
@ -508,11 +585,11 @@ MatrixForTransformFunction(gfx3DMatrix& aMatrix,
|
||||||
switch (TransformFunctionOf(aData)) {
|
switch (TransformFunctionOf(aData)) {
|
||||||
case eCSSKeyword_translatex:
|
case eCSSKeyword_translatex:
|
||||||
ProcessTranslateX(aMatrix, aData, aContext, aPresContext,
|
ProcessTranslateX(aMatrix, aData, aContext, aPresContext,
|
||||||
aCanStoreInRuleTree, aBounds);
|
aCanStoreInRuleTree, aRefBox);
|
||||||
break;
|
break;
|
||||||
case eCSSKeyword_translatey:
|
case eCSSKeyword_translatey:
|
||||||
ProcessTranslateY(aMatrix, aData, aContext, aPresContext,
|
ProcessTranslateY(aMatrix, aData, aContext, aPresContext,
|
||||||
aCanStoreInRuleTree, aBounds);
|
aCanStoreInRuleTree, aRefBox);
|
||||||
break;
|
break;
|
||||||
case eCSSKeyword_translatez:
|
case eCSSKeyword_translatez:
|
||||||
ProcessTranslateZ(aMatrix, aData, aContext, aPresContext,
|
ProcessTranslateZ(aMatrix, aData, aContext, aPresContext,
|
||||||
|
@ -520,11 +597,11 @@ MatrixForTransformFunction(gfx3DMatrix& aMatrix,
|
||||||
break;
|
break;
|
||||||
case eCSSKeyword_translate:
|
case eCSSKeyword_translate:
|
||||||
ProcessTranslate(aMatrix, aData, aContext, aPresContext,
|
ProcessTranslate(aMatrix, aData, aContext, aPresContext,
|
||||||
aCanStoreInRuleTree, aBounds);
|
aCanStoreInRuleTree, aRefBox);
|
||||||
break;
|
break;
|
||||||
case eCSSKeyword_translate3d:
|
case eCSSKeyword_translate3d:
|
||||||
ProcessTranslate3D(aMatrix, aData, aContext, aPresContext,
|
ProcessTranslate3D(aMatrix, aData, aContext, aPresContext,
|
||||||
aCanStoreInRuleTree, aBounds);
|
aCanStoreInRuleTree, aRefBox);
|
||||||
break;
|
break;
|
||||||
case eCSSKeyword_scalex:
|
case eCSSKeyword_scalex:
|
||||||
ProcessScaleX(aMatrix, aData);
|
ProcessScaleX(aMatrix, aData);
|
||||||
|
@ -565,15 +642,15 @@ MatrixForTransformFunction(gfx3DMatrix& aMatrix,
|
||||||
break;
|
break;
|
||||||
case eCSSKeyword_matrix:
|
case eCSSKeyword_matrix:
|
||||||
ProcessMatrix(aMatrix, aData, aContext, aPresContext,
|
ProcessMatrix(aMatrix, aData, aContext, aPresContext,
|
||||||
aCanStoreInRuleTree, aBounds);
|
aCanStoreInRuleTree, aRefBox);
|
||||||
break;
|
break;
|
||||||
case eCSSKeyword_matrix3d:
|
case eCSSKeyword_matrix3d:
|
||||||
ProcessMatrix3D(aMatrix, aData, aContext, aPresContext,
|
ProcessMatrix3D(aMatrix, aData, aContext, aPresContext,
|
||||||
aCanStoreInRuleTree, aBounds);
|
aCanStoreInRuleTree, aRefBox);
|
||||||
break;
|
break;
|
||||||
case eCSSKeyword_interpolatematrix:
|
case eCSSKeyword_interpolatematrix:
|
||||||
ProcessInterpolateMatrix(aMatrix, aData, aContext, aPresContext,
|
ProcessInterpolateMatrix(aMatrix, aData, aContext, aPresContext,
|
||||||
aCanStoreInRuleTree, aBounds);
|
aCanStoreInRuleTree, aRefBox);
|
||||||
break;
|
break;
|
||||||
case eCSSKeyword_perspective:
|
case eCSSKeyword_perspective:
|
||||||
ProcessPerspective(aMatrix, aData, aContext, aPresContext,
|
ProcessPerspective(aMatrix, aData, aContext, aPresContext,
|
||||||
|
@ -600,7 +677,7 @@ ReadTransforms(const nsCSSValueList* aList,
|
||||||
nsStyleContext* aContext,
|
nsStyleContext* aContext,
|
||||||
nsPresContext* aPresContext,
|
nsPresContext* aPresContext,
|
||||||
bool &aCanStoreInRuleTree,
|
bool &aCanStoreInRuleTree,
|
||||||
nsRect& aBounds,
|
TransformReferenceBox& aRefBox,
|
||||||
float aAppUnitsPerMatrixUnit)
|
float aAppUnitsPerMatrixUnit)
|
||||||
{
|
{
|
||||||
gfx3DMatrix result;
|
gfx3DMatrix result;
|
||||||
|
@ -619,7 +696,7 @@ ReadTransforms(const nsCSSValueList* aList,
|
||||||
|
|
||||||
/* Read in a single transform matrix. */
|
/* Read in a single transform matrix. */
|
||||||
MatrixForTransformFunction(result, currElem.GetArrayValue(), aContext,
|
MatrixForTransformFunction(result, currElem.GetArrayValue(), aContext,
|
||||||
aPresContext, aCanStoreInRuleTree, aBounds);
|
aPresContext, aCanStoreInRuleTree, aRefBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
float scale = float(nsPresContext::AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit;
|
float scale = float(nsPresContext::AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit;
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "nsCSSValue.h"
|
#include "nsCSSValue.h"
|
||||||
#include "gfx3DMatrix.h"
|
#include "gfx3DMatrix.h"
|
||||||
|
|
||||||
|
class nsIFrame;
|
||||||
class nsStyleContext;
|
class nsStyleContext;
|
||||||
class nsPresContext;
|
class nsPresContext;
|
||||||
struct nsRect;
|
struct nsRect;
|
||||||
|
@ -21,7 +22,86 @@ struct nsRect;
|
||||||
* A helper to generate gfxMatrixes from css transform functions.
|
* A helper to generate gfxMatrixes from css transform functions.
|
||||||
*/
|
*/
|
||||||
namespace nsStyleTransformMatrix {
|
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
|
* Return the transform function, as an nsCSSKeyword, for the given
|
||||||
* nsCSSValue::Array from a transform list.
|
* nsCSSValue::Array from a transform list.
|
||||||
|
@ -32,7 +112,8 @@ namespace nsStyleTransformMatrix {
|
||||||
nsStyleContext* aContext,
|
nsStyleContext* aContext,
|
||||||
nsPresContext* aPresContext,
|
nsPresContext* aPresContext,
|
||||||
bool& aCanStoreInRuleTree,
|
bool& aCanStoreInRuleTree,
|
||||||
nscoord aSize);
|
TransformReferenceBox* aRefBox,
|
||||||
|
TransformReferenceBox::DimensionGetter aDimensionGetter = nullptr);
|
||||||
|
|
||||||
void
|
void
|
||||||
ProcessInterpolateMatrix(gfx3DMatrix& aMatrix,
|
ProcessInterpolateMatrix(gfx3DMatrix& aMatrix,
|
||||||
|
@ -40,7 +121,7 @@ namespace nsStyleTransformMatrix {
|
||||||
nsStyleContext* aContext,
|
nsStyleContext* aContext,
|
||||||
nsPresContext* aPresContext,
|
nsPresContext* aPresContext,
|
||||||
bool& aCanStoreInRuleTree,
|
bool& aCanStoreInRuleTree,
|
||||||
nsRect& aBounds);
|
TransformReferenceBox& aBounds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an nsCSSValueList containing -moz-transform functions,
|
* Given an nsCSSValueList containing -moz-transform functions,
|
||||||
|
@ -62,7 +143,7 @@ namespace nsStyleTransformMatrix {
|
||||||
nsStyleContext* aContext,
|
nsStyleContext* aContext,
|
||||||
nsPresContext* aPresContext,
|
nsPresContext* aPresContext,
|
||||||
bool &aCanStoreInRuleTree,
|
bool &aCanStoreInRuleTree,
|
||||||
nsRect& aBounds,
|
TransformReferenceBox& aBounds,
|
||||||
float aAppUnitsPerMatrixUnit);
|
float aAppUnitsPerMatrixUnit);
|
||||||
|
|
||||||
} // namespace nsStyleTransformMatrix
|
} // namespace nsStyleTransformMatrix
|
||||||
|
|
|
@ -298,7 +298,8 @@ function Blocklist() {
|
||||||
gPref.addObserver(PREF_EM_LOGGING_ENABLED, this, false);
|
gPref.addObserver(PREF_EM_LOGGING_ENABLED, this, false);
|
||||||
this.wrappedJSObject = this;
|
this.wrappedJSObject = this;
|
||||||
// requests from child processes come in here, see receiveMessage.
|
// 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 = {
|
Blocklist.prototype = {
|
||||||
|
@ -322,7 +323,8 @@ Blocklist.prototype = {
|
||||||
|
|
||||||
shutdown: function () {
|
shutdown: function () {
|
||||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
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("extensions.blocklist.", this);
|
||||||
gPref.removeObserver(PREF_EM_LOGGING_ENABLED, this);
|
gPref.removeObserver(PREF_EM_LOGGING_ENABLED, this);
|
||||||
},
|
},
|
||||||
|
@ -359,10 +361,13 @@ Blocklist.prototype = {
|
||||||
// Message manager message handlers
|
// Message manager message handlers
|
||||||
receiveMessage: function (aMsg) {
|
receiveMessage: function (aMsg) {
|
||||||
switch (aMsg.name) {
|
switch (aMsg.name) {
|
||||||
case "Blocklist::getPluginBlocklistState":
|
case "Blocklist:getPluginBlocklistState":
|
||||||
return this.getPluginBlocklistState(aMsg.data.addonData,
|
return this.getPluginBlocklistState(aMsg.data.addonData,
|
||||||
aMsg.data.appVersion,
|
aMsg.data.appVersion,
|
||||||
aMsg.data.toolkitVersion);
|
aMsg.data.toolkitVersion);
|
||||||
|
case "Blocklist:content-blocklist-updated":
|
||||||
|
Services.obs.notifyObservers(null, "content-blocklist-updated", null);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error("Unknown blocklist message received from content: " + aMsg.name);
|
throw new Error("Unknown blocklist message received from content: " + aMsg.name);
|
||||||
}
|
}
|
||||||
|
@ -1192,6 +1197,11 @@ Blocklist.prototype = {
|
||||||
return blockEntry.infoURL;
|
return blockEntry.infoURL;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_notifyObserversBlocklistUpdated: function () {
|
||||||
|
Services.obs.notifyObservers(this, "blocklist-updated", "");
|
||||||
|
Services.ppmm.broadcastAsyncMessage("Blocklist:blocklistInvalidated", {});
|
||||||
|
},
|
||||||
|
|
||||||
_blocklistUpdated: function Blocklist_blocklistUpdated(oldAddonEntries, oldPluginEntries) {
|
_blocklistUpdated: function Blocklist_blocklistUpdated(oldAddonEntries, oldPluginEntries) {
|
||||||
var addonList = [];
|
var addonList = [];
|
||||||
|
|
||||||
|
@ -1296,7 +1306,7 @@ Blocklist.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addonList.length == 0) {
|
if (addonList.length == 0) {
|
||||||
Services.obs.notifyObservers(self, "blocklist-updated", "");
|
self._notifyObserversBlocklistUpdated();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1308,7 +1318,7 @@ Blocklist.prototype = {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
LOG(e);
|
LOG(e);
|
||||||
}
|
}
|
||||||
Services.obs.notifyObservers(self, "blocklist-updated", "");
|
self._notifyObserversBlocklistUpdated();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1342,7 +1352,7 @@ Blocklist.prototype = {
|
||||||
if (args.restart)
|
if (args.restart)
|
||||||
restartApp();
|
restartApp();
|
||||||
|
|
||||||
Services.obs.notifyObservers(self, "blocklist-updated", "");
|
self._notifyObserversBlocklistUpdated();
|
||||||
Services.obs.removeObserver(applyBlocklistChanges, "addon-blocklist-closed");
|
Services.obs.removeObserver(applyBlocklistChanges, "addon-blocklist-closed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,19 +21,51 @@ const kMissingAPIMessage = "Unsupported blocklist call in the child process."
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Blocklist() {
|
function Blocklist() {
|
||||||
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
Blocklist.prototype = {
|
Blocklist.prototype = {
|
||||||
classID: Components.ID("{e0a106ed-6ad4-47a4-b6af-2f1c8aa4712d}"),
|
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
|
* A helper that queries key data from a plugin or addon object
|
||||||
* and generates a simple data wrapper suitable for ipc. We hand
|
* and generates a simple data wrapper suitable for ipc. We hand
|
||||||
* these directly to the nsBlockListService in the parent which
|
* these directly to the nsBlockListService in the parent which
|
||||||
* doesn't query for much.. allowing us to get away with this.
|
* doesn't query for much.. allowing us to get away with this.
|
||||||
*/
|
*/
|
||||||
flattenObject: function (aTag) {
|
flattenObject: function (aTag) {
|
||||||
// Based on debugging the nsBlocklistService, these are the props the
|
// Based on debugging the nsBlocklistService, these are the props the
|
||||||
// parent side will check on our objects.
|
// parent side will check on our objects.
|
||||||
|
@ -49,15 +81,16 @@ Blocklist.prototype = {
|
||||||
// only calls getPluginBlocklistState.
|
// only calls getPluginBlocklistState.
|
||||||
|
|
||||||
isAddonBlocklisted: function (aAddon, aAppVersion, aToolkitVersion) {
|
isAddonBlocklisted: function (aAddon, aAppVersion, aToolkitVersion) {
|
||||||
throw new Error(kMissingAPIMessage);
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
getAddonBlocklistState: function (aAddon, aAppVersion, aToolkitVersion) {
|
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) {
|
getPluginBlocklistState: function (aPluginTag, aAppVersion, aToolkitVersion) {
|
||||||
return Services.cpmm.sendSyncMessage("Blocklist::getPluginBlocklistState", {
|
return Services.cpmm.sendSyncMessage("Blocklist:getPluginBlocklistState", {
|
||||||
addonData: this.flattenObject(aPluginTag),
|
addonData: this.flattenObject(aPluginTag),
|
||||||
appVersion: aAppVersion,
|
appVersion: aAppVersion,
|
||||||
toolkitVersion: aToolkitVersion
|
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
|
// be reallocated regardless (disposing the old buffer is taken care of internally, see
|
||||||
// the note below).
|
// 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
|
nsresult
|
||||||
nsLinebreakHelpers :: ConvertPlatformToDOMLinebreaks ( const char* inFlavor, void** ioData,
|
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
|
// be reallocated regardless (disposing the old buffer is taken care of internally, see
|
||||||
// the note below).
|
// 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 ) ;
|
static nsresult ConvertPlatformToDOMLinebreaks ( const char* inFlavor, void** ioData, int32_t* ioLengthInBytes ) ;
|
||||||
|
|
||||||
}; // class nsLinebreakHelpers
|
}; // class nsLinebreakHelpers
|
||||||
|
|
Загрузка…
Ссылка в новой задаче