diff options
Diffstat (limited to 'Source/WebCore/html/HTMLPlugInElement.cpp')
-rw-r--r-- | Source/WebCore/html/HTMLPlugInElement.cpp | 168 |
1 files changed, 78 insertions, 90 deletions
diff --git a/Source/WebCore/html/HTMLPlugInElement.cpp b/Source/WebCore/html/HTMLPlugInElement.cpp index 93643c7a6..576831afa 100644 --- a/Source/WebCore/html/HTMLPlugInElement.cpp +++ b/Source/WebCore/html/HTMLPlugInElement.cpp @@ -1,8 +1,8 @@ -/** +/* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2000 Stefan Schimanski (1Stein@gmx.de) - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2004-2017 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -23,10 +23,7 @@ #include "config.h" #include "HTMLPlugInElement.h" -#include "Attribute.h" #include "BridgeJSC.h" -#include "Chrome.h" -#include "ChromeClient.h" #include "CSSPropertyNames.h" #include "Document.h" #include "Event.h" @@ -55,8 +52,9 @@ #include "npruntime_impl.h" #endif -#if PLATFORM(MAC) +#if PLATFORM(COCOA) #include "QuickTimePluginReplacement.h" +#include "YouTubePluginReplacement.h" #endif namespace WebCore { @@ -66,10 +64,7 @@ using namespace HTMLNames; HTMLPlugInElement::HTMLPlugInElement(const QualifiedName& tagName, Document& document) : HTMLFrameOwnerElement(tagName, document) , m_inBeforeLoadEventHandler(false) - , m_swapRendererTimer(this, &HTMLPlugInElement::swapRendererTimerFired) -#if ENABLE(NETSCAPE_PLUGIN_API) - , m_NPObject(0) -#endif + , m_swapRendererTimer(*this, &HTMLPlugInElement::swapRendererTimerFired) , m_isCapturingMouseEvents(false) , m_displayState(Playing) { @@ -79,18 +74,11 @@ HTMLPlugInElement::HTMLPlugInElement(const QualifiedName& tagName, Document& doc HTMLPlugInElement::~HTMLPlugInElement() { ASSERT(!m_instance); // cleared in detach() - -#if ENABLE(NETSCAPE_PLUGIN_API) - if (m_NPObject) { - _NPN_ReleaseObject(m_NPObject); - m_NPObject = 0; - } -#endif } bool HTMLPlugInElement::canProcessDrag() const { - const PluginViewBase* plugin = pluginWidget() && pluginWidget()->isPluginViewBase() ? toPluginViewBase(pluginWidget()) : nullptr; + const PluginViewBase* plugin = is<PluginViewBase>(pluginWidget()) ? downcast<PluginViewBase>(pluginWidget()) : nullptr; return plugin ? plugin->canProcessDrag() : false; } @@ -104,42 +92,34 @@ bool HTMLPlugInElement::willRespondToMouseClickEvents() void HTMLPlugInElement::willDetachRenderers() { - m_instance.clear(); + m_instance = nullptr; if (m_isCapturingMouseEvents) { if (Frame* frame = document().frame()) frame->eventHandler().setCapturingMouseEventsElement(nullptr); m_isCapturingMouseEvents = false; } - -#if ENABLE(NETSCAPE_PLUGIN_API) - if (m_NPObject) { - _NPN_ReleaseObject(m_NPObject); - m_NPObject = 0; - } -#endif } void HTMLPlugInElement::resetInstance() { - m_instance.clear(); + m_instance = nullptr; } -PassRefPtr<JSC::Bindings::Instance> HTMLPlugInElement::getInstance() +JSC::Bindings::Instance* HTMLPlugInElement::bindingsInstance() { - Frame* frame = document().frame(); + auto* frame = document().frame(); if (!frame) - return 0; + return nullptr; // If the host dynamically turns off JavaScript (or Java) we will still return // the cached allocated Bindings::Instance. Not supporting this edge-case is OK. - if (m_instance) - return m_instance; - - if (Widget* widget = pluginWidget()) - m_instance = frame->script().createScriptInstanceForWidget(widget); - return m_instance; + if (!m_instance) { + if (auto* widget = pluginWidget()) + m_instance = frame->script().createScriptInstanceForWidget(widget); + } + return m_instance.get(); } bool HTMLPlugInElement::guardedDispatchBeforeLoadEvent(const String& sourceURL) @@ -157,17 +137,17 @@ bool HTMLPlugInElement::guardedDispatchBeforeLoadEvent(const String& sourceURL) return beforeLoadAllowedLoad; } -Widget* HTMLPlugInElement::pluginWidget() const +Widget* HTMLPlugInElement::pluginWidget(PluginLoadingPolicy loadPolicy) 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; + return nullptr; } - RenderWidget* renderWidget = renderWidgetForJSBindings(); + RenderWidget* renderWidget = loadPolicy == PluginLoadingPolicy::Load ? renderWidgetLoadingPlugin() : this->renderWidget(); if (!renderWidget) - return 0; + return nullptr; return renderWidget->widget(); } @@ -197,7 +177,7 @@ void HTMLPlugInElement::collectStyleForPresentationAttribute(const QualifiedName HTMLFrameOwnerElement::collectStyleForPresentationAttribute(name, value, style); } -void HTMLPlugInElement::defaultEventHandler(Event* event) +void HTMLPlugInElement::defaultEventHandler(Event& event) { // Firefox seems to use a fake event listener to dispatch events to plug-in (tested with mouse events only). // This is observable via different order of events - in Firefox, event listeners specified in HTML attributes fires first, then an event @@ -206,17 +186,17 @@ void HTMLPlugInElement::defaultEventHandler(Event* event) // FIXME: Mouse down and scroll events are passed down to plug-in via custom code in EventHandler; these code paths should be united. auto renderer = this->renderer(); - if (!renderer || !renderer->isWidget()) + if (!is<RenderWidget>(renderer)) return; - if (renderer->isEmbeddedObject()) { - if (toRenderEmbeddedObject(renderer)->isPluginUnavailable()) { - toRenderEmbeddedObject(renderer)->handleUnavailablePluginIndicatorEvent(event); + if (is<RenderEmbeddedObject>(*renderer)) { + if (downcast<RenderEmbeddedObject>(*renderer).isPluginUnavailable()) { + downcast<RenderEmbeddedObject>(*renderer).handleUnavailablePluginIndicatorEvent(&event); return; } - if (toRenderEmbeddedObject(renderer)->isSnapshottedPlugIn() && displayState() < Restarting) { - toRenderSnapshottedPlugIn(renderer)->handleEvent(event); + if (is<RenderSnapshottedPlugIn>(*renderer) && displayState() < Restarting) { + downcast<RenderSnapshottedPlugIn>(*renderer).handleEvent(event); HTMLFrameOwnerElement::defaultEventHandler(event); return; } @@ -225,26 +205,29 @@ void HTMLPlugInElement::defaultEventHandler(Event* event) return; } - RefPtr<Widget> widget = toRenderWidget(renderer)->widget(); - if (!widget) - return; - widget->handleEvent(event); - if (event->defaultHandled()) - return; + // Don't keep the widget alive over the defaultEventHandler call, since that can do things like navigate. + { + RefPtr<Widget> widget = downcast<RenderWidget>(*renderer).widget(); + if (!widget) + return; + widget->handleEvent(&event); + if (event.defaultHandled()) + return; + } HTMLFrameOwnerElement::defaultEventHandler(event); } -bool HTMLPlugInElement::isKeyboardFocusable(KeyboardEvent*) const +bool HTMLPlugInElement::isKeyboardFocusable(KeyboardEvent&) const { // FIXME: Why is this check needed? if (!document().page()) return false; Widget* widget = pluginWidget(); - if (!widget || !widget->isPluginViewBase()) + if (!is<PluginViewBase>(widget)) return false; - return toPluginViewBase(widget)->supportsKeyboardFocus(); + return downcast<PluginViewBase>(*widget).supportsKeyboardFocus(); } bool HTMLPlugInElement::isPluginElement() const @@ -252,37 +235,42 @@ bool HTMLPlugInElement::isPluginElement() const return true; } -bool HTMLPlugInElement::supportsFocus() const +bool HTMLPlugInElement::isUserObservable() const { - if (HTMLFrameOwnerElement::supportsFocus()) + // No widget - can't be anything to see or hear here. + Widget* widget = pluginWidget(PluginLoadingPolicy::DoNotLoad); + if (!is<PluginViewBase>(widget)) + return false; + + PluginViewBase& pluginView = downcast<PluginViewBase>(*widget); + + // If audio is playing (or might be) then the plugin is detectable. + if (pluginView.audioHardwareActivity() != AudioHardwareActivityType::IsInactive) return true; - if (useFallbackContent() || !renderer() || !renderer()->isEmbeddedObject()) - return false; - return !toRenderEmbeddedObject(renderer())->isPluginUnavailable(); + // If the plugin is visible and not vanishingly small in either dimension it is detectable. + return pluginView.isVisible() && pluginView.width() > 2 && pluginView.height() > 2; } -#if ENABLE(NETSCAPE_PLUGIN_API) - -NPObject* HTMLPlugInElement::getNPObject() +bool HTMLPlugInElement::supportsFocus() const { - ASSERT(document().frame()); - if (!m_NPObject) - m_NPObject = document().frame()->script().createScriptObjectForPluginElement(this); - return m_NPObject; -} + if (HTMLFrameOwnerElement::supportsFocus()) + return true; -#endif /* ENABLE(NETSCAPE_PLUGIN_API) */ + if (useFallbackContent() || !is<RenderEmbeddedObject>(renderer())) + return false; + return !downcast<RenderEmbeddedObject>(*renderer()).isPluginUnavailable(); +} -RenderPtr<RenderElement> HTMLPlugInElement::createElementRenderer(PassRef<RenderStyle> style) +RenderPtr<RenderElement> HTMLPlugInElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition& insertionPosition) { if (m_pluginReplacement && m_pluginReplacement->willCreateRenderer()) - return m_pluginReplacement->createElementRenderer(*this, std::move(style)); + return m_pluginReplacement->createElementRenderer(*this, WTFMove(style), insertionPosition); - return createRenderer<RenderEmbeddedObject>(*this, std::move(style)); + return createRenderer<RenderEmbeddedObject>(*this, WTFMove(style)); } -void HTMLPlugInElement::swapRendererTimerFired(Timer<HTMLPlugInElement>&) +void HTMLPlugInElement::swapRendererTimerFired() { ASSERT(displayState() == PreparingPluginReplacement || displayState() == DisplayingSnapshot); if (userAgentShadowRoot()) @@ -307,33 +295,34 @@ void HTMLPlugInElement::didAddUserAgentShadowRoot(ShadowRoot* root) return; root->setResetStyleInheritance(true); - if (m_pluginReplacement->installReplacement(root)) { + if (m_pluginReplacement->installReplacement(*root)) { setDisplayState(DisplayingPluginReplacement); - setNeedsStyleRecalc(ReconstructRenderTree); + invalidateStyleAndRenderersForSubtree(); } } -#if PLATFORM(MAC) +#if PLATFORM(COCOA) static void registrar(const ReplacementPlugin&); #endif static Vector<ReplacementPlugin*>& registeredPluginReplacements() { - DEFINE_STATIC_LOCAL(Vector<ReplacementPlugin*>, registeredReplacements, ()); + static NeverDestroyed<Vector<ReplacementPlugin*>> registeredReplacements; static bool enginesQueried = false; if (enginesQueried) return registeredReplacements; enginesQueried = true; -#if PLATFORM(MAC) +#if PLATFORM(COCOA) QuickTimePluginReplacement::registerPluginReplacement(registrar); + YouTubePluginReplacement::registerPluginReplacement(registrar); #endif return registeredReplacements; } -#if PLATFORM(MAC) +#if PLATFORM(COCOA) static void registrar(const ReplacementPlugin& replacement) { registeredPluginReplacements().append(new ReplacementPlugin(replacement)); @@ -357,9 +346,10 @@ static ReplacementPlugin* pluginReplacementForType(const URL& url, const String& type = mimeTypeFromDataURL(url.string()); if (type.isEmpty() && !extension.isEmpty()) { - for (size_t i = 0; i < replacements.size(); i++) - if (replacements[i]->supportsFileExtension(extension)) - return replacements[i]; + for (auto* replacement : replacements) { + if (replacement->supportsFileExtension(extension) && replacement->supportsURL(url)) + return replacement; + } } if (type.isEmpty()) { @@ -371,18 +361,16 @@ static ReplacementPlugin* pluginReplacementForType(const URL& url, const String& if (type.isEmpty()) return nullptr; - for (unsigned i = 0; i < replacements.size(); i++) - if (replacements[i]->supportsType(type)) - return replacements[i]; + for (auto* replacement : replacements) { + if (replacement->supportsType(type) && replacement->supportsURL(url)) + return replacement; + } return nullptr; } bool HTMLPlugInElement::requestObject(const String& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues) { - if (!RuntimeEnabledFeatures::sharedFeatures().pluginReplacementEnabled()) - return false; - if (m_pluginReplacement) return true; @@ -391,7 +379,7 @@ bool HTMLPlugInElement::requestObject(const String& url, const String& mimeType, completedURL = document().completeURL(url); ReplacementPlugin* replacement = pluginReplacementForType(completedURL, mimeType); - if (!replacement) + if (!replacement || !replacement->isEnabledBySettings(document().settings())) return false; LOG(Plugins, "%p - Found plug-in replacement for %s.", this, completedURL.string().utf8().data()); |