Index: Source/core/html/HTMLPlugInElement.cpp |
diff --git a/Source/core/html/HTMLPlugInElement.cpp b/Source/core/html/HTMLPlugInElement.cpp |
index f2aaf0418bfc21ba56688e9ef998e4426212792f..9dac6104794456ec36993b9a60803648a2349737 100644 |
--- a/Source/core/html/HTMLPlugInElement.cpp |
+++ b/Source/core/html/HTMLPlugInElement.cpp |
@@ -33,6 +33,7 @@ |
#include "core/events/Event.h" |
#include "core/frame/ContentSecurityPolicy.h" |
#include "core/frame/Frame.h" |
+#include "core/frame/FrameView.h" |
#include "core/html/HTMLImageLoader.h" |
#include "core/html/PluginDocument.h" |
#include "core/html/shadow/HTMLContentElement.h" |
@@ -67,6 +68,7 @@ HTMLPlugInElement::HTMLPlugInElement(const QualifiedName& tagName, Document& doc |
, m_needsWidgetUpdate(!createdByParser) |
, m_shouldPreferPlugInsForImages(preferPlugInsForImagesOption == ShouldPreferPlugInsForImages) |
, m_displayState(Playing) |
+ , m_persistedPluginWidget(0) |
eseidel
2013/12/18 18:38:18
nit: RefPtr's default construtor sets to 0, no nee
wjmaclean
2013/12/23 23:49:53
Done.
|
{ |
setHasCustomStyleCallbacks(); |
} |
@@ -84,7 +86,7 @@ HTMLPlugInElement::~HTMLPlugInElement() |
bool HTMLPlugInElement::canProcessDrag() const |
{ |
- return pluginWidget() && pluginWidget()->isPluginView() && toPluginView(pluginWidget())->canProcessDrag(); |
+ return widget() && widget()->isPluginView() && toPluginView(widget())->canProcessDrag(); |
} |
bool HTMLPlugInElement::willRespondToMouseClickEvents() |
@@ -141,6 +143,35 @@ void HTMLPlugInElement::updateWidget() |
} |
} |
+void HTMLPlugInElement::requestPluginCreationWithoutRendererIfPossible() |
+{ |
+ if (m_serviceType.isEmpty()) |
+ return; |
+ |
+ if (!document().frame()->loader().client()->canCreatePluginWithoutRenderer(m_serviceType)) |
+ return; |
+ |
+ if (renderer() && renderer()->isWidget()) |
+ return; |
+ |
+ createPluginWithoutRenderer(); |
+} |
+ |
+void HTMLPlugInElement::createPluginWithoutRenderer() |
+{ |
+ ASSERT(document().frame()->loader().client()->canCreatePluginWithoutRenderer(m_serviceType)); |
+ |
+ KURL url; |
+ Vector<String> paramNames; |
+ Vector<String> paramValues; |
+ |
+ paramNames.append("type"); |
+ paramValues.append(m_serviceType); |
+ |
+ bool useFallback = false; |
+ loadPlugin(url, m_serviceType, paramNames, paramValues, useFallback, false); |
+} |
+ |
void HTMLPlugInElement::detach(const AttachContext& context) |
{ |
// Update the widget the next time we attach (detaching destroys the plugin). |
@@ -152,7 +183,12 @@ void HTMLPlugInElement::detach(const AttachContext& context) |
document().decrementLoadEventDelayCount(); |
} |
+ Widget* plugin = widget(); |
+ if (plugin && plugin->pluginShouldPersist()) |
+ m_persistedPluginWidget = plugin; |
resetInstance(); |
+ setWidget(0); |
+ |
if (m_isCapturingMouseEvents) { |
if (Frame* frame = document().frame()) |
@@ -218,8 +254,19 @@ SharedPersistent<v8::Object>* HTMLPlugInElement::pluginWrapper() |
// return the cached allocated Bindings::Instance. Not supporting this |
// edge-case is OK. |
if (!m_pluginWrapper) { |
- if (Widget* widget = pluginWidget()) |
- m_pluginWrapper = frame->script().createPluginWrapper(widget); |
+ Widget* plugin = widget(); |
+ if (!plugin && m_persistedPluginWidget) |
+ plugin = m_persistedPluginWidget.get(); |
+ if (!plugin && !m_inBeforeLoadEventHandler) { |
+ // If the plugin wasn't created without a renderer, then we can |
+ // trigger its creation here. Although widgets are no longer owned |
+ // by the renderWidget, the creation of the latter will still lead |
+ // to loadPlugin() being called. |
+ renderWidgetForJSBindings(); |
+ plugin = widget(); |
+ } |
+ if (plugin) |
+ m_pluginWrapper = frame->script().createPluginWrapper(plugin); |
} |
return m_pluginWrapper.get(); |
} |
@@ -237,20 +284,6 @@ bool HTMLPlugInElement::dispatchBeforeLoadEvent(const String& sourceURL) |
return beforeLoadAllowedLoad; |
} |
-Widget* HTMLPlugInElement::pluginWidget() const |
-{ |
- if (m_inBeforeLoadEventHandler) { |
- // The plug-in hasn't loaded yet, and it makes no sense to try to load |
- // if beforeload handler happened to touch the plug-in element. That |
- // would recursively call beforeload for the same element. |
- return 0; |
- } |
- |
- if (RenderWidget* renderWidget = renderWidgetForJSBindings()) |
- return renderWidget->widget(); |
- return 0; |
-} |
- |
bool HTMLPlugInElement::isPresentationAttribute(const QualifiedName& name) const |
{ |
if (name == widthAttr || name == heightAttr || name == vspaceAttr || name == hspaceAttr || name == alignAttr) |
@@ -320,7 +353,7 @@ bool HTMLPlugInElement::isKeyboardFocusable() const |
{ |
if (!document().isActive()) |
return false; |
- return pluginWidget() && pluginWidget()->isPluginView() && toPluginView(pluginWidget())->supportsKeyboardFocus(); |
+ return widget() && widget()->isPluginView() && toPluginView(widget())->supportsKeyboardFocus(); |
} |
bool HTMLPlugInElement::isPluginElement() const |
@@ -412,8 +445,9 @@ bool HTMLPlugInElement::requestObject(const String& url, const String& mimeType, |
KURL completedURL = document().completeURL(url); |
bool useFallback; |
+ bool requireRenderer = true; |
if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(), useFallback)) |
- return loadPlugin(completedURL, mimeType, paramNames, paramValues, useFallback); |
+ return loadPlugin(completedURL, mimeType, paramNames, paramValues, useFallback, requireRenderer); |
// If the plug-in element already contains a subframe, |
// loadOrRedirectSubframe will re-use it. Otherwise, it will create a new |
@@ -422,7 +456,7 @@ bool HTMLPlugInElement::requestObject(const String& url, const String& mimeType, |
return loadOrRedirectSubframe(completedURL, getNameAttribute(), true); |
} |
-bool HTMLPlugInElement::loadPlugin(const KURL& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback) |
+bool HTMLPlugInElement::loadPlugin(const KURL& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback, bool requireRenderer) |
{ |
Frame* frame = document().frame(); |
@@ -434,26 +468,46 @@ bool HTMLPlugInElement::loadPlugin(const KURL& url, const String& mimeType, cons |
RenderEmbeddedObject* renderer = renderEmbeddedObject(); |
// FIXME: This code should not depend on renderer! |
- if (!renderer || useFallback) |
+ if ((!renderer && requireRenderer) || useFallback) |
return false; |
+ FrameLoaderClient::PluginLoadType loadType = renderer ? FrameLoaderClient::PluginLoadRequiresRenderer : FrameLoaderClient::PluginLoadWithoutRenderer; |
+ |
WTF_LOG(Plugins, "%p Plug-in URL: %s", this, m_url.utf8().data()); |
WTF_LOG(Plugins, " Loaded URL: %s", url.string().utf8().data()); |
+ |
m_loadedUrl = url; |
- IntSize contentSize = roundedIntSize(LayoutSize(renderer->contentWidth(), renderer->contentHeight())); |
- bool loadManually = document().isPluginDocument() && !document().containsPlugins() && toPluginDocument(document()).shouldLoadPluginManually(); |
- RefPtr<Widget> widget = frame->loader().client()->createPlugin(contentSize, this, url, paramNames, paramValues, mimeType, loadManually); |
+ IntSize contentSize; |
+ if (renderer) |
+ contentSize = roundedIntSize(LayoutSize(renderer->contentWidth(), renderer->contentHeight())); |
+ RefPtr<Widget> plugin = m_persistedPluginWidget; |
- if (!widget) { |
- if (!renderer->showsUnavailablePluginIndicator()) |
+ if (!plugin) { |
+ bool loadManually = document().isPluginDocument() && !document().containsPlugins() && toPluginDocument(document()).shouldLoadPluginManually(); |
+ plugin = frame->loader().client()->createPlugin(contentSize, this, url, paramNames, paramValues, mimeType, loadManually, loadType); |
+ } |
+ |
+ if (!plugin) { |
+ if (renderer && !renderer->showsUnavailablePluginIndicator()) |
renderer->setPluginUnavailabilityReason(RenderEmbeddedObject::PluginMissing); |
return false; |
} |
- renderer->setWidget(widget); |
- document().setContainsPlugins(); |
+ ASSERT(plugin->isPluginContainer()); |
+ |
+ if (renderer) { |
+ // FIXME: We assume we don't layout without a renderer, but check this assumption. |
eseidel
2013/12/18 18:38:18
I'm not sure I understand this comment.
wjmaclean
2013/12/23 23:49:53
This was just a reminder to myself ... removed.
|
+ setWidget(plugin); |
+ m_persistedPluginWidget = 0; |
+ } else { |
+ if (plugin != m_persistedPluginWidget) |
+ m_persistedPluginWidget = plugin; |
+ } |
+ // FIXME: it may be that nothing has change (we might be continuing to |
eseidel
2013/12/18 18:38:18
No, the recalc style is only needed to trigger ren
wjmaclean
2013/12/23 23:49:53
recalc style removed.
|
+ // persist the same plugin? In that case, would we need to recalc style? |
setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer); |
+ document().setContainsPlugins(); |
return true; |
} |