2 * Copyright (C) 2008, 2011, 2012 Apple Inc. All rights reserved.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
22 #include "HTMLPlugInImageElement.h"
25 #include "ChromeClient.h"
27 #include "FrameLoader.h"
28 #include "FrameLoaderClient.h"
29 #include "FrameView.h"
30 #include "HTMLDivElement.h"
31 #include "HTMLImageLoader.h"
33 #include "LocalizedStrings.h"
35 #include "MouseEvent.h"
37 #include "NodeRenderStyle.h"
38 #include "NodeRenderingContext.h"
40 #include "PlugInClient.h"
41 #include "PluginViewBase.h"
42 #include "RenderEmbeddedObject.h"
43 #include "RenderImage.h"
44 #include "RenderSnapshottedPlugIn.h"
45 #include "SchemeRegistry.h"
46 #include "ScriptController.h"
47 #include "SecurityOrigin.h"
49 #include "ShadowRoot.h"
50 #include "StyleResolver.h"
52 #include <wtf/CurrentTime.h>
56 using namespace HTMLNames;
58 typedef Vector<RefPtr<HTMLPlugInImageElement> > HTMLPlugInImageElementList;
60 static const int sizingTinyDimensionThreshold = 40;
61 static const int sizingSmallWidthThreshold = 250;
62 static const int sizingMediumWidthThreshold = 450;
63 static const int sizingMediumHeightThreshold = 300;
64 static const float sizingFullPageAreaRatioThreshold = 0.96;
65 static const float autostartSoonAfterUserGestureThreshold = 5.0;
67 // This delay should not exceed the snapshot delay in PluginView.cpp
68 static const double simulatedMouseClickTimerDelay = .75;
69 static const double removeSnapshotTimerDelay = 1.5;
71 HTMLPlugInImageElement::HTMLPlugInImageElement(const QualifiedName& tagName, Document* document, bool createdByParser, PreferPlugInsForImagesOption preferPlugInsForImagesOption)
72 : HTMLPlugInElement(tagName, document)
73 // m_needsWidgetUpdate(!createdByParser) allows HTMLObjectElement to delay
74 // widget updates until after all children are parsed. For HTMLEmbedElement
75 // this delay is unnecessary, but it is simpler to make both classes share
76 // the same codepath in this class.
77 , m_needsWidgetUpdate(!createdByParser)
78 , m_shouldPreferPlugInsForImages(preferPlugInsForImagesOption == ShouldPreferPlugInsForImages)
79 , m_needsDocumentActivationCallbacks(false)
80 , m_simulatedMouseClickTimer(this, &HTMLPlugInImageElement::simulatedMouseClickTimerFired, simulatedMouseClickTimerDelay)
81 , m_swapRendererTimer(this, &HTMLPlugInImageElement::swapRendererTimerFired)
82 , m_removeSnapshotTimer(this, &HTMLPlugInImageElement::removeSnapshotTimerFired)
83 , m_createdDuringUserGesture(ScriptController::processingUserGesture())
84 , m_restartedPlugin(false)
85 , m_needsCheckForSizeChange(false)
86 , m_snapshotDecision(SnapshotNotYetDecided)
88 setHasCustomStyleCallbacks();
91 HTMLPlugInImageElement::~HTMLPlugInImageElement()
93 if (m_needsDocumentActivationCallbacks)
94 document()->unregisterForPageCacheSuspensionCallbacks(this);
97 void HTMLPlugInImageElement::setDisplayState(DisplayState state)
100 if (state == RestartingWithPendingMouseClick || state == Restarting) {
101 m_restartedPlugin = true;
102 m_snapshotDecision = NeverSnapshot;
103 if (displayState() == DisplayingSnapshot)
104 m_removeSnapshotTimer.startOneShot(removeSnapshotTimerDelay);
108 HTMLPlugInElement::setDisplayState(state);
110 if (state == DisplayingSnapshot)
111 m_swapRendererTimer.startOneShot(0);
114 RenderEmbeddedObject* HTMLPlugInImageElement::renderEmbeddedObject() const
116 // HTMLObjectElement and HTMLEmbedElement may return arbitrary renderers
117 // when using fallback content.
118 if (!renderer() || !renderer()->isEmbeddedObject())
120 return toRenderEmbeddedObject(renderer());
123 bool HTMLPlugInImageElement::isImageType()
125 if (m_serviceType.isEmpty() && protocolIs(m_url, "data"))
126 m_serviceType = mimeTypeFromDataURL(m_url);
128 if (Frame* frame = document()->frame()) {
129 KURL completedURL = document()->completeURL(m_url);
130 return frame->loader()->client()->objectContentType(completedURL, m_serviceType, shouldPreferPlugInsForImages()) == ObjectContentImage;
133 return Image::supportsType(m_serviceType);
136 // We don't use m_url, as it may not be the final URL that the object loads,
137 // depending on <param> values.
138 bool HTMLPlugInImageElement::allowedToLoadFrameURL(const String& url)
140 KURL completeURL = document()->completeURL(url);
142 if (contentFrame() && protocolIsJavaScript(completeURL)
143 && !document()->securityOrigin()->canAccess(contentDocument()->securityOrigin()))
146 return document()->frame()->isURLAllowed(completeURL);
149 // We don't use m_url, or m_serviceType as they may not be the final values
150 // that <object> uses depending on <param> values.
151 bool HTMLPlugInImageElement::wouldLoadAsNetscapePlugin(const String& url, const String& serviceType)
154 ASSERT(document()->frame());
157 completedURL = document()->completeURL(url);
159 FrameLoader* frameLoader = document()->frame()->loader();
161 if (frameLoader->client()->objectContentType(completedURL, serviceType, shouldPreferPlugInsForImages()) == ObjectContentNetscapePlugin)
166 RenderObject* HTMLPlugInImageElement::createRenderer(RenderArena* arena, RenderStyle* style)
168 // Once a PlugIn Element creates its renderer, it needs to be told when the Document goes
169 // inactive or reactivates so it can clear the renderer before going into the page cache.
170 if (!m_needsDocumentActivationCallbacks) {
171 m_needsDocumentActivationCallbacks = true;
172 document()->registerForPageCacheSuspensionCallbacks(this);
175 if (displayState() == DisplayingSnapshot) {
176 RenderSnapshottedPlugIn* renderSnapshottedPlugIn = new (arena) RenderSnapshottedPlugIn(this);
177 renderSnapshottedPlugIn->updateSnapshot(m_snapshotImage);
178 return renderSnapshottedPlugIn;
181 // Fallback content breaks the DOM->Renderer class relationship of this
182 // class and all superclasses because createObject won't necessarily
183 // return a RenderEmbeddedObject, RenderPart or even RenderWidget.
184 if (useFallbackContent())
185 return RenderObject::createObject(this, style);
188 RenderImage* image = new (arena) RenderImage(this);
189 image->setImageResource(RenderImageResource::create());
193 return new (arena) RenderEmbeddedObject(this);
196 bool HTMLPlugInImageElement::willRecalcStyle(StyleChange)
198 // FIXME: Why is this necessary? Manual re-attach is almost always wrong.
199 if (!useFallbackContent() && needsWidgetUpdate() && renderer() && !isImageType() && (displayState() != DisplayingSnapshot))
204 void HTMLPlugInImageElement::attach()
206 PostAttachCallbackDisabler disabler(this);
208 bool isImage = isImageType();
211 queuePostAttachCallback(&HTMLPlugInImageElement::updateWidgetCallback, this);
213 HTMLPlugInElement::attach();
215 if (isImage && renderer() && !useFallbackContent()) {
217 m_imageLoader = adoptPtr(new HTMLImageLoader(this));
218 m_imageLoader->updateFromElement();
222 void HTMLPlugInImageElement::detach()
224 // FIXME: Because of the insanity that is HTMLPlugInImageElement::recalcStyle,
225 // we can end up detaching during an attach() call, before we even have a
226 // renderer. In that case, don't mark the widget for update.
227 if (attached() && renderer() && !useFallbackContent())
228 // Update the widget the next time we attach (detaching destroys the plugin).
229 setNeedsWidgetUpdate(true);
230 HTMLPlugInElement::detach();
233 void HTMLPlugInImageElement::updateWidgetIfNecessary()
235 document()->updateStyleIfNeeded();
237 if (!needsWidgetUpdate() || useFallbackContent() || isImageType())
240 if (!renderEmbeddedObject() || renderEmbeddedObject()->showsUnavailablePluginIndicator())
243 updateWidget(CreateOnlyNonNetscapePlugins);
246 void HTMLPlugInImageElement::finishParsingChildren()
248 HTMLPlugInElement::finishParsingChildren();
249 if (useFallbackContent())
252 setNeedsWidgetUpdate(true);
254 setNeedsStyleRecalc();
257 void HTMLPlugInImageElement::didMoveToNewDocument(Document* oldDocument)
259 if (m_needsDocumentActivationCallbacks) {
261 oldDocument->unregisterForPageCacheSuspensionCallbacks(this);
262 document()->registerForPageCacheSuspensionCallbacks(this);
266 m_imageLoader->elementDidMoveToNewDocument();
267 HTMLPlugInElement::didMoveToNewDocument(oldDocument);
270 void HTMLPlugInImageElement::documentWillSuspendForPageCache()
272 if (RenderStyle* renderStyle = this->renderStyle()) {
273 m_customStyleForPageCache = RenderStyle::clone(renderStyle);
274 m_customStyleForPageCache->setDisplay(NONE);
278 HTMLPlugInElement::documentWillSuspendForPageCache();
281 void HTMLPlugInImageElement::documentDidResumeFromPageCache()
283 if (m_customStyleForPageCache) {
284 m_customStyleForPageCache = 0;
288 HTMLPlugInElement::documentDidResumeFromPageCache();
291 PassRefPtr<RenderStyle> HTMLPlugInImageElement::customStyleForRenderer()
293 if (!m_customStyleForPageCache)
294 return document()->styleResolver()->styleForElement(this);
295 return m_customStyleForPageCache;
298 void HTMLPlugInImageElement::updateWidgetCallback(Node* n, unsigned)
300 static_cast<HTMLPlugInImageElement*>(n)->updateWidgetIfNecessary();
303 void HTMLPlugInImageElement::updateSnapshot(PassRefPtr<Image> image)
305 if (displayState() > DisplayingSnapshot)
308 m_snapshotImage = image;
310 if (renderer()->isSnapshottedPlugIn()) {
311 toRenderSnapshottedPlugIn(renderer())->updateSnapshot(image);
315 if (renderer()->isEmbeddedObject())
316 renderer()->repaint();
319 static AtomicString classNameForShadowRoot(const Node* node)
321 DEFINE_STATIC_LOCAL(const AtomicString, plugInTinySizeClassName, ("tiny", AtomicString::ConstructFromLiteral));
322 DEFINE_STATIC_LOCAL(const AtomicString, plugInSmallSizeClassName, ("small", AtomicString::ConstructFromLiteral));
323 DEFINE_STATIC_LOCAL(const AtomicString, plugInMediumSizeClassName, ("medium", AtomicString::ConstructFromLiteral));
324 DEFINE_STATIC_LOCAL(const AtomicString, plugInLargeSizeClassName, ("large", AtomicString::ConstructFromLiteral));
326 RenderBox* renderBox = static_cast<RenderBox*>(node->renderer());
327 LayoutUnit width = renderBox->contentWidth();
328 LayoutUnit height = renderBox->contentHeight();
330 if (width < sizingTinyDimensionThreshold || height < sizingTinyDimensionThreshold)
331 return plugInTinySizeClassName;
333 if (width < sizingSmallWidthThreshold)
334 return plugInSmallSizeClassName;
336 if (width < sizingMediumWidthThreshold || height < sizingMediumHeightThreshold)
337 return plugInMediumSizeClassName;
339 return plugInLargeSizeClassName;
342 void HTMLPlugInImageElement::checkSnapshotStatus()
344 if (!renderer()->isSnapshottedPlugIn()) {
345 if (displayState() == Playing)
346 checkSizeChangeForSnapshotting();
350 ShadowRoot* root = userAgentShadowRoot();
354 Element* shadowContainer = toElement(root->firstChild());
355 shadowContainer->setAttribute(classAttr, classNameForShadowRoot(this));
358 void HTMLPlugInImageElement::didAddUserAgentShadowRoot(ShadowRoot* root)
360 Document* doc = document();
362 m_shadowContainer = HTMLDivElement::create(doc);
363 m_shadowContainer->setPseudo(AtomicString("-webkit-snapshotted-plugin-content", AtomicString::ConstructFromLiteral));
365 RefPtr<Element> container = HTMLDivElement::create(doc);
366 container->setAttribute(classAttr, AtomicString("snapshot-container", AtomicString::ConstructFromLiteral));
368 RefPtr<Element> overlay = HTMLDivElement::create(doc);
369 overlay->setAttribute(classAttr, AtomicString("snapshot-overlay", AtomicString::ConstructFromLiteral));
370 container->appendChild(overlay, ASSERT_NO_EXCEPTION);
372 m_snapshotLabel = HTMLDivElement::create(doc);
373 m_snapshotLabel->setAttribute(classAttr, AtomicString("snapshot-label", AtomicString::ConstructFromLiteral));
375 String titleText = snapshottedPlugInLabelTitle();
376 String subtitleText = snapshottedPlugInLabelSubtitle();
377 if (document()->page()) {
378 String clientTitleText = document()->page()->chrome()->client()->plugInStartLabelTitle();
379 if (!clientTitleText.isEmpty())
380 titleText = clientTitleText;
381 String clientSubtitleText = document()->page()->chrome()->client()->plugInStartLabelSubtitle();
382 if (!clientSubtitleText.isEmpty())
383 subtitleText = clientSubtitleText;
386 RefPtr<Element> title = HTMLDivElement::create(doc);
387 title->setAttribute(classAttr, AtomicString("snapshot-title", AtomicString::ConstructFromLiteral));
388 title->appendChild(doc->createTextNode(titleText), ASSERT_NO_EXCEPTION);
389 m_snapshotLabel->appendChild(title, ASSERT_NO_EXCEPTION);
391 RefPtr<Element> subTitle = HTMLDivElement::create(doc);
392 subTitle->setAttribute(classAttr, AtomicString("snapshot-subtitle", AtomicString::ConstructFromLiteral));
393 subTitle->appendChild(doc->createTextNode(subtitleText), ASSERT_NO_EXCEPTION);
394 m_snapshotLabel->appendChild(subTitle, ASSERT_NO_EXCEPTION);
396 container->appendChild(m_snapshotLabel, ASSERT_NO_EXCEPTION);
398 // Make this into a button for accessibility clients.
399 String combinedText = titleText;
400 if (!combinedText.isEmpty() && !subtitleText.isEmpty())
401 combinedText.append(" ");
402 combinedText.append(subtitleText);
403 container->setAttribute(aria_labelAttr, combinedText);
404 container->setAttribute(roleAttr, "button");
406 m_shadowContainer->appendChild(container, ASSERT_NO_EXCEPTION);
407 root->appendChild(m_shadowContainer, ASSERT_NO_EXCEPTION);
410 bool HTMLPlugInImageElement::partOfSnapshotLabel(Node* node)
412 return node && (node == m_snapshotLabel.get() || node->isDescendantOf(m_snapshotLabel.get()));
415 void HTMLPlugInImageElement::swapRendererTimerFired(Timer<HTMLPlugInImageElement>*)
417 ASSERT(displayState() == DisplayingSnapshot);
418 if (userAgentShadowRoot())
421 // Create a shadow root, which will trigger the code to add a snapshot container
422 // and reattach, thus making a new Renderer.
423 ensureUserAgentShadowRoot();
426 void HTMLPlugInImageElement::removeSnapshotTimerFired(Timer<HTMLPlugInImageElement>*)
428 m_snapshotImage = nullptr;
429 m_restartedPlugin = false;
431 renderer()->repaint();
434 static void addPlugInsFromNodeListMatchingPlugInOrigin(HTMLPlugInImageElementList& plugInList, PassRefPtr<NodeList> collection, const String& plugInOrigin, const String& mimeType)
436 for (unsigned i = 0, length = collection->length(); i < length; i++) {
437 Node* node = collection->item(i);
438 if (node->isPluginElement()) {
439 HTMLPlugInElement* plugInElement = toHTMLPlugInElement(node);
440 if (plugInElement->isPlugInImageElement()) {
441 HTMLPlugInImageElement* plugInImageElement = toHTMLPlugInImageElement(node);
442 const KURL& loadedURL = plugInImageElement->loadedUrl();
443 String otherMimeType = plugInImageElement->loadedMimeType();
444 if (plugInOrigin == loadedURL.host() && mimeType == otherMimeType)
445 plugInList.append(plugInImageElement);
451 void HTMLPlugInImageElement::restartSimilarPlugIns()
453 // Restart any other snapshotted plugins in the page with the same origin. Note that they
454 // may be in different frames, so traverse from the top of the document.
456 String plugInOrigin = m_loadedUrl.host();
457 String mimeType = loadedMimeType();
458 HTMLPlugInImageElementList similarPlugins;
460 if (!document()->page())
463 for (Frame* frame = document()->page()->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
464 if (!frame->loader()->subframeLoader()->containsPlugins())
467 if (!frame->document())
470 RefPtr<NodeList> plugIns = frame->document()->getElementsByTagName(embedTag.localName());
472 addPlugInsFromNodeListMatchingPlugInOrigin(similarPlugins, plugIns, plugInOrigin, mimeType);
474 plugIns = frame->document()->getElementsByTagName(objectTag.localName());
476 addPlugInsFromNodeListMatchingPlugInOrigin(similarPlugins, plugIns, plugInOrigin, mimeType);
479 for (size_t i = 0, length = similarPlugins.size(); i < length; ++i) {
480 HTMLPlugInImageElement* plugInToRestart = similarPlugins[i].get();
481 if (plugInToRestart->displayState() <= HTMLPlugInElement::DisplayingSnapshot) {
482 LOG(Plugins, "%p Plug-in looks similar to a restarted plug-in. Restart.", plugInToRestart);
483 plugInToRestart->setDisplayState(Playing);
484 plugInToRestart->restartSnapshottedPlugIn();
486 plugInToRestart->m_snapshotDecision = NeverSnapshot;
490 void HTMLPlugInImageElement::userDidClickSnapshot(PassRefPtr<MouseEvent> event, bool forwardEvent)
493 m_pendingClickEventFromSnapshot = event;
495 String plugInOrigin = m_loadedUrl.host();
496 if (document()->page() && !SchemeRegistry::shouldTreatURLSchemeAsLocal(document()->page()->mainFrame()->document()->baseURL().protocol()) && document()->page()->settings()->autostartOriginPlugInSnapshottingEnabled())
497 document()->page()->plugInClient()->didStartFromOrigin(document()->page()->mainFrame()->document()->baseURL().host(), plugInOrigin, loadedMimeType());
499 LOG(Plugins, "%p User clicked on snapshotted plug-in. Restart.", this);
500 restartSnapshottedPlugIn();
501 restartSimilarPlugIns();
504 void HTMLPlugInImageElement::setIsPrimarySnapshottedPlugIn(bool isPrimarySnapshottedPlugIn)
506 if (!document()->page() || !document()->page()->settings()->primaryPlugInSnapshotDetectionEnabled() || document()->page()->settings()->snapshotAllPlugIns())
509 if (isPrimarySnapshottedPlugIn) {
510 LOG(Plugins, "%p Plug-in was detected as the primary element in the page. Restart.", this);
511 restartSnapshottedPlugIn();
512 restartSimilarPlugIns();
516 void HTMLPlugInImageElement::restartSnapshottedPlugIn()
518 if (displayState() != RestartingWithPendingMouseClick)
519 setDisplayState(Restarting);
524 void HTMLPlugInImageElement::dispatchPendingMouseClick()
526 ASSERT(!m_simulatedMouseClickTimer.isActive());
527 m_simulatedMouseClickTimer.restart();
530 void HTMLPlugInImageElement::simulatedMouseClickTimerFired(DeferrableOneShotTimer<HTMLPlugInImageElement>*)
532 ASSERT(displayState() == RestartingWithPendingMouseClick);
533 ASSERT(m_pendingClickEventFromSnapshot);
535 dispatchSimulatedClick(m_pendingClickEventFromSnapshot.get(), SendMouseOverUpDownEvents, DoNotShowPressedLook);
537 setDisplayState(Playing);
538 m_pendingClickEventFromSnapshot = nullptr;
541 void HTMLPlugInImageElement::checkSizeChangeForSnapshotting()
543 if (!m_needsCheckForSizeChange || m_snapshotDecision != MaySnapshotWhenResized)
546 m_needsCheckForSizeChange = false;
547 LayoutRect contentBoxRect = toRenderBox(renderer())->contentBoxRect();
548 int contentWidth = contentBoxRect.width();
549 int contentHeight = contentBoxRect.height();
551 if (contentWidth <= sizingTinyDimensionThreshold || contentHeight <= sizingTinyDimensionThreshold)
554 LOG(Plugins, "%p Plug-in originally avoided snapshotting because it was sized %dx%d. Now it is %dx%d. Tell it to snapshot.\n", this, m_sizeWhenSnapshotted.width(), m_sizeWhenSnapshotted.height(), contentWidth, contentHeight);
555 setDisplayState(WaitingForSnapshot);
556 m_snapshotDecision = Snapshotted;
557 Widget* widget = pluginWidget();
558 if (widget && widget->isPluginViewBase())
559 toPluginViewBase(widget)->beginSnapshottingRunningPlugin();
562 void HTMLPlugInImageElement::subframeLoaderWillCreatePlugIn(const KURL& url)
564 LOG(Plugins, "%p Plug-in URL: %s", this, m_url.utf8().data());
565 LOG(Plugins, " Loaded URL: %s", url.string().utf8().data());
569 if (!document()->page() || !document()->page()->settings()->plugInSnapshottingEnabled()) {
570 m_snapshotDecision = NeverSnapshot;
574 if (displayState() == Restarting) {
575 LOG(Plugins, "%p Plug-in is explicitly restarting", this);
576 m_snapshotDecision = NeverSnapshot;
577 setDisplayState(Playing);
581 if (displayState() == RestartingWithPendingMouseClick) {
582 LOG(Plugins, "%p Plug-in is explicitly restarting but also waiting for a click", this);
583 m_snapshotDecision = NeverSnapshot;
587 if (m_snapshotDecision == NeverSnapshot) {
588 LOG(Plugins, "%p Plug-in is blessed, allow it to start", this);
592 bool inMainFrame = document()->frame() == document()->page()->mainFrame();
594 if (document()->isPluginDocument() && inMainFrame) {
595 LOG(Plugins, "%p Plug-in document in main frame", this);
596 m_snapshotDecision = NeverSnapshot;
600 if (ScriptController::processingUserGesture()) {
601 LOG(Plugins, "%p Script is currently processing user gesture, set to play", this);
602 m_snapshotDecision = NeverSnapshot;
606 if (m_createdDuringUserGesture) {
607 LOG(Plugins, "%p Plug-in was created when processing user gesture, set to play", this);
608 m_snapshotDecision = NeverSnapshot;
612 double lastKnownUserGestureTimestamp = document()->lastHandledUserGestureTimestamp();
613 if (!inMainFrame && document()->page()->mainFrame() && document()->page()->mainFrame()->document())
614 lastKnownUserGestureTimestamp = std::max(lastKnownUserGestureTimestamp, document()->page()->mainFrame()->document()->lastHandledUserGestureTimestamp());
615 if (currentTime() - lastKnownUserGestureTimestamp < autostartSoonAfterUserGestureThreshold) {
616 LOG(Plugins, "%p Plug-in was created shortly after a user gesture, set to play", this);
617 m_snapshotDecision = NeverSnapshot;
621 if (document()->page()->settings()->snapshotAllPlugIns()) {
622 LOG(Plugins, "%p Plug-in forced to snapshot by user preference", this);
623 m_snapshotDecision = Snapshotted;
624 setDisplayState(WaitingForSnapshot);
628 if (document()->page()->settings()->autostartOriginPlugInSnapshottingEnabled() && document()->page()->plugInClient()->shouldAutoStartFromOrigin(document()->page()->mainFrame()->document()->baseURL().host(), url.host(), loadedMimeType())) {
629 LOG(Plugins, "%p Plug-in from (%s, %s) is marked to auto-start, set to play", this, document()->page()->mainFrame()->document()->baseURL().host().utf8().data(), url.host().utf8().data());
630 m_snapshotDecision = NeverSnapshot;
634 RenderBox* renderEmbeddedObject = toRenderBox(renderer());
635 Length styleWidth = renderEmbeddedObject->style()->width();
636 Length styleHeight = renderEmbeddedObject->style()->height();
637 LayoutRect contentBoxRect = renderEmbeddedObject->contentBoxRect();
638 int contentWidth = contentBoxRect.width();
639 int contentHeight = contentBoxRect.height();
640 int contentArea = contentWidth * contentHeight;
641 IntSize visibleViewSize = document()->frame()->view()->visibleSize();
642 int visibleArea = visibleViewSize.width() * visibleViewSize.height();
644 if (inMainFrame && styleWidth.isPercent() && (styleWidth.percent() == 100)
645 && styleHeight.isPercent() && (styleHeight.percent() == 100)
646 && (static_cast<float>(contentArea) / visibleArea > sizingFullPageAreaRatioThreshold)) {
647 LOG(Plugins, "%p Plug-in is top level full page, set to play", this);
648 m_snapshotDecision = NeverSnapshot;
652 if (contentWidth <= sizingTinyDimensionThreshold || contentHeight <= sizingTinyDimensionThreshold) {
653 LOG(Plugins, "%p Plug-in is very small %dx%d, set to play", this, contentWidth, contentHeight);
654 m_sizeWhenSnapshotted = IntSize(contentBoxRect.width().toInt(), contentBoxRect.height().toInt());
655 m_snapshotDecision = MaySnapshotWhenResized;
659 if (!document()->page()->plugInClient()) {
660 LOG(Plugins, "%p There is no plug-in client. Set to wait for snapshot", this);
661 m_snapshotDecision = NeverSnapshot;
662 setDisplayState(WaitingForSnapshot);
666 LOG(Plugins, "%p Plug-in from (%s, %s) is not auto-start, sized at %dx%d, set to wait for snapshot", this, document()->page()->mainFrame()->document()->baseURL().host().utf8().data(), url.host().utf8().data(), contentWidth, contentHeight);
667 m_snapshotDecision = Snapshotted;
668 setDisplayState(WaitingForSnapshot);
671 void HTMLPlugInImageElement::subframeLoaderDidCreatePlugIn(const Widget* widget)
673 if (!widget->isPluginViewBase() || !toPluginViewBase(widget)->shouldAlwaysAutoStart())
676 LOG(Plugins, "%p Plug-in should auto-start, set to play", this);
677 m_snapshotDecision = NeverSnapshot;
678 setDisplayState(Playing);
681 } // namespace WebCore