Backed out changeset 2d9ed9032a45 (bug 1192831) for suspicion of causing bug 1178709 to spike.

This commit is contained in:
Ryan VanderMeulen 2015-08-23 15:21:23 -04:00
parent 1f37202f72
commit 7e078b31d6
23 changed files with 1190 additions and 10 deletions

View File

@ -34,6 +34,7 @@ support-files =
plugin_test.html
plugin_test2.html
plugin_test3.html
plugin_test_w_src.html
plugin_two_types.html
plugin_unknown.html
plugin_crashCommentAndURL.html
@ -75,6 +76,12 @@ skip-if = !crashreporter
[browser_pluginCrashCommentAndURL.js]
skip-if = !crashreporter
[browser_pageInfo_plugins.js]
[browser_pluginplaypreview.js]
skip-if = e10s # bug 1148827
[browser_pluginplaypreview2.js]
skip-if = e10s # bug 1148827
[browser_pluginplaypreview3.js]
skip-if = e10s # bug 1148827
[browser_pluginCrashReportNonDeterminism.js]
skip-if = !crashreporter || os == 'linux' # Bug 1152811

View File

@ -0,0 +1,317 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;
var gTestBrowser = null;
var gNextTest = null;
var gNextTestSkip = 0;
var gPlayPreviewPluginActualEvents = 0;
var gPlayPreviewPluginExpectedEvents = 1;
var gPlayPreviewRegistration = null;
function registerPlayPreview(mimeType, targetUrl) {
function StreamConverterFactory() {}
StreamConverterFactory.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory]),
_targetConstructor: null,
register: function register(targetConstructor) {
this._targetConstructor = targetConstructor;
var proto = targetConstructor.prototype;
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(proto.classID, proto.classDescription,
proto.contractID, this);
},
unregister: function unregister() {
var proto = this._targetConstructor.prototype;
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
registrar.unregisterFactory(proto.classID, this);
this._targetConstructor = null;
},
// nsIFactory
createInstance: function createInstance(aOuter, iid) {
if (aOuter !== null)
throw Cr.NS_ERROR_NO_AGGREGATION;
return (new (this._targetConstructor)).QueryInterface(iid);
},
// nsIFactory
lockFactory: function lockFactory(lock) {
// No longer used as of gecko 1.7.
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
}
};
function OverlayStreamConverter() {}
OverlayStreamConverter.prototype = {
QueryInterface: XPCOMUtils.generateQI([
Ci.nsISupports,
Ci.nsIStreamConverter,
Ci.nsIStreamListener,
Ci.nsIRequestObserver
]),
classID: Components.ID('{4c6030f7-e20a-264f-0f9b-ada3a9e97384}'),
classDescription: 'overlay-test-data Component',
contractID: '@mozilla.org/streamconv;1?from=application/x-moz-playpreview&to=*/*',
// nsIStreamConverter::convert
convert: function(aFromStream, aFromType, aToType, aCtxt) {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
// nsIStreamConverter::asyncConvertData
asyncConvertData: function(aFromType, aToType, aListener, aCtxt) {
var isValidRequest = false;
try {
var request = aCtxt;
request.QueryInterface(Ci.nsIChannel);
var spec = request.URI.spec;
var expectedSpec = 'data:application/x-moz-playpreview;,' + mimeType;
isValidRequest = (spec == expectedSpec);
} catch (e) { }
if (!isValidRequest)
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
// Store the listener passed to us
this.listener = aListener;
},
// nsIStreamListener::onDataAvailable
onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) {
// Do nothing since all the data loading is handled by the viewer.
ok(false, "onDataAvailable should not be called");
},
// nsIRequestObserver::onStartRequest
onStartRequest: function(aRequest, aContext) {
// Setup the request so we can use it below.
aRequest.QueryInterface(Ci.nsIChannel);
// Cancel the request so the viewer can handle it.
aRequest.cancel(Cr.NS_BINDING_ABORTED);
// Create a new channel that is viewer loaded as a resource.
var ioService = Services.io;
var channel = ioService.newChannel2(targetUrl,
null,
null,
null, // aLoadingNode
Services.scriptSecurityManager.getSystemPrincipal(),
null, // aTriggeringPrincipal
Ci.nsILoadInfo.SEC_NORMAL,
Ci.nsIContentPolicy.TYPE_OTHER);
channel.asyncOpen(this.listener, aContext);
},
// nsIRequestObserver::onStopRequest
onStopRequest: function(aRequest, aContext, aStatusCode) {
// Do nothing.
}
};
var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
ph.registerPlayPreviewMimeType(mimeType, true); // ignoring CTP rules
var factory = new StreamConverterFactory();
factory.register(OverlayStreamConverter);
return (gPlayPreviewRegistration = {
unregister: function() {
ph.unregisterPlayPreviewMimeType(mimeType);
factory.unregister();
gPlayPreviewRegistration = null;
}
});
}
function unregisterPlayPreview() {
gPlayPreviewRegistration.unregister();
}
Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
if (gPlayPreviewRegistration)
gPlayPreviewRegistration.unregister();
Services.prefs.clearUserPref("plugins.click_to_play");
});
var newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
gTestBrowser.addEventListener("PluginBindingAttached", handleBindingAttached, true, true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
registerPlayPreview('application/x-test', 'about:');
prepareTest(test1a, gTestRoot + "plugin_test.html", 1);
}
function finishTest() {
gTestBrowser.removeEventListener("load", pageLoad, true);
gTestBrowser.removeEventListener("PluginBindingAttached", handleBindingAttached, true, true);
gBrowser.removeCurrentTab();
window.focus();
finish();
}
function handleBindingAttached(evt) {
if (evt.target instanceof Ci.nsIObjectLoadingContent &&
evt.target.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW)
gPlayPreviewPluginActualEvents++;
}
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
// iframe might triggers load event as well, making sure we skip some to let
// all iframes on the page be loaded as well
if (gNextTestSkip) {
gNextTestSkip--;
return;
}
executeSoon(gNextTest);
}
function prepareTest(nextTest, url, skip) {
gNextTest = nextTest;
gNextTestSkip = skip;
gTestBrowser.contentWindow.location = url;
}
// Tests a page with normal play preview registration (1/2)
function test1a() {
var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
ok(!notificationBox.getNotificationWithValue("blocked-plugins"), "Test 1a, Should not have displayed the blocked plugin notification");
var pluginInfo = getTestPlugin();
ok(pluginInfo, "Should have a test plugin");
var doc = gTestBrowser.contentDocument;
var plugin = doc.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 1a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
ok(!objLoadingContent.activated, "Test 1a, Plugin should not be activated");
var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
ok(overlay, "Test 1a, the overlay div is expected");
var iframe = overlay.getElementsByClassName("previewPluginContentFrame")[0];
ok(iframe && iframe.localName == "iframe", "Test 1a, the overlay iframe is expected");
var iframeHref = iframe.contentWindow.location.href;
ok(iframeHref == "about:", "Test 1a, the overlay about: content is expected");
var rect = iframe.getBoundingClientRect();
ok(rect.width == 200, "Test 1a, Plugin with id=" + plugin.id + " overlay rect should have 200px width before being replaced by actual plugin");
ok(rect.height == 200, "Test 1a, Plugin with id=" + plugin.id + " overlay rect should have 200px height before being replaced by actual plugin");
var e = overlay.ownerDocument.createEvent("CustomEvent");
e.initCustomEvent("MozPlayPlugin", true, true, null);
overlay.dispatchEvent(e);
var condition = function() objLoadingContent.activated;
waitForCondition(condition, test1b, "Test 1a, Waited too long for plugin to stop play preview");
}
// Tests that activating via MozPlayPlugin through the notification works (part 2/2)
function test1b() {
var plugin = gTestBrowser.contentDocument.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 1b, Plugin should be activated");
is(gPlayPreviewPluginActualEvents, gPlayPreviewPluginExpectedEvents,
"There should be exactly one PluginPlayPreview event");
unregisterPlayPreview();
prepareTest(test2, gTestRoot + "plugin_test.html");
}
// Tests a page with a working plugin in it -- the mime type was just unregistered.
function test2() {
var plugin = gTestBrowser.contentDocument.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 2, Plugin should be activated");
registerPlayPreview('application/x-unknown', 'about:');
prepareTest(test3, gTestRoot + "plugin_test.html");
}
// Tests a page with a working plugin in it -- diffent play preview type is reserved.
function test3() {
var plugin = gTestBrowser.contentDocument.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 3, Plugin should be activated");
unregisterPlayPreview();
registerPlayPreview('application/x-test', 'about:');
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
prepareTest(test4a, gTestRoot + "plugin_test.html", 1);
}
// Test a fallback to the click-to-play
function test4a() {
var doc = gTestBrowser.contentDocument;
var plugin = doc.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 4a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
ok(!objLoadingContent.activated, "Test 4a, Plugin should not be activated");
var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
ok(overlay, "Test 4a, the overlay div is expected");
var e = overlay.ownerDocument.createEvent("CustomEvent");
e.initCustomEvent("MozPlayPlugin", true, true, true);
overlay.dispatchEvent(e);
var condition = function() objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY;
waitForCondition(condition, test4b, "Test 4a, Waited too long for plugin to stop play preview");
}
function test4b() {
var doc = gTestBrowser.contentDocument;
var plugin = doc.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.pluginFallbackType != Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 4b, plugin fallback type should not be PLUGIN_PLAY_PREVIEW");
ok(!objLoadingContent.activated, "Test 4b, Plugin should not be activated");
prepareTest(test5a, gTestRoot + "plugin_test.html", 1);
}
// Test a bypass of the click-to-play
function test5a() {
var doc = gTestBrowser.contentDocument;
var plugin = doc.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 5a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
ok(!objLoadingContent.activated, "Test 5a, Plugin should not be activated");
var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
ok(overlay, "Test 5a, the overlay div is expected");
var e = overlay.ownerDocument.createEvent("CustomEvent");
e.initCustomEvent("MozPlayPlugin", true, true, false);
overlay.dispatchEvent(e);
var condition = function() objLoadingContent.activated;
waitForCondition(condition, test5b, "Test 5a, Waited too long for plugin to stop play preview");
}
function test5b() {
var doc = gTestBrowser.contentDocument;
var plugin = doc.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 5b, Plugin should be activated");
finishTest();
}

View File

@ -0,0 +1,171 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;
var gTestBrowser = null;
var gNextTest = null;
var gNextTestSkip = 0;
var gPlayPreviewPluginActualEvents = 0;
var gPlayPreviewPluginExpectedEvents = 1;
var gPlayPreviewRegistration = null;
function registerPlayPreview(mimeType, targetUrl) {
var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
ph.registerPlayPreviewMimeType(mimeType, false, targetUrl);
return (gPlayPreviewRegistration = {
unregister: function() {
ph.unregisterPlayPreviewMimeType(mimeType);
gPlayPreviewRegistration = null;
}
});
}
function unregisterPlayPreview() {
gPlayPreviewRegistration.unregister();
}
Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
if (gPlayPreviewRegistration)
gPlayPreviewRegistration.unregister();
Services.prefs.clearUserPref("plugins.click_to_play");
});
var newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
gTestBrowser.addEventListener("PluginBindingAttached", handleBindingAttached, true, true);
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
registerPlayPreview('application/x-test', 'about:');
prepareTest(test1a, gTestRoot + "plugin_test.html", 1);
}
function finishTest() {
gTestBrowser.removeEventListener("load", pageLoad, true);
gTestBrowser.removeEventListener("PluginBindingAttached", handleBindingAttached, true, true);
gBrowser.removeCurrentTab();
window.focus();
finish();
}
function handleBindingAttached(evt) {
if (evt.target instanceof Ci.nsIObjectLoadingContent &&
evt.target.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW)
gPlayPreviewPluginActualEvents++;
}
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
// iframe might triggers load event as well, making sure we skip some to let
// all iframes on the page be loaded as well
if (gNextTestSkip) {
gNextTestSkip--;
return;
}
executeSoon(gNextTest);
}
function prepareTest(nextTest, url, skip) {
gNextTest = nextTest;
gNextTestSkip = skip;
gTestBrowser.contentWindow.location = url;
}
// Tests a page with normal play preview registration (1/2)
function test1a() {
var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
ok(!notificationBox.getNotificationWithValue("blocked-plugins"), "Test 1a, Should not have displayed the blocked plugin notification");
var pluginInfo = getTestPlugin();
ok(pluginInfo, "Should have a test plugin");
var doc = gTestBrowser.contentDocument;
var plugin = doc.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 1a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
ok(!objLoadingContent.activated, "Test 1a, Plugin should not be activated");
var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
ok(overlay, "Test 1a, the overlay div is expected");
var iframe = overlay.getElementsByClassName("previewPluginContentFrame")[0];
ok(iframe && iframe.localName == "iframe", "Test 1a, the overlay iframe is expected");
var iframeHref = iframe.contentWindow.location.href;
ok(iframeHref == "about:", "Test 1a, the overlay about: content is expected");
var rect = iframe.getBoundingClientRect();
ok(rect.width == 200, "Test 1a, Plugin with id=" + plugin.id + " overlay rect should have 200px width before being replaced by actual plugin");
ok(rect.height == 200, "Test 1a, Plugin with id=" + plugin.id + " overlay rect should have 200px height before being replaced by actual plugin");
var e = overlay.ownerDocument.createEvent("CustomEvent");
e.initCustomEvent("MozPlayPlugin", true, true, null);
overlay.dispatchEvent(e);
var condition = function() objLoadingContent.activated;
waitForCondition(condition, test1b, "Test 1a, Waited too long for plugin to stop play preview");
}
// Tests that activating via MozPlayPlugin through the notification works (part 2/2)
function test1b() {
var plugin = gTestBrowser.contentDocument.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 1b, Plugin should be activated");
is(gPlayPreviewPluginActualEvents, gPlayPreviewPluginExpectedEvents,
"There should be exactly one PluginPlayPreview event");
unregisterPlayPreview();
prepareTest(test2, gTestRoot + "plugin_test.html");
}
// Tests a page with a working plugin in it -- the mime type was just unregistered.
function test2() {
var doc = gTestBrowser.contentDocument;
var plugin = doc.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.pluginFallbackType != Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 2, plugin fallback type should not be PLUGIN_PLAY_PREVIEW");
ok(!objLoadingContent.activated, "Test 2, Plugin should not be activated");
registerPlayPreview('application/x-unknown', 'about:');
prepareTest(test3, gTestRoot + "plugin_test.html");
}
// Tests a page with a working plugin in it -- diffent play preview type is reserved.
function test3() {
var doc = gTestBrowser.contentDocument;
var plugin = doc.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.pluginFallbackType != Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 3, plugin fallback type should not be PLUGIN_PLAY_PREVIEW");
ok(!objLoadingContent.activated, "Test 3, Plugin should not be activated");
unregisterPlayPreview();
registerPlayPreview('application/x-test', 'about:');
Services.prefs.setBoolPref("plugins.click_to_play", false);
var plugin = getTestPlugin();
plugin.enabledState = Ci.nsIPluginTag.STATE_ENABLED;
prepareTest(test4, gTestRoot + "plugin_test.html");
}
// Tests a page with a working plugin in it -- click-to-play is off
function test4() {
var plugin = gTestBrowser.contentDocument.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 4, Plugin should be activated");
finishTest();
}

View File

@ -0,0 +1,130 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;
var gTestBrowser = null;
var gNextTest = null;
var gNextTestSkip = 0;
var gPlayPreviewRegistration = null;
var gTestPluginType = 'application/x-test';
var gTestPluginPreviewUrl = 'about:';
function registerPlayPreview(whitelist) {
var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
ph.registerPlayPreviewMimeType(gTestPluginType, true,
gTestPluginPreviewUrl, whitelist);
return (gPlayPreviewRegistration = {
unregister: function() {
ph.unregisterPlayPreviewMimeType(gTestPluginType);
gPlayPreviewRegistration = null;
}
});
}
function unregisterPlayPreview() {
gPlayPreviewRegistration.unregister();
}
Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
if (gPlayPreviewRegistration) {
gPlayPreviewRegistration.unregister();
}
});
var newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
registerPlayPreview('@*plugin_test.html');
prepareTest(test1a, gTestRoot + "plugin_test.html", 1);
}
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
// iframe might triggers load event as well, making sure we skip some to let
// all iframes on the page be loaded as well
if (gNextTestSkip) {
gNextTestSkip--;
return;
}
executeSoon(gNextTest);
}
function prepareTest(nextTest, url, skip) {
gNextTest = nextTest;
gNextTestSkip = skip;
gTestBrowser.contentWindow.location = url;
}
// Tests plugin on a whitelisted page.
function test1a() {
var plugin = gTestBrowser.contentDocument.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 1a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
ok(!objLoadingContent.activated, "Test 1a, Plugin should not be activated");
unregisterPlayPreview();
registerPlayPreview('@*plugin_wrong.html');
var plugin = getTestPlugin();
plugin.enabledState = Ci.nsIPluginTag.STATE_ENABLED;
prepareTest(test1b, gTestRoot + "plugin_test.html");
}
// Tests plugin on a non-whitelisted page.
function test1b() {
var plugin = gTestBrowser.contentDocument.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 1b, Plugin should be activated");
unregisterPlayPreview();
registerPlayPreview('*browser_pluginplaypreview3.js');
var plugin = getTestPlugin();
plugin.enabledState = Ci.nsIPluginTag.STATE_ENABLED;
prepareTest(test2a, gTestRoot + "plugin_test_w_src.html");
}
// Tests plugin with whitelisted src/data.
function test2a() {
var plugin = gTestBrowser.contentDocument.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "Test 2a, Plugin should not be activated");
unregisterPlayPreview();
registerPlayPreview('*plugin_test_w_src.html');
var plugin = getTestPlugin();
plugin.enabledState = Ci.nsIPluginTag.STATE_ENABLED;
prepareTest(test2b, gTestRoot + "plugin_test_w_src.html");
}
// Tests plugin with non-whitelisted src/data.
function test2b() {
var plugin = gTestBrowser.contentDocument.getElementById("test");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 2b, Plugin should be activated");
finishTest();
}

View File

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

View File

@ -311,6 +311,8 @@ PluginContent.prototype = {
return "PluginVulnerableUpdatable";
case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE:
return "PluginVulnerableNoUpdate";
case Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW:
return "PluginPlayPreview";
default:
// Not all states map to a handler
return null;
@ -415,6 +417,10 @@ PluginContent.prototype = {
shouldShowNotification = true;
break;
case "PluginPlayPreview":
this._handlePlayPreviewEvent(plugin);
break;
case "PluginDisabled":
let manageLink = this.getPluginUI(plugin, "managePluginsLink");
this.addLinkClickCallback(manageLink, "forwardCallback", "managePlugins");
@ -525,6 +531,12 @@ PluginContent.prototype = {
objLoadingContent.pluginFallbackType >= Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY &&
objLoadingContent.pluginFallbackType <= Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE;
if (objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW) {
// checking if play preview is subject to CTP rules
let playPreviewInfo = pluginHost.getPlayPreviewInfo(objLoadingContent.actualType);
isFallbackTypeValid = !playPreviewInfo.ignoreCTP;
}
return !objLoadingContent.activated &&
pluginPermission != Ci.nsIPermissionManager.DENY_ACTION &&
isFallbackTypeValid;
@ -537,6 +549,17 @@ PluginContent.prototype = {
}
},
stopPlayPreview: function (plugin, playPlugin) {
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
if (objLoadingContent.activated)
return;
if (playPlugin)
objLoadingContent.playPlugin();
else
objLoadingContent.cancelPlayPreview();
},
// Forward a link click callback to the chrome process.
forwardCallback: function (name) {
this.global.sendAsyncMessage("PluginContent:LinkClickCallback", { name: name });
@ -618,6 +641,49 @@ PluginContent.prototype = {
}
},
_handlePlayPreviewEvent: function (plugin) {
let doc = plugin.ownerDocument;
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
let pluginInfo = this._getPluginInfo(plugin);
let playPreviewInfo = pluginHost.getPlayPreviewInfo(pluginInfo.mimetype);
let previewContent = this.getPluginUI(plugin, "previewPluginContent");
let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
if (!iframe) {
// lazy initialization of the iframe
iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
iframe.className = "previewPluginContentFrame";
previewContent.appendChild(iframe);
// Force a style flush, so that we ensure our binding is attached.
plugin.clientTop;
}
iframe.src = playPreviewInfo.redirectURL;
// MozPlayPlugin event can be dispatched from the extension chrome
// code to replace the preview content with the native plugin
let playPluginHandler = (event) => {
if (!event.isTrusted)
return;
previewContent.removeEventListener("MozPlayPlugin", playPluginHandler, true);
let playPlugin = !event.detail;
this.stopPlayPreview(plugin, playPlugin);
// cleaning up: removes overlay iframe from the DOM
let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
if (iframe)
previewContent.removeChild(iframe);
};
previewContent.addEventListener("MozPlayPlugin", playPluginHandler, true);
if (!playPreviewInfo.ignoreCTP) {
this._showClickToPlayNotification(plugin, false);
}
},
reshowClickToPlayNotification: function () {
let contentWindow = this.global.content;
let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)

View File

@ -25,7 +25,7 @@ class nsNPAPIPluginInstance;
* interface to mirror this interface when changing it.
*/
[scriptable, uuid(2eb3195e-3eea-4083-bb1d-d2d70fa35ccb)]
[scriptable, uuid(5efbd411-5bbe-4de1-9f3a-1c3459696eb2)]
interface nsIObjectLoadingContent : nsISupports
{
/**
@ -65,6 +65,8 @@ interface nsIObjectLoadingContent : nsISupports
const unsigned long PLUGIN_VULNERABLE_UPDATABLE = 9;
// The plugin is vulnerable (no update available)
const unsigned long PLUGIN_VULNERABLE_NO_UPDATE = 10;
// The plugin is in play preview mode
const unsigned long PLUGIN_PLAY_PREVIEW = 11;
/**
* The actual mime type (the one we got back from the network
@ -126,7 +128,8 @@ interface nsIObjectLoadingContent : nsISupports
in boolean submittedCrashReport);
/**
* This method will play a plugin that has been stopped by click-to-play.
* This method will play a plugin that has been stopped by the
* click-to-play plugins or play-preview features.
*/
void playPlugin();
@ -141,7 +144,7 @@ interface nsIObjectLoadingContent : nsISupports
/**
* This attribute will return true if the current content type has been
* activated, either explicitly or by passing checks that would have it be
* click-to-play.
* click-to-play or play-preview.
*/
readonly attribute boolean activated;
@ -181,6 +184,11 @@ interface nsIObjectLoadingContent : nsISupports
*/
readonly attribute bool hasRunningPlugin;
/**
* This method will disable the play-preview plugin state.
*/
void cancelPlayPreview();
/**
* If this plugin runs out-of-process, it has a runID to differentiate
* between different times the plugin process has been instantiated.

View File

@ -715,6 +715,7 @@ nsObjectLoadingContent::nsObjectLoadingContent()
, mInstantiating(false)
, mNetworkCreated(true)
, mActivated(false)
, mPlayPreviewCanceled(false)
, mIsStopping(false)
, mIsLoading(false)
, mScriptRequested(false) {}
@ -1405,6 +1406,8 @@ nsObjectLoadingContent::ObjectState() const
return NS_EVENT_STATE_USERDISABLED;
case eFallbackClickToPlay:
return NS_EVENT_STATE_TYPE_CLICK_TO_PLAY;
case eFallbackPlayPreview:
return NS_EVENT_STATE_TYPE_PLAY_PREVIEW;
case eFallbackDisabled:
return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_DISABLED;
case eFallbackBlocklisted:
@ -3119,7 +3122,7 @@ nsObjectLoadingContent::PlayPlugin()
LOG(("OBJLC [%p]: Activated by user", this));
}
// If we're in a click-to-play state, reload.
// If we're in a click-to-play or play preview state, we need to reload
// Fallback types >= eFallbackClickToPlay are plugin-replacement types, see
// header
if (mType == eType_Null && mFallbackType >= eFallbackClickToPlay) {
@ -3134,6 +3137,7 @@ nsObjectLoadingContent::Reload(bool aClearActivation)
{
if (aClearActivation) {
mActivated = false;
mPlayPreviewCanceled = false;
}
return LoadObject(true, true);
@ -3173,6 +3177,22 @@ nsObjectLoadingContent::GetHasRunningPlugin(bool *aHasPlugin)
return NS_OK;
}
NS_IMETHODIMP
nsObjectLoadingContent::CancelPlayPreview()
{
if (!nsContentUtils::IsCallerChrome())
return NS_ERROR_NOT_AVAILABLE;
mPlayPreviewCanceled = true;
// If we're in play preview state already, reload
if (mType == eType_Null && mFallbackType == eFallbackPlayPreview) {
return LoadObject(true, true);
}
return NS_OK;
}
NS_IMETHODIMP
nsObjectLoadingContent::GetRunID(uint32_t* aRunID)
{
@ -3218,6 +3238,31 @@ nsObjectLoadingContent::ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentTyp
nsRefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
nsCOMPtr<nsIPluginPlayPreviewInfo> playPreviewInfo;
bool isPlayPreviewSpecified = NS_SUCCEEDED(pluginHost->GetPlayPreviewInfo(
mContentType, getter_AddRefs(playPreviewInfo)));
if (isPlayPreviewSpecified) {
// Checking PlayPreview whitelist as well.
nsCString uriSpec, baseSpec;
if (mURI) {
mURI->GetSpec(uriSpec);
}
if (mBaseURI) {
mBaseURI->GetSpec(baseSpec);
}
playPreviewInfo->CheckWhitelist(baseSpec, uriSpec, &isPlayPreviewSpecified);
}
bool ignoreCTP = false;
if (isPlayPreviewSpecified) {
playPreviewInfo->GetIgnoreCTP(&ignoreCTP);
}
if (isPlayPreviewSpecified && !mPlayPreviewCanceled &&
ignoreCTP) {
// play preview in ignoreCTP mode is shown even if the native plugin
// is not present/installed
aReason = eFallbackPlayPreview;
return false;
}
// at this point if it's not a plugin, we let it play/fallback
if (!aIgnoreCurrentType && mType != eType_Plugin) {
return true;
@ -3227,6 +3272,8 @@ nsObjectLoadingContent::ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentTyp
// * Assume a default of click-to-play
// * If globally disabled, per-site permissions cannot override.
// * If blocklisted, override the reason with the blocklist reason
// * If not blocklisted but playPreview, override the reason with the
// playPreview reason.
// * Check per-site permissions and follow those if specified.
// * Honor per-plugin disabled permission
// * Blocklisted plugins are forced to CtP
@ -3262,6 +3309,12 @@ nsObjectLoadingContent::ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentTyp
aReason = eFallbackVulnerableNoUpdate;
}
if (aReason == eFallbackClickToPlay && isPlayPreviewSpecified &&
!mPlayPreviewCanceled && !ignoreCTP) {
// play preview in click-to-play mode is shown instead of standard CTP UI
aReason = eFallbackPlayPreview;
}
// Check the permission manager for permission based on the principal of
// the toplevel content.

View File

@ -94,6 +94,9 @@ class nsObjectLoadingContent : public nsImageLoadingContent
eFallbackVulnerableUpdatable = nsIObjectLoadingContent::PLUGIN_VULNERABLE_UPDATABLE,
// The plugin is vulnerable (no update available)
eFallbackVulnerableNoUpdate = nsIObjectLoadingContent::PLUGIN_VULNERABLE_NO_UPDATE,
// The plugin is disabled and play preview content is displayed until
// the extension code enables it by sending the MozPlayPlugin event
eFallbackPlayPreview = nsIObjectLoadingContent::PLUGIN_PLAY_PREVIEW
};
nsObjectLoadingContent();
@ -222,6 +225,10 @@ class nsObjectLoadingContent : public nsImageLoadingContent
{
return !!mInstanceOwner;
}
void CancelPlayPreview(mozilla::ErrorResult& aRv)
{
aRv = CancelPlayPreview();
}
void SwapFrameLoaders(nsXULElement& aOtherOwner, mozilla::ErrorResult& aRv)
{
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
@ -615,13 +622,16 @@ class nsObjectLoadingContent : public nsImageLoadingContent
// activated by PlayPlugin(). (see ShouldPlay())
bool mActivated : 1;
// Used to keep track of whether or not a plugin is blocked by play-preview.
bool mPlayPreviewCanceled : 1;
// Protects DoStopPlugin from reentry (bug 724781).
bool mIsStopping : 1;
// Protects LoadObject from re-entry
bool mIsLoading : 1;
// For plugin stand-in types (click-to-play) tracks
// For plugin stand-in types (click-to-play, play preview, ...) tracks
// whether content js has tried to access the plugin script object.
bool mScriptRequested : 1;

View File

@ -262,6 +262,8 @@ private:
#define NS_EVENT_STATE_LTR NS_DEFINE_EVENT_STATE_MACRO(42)
// Element is rtl (for :dir pseudo-class)
#define NS_EVENT_STATE_RTL NS_DEFINE_EVENT_STATE_MACRO(43)
// Handler for play preview plugin
#define NS_EVENT_STATE_TYPE_PLAY_PREVIEW NS_DEFINE_EVENT_STATE_MACRO(44)
// Element is highlighted (devtools inspector)
#define NS_EVENT_STATE_DEVTOOLS_HIGHLIGHTED NS_DEFINE_EVENT_STATE_MACRO(45)
// Element is an unresolved custom element candidate

View File

@ -32,6 +32,7 @@ EXPORTS += [
'nsPluginLogging.h',
'nsPluginNativeWindow.h',
'nsPluginNativeWindowGtk.h',
'nsPluginPlayPreviewInfo.h',
'nsPluginsCID.h',
'nsPluginsDir.h',
'nsPluginTags.h',
@ -47,6 +48,7 @@ UNIFIED_SOURCES += [
'nsNPAPIPluginStreamListener.cpp',
'nsPluginInstanceOwner.cpp',
'nsPluginModule.cpp',
'nsPluginPlayPreviewInfo.cpp',
'nsPluginStreamListenerPeer.cpp',
'nsPluginTags.cpp',
'PluginPRLibrary.cpp',

View File

@ -12,6 +12,21 @@
"@mozilla.org/plugin/host;1"
%}
[scriptable, uuid(57069ada-2845-46ef-b57f-233596d1c02c)]
interface nsIPluginPlayPreviewInfo : nsISupports
{
readonly attribute AUTF8String mimeType;
readonly attribute boolean ignoreCTP;
readonly attribute AUTF8String redirectURL;
readonly attribute AUTF8String whitelist;
/**
* Checks if pageURI and objectURI matches once of the entries in
* the whitelist. If whitelist is empty, returns true.
*/
boolean checkWhitelist(in AUTF8String pageURI, in AUTF8String objectURI);
};
[scriptable, function, uuid(9c311778-7c2c-4ad8-b439-b8a2786a20dd)]
interface nsIClearSiteDataCallback : nsISupports
{
@ -21,7 +36,7 @@ interface nsIClearSiteDataCallback : nsISupports
void callback(in nsresult rv);
};
[scriptable, uuid(f938f5ba-7093-42cd-a559-af8039d99204)]
[scriptable, uuid(0f73bbd2-fc89-41df-b31b-38c09903d187)]
interface nsIPluginHost : nsISupports
{
/**
@ -87,6 +102,27 @@ interface nsIPluginHost : nsISupports
*/
boolean siteHasData(in nsIPluginTag plugin, in AUTF8String domain);
/**
* Registers the play preview plugin mode for specific mime type
*
* @param mimeType: specifies plugin mime type.
* @param ignoreCTP: if true, the play preview ignores CTP rules, e.g.
whitelisted websites, will not notify about plugin
presence in the address bar.
* @param redirectURL: specifies url for the overlay iframe
* @param whitelist: specifies plugin whitelist in form of comma separated
* "[@page_url object_url|@page_url|object_url]" entries,
* e.g. @http://example.org/* http://example.org/t.swf
*/
void registerPlayPreviewMimeType(in AUTF8String mimeType,
[optional] in boolean ignoreCTP,
[optional] in AUTF8String redirectURL,
[optional] in AUTF8String whitelist);
void unregisterPlayPreviewMimeType(in AUTF8String mimeType);
nsIPluginPlayPreviewInfo getPlayPreviewInfo(in AUTF8String mimeType);
/**
* Get the "permission string" for the plugin. This is a string that can be
* passed to the permission manager to see whether the plugin is allowed to

View File

@ -1598,6 +1598,58 @@ nsPluginHost::UnregisterFakePlugin(const nsACString& aHandlerURI)
return NS_OK;
}
NS_IMETHODIMP
nsPluginHost::RegisterPlayPreviewMimeType(const nsACString& mimeType,
bool ignoreCTP,
const nsACString& redirectURL,
const nsACString& whitelist)
{
nsAutoCString mt(mimeType);
nsAutoCString url(redirectURL);
if (url.Length() == 0) {
// using default play preview iframe URL, if redirectURL is not specified
url.AssignLiteral("data:application/x-moz-playpreview;,");
url.Append(mimeType);
}
nsAutoCString wl(whitelist);
nsRefPtr<nsPluginPlayPreviewInfo> playPreview =
new nsPluginPlayPreviewInfo(mt.get(), ignoreCTP, url.get(), wl.get());
mPlayPreviewMimeTypes.AppendElement(playPreview);
return NS_OK;
}
NS_IMETHODIMP
nsPluginHost::UnregisterPlayPreviewMimeType(const nsACString& mimeType)
{
nsAutoCString mimeTypeToRemove(mimeType);
for (uint32_t i = mPlayPreviewMimeTypes.Length(); i > 0; i--) {
nsRefPtr<nsPluginPlayPreviewInfo> pp = mPlayPreviewMimeTypes[i - 1];
if (PL_strcasecmp(pp.get()->mMimeType.get(), mimeTypeToRemove.get()) == 0) {
mPlayPreviewMimeTypes.RemoveElementAt(i - 1);
break;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsPluginHost::GetPlayPreviewInfo(const nsACString& mimeType,
nsIPluginPlayPreviewInfo** aResult)
{
nsAutoCString mimeTypeToFind(mimeType);
for (uint32_t i = 0; i < mPlayPreviewMimeTypes.Length(); i++) {
nsRefPtr<nsPluginPlayPreviewInfo> pp = mPlayPreviewMimeTypes[i];
if (PL_strcasecmp(pp.get()->mMimeType.get(), mimeTypeToFind.get()) == 0) {
*aResult = new nsPluginPlayPreviewInfo(pp.get());
NS_ADDREF(*aResult);
return NS_OK;
}
}
*aResult = nullptr;
return NS_ERROR_NOT_AVAILABLE;
}
// FIXME-jsplugins Is this method actually needed?
NS_IMETHODIMP
nsPluginHost::GetFakePlugin(const nsACString & aMimeType,

View File

@ -12,6 +12,7 @@
#include "prlink.h"
#include "prclist.h"
#include "nsIPluginTag.h"
#include "nsPluginPlayPreviewInfo.h"
#include "nsPluginsDir.h"
#include "nsPluginDirServiceProvider.h"
#include "nsAutoPtr.h"
@ -368,6 +369,7 @@ private:
nsRefPtr<nsPluginTag> mPlugins;
nsRefPtr<nsPluginTag> mCachedPlugins;
nsRefPtr<nsInvalidPluginTag> mInvalidPlugins;
nsTArray< nsRefPtr<nsPluginPlayPreviewInfo> > mPlayPreviewMimeTypes;
nsTArray< nsRefPtr<nsFakePluginTag> > mFakePlugins;

View File

@ -0,0 +1,154 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsPluginPlayPreviewInfo.h"
#include "nsWildCard.h"
using namespace mozilla;
nsPluginPlayPreviewInfo::nsPluginPlayPreviewInfo(const char* aMimeType,
bool aIgnoreCTP,
const char* aRedirectURL,
const char* aWhitelist)
: mMimeType(aMimeType), mIgnoreCTP(aIgnoreCTP), mRedirectURL(aRedirectURL),
mWhitelist(aWhitelist) {}
nsPluginPlayPreviewInfo::nsPluginPlayPreviewInfo(
const nsPluginPlayPreviewInfo* aSource)
{
MOZ_ASSERT(aSource);
mMimeType = aSource->mMimeType;
mIgnoreCTP = aSource->mIgnoreCTP;
mRedirectURL = aSource->mRedirectURL;
mWhitelist = aSource->mWhitelist;
}
nsPluginPlayPreviewInfo::~nsPluginPlayPreviewInfo()
{
}
NS_IMPL_ISUPPORTS(nsPluginPlayPreviewInfo, nsIPluginPlayPreviewInfo)
NS_IMETHODIMP
nsPluginPlayPreviewInfo::GetMimeType(nsACString& aMimeType)
{
aMimeType = mMimeType;
return NS_OK;
}
NS_IMETHODIMP
nsPluginPlayPreviewInfo::GetIgnoreCTP(bool* aIgnoreCTP)
{
*aIgnoreCTP = mIgnoreCTP;
return NS_OK;
}
NS_IMETHODIMP
nsPluginPlayPreviewInfo::GetRedirectURL(nsACString& aRedirectURL)
{
aRedirectURL = mRedirectURL;
return NS_OK;
}
NS_IMETHODIMP
nsPluginPlayPreviewInfo::GetWhitelist(nsACString& aWhitelist)
{
aWhitelist = mWhitelist;
return NS_OK;
}
/* static */ nsresult
nsPluginPlayPreviewInfo::CheckWhitelist(const nsACString& aPageURI,
const nsACString& aObjectURI,
const nsACString& aWhitelist,
bool *_retval)
{
if (aWhitelist.Length() == 0) {
// Considering empty whitelist as '*' entry.
*_retval = true;
return NS_OK;
}
// Parses whitelist as comma separated entries of
// [@page_url object_url|@page_url|object_url]
// where page_url and object_url pattern matches for aPageURI
// and aObjectURI, and performs matching as the same time.
nsACString::const_iterator start, end;
aWhitelist.BeginReading(start);
aWhitelist.EndReading(end);
nsAutoCString pageURI(aPageURI);
nsAutoCString objectURI(aObjectURI);
nsACString::const_iterator pos = start, entryStart, entryEnd;
nsACString::const_iterator pagePatternStart, pagePatternEnd;
nsACString::const_iterator objectPatternStart, objectPatternEnd;
int matchResult;
bool matched, didMatching;
while (pos != end) {
matched = true;
didMatching = false;
entryStart = pos;
// Looking for end of the entry.
while (pos != end && *pos != ',') {
pos++;
}
entryEnd = pos;
if (entryStart != entryEnd && *entryStart == '@') {
// Pattern for aPageURL is found, finding a space or end of the entry.
pagePatternStart = entryStart;
pagePatternStart++;
pagePatternEnd = pagePatternStart;
while (pagePatternEnd != entryEnd && *pagePatternEnd != ' ') {
pagePatternEnd++;
}
nsAutoCString pagePattern(Substring(pagePatternStart, pagePatternEnd));
matchResult = NS_WildCardMatch(pageURI.get(), pagePattern.get(), true);
matched &= matchResult == MATCH;
didMatching = true;
objectPatternStart = pagePatternEnd;
} else {
objectPatternStart = entryStart;
}
while (objectPatternStart != entryEnd && *objectPatternStart == ' ') {
objectPatternStart++;
}
if (objectPatternStart != entryEnd) {
// Pattern for aObjectURL is found, removing trailing spaces.
objectPatternEnd = entryEnd;
--objectPatternEnd;
while (objectPatternStart != objectPatternEnd &&
*objectPatternEnd == ' ') {
objectPatternEnd--;
};
objectPatternEnd++;
nsAutoCString objectPattern(Substring(objectPatternStart,
objectPatternEnd));
matchResult = NS_WildCardMatch(objectURI.get(), objectPattern.get(), true);
matched &= matchResult == MATCH;
didMatching = true;
}
// Ignoring match result for empty entries.
if (didMatching && matched) {
*_retval = true;
return NS_OK;
}
if (pos == end) {
break;
}
pos++;
}
*_retval = false;
return NS_OK;
}
NS_IMETHODIMP
nsPluginPlayPreviewInfo::CheckWhitelist(const nsACString& aPageURI,
const nsACString& aObjectURI,
bool *_retval)
{
return CheckWhitelist(aPageURI, aObjectURI, mWhitelist, _retval);
}

View File

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsPluginPlayPreviewInfo_h_
#define nsPluginPlayPreviewInfo_h_
#include "nsString.h"
#include "nsIPluginHost.h"
class nsPluginPlayPreviewInfo : public nsIPluginPlayPreviewInfo
{
virtual ~nsPluginPlayPreviewInfo();
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPLUGINPLAYPREVIEWINFO
nsPluginPlayPreviewInfo(const char* aMimeType,
bool aIgnoreCTP,
const char* aRedirectURL,
const char* aWhitelist);
explicit nsPluginPlayPreviewInfo(const nsPluginPlayPreviewInfo* aSource);
/** This function checks aPageURI and aObjectURI against the whitelist
* specified in aWhitelist. This is public static function because this
* whitelist checking code needs to be accessed without any instances of
* nsIPluginPlayPreviewInfo. In particular, the Shumway whitelist is
* obtained directly from prefs and compared using this code for telemetry
* purposes.
*/
static nsresult CheckWhitelist(const nsACString& aPageURI,
const nsACString& aObjectURI,
const nsACString& aWhitelist,
bool *_retval);
nsCString mMimeType;
bool mIgnoreCTP;
nsCString mRedirectURL;
nsCString mWhitelist;
};
#endif // nsPluginPlayPreviewInfo_h_

View File

@ -167,7 +167,26 @@ PluginInstanceParent::InitMetadata(const nsACString& aMimeType,
return false;
}
nsCOMPtr<nsIURI> baseUri(owner->GetBaseURI());
return NS_SUCCEEDED(NS_MakeAbsoluteURI(mSrcAttribute, aSrcAttribute, baseUri));
nsresult rv = NS_MakeAbsoluteURI(mSrcAttribute, aSrcAttribute, baseUri);
if (NS_FAILED(rv)) {
return false;
}
// Check the whitelist
nsAutoCString baseUrlSpec;
rv = baseUri->GetSpec(baseUrlSpec);
if (NS_FAILED(rv)) {
return false;
}
auto whitelist = Preferences::GetCString(kShumwayWhitelistPref);
// Empty whitelist is interpreted by CheckWhitelist as "allow everything,"
// which is not valid for our use case and should be treated as a failure.
if (whitelist.IsEmpty()) {
return false;
}
rv = nsPluginPlayPreviewInfo::CheckWhitelist(baseUrlSpec, mSrcAttribute,
whitelist,
&mIsWhitelistedForShumway);
return NS_SUCCEEDED(rv);
}
void

View File

@ -129,6 +129,9 @@ interface MozObjectLoadingContent {
// The plugin is vulnerable (no update available)
[ChromeOnly]
const unsigned long PLUGIN_VULNERABLE_NO_UPDATE = 10;
// The plugin is in play preview mode
[ChromeOnly]
const unsigned long PLUGIN_PLAY_PREVIEW = 11;
/**
* The actual mime type (the one we got back from the network
@ -160,8 +163,8 @@ interface MozObjectLoadingContent {
sequence<MozPluginParameter> getPluginParameters();
/**
* This method will play a plugin that has been stopped by the click-to-play
* feature.
* This method will play a plugin that has been stopped by the
* click-to-play plugins or play-preview features.
*/
[ChromeOnly, Throws]
void playPlugin();
@ -178,7 +181,7 @@ interface MozObjectLoadingContent {
/**
* This attribute will return true if the current content type has been
* activated, either explicitly or by passing checks that would have it be
* click-to-play.
* click-to-play or play-preview.
*/
[ChromeOnly]
readonly attribute boolean activated;
@ -203,6 +206,12 @@ interface MozObjectLoadingContent {
[ChromeOnly]
readonly attribute boolean hasRunningPlugin;
/**
* This method will disable the play-preview plugin state.
*/
[ChromeOnly, Throws]
void cancelPlayPreview();
[ChromeOnly, Throws]
readonly attribute unsigned long runID;
};

View File

@ -179,6 +179,8 @@ CSS_STATE_PSEUDO_CLASS(mozTypeUnsupportedPlatform, ":-moz-type-unsupported-platf
NS_EVENT_STATE_TYPE_UNSUPPORTED_PLATFORM)
CSS_STATE_PSEUDO_CLASS(mozHandlerClickToPlay, ":-moz-handler-clicktoplay", 0, "",
NS_EVENT_STATE_TYPE_CLICK_TO_PLAY)
CSS_STATE_PSEUDO_CLASS(mozHandlerPlayPreview, ":-moz-handler-playpreview", 0, "",
NS_EVENT_STATE_TYPE_PLAY_PREVIEW)
CSS_STATE_PSEUDO_CLASS(mozHandlerVulnerableUpdatable, ":-moz-handler-vulnerable-updatable", 0, "",
NS_EVENT_STATE_VULNERABLE_UPDATABLE)
CSS_STATE_PSEUDO_CLASS(mozHandlerVulnerableNoUpdate, ":-moz-handler-vulnerable-no-update", 0, "",

View File

@ -87,6 +87,17 @@ var PluginHelper = {
objLoadingContent.playPlugin();
},
stopPlayPreview: function(plugin, playPlugin) {
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
if (objLoadingContent.activated)
return;
if (playPlugin)
objLoadingContent.playPlugin();
else
objLoadingContent.cancelPlayPreview();
},
getPluginPreference: function getPluginPreference() {
let pluginDisable = Services.prefs.getBoolPref("plugin.disable");
if (pluginDisable)
@ -201,6 +212,54 @@ var PluginHelper = {
break;
}
case "PluginPlayPreview": {
let previewContent = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
let mimeType = PluginHelper.getPluginMimeType(plugin);
let playPreviewInfo = pluginHost.getPlayPreviewInfo(mimeType);
if (!playPreviewInfo.ignoreCTP) {
// Check if plugins have already been activated for this page, or if
// the user has set a permission to always play plugins on the site
if (aTab.clickToPlayPluginsActivated ||
Services.perms.testPermission(aTab.browser.currentURI, "plugins") ==
Services.perms.ALLOW_ACTION) {
PluginHelper.playPlugin(plugin);
return;
}
// Always show door hanger for play preview plugins
PluginHelper.delayAndShowDoorHanger(aTab);
}
let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
if (!iframe) {
// lazy initialization of the iframe
iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
iframe.className = "previewPluginContentFrame";
previewContent.appendChild(iframe);
}
iframe.src = playPreviewInfo.redirectURL;
// MozPlayPlugin event can be dispatched from the extension chrome
// code to replace the preview content with the native plugin
previewContent.addEventListener("MozPlayPlugin", function playPluginHandler(e) {
if (!e.isTrusted)
return;
previewContent.removeEventListener("MozPlayPlugin", playPluginHandler, true);
let playPlugin = !aEvent.detail;
PluginHelper.stopPlayPreview(plugin, playPlugin);
// cleaning up: removes overlay iframe from the DOM
let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
if (iframe)
previewContent.removeChild(iframe);
}, true);
break;
}
case "PluginNotFound": {
// On devices where we don't support Flash, there will be a
// "Learn More..." link in the missing plugin error message.
@ -224,6 +283,8 @@ var PluginHelper = {
return "PluginNotFound";
case Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY:
return "PluginClickToPlay";
case Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW:
return "PluginPlayPreview";
default:
// Not all states map to a handler
return null;

View File

@ -67,6 +67,7 @@
</html:div>
<html:button class="closeIcon" anonid="closeIcon" title="&hidePluginBtn.label;"/>
</html:div>
<html:div class="previewPluginContent" anonid="previewPluginContent"><!-- iframe and its src will be set at runtime --></html:div>
<html:div style="display:none;"><children/></html:div>
</content>
<implementation>

View File

@ -8,18 +8,21 @@ embed:-moz-handler-disabled,
embed:-moz-handler-blocked,
embed:-moz-handler-crashed,
embed:-moz-handler-clicktoplay,
embed:-moz-handler-playpreview,
embed:-moz-handler-vulnerable-updatable,
embed:-moz-handler-vulnerable-no-update,
applet:-moz-handler-disabled,
applet:-moz-handler-blocked,
applet:-moz-handler-crashed,
applet:-moz-handler-clicktoplay,
applet:-moz-handler-playpreview,
applet:-moz-handler-vulnerable-updatable,
applet:-moz-handler-vulnerable-no-update,
object:-moz-handler-disabled,
object:-moz-handler-blocked,
object:-moz-handler-crashed,
object:-moz-handler-clicktoplay,
object:-moz-handler-playpreview,
object:-moz-handler-vulnerable-updatable,
object:-moz-handler-vulnerable-no-update {
display: inline-block;

View File

@ -71,6 +71,10 @@ html|applet:not([height]), html|applet[height=""] {
direction: rtl;
}
:-moz-handler-playpreview .mainBox {
display: none;
}
:-moz-handler-clicktoplay .hoverBox,
:-moz-handler-vulnerable-updatable .hoverBox,
:-moz-handler-vulnerable-no-update .hoverBox {
@ -84,6 +88,23 @@ html|applet:not([height]), html|applet[height=""] {
cursor: inherit;
}
.previewPluginContent {
display: none;
}
.previewPluginContent > iframe {
width: inherit;
height: inherit;
border: none;
}
:-moz-handler-playpreview .previewPluginContent {
display: block;
width: inherit;
height: inherit;
overflow: hidden;
}
.msg {
display: none;
}