Chromium Code Reviews| 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; |
| } |