mobile/android/chrome/content/PluginHelper.js

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:6fa892c26d34
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 "use strict";
5
6 var PluginHelper = {
7 showDoorHanger: function(aTab) {
8 if (!aTab.browser)
9 return;
10
11 // Even though we may not end up showing a doorhanger, this flag
12 // lets us know that we've tried to show a doorhanger.
13 aTab.shouldShowPluginDoorhanger = false;
14
15 let uri = aTab.browser.currentURI;
16
17 // If the user has previously set a plugins permission for this website,
18 // either play or don't play the plugins instead of showing a doorhanger.
19 let permValue = Services.perms.testPermission(uri, "plugins");
20 if (permValue != Services.perms.UNKNOWN_ACTION) {
21 if (permValue == Services.perms.ALLOW_ACTION)
22 PluginHelper.playAllPlugins(aTab.browser.contentWindow);
23
24 return;
25 }
26
27 let message = Strings.browser.formatStringFromName("clickToPlayPlugins.message2",
28 [uri.host], 1);
29 let buttons = [
30 {
31 label: Strings.browser.GetStringFromName("clickToPlayPlugins.activate"),
32 callback: function(aChecked) {
33 // If the user checked "Don't ask again", make a permanent exception
34 if (aChecked)
35 Services.perms.add(uri, "plugins", Ci.nsIPermissionManager.ALLOW_ACTION);
36
37 PluginHelper.playAllPlugins(aTab.browser.contentWindow);
38 }
39 },
40 {
41 label: Strings.browser.GetStringFromName("clickToPlayPlugins.dontActivate"),
42 callback: function(aChecked) {
43 // If the user checked "Don't ask again", make a permanent exception
44 if (aChecked)
45 Services.perms.add(uri, "plugins", Ci.nsIPermissionManager.DENY_ACTION);
46
47 // Other than that, do nothing
48 }
49 }
50 ];
51
52 // Add a checkbox with a "Don't ask again" message if the uri contains a
53 // host. Adding a permanent exception will fail if host is not present.
54 let options = uri.host ? { checkbox: Strings.browser.GetStringFromName("clickToPlayPlugins.dontAskAgain") } : {};
55
56 NativeWindow.doorhanger.show(message, "ask-to-play-plugins", buttons, aTab.id, options);
57 },
58
59 delayAndShowDoorHanger: function(aTab) {
60 // To avoid showing the doorhanger if there are also visible plugin
61 // overlays on the page, delay showing the doorhanger to check if
62 // visible plugins get added in the near future.
63 if (!aTab.pluginDoorhangerTimeout) {
64 aTab.pluginDoorhangerTimeout = setTimeout(function() {
65 if (this.shouldShowPluginDoorhanger) {
66 PluginHelper.showDoorHanger(this);
67 }
68 }.bind(aTab), 500);
69 }
70 },
71
72 playAllPlugins: function(aContentWindow) {
73 let cwu = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
74 .getInterface(Ci.nsIDOMWindowUtils);
75 // XXX not sure if we should enable plugins for the parent documents...
76 let plugins = cwu.plugins;
77 if (!plugins || !plugins.length)
78 return;
79
80 plugins.forEach(this.playPlugin);
81 },
82
83 playPlugin: function(plugin) {
84 let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
85 if (!objLoadingContent.activated)
86 objLoadingContent.playPlugin();
87 },
88
89 stopPlayPreview: function(plugin, playPlugin) {
90 let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
91 if (objLoadingContent.activated)
92 return;
93
94 if (playPlugin)
95 objLoadingContent.playPlugin();
96 else
97 objLoadingContent.cancelPlayPreview();
98 },
99
100 getPluginPreference: function getPluginPreference() {
101 let pluginDisable = Services.prefs.getBoolPref("plugin.disable");
102 if (pluginDisable)
103 return "0";
104
105 let state = Services.prefs.getIntPref("plugin.default.state");
106 return state == Ci.nsIPluginTag.STATE_CLICKTOPLAY ? "2" : "1";
107 },
108
109 setPluginPreference: function setPluginPreference(aValue) {
110 switch (aValue) {
111 case "0": // Enable Plugins = No
112 Services.prefs.setBoolPref("plugin.disable", true);
113 Services.prefs.clearUserPref("plugin.default.state");
114 break;
115 case "1": // Enable Plugins = Yes
116 Services.prefs.clearUserPref("plugin.disable");
117 Services.prefs.setIntPref("plugin.default.state", Ci.nsIPluginTag.STATE_ENABLED);
118 break;
119 case "2": // Enable Plugins = Tap to Play (default)
120 Services.prefs.clearUserPref("plugin.disable");
121 Services.prefs.clearUserPref("plugin.default.state");
122 break;
123 }
124 },
125
126 // Copied from /browser/base/content/browser.js
127 isTooSmall : function (plugin, overlay) {
128 // Is the <object>'s size too small to hold what we want to show?
129 let pluginRect = plugin.getBoundingClientRect();
130 // XXX bug 446693. The text-shadow on the submitted-report text at
131 // the bottom causes scrollHeight to be larger than it should be.
132 let overflows = (overlay.scrollWidth > pluginRect.width) ||
133 (overlay.scrollHeight - 5 > pluginRect.height);
134
135 return overflows;
136 },
137
138 getPluginMimeType: function (plugin) {
139 var tagMimetype = plugin.actualType;
140
141 if (tagMimetype == "") {
142 tagMimetype = plugin.type;
143 }
144
145 return tagMimetype;
146 },
147
148 handlePluginBindingAttached: function (aTab, aEvent) {
149 let plugin = aEvent.target;
150 let doc = plugin.ownerDocument;
151 let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
152 if (!overlay || overlay._bindingHandled) {
153 return;
154 }
155 overlay._bindingHandled = true;
156
157 let eventType = PluginHelper._getBindingType(plugin);
158 if (!eventType) {
159 // Not all bindings have handlers
160 return;
161 }
162
163 switch (eventType) {
164 case "PluginClickToPlay": {
165 // Check if plugins have already been activated for this page, or if
166 // the user has set a permission to always play plugins on the site
167 if (aTab.clickToPlayPluginsActivated ||
168 Services.perms.testPermission(aTab.browser.currentURI, "plugins") ==
169 Services.perms.ALLOW_ACTION) {
170 PluginHelper.playPlugin(plugin);
171 return;
172 }
173
174 // If the plugin is hidden, or if the overlay is too small, show a
175 // doorhanger notification
176 if (PluginHelper.isTooSmall(plugin, overlay)) {
177 PluginHelper.delayAndShowDoorHanger(aTab);
178 } else {
179 // There's a large enough visible overlay that we don't need to show
180 // the doorhanger.
181 aTab.shouldShowPluginDoorhanger = false;
182 overlay.classList.add("visible");
183 }
184
185 // Add click to play listener to the overlay
186 overlay.addEventListener("click", function(e) {
187 if (!e.isTrusted)
188 return;
189 e.preventDefault();
190 let win = e.target.ownerDocument.defaultView.top;
191 let tab = BrowserApp.getTabForWindow(win);
192 tab.clickToPlayPluginsActivated = true;
193 PluginHelper.playAllPlugins(win);
194
195 NativeWindow.doorhanger.hide("ask-to-play-plugins", tab.id);
196 }, true);
197
198 // Add handlers for over- and underflow in case the plugin gets resized
199 plugin.addEventListener("overflow", function(event) {
200 overlay.classList.remove("visible");
201 PluginHelper.delayAndShowDoorHanger(aTab);
202 });
203 plugin.addEventListener("underflow", function(event) {
204 // This is also triggered if only one dimension underflows,
205 // the other dimension might still overflow
206 if (!PluginHelper.isTooSmall(plugin, overlay)) {
207 overlay.classList.add("visible");
208 }
209 });
210
211 break;
212 }
213
214 case "PluginPlayPreview": {
215 let previewContent = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
216 let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
217 let mimeType = PluginHelper.getPluginMimeType(plugin);
218 let playPreviewInfo = pluginHost.getPlayPreviewInfo(mimeType);
219
220 if (!playPreviewInfo.ignoreCTP) {
221 // Check if plugins have already been activated for this page, or if
222 // the user has set a permission to always play plugins on the site
223 if (aTab.clickToPlayPluginsActivated ||
224 Services.perms.testPermission(aTab.browser.currentURI, "plugins") ==
225 Services.perms.ALLOW_ACTION) {
226 PluginHelper.playPlugin(plugin);
227 return;
228 }
229
230 // Always show door hanger for play preview plugins
231 PluginHelper.delayAndShowDoorHanger(aTab);
232 }
233
234 let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
235 if (!iframe) {
236 // lazy initialization of the iframe
237 iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
238 iframe.className = "previewPluginContentFrame";
239 previewContent.appendChild(iframe);
240 }
241 iframe.src = playPreviewInfo.redirectURL;
242
243 // MozPlayPlugin event can be dispatched from the extension chrome
244 // code to replace the preview content with the native plugin
245 previewContent.addEventListener("MozPlayPlugin", function playPluginHandler(e) {
246 if (!e.isTrusted)
247 return;
248
249 previewContent.removeEventListener("MozPlayPlugin", playPluginHandler, true);
250
251 let playPlugin = !aEvent.detail;
252 PluginHelper.stopPlayPreview(plugin, playPlugin);
253
254 // cleaning up: removes overlay iframe from the DOM
255 let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
256 if (iframe)
257 previewContent.removeChild(iframe);
258 }, true);
259 break;
260 }
261
262 case "PluginNotFound": {
263 // On devices where we don't support Flash, there will be a
264 // "Learn More..." link in the missing plugin error message.
265 let learnMoreLink = doc.getAnonymousElementByAttribute(plugin, "class", "unsupportedLearnMoreLink");
266 let learnMoreUrl = Services.urlFormatter.formatURLPref("app.support.baseURL");
267 learnMoreUrl += "mobile-flash-unsupported";
268 learnMoreLink.href = learnMoreUrl;
269 overlay.classList.add("visible");
270 break;
271 }
272 }
273 },
274
275 // Helper to get the binding handler type from a plugin object
276 _getBindingType: function(plugin) {
277 if (!(plugin instanceof Ci.nsIObjectLoadingContent))
278 return null;
279
280 switch (plugin.pluginFallbackType) {
281 case Ci.nsIObjectLoadingContent.PLUGIN_UNSUPPORTED:
282 return "PluginNotFound";
283 case Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY:
284 return "PluginClickToPlay";
285 case Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW:
286 return "PluginPlayPreview";
287 default:
288 // Not all states map to a handler
289 return null;
290 }
291 }
292 };

mercurial