summaryrefslogtreecommitdiff
path: root/Source/WebCore/html/HTMLPlugInElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/html/HTMLPlugInElement.cpp')
-rw-r--r--Source/WebCore/html/HTMLPlugInElement.cpp168
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());