Chromium Code Reviews| Index: Source/core/html/HTMLPlugInElement.cpp | 
| diff --git a/Source/core/html/HTMLPlugInElement.cpp b/Source/core/html/HTMLPlugInElement.cpp | 
| index ebbbdd8bfaca2ce0bf9ed10d389d7796e00871be..c6d1a4698dc96017a18dc00a7f5b890a5dca6418 100644 | 
| --- a/Source/core/html/HTMLPlugInElement.cpp | 
| +++ b/Source/core/html/HTMLPlugInElement.cpp | 
| @@ -82,7 +82,7 @@ HTMLPlugInElement::~HTMLPlugInElement() | 
| bool HTMLPlugInElement::canProcessDrag() const | 
| { | 
| - return pluginWidget() && pluginWidget()->isPluginView() && toPluginView(pluginWidget())->canProcessDrag(); | 
| + return widget() && widget()->isPluginView() && toPluginView(widget())->canProcessDrag(); | 
| } | 
| bool HTMLPlugInElement::willRespondToMouseClickEvents() | 
| @@ -136,12 +136,46 @@ void HTMLPlugInElement::updateWidgetIfNecessary() | 
| if (!needsWidgetUpdate() || useFallbackContent() || isImageType()) | 
| return; | 
| + | 
| + if (!renderEmbeddedObject() && !m_serviceType.isEmpty()) { | 
| + createPluginWithoutRenderer(m_serviceType); | 
| + return; | 
| + } | 
| + | 
| if (!renderEmbeddedObject() || renderEmbeddedObject()->showsUnavailablePluginIndicator()) | 
| return; | 
| updateWidget(CreateOnlyNonNetscapePlugins); | 
| } | 
| +void HTMLPlugInElement::createPluginWithoutRenderer(const String& mimeType) | 
| +{ | 
| + KURL url; | 
| + Vector<String> paramNames; | 
| + Vector<String> paramValues; | 
| + | 
| + paramNames.append("type"); | 
| + paramValues.append(mimeType); | 
| + | 
| + bool useFallback = false; | 
| + if (loadPlugin(url, mimeType, paramNames, paramValues, useFallback)) { | 
| + // Register the bindings with V8 as a scriptable object; normally this | 
| + // as done in getInstance(), but that is only called after a renderer | 
| + // has been assigned. | 
| + // If we've created a plugin without a renderer, it may want to be able | 
| + // to configure itself before attach, so make sure it has a script | 
| + // object. | 
| + // FIXME: Do we need a new script object and plugin wrapper when we | 
| + // create a plugin? Or can we re-use any existing ones? | 
| + Widget* plugin = widget(); | 
| + ASSERT(plugin); | 
| + Frame* frame = document().frame(); | 
| + if (!m_NPObject) | 
| + m_NPObject = frame->script().createScriptObjectForPluginElement(this); | 
| + m_pluginWrapper = frame->script().createPluginWrapper(plugin); | 
| + } | 
| +} | 
| + | 
| void HTMLPlugInElement::detach(const AttachContext& context) | 
| { | 
| // Update the widget the next time we attach (detaching destroys the plugin). | 
| @@ -149,7 +183,13 @@ void HTMLPlugInElement::detach(const AttachContext& context) | 
| if (renderer() && !useFallbackContent()) | 
| setNeedsWidgetUpdate(true); | 
| - resetInstance(); | 
| + Widget* plugin = widget(); | 
| + if (plugin) { | 
| 
 
eseidel
2013/12/02 16:28:34
Just combine these two ifs into one line?
 
wjmaclean
2013/12/02 21:51:55
This disappears in the new patch :-)
 
 | 
| + if (!plugin->pluginShouldPersist()) { | 
| + setWidget(0); | 
| + resetInstance(); | 
| + } | 
| + } | 
| if (m_isCapturingMouseEvents) { | 
| if (Frame* frame = document().frame()) | 
| @@ -215,8 +255,8 @@ 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); | 
| + if (Widget* plugin = widget()) | 
| + m_pluginWrapper = frame->script().createPluginWrapper(plugin); | 
| } | 
| return m_pluginWrapper.get(); | 
| } | 
| @@ -234,20 +274,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) | 
| @@ -317,7 +343,7 @@ bool HTMLPlugInElement::isKeyboardFocusable() const | 
| { | 
| if (!document().page()) | 
| return false; | 
| - return pluginWidget() && pluginWidget()->isPluginView() && toPluginView(pluginWidget())->supportsKeyboardFocus(); | 
| + return widget() && widget()->isPluginView() && toPluginView(widget())->supportsKeyboardFocus(); | 
| } | 
| bool HTMLPlugInElement::isPluginElement() const | 
| @@ -429,28 +455,43 @@ bool HTMLPlugInElement::loadPlugin(const KURL& url, const String& mimeType, cons | 
| if (!pluginIsLoadable(url, mimeType)) | 
| return false; | 
| + bool canCreateWithoutRenderer = frame->loader().client()->canCreatePluginWithoutRenderer(mimeType); | 
| + | 
| RenderEmbeddedObject* renderer = renderEmbeddedObject(); | 
| // FIXME: This code should not depend on renderer! | 
| - if (!renderer || useFallback) | 
| + if ((!renderer && !canCreateWithoutRenderer) || useFallback) | 
| return false; | 
| + FrameLoaderClient::PluginLoadType loadType = renderer ? FrameLoaderClient::PluginLoadRequiresRenderer : FrameLoaderClient::PluginLoadWithoutRenderer; | 
| + | 
| LOG(Plugins, "%p Plug-in URL: %s", this, m_url.utf8().data()); | 
| 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 = widget(); | 
| + | 
| + 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 (!widget) { | 
| - if (!renderer->showsUnavailablePluginIndicator()) | 
| + if (!plugin) { | 
| + if (renderer && !renderer->showsUnavailablePluginIndicator()) | 
| renderer->setPluginUnavailabilityReason(RenderEmbeddedObject::PluginMissing); | 
| return false; | 
| } | 
| - renderer->setWidget(widget); | 
| + ASSERT(plugin->isPluginContainer()); | 
| + setWidget(plugin); | 
| + | 
| + if (renderer) { | 
| + // FIXME: We assume we don't layout without a renderer, but check this assumption. | 
| 
 
eseidel
2013/12/02 16:28:34
style recalc creates/destroys renderers.  I doubt
 
wjmaclean
2013/12/02 21:51:55
Thanks, that's useful to know. I'll remove the if(
 
 | 
| + setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer); | 
| + } | 
| document().setContainsPlugins(); | 
| - setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer); | 
| return true; | 
| } |