Bug 839714 - Extend PlayPreview API. r=jschoenick, r=jwein

This commit is contained in:
Yury Delendik 2013-02-14 15:38:41 -06:00
parent f5026d4a7a
commit 0d6cb92088
13 changed files with 409 additions and 73 deletions

View File

@ -304,10 +304,19 @@ var gPluginHandler = {
let browser = gBrowser.getBrowserForDocument(objLoadingContent.ownerDocument.defaultView.top.document);
let pluginPermission = Services.perms.testPermission(browser.currentURI, permissionString);
let isFallbackTypeValid =
objLoadingContent.pluginFallbackType >= Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY &&
objLoadingContent.pluginFallbackType <= Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE;
if (objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW) {
// checking if play preview is subject to CTP rules
let playPreviewInfo = pluginHost.getPlayPreviewInfo(objLoadingContent.actualType);
isFallbackTypeValid = !playPreviewInfo.ignoreCTP;
}
return !objLoadingContent.activated &&
pluginPermission != Ci.nsIPermissionManager.DENY_ACTION &&
objLoadingContent.pluginFallbackType >= Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY &&
objLoadingContent.pluginFallbackType <= Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE;
isFallbackTypeValid;
},
activatePlugins: function PH_activatePlugins(aContentWindow) {
@ -472,6 +481,21 @@ var gPluginHandler = {
_handlePlayPreviewEvent: function PH_handlePlayPreviewEvent(aPlugin) {
let doc = aPlugin.ownerDocument;
let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
let pluginInfo = this._getPluginInfo(aPlugin);
let playPreviewInfo = pluginHost.getPlayPreviewInfo(pluginInfo.mimetype);
if (!playPreviewInfo.ignoreCTP) {
// if click-to-play rules used, play plugin at once if plugins were
// activated for this window
if (browser._clickToPlayAllPluginsActivated ||
browser._clickToPlayPluginsActivated.get(pluginInfo.pluginName)) {
objLoadingContent.playPlugin();
return;
}
}
let previewContent = doc.getAnonymousElementByAttribute(aPlugin, "class", "previewPluginContent");
let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
if (!iframe) {
@ -483,9 +507,7 @@ var gPluginHandler = {
// Force a style flush, so that we ensure our binding is attached.
aPlugin.clientTop;
}
let pluginInfo = this._getPluginInfo(aPlugin);
let playPreviewUri = "data:application/x-moz-playpreview;," + pluginInfo.mimetype;
iframe.src = playPreviewUri;
iframe.src = playPreviewInfo.redirectURL;
// MozPlayPlugin event can be dispatched from the extension chrome
// code to replace the preview content with the native plugin
@ -503,6 +525,10 @@ var gPluginHandler = {
if (iframe)
previewContent.removeChild(iframe);
}, true);
if (!playPreviewInfo.ignoreCTP) {
gPluginHandler._showClickToPlayNotification(browser);
}
},
reshowClickToPlayNotification: function PH_reshowClickToPlayNotification() {

View File

@ -186,6 +186,7 @@ _BROWSER_FILES = \
browser_plugins_added_dynamically.js \
browser_CTPScriptPlugin.js \
browser_pluginplaypreview.js \
browser_pluginplaypreview2.js \
browser_private_browsing_window.js \
browser_relatedTabs.js \
browser_sanitize-passwordDisabledHosts.js \

View File

@ -111,7 +111,7 @@ function registerPlayPreview(mimeType, targetUrl) {
};
var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
ph.registerPlayPreviewMimeType(mimeType);
ph.registerPlayPreviewMimeType(mimeType, true); // ignoring CTP rules
var factory = new StreamConverterFactory();
factory.register(OverlayStreamConverter);

View File

@ -0,0 +1,173 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;
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);
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("missing-plugins"), "Test 1a, Should not have displayed the missing plugin notification");
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);
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

@ -1758,26 +1758,20 @@ nsObjectLoadingContent::LoadObject(bool aNotify,
}
}
// Items resolved as Image/Document will not be checked for previews, as well
// as invalid plugins (they will not have the mContentType set).
if ((mType == eType_Null || mType == eType_Plugin) && ShouldPreview()) {
// If plugin preview exists, we shall use it
LOG(("OBJLC [%p]: Using plugin preview", this));
mType = eType_Null;
fallbackType = eFallbackPlayPreview;
}
// If we're a plugin but shouldn't start yet, load fallback with
// reason click-to-play instead
// reason click-to-play instead. Items resolved as Image/Document
// will not be checked for previews, as well as invalid plugins
// (they will not have the mContentType set).
FallbackType clickToPlayReason;
if (mType == eType_Plugin && !ShouldPlay(clickToPlayReason)) {
if ((mType == eType_Null || mType == eType_Plugin) &&
!ShouldPlay(clickToPlayReason)) {
LOG(("OBJLC [%p]: Marking plugin as click-to-play", this));
mType = eType_Null;
fallbackType = clickToPlayReason;
}
if (!mActivated && mType == eType_Plugin) {
// Object passed ShouldPlay and !ShouldPreview, so it should be considered
// Object passed ShouldPlay, so it should be considered
// activated until it changes content type
LOG(("OBJLC [%p]: Object implicitly activated", this));
mActivated = true;
@ -2649,18 +2643,6 @@ nsObjectLoadingContent::CancelPlayPreview()
return NS_OK;
}
bool
nsObjectLoadingContent::ShouldPreview()
{
if (mPlayPreviewCanceled || mActivated)
return false;
nsRefPtr<nsPluginHost> pluginHost =
already_AddRefed<nsPluginHost>(nsPluginHost::GetInst());
return pluginHost->IsPluginPlayPreviewForType(mContentType.get());
}
bool
nsObjectLoadingContent::ShouldPlay(FallbackType &aReason)
{
@ -2671,6 +2653,25 @@ nsObjectLoadingContent::ShouldPlay(FallbackType &aReason)
nsRefPtr<nsPluginHost> pluginHost =
already_AddRefed<nsPluginHost>(nsPluginHost::GetInst());
nsCOMPtr<nsIPluginPlayPreviewInfo> playPreviewInfo;
bool isPlayPreviewSpecified = NS_SUCCEEDED(pluginHost->GetPlayPreviewInfo(
mContentType, getter_AddRefs(playPreviewInfo)));
bool ignoreCTP = false;
if (isPlayPreviewSpecified) {
playPreviewInfo->GetIgnoreCTP(&ignoreCTP);
}
if (isPlayPreviewSpecified && !mPlayPreviewCanceled && !mActivated &&
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 (mType != eType_Plugin) {
return true;
}
bool isCTP;
nsresult rv = pluginHost->IsPluginClickToPlayForType(mContentType, &isCTP);
if (NS_FAILED(rv)) {
@ -2735,6 +2736,12 @@ nsObjectLoadingContent::ShouldPlay(FallbackType &aReason)
allowPerm = permission == nsIPermissionManager::ALLOW_ACTION;
}
if (aReason == eFallbackClickToPlay && isPlayPreviewSpecified &&
!mPlayPreviewCanceled && !ignoreCTP) {
// play preview in click-to-play mode is shown instead of standard CTP UI
aReason = eFallbackPlayPreview;
}
return allowPerm;
}

View File

@ -301,11 +301,6 @@ class nsObjectLoadingContent : public nsImageLoadingContent
*/
bool ShouldPlay(FallbackType &aReason);
/**
* If the object should display preview content for the current mContentType
*/
bool ShouldPreview();
/**
* Helper to check if our current URI passes policy
*

View File

@ -45,6 +45,7 @@ EXPORTS = \
nsPluginDirServiceProvider.h \
nsPluginHost.h \
nsPluginInstanceOwner.h \
nsPluginPlayPreviewInfo.h \
$(NULL)
EXPORTS_mozilla = \
@ -62,6 +63,7 @@ CPPSRCS = \
nsPluginTags.cpp \
PluginPRLibrary.cpp \
nsPluginInstanceOwner.cpp \
nsPluginPlayPreviewInfo.cpp \
$(NULL)
ifeq ($(MOZ_WIDGET_TOOLKIT),android)

View File

@ -12,7 +12,15 @@
"@mozilla.org/plugin/host;1"
%}
[scriptable, uuid(3ac8fe33-c38c-4123-b2f0-0e8a2824b9c5)]
[scriptable, uuid(f89e7679-0adf-4a30-bda9-1afe1ee270d6)]
interface nsIPluginPlayPreviewInfo : nsISupports
{
readonly attribute AUTF8String mimeType;
readonly attribute boolean ignoreCTP;
readonly attribute AUTF8String redirectURL;
};
[scriptable, uuid(67ebff01-0dce-48f7-b6a5-6235fc78382b)]
interface nsIPluginHost : nsISupports
{
/**
@ -76,12 +84,20 @@ interface nsIPluginHost : nsISupports
/**
* Registers the play preview plugin mode for specific mime type
*
* @param mimeType - specified 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
*/
void registerPlayPreviewMimeType(in AUTF8String mimeType);
void registerPlayPreviewMimeType(in AUTF8String mimeType,
[optional] in boolean ignoreCTP,
[optional] in AUTF8String redirectURL);
void unregisterPlayPreviewMimeType(in AUTF8String mimeType);
nsIPluginPlayPreviewInfo getPlayPreviewInfo(in AUTF8String mimeType);
ACString getPermissionStringForType(in AUTF8String mimeType);
bool isPluginClickToPlayForType(in AUTF8String mimeType);

View File

@ -1154,17 +1154,6 @@ nsPluginHost::IsPluginClickToPlayForType(const nsACString &aMimeType, bool *aRes
return NS_OK;
}
bool
nsPluginHost::IsPluginPlayPreviewForType(const char* aMimeType)
{
for (uint32_t i = 0; i < mPlayPreviewMimeTypes.Length(); i++) {
nsCString mt = mPlayPreviewMimeTypes[i];
if (PL_strcasecmp(mt.get(), aMimeType) == 0)
return true;
}
return false;
}
nsresult
nsPluginHost::GetBlocklistStateForType(const char *aMimeType, uint32_t *aState)
{
@ -1648,9 +1637,21 @@ nsPluginHost::EnumerateSiteData(const nsACString& domain,
}
NS_IMETHODIMP
nsPluginHost::RegisterPlayPreviewMimeType(const nsACString& mimeType)
nsPluginHost::RegisterPlayPreviewMimeType(const nsACString& mimeType,
bool ignoreCTP,
const nsACString& redirectURL)
{
mPlayPreviewMimeTypes.AppendElement(mimeType);
nsAutoCString mt(mimeType);
nsAutoCString url(redirectURL);
if (url.Length() == 0) {
// using default play preview iframe URL, if redirectURL is not specified
url.Assign("data:application/x-moz-playpreview;,");
url.Append(mimeType);
}
nsRefPtr<nsPluginPlayPreviewInfo> playPreview =
new nsPluginPlayPreviewInfo(mt.get(), ignoreCTP, url.get());
mPlayPreviewMimeTypes.AppendElement(playPreview);
return NS_OK;
}
@ -1658,16 +1659,33 @@ NS_IMETHODIMP
nsPluginHost::UnregisterPlayPreviewMimeType(const nsACString& mimeType)
{
nsAutoCString mimeTypeToRemove(mimeType);
for (uint32_t i = mPlayPreviewMimeTypes.Length(); i > 0;) {
nsCString mt = mPlayPreviewMimeTypes[--i];
if (PL_strcasecmp(mt.get(), mimeTypeToRemove.get()) == 0) {
mPlayPreviewMimeTypes.RemoveElementAt(i);
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;
}
NS_IMETHODIMP
nsPluginHost::ClearSiteData(nsIPluginTag* plugin, const nsACString& domain,
uint64_t flags, int64_t maxAge)

View File

@ -25,6 +25,7 @@
#include "nsTObserverArray.h"
#include "nsITimer.h"
#include "nsPluginTags.h"
#include "nsPluginPlayPreviewInfo.h"
#include "nsIEffectiveTLDService.h"
#include "nsIIDNService.h"
#include "nsCRT.h"
@ -80,7 +81,6 @@ public:
nsPluginInstanceOwner *aOwner);
nsresult IsPluginEnabledForType(const char* aMimeType);
nsresult IsPluginEnabledForExtension(const char* aExtension, const char* &aMimeType);
bool IsPluginPlayPreviewForType(const char *aMimeType);
nsresult GetBlocklistStateForType(const char *aMimeType, uint32_t *state);
nsresult GetPluginCount(uint32_t* aPluginCount);
@ -262,7 +262,7 @@ private:
nsRefPtr<nsPluginTag> mPlugins;
nsRefPtr<nsPluginTag> mCachedPlugins;
nsRefPtr<nsInvalidPluginTag> mInvalidPlugins;
nsTArray<nsCString> mPlayPreviewMimeTypes;
nsTArray< nsRefPtr<nsPluginPlayPreviewInfo> > mPlayPreviewMimeTypes;
bool mPluginsLoaded;
// set by pref plugin.override_internal_types

View File

@ -0,0 +1,50 @@
/* -*- 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"
using namespace mozilla;
nsPluginPlayPreviewInfo::nsPluginPlayPreviewInfo(const char* aMimeType,
bool aIgnoreCTP,
const char* aRedirectURL)
: mMimeType(aMimeType), mIgnoreCTP(aIgnoreCTP), mRedirectURL(aRedirectURL) {}
nsPluginPlayPreviewInfo::nsPluginPlayPreviewInfo(
const nsPluginPlayPreviewInfo* aSource)
{
MOZ_ASSERT(aSource);
mMimeType = aSource->mMimeType;
mIgnoreCTP = aSource->mIgnoreCTP;
mRedirectURL = aSource->mRedirectURL;
}
nsPluginPlayPreviewInfo::~nsPluginPlayPreviewInfo()
{
}
NS_IMPL_ISUPPORTS1(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;
}

View File

@ -0,0 +1,30 @@
/* -*- 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
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPLUGINPLAYPREVIEWINFO
nsPluginPlayPreviewInfo(const char* aMimeType,
bool aIgnoreCTP,
const char* aRedirectURL);
nsPluginPlayPreviewInfo(const nsPluginPlayPreviewInfo* aSource);
virtual ~nsPluginPlayPreviewInfo();
nsCString mMimeType;
bool mIgnoreCTP;
nsCString mRedirectURL;
};
#endif // nsPluginPlayPreviewInfo_h_

View File

@ -6167,6 +6167,19 @@ var PluginHelper = {
NativeWindow.doorhanger.show(message, "ask-to-play-plugins", buttons, aTab.id, options);
},
delayAndShowDoorHanger: function(aTab) {
// To avoid showing the doorhanger if there are also visible plugin
// overlays on the page, delay showing the doorhanger to check if
// visible plugins get added in the near future.
if (!aTab.pluginDoorhangerTimeout) {
aTab.pluginDoorhangerTimeout = setTimeout(function() {
if (this.shouldShowPluginDoorhanger) {
PluginHelper.showDoorHanger(this);
}
}.bind(aTab), 500);
}
},
playAllPlugins: function(aContentWindow) {
let cwu = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
@ -6180,8 +6193,7 @@ var PluginHelper = {
playPlugin: function(plugin) {
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
if (!objLoadingContent.activated &&
objLoadingContent.pluginFallbackType !== Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW)
if (!objLoadingContent.activated)
objLoadingContent.playPlugin();
},
@ -6279,17 +6291,7 @@ var PluginHelper = {
// If the plugin is hidden, or if the overlay is too small, show a
// doorhanger notification
if (PluginHelper.isTooSmall(plugin, overlay)) {
// To avoid showing the doorhanger if there are also visible plugin
// overlays on the page, delay showing the doorhanger to check if
// visible plugins get added in the near future.
if (!aTab.pluginDoorhangerTimeout) {
aTab.pluginDoorhangerTimeout = setTimeout(function() {
if (this.shouldShowPluginDoorhanger) {
PluginHelper.showDoorHanger(this);
}
}.bind(aTab), 500);
}
PluginHelper.delayAndShowDoorHanger(aTab);
} else {
// There's a large enough visible overlay that we don't need to show
// the doorhanger.
@ -6313,6 +6315,24 @@ var PluginHelper = {
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
@ -6320,9 +6340,7 @@ var PluginHelper = {
iframe.className = "previewPluginContentFrame";
previewContent.appendChild(iframe);
}
let mimeType = PluginHelper.getPluginMimeType(plugin);
let playPreviewUri = "data:application/x-moz-playpreview;," + mimeType;
iframe.src = playPreviewUri;
iframe.src = playPreviewInfo.redirectURL;
// MozPlayPlugin event can be dispatched from the extension chrome
// code to replace the preview content with the native plugin