1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // This file adheres to closure-compiler conventions in order to enable
6 // compilation with ADVANCED_OPTIMIZATIONS. See http://goo.gl/FwOgy
8 // Installs and runs the plugin placeholder function on the |__gCrWeb| object.
11 * Namespace for this file. It depends on |__gCrWeb| having already been
14 __gCrWeb
['plugin'] = {};
16 /* Beginning of anonymous object. */
19 /* Data-URL version of plugin_blocked_android.png. Served this way rather
20 * than with an intercepted URL to avoid messing up https pages.
22 __gCrWeb
['plugin'].imageData_
=
23 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAQAAABLCVATAAAD' +
24 'aklEQVR4Xn2Wz2tcVRTHP/e+O28mMxONJKlF4kIkP4luXFgQuuxCBaG41IWrLupOXLur+A' +
25 'e4cmV3LiS6qujSLgq2CIKQUqS2YnWsRkzGSTIz7zyHw+EdchnkcOd+7+OeT84578tMwmet' +
26 'O1fkar1RRNAgUJuqbeEn/0RUcdS6UX7w0X54/93qw4V+m0IReBiizhAYpG52kfrO86+F9/' +
27 'YXNnukHOTpc5SHgpiOu1cT623FBELeGvgTXfppOAjN3dCKm7GIkWiY4LsBnqBPpGqAgN/z' +
28 'CDMMBsCWX+pwibd5hzdZZmLNOsxDm8VAzIkt1hX5NLucqgrZm3RlIC/XscKTNlAQpvncMi' +
29 'tAnEM33D4nqgbcosBSPT3DRTJ3+Cx+4UfV3/CQniMQQ5g2WMJkoGKHNodUCBDpsYEQ2KGm' +
30 'JBKIFPT4nYckB9ueaPxRscamWczco3qXLcR9wx4ndBsziqFSjaOCAWLm4kj0xhhSMVFli4' +
31 'opyYuLlJ7s+/xTE6IgcVBthUuW6goHZDiA5IeCAnFEhkKVxxQh+pnoqSeMCEw4Uvt5kEHP' +
32 'c8IyF3iJ5De1NYSAMOYvOtxgwBqv0wcE5rR4gcQGq9Sc5wt7bq2JtfYtI0Ys8mCmLhFg7q' +
33 'w6XKRStUHJiMJmpC8vglqypAOU/MwRiw7KYGKqxZSKqE/iTKrQAwGxv5oU4ZbzGHCTf1QN' +
34 'OTXbQhJ/gbxKjy85IPECHQSQ3EFUfM0+93iZgluM6LuzDUTJOXpc5jcWeDb3DjQrsMhj9t' +
35 'TdPcAq8mtjjunyFEtN8ohfOWaVZR88Qd2WKK15a5zoRY8ZmRaNIZ/yCZ/P1u0zY+9TASjc' +
36 'q04YMzBhqAAUBXf5iWcITGdql3aTtpIZVnxGYvSxj1VPXUB0EtHnxBoT6iwgeXEwQfwC69' +
37 'xmROAcr5DwESxa3XLGW9G9AgPGVKahzzb/UvEcq81PwCl/MyDMrUgxQeMH7tNniQW6nPKA' +
38 'e5TU3KUFjPmTRxyofUsFeFVQqyENBHDAYyodJhR0CFrnfaYECgvAjdogEwZCVySQaJ8Zeq' +
39 'AL874rsy+2ofT1ev5fkSdmihwF0jpOra/kskTHkGMckkG9Gg7Xvw9XtifXOy/GEgCr7H/r' +
40 'yepFOFy5fu1agI9XH71RbRWRrDmHOhrfLYrx9ndv3Wz98R+P7LgG2uyMvgAAAABJRU5Erk' +
44 * Returns the first <embed> child of the given node, if any.
45 * @param {HTMLElement} node The node to check.
46 * @return {HTMLElement} The first <embed> child, or null.
49 __gCrWeb
['plugin'].getEmbedChild_ = function(node
) {
50 if (node
.hasChildNodes()) {
51 for (var i
= 0; i
< node
.childNodes
.length
; i
++) {
52 if (node
.childNodes
[i
].nodeName
=== 'EMBED') {
53 return node
.childNodes
[i
];
61 * Returns the size for the given plugin element. For the common
62 * pattern of an IE-specific <object> wrapping an all-other-browsers <embed>,
63 * the object doesn't have real style info (most notably size), so this uses
64 * the embed in that case.
65 * @param {HTMLElement} plugin The <object> node to check.
66 * @return {Object} The size (width and height) for the plugin element.
69 __gCrWeb
['plugin'].getPluginSize_ = function(plugin
) {
71 // For the common pattern of an IE-specific <object> wrapping an
72 // all-other-browsers <embed>, the object doesn't have real style info
73 // (most notably size), so this uses the embed in that case.
74 var embedChild
= __gCrWeb
['plugin'].getEmbedChild_(plugin
);
76 style
= window
.getComputedStyle(embedChild
);
78 style
= window
.getComputedStyle(plugin
);
81 var width
= parseFloat(style
.width
);
82 var height
= parseFloat(style
.height
);
83 if (plugin
.tagName
=== 'APPLET') {
84 // Size computation doesn't always work correctly with applets in
85 // UIWebView, so use the attributes as fallbacks.
87 width
= parseFloat(plugin
.width
);
90 height
= parseFloat(plugin
.height
);
101 * Checks whether an element is "significant". Whether a plugin is
102 * "significant" is a heuristic that attempts to determine if it's a critical
103 * visual element for the page (i.e., not invisible, or an incidental ad).
104 * @param {HTMLElement} plugin The <object> node to check.
105 * @return {boolean} Whether the node is significant.
108 __gCrWeb
['plugin'].isSignificantPlugin_ = function(plugin
) {
109 var windowWidth
= window
.innerWidth
;
110 var windowHeight
= window
.innerHeight
;
111 var pluginSize
= __gCrWeb
['plugin'].getPluginSize_(plugin
);
112 var pluginWidth
= parseFloat(pluginSize
.width
);
113 var pluginHeight
= parseFloat(pluginSize
.height
);
114 // A plugin must be at least |significantFraction| of one dimension of the
115 // page, and a minimum size in the other dimension (to weed out banners and
117 var minSize
= Math
.min(200, windowWidth
/ 2, windowHeight
/ 2);
118 var significantFraction
= 0.5;
119 return (pluginWidth
> windowWidth
* significantFraction
&&
120 pluginHeight
> minSize
) ||
121 (pluginHeight
> windowHeight
* significantFraction
&&
122 pluginWidth
> minSize
);
126 * Walks the list of detected plugin elements, adding a placeholder to any
127 * that are "significant" (see above).
128 * @param {string} message The message to show in the placeholder.
130 __gCrWeb
['plugin']['addPluginPlaceholders'] = function(message
) {
131 var plugins
= __gCrWeb
['placeholderTargetPlugins'];
132 for (i
= 0; i
< plugins
.length
; i
++) {
133 var plugin
= plugins
[i
];
134 if (!__gCrWeb
['plugin'].isSignificantPlugin_(plugin
)) {
138 var pluginSize
= __gCrWeb
['plugin'].getPluginSize_(plugin
);
139 var widthStyle
= pluginSize
.width
+ 'px';
140 var heightStyle
= pluginSize
.height
+ 'px';
142 // The outer wrapper is a div with relative positioning, as an anchor for
143 // an inner absolute-position element, whose height is based on whether or
144 // not there's an embed. If there is, then it's zero height, to avoid
145 // affecting the layout of the (presumably-full-size) <embed> fallback. If
146 // not, it's full-height to ensure the placeholder takes up the right
147 // amount of space in the page layout. Width is full-width either way, to
148 // avoid being affected by container alignment.
149 var placeholder
= document
.createElement('div');
150 placeholder
.style
.width
= widthStyle
;
151 if (__gCrWeb
['plugin'].getEmbedChild_(plugin
)) {
152 placeholder
.style
.height
= '0';
154 placeholder
.style
.height
= heightStyle
;
156 placeholder
.style
.position
= 'relative';
158 // Inside is a full-plugin-size solid box.
159 var placeholderBox
= document
.createElement('div');
160 placeholderBox
.style
.position
= 'absolute';
161 placeholderBox
.style
.boxSizing
= 'border-box';
162 placeholderBox
.style
.width
= widthStyle
;
163 placeholderBox
.style
.height
= heightStyle
;
164 placeholderBox
.style
.border
= '1px solid black';
165 placeholderBox
.style
.backgroundColor
= '#808080';
166 placeholder
.appendChild(placeholderBox
);
168 // Inside that is the plugin placeholder image, centered.
169 var pluginImg
= document
.createElement('img');
171 pluginImg
.width
= imageSize
;
172 pluginImg
.height
= imageSize
;
173 pluginImg
.style
.position
= 'absolute';
174 // Center vertically and horizontally.
175 var halfSize
= imageSize
/ 2;
176 pluginImg
.style
.top
= '50%';
177 pluginImg
.style
.marginTop
= '-' + halfSize
+ 'px';
178 pluginImg
.style
.left
= '50%';
179 pluginImg
.style
.marginLeft
= '-' + halfSize
+ 'px';
180 pluginImg
.src
= __gCrWeb
['plugin'].imageData_
;
181 placeholderBox
.appendChild(pluginImg
);
183 // And below that, the message.
184 var label
= document
.createElement('p');
185 label
.style
.width
= widthStyle
;
186 label
.style
.height
= '1.5em';
187 label
.style
.position
= 'absolute';
188 // Position below the image.
189 label
.style
.top
= '50%';
190 label
.style
.marginTop
= imageSize
+ 'px';
191 // Center horizontally.
192 label
.style
.textAlign
= 'center';
193 label
.textContent
= message
;
194 placeholderBox
.appendChild(label
);
196 plugin
.insertBefore(placeholder
, plugin
.firstChild
);
199 }()); // End of anonymous object