1/** 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 4 * (C) 2000 Stefan Schimanski (1Stein@gmx.de) 5 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Library General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Library General Public License for more details. 16 * 17 * You should have received a copy of the GNU Library General Public License 18 * along with this library; see the file COPYING.LIB. If not, write to 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA. 21 */ 22 23#include "config.h" 24#include "HTMLPlugInElement.h" 25 26#include "Attribute.h" 27#include "BridgeJSC.h" 28#include "Chrome.h" 29#include "ChromeClient.h" 30#include "CSSPropertyNames.h" 31#include "Document.h" 32#include "Event.h" 33#include "EventHandler.h" 34#include "Frame.h" 35#include "FrameLoader.h" 36#include "FrameTree.h" 37#include "HTMLNames.h" 38#include "Page.h" 39#include "PluginViewBase.h" 40#include "RenderEmbeddedObject.h" 41#include "RenderSnapshottedPlugIn.h" 42#include "RenderWidget.h" 43#include "ScriptController.h" 44#include "Settings.h" 45#include "Widget.h" 46 47#if ENABLE(NETSCAPE_PLUGIN_API) 48#include "npruntime_impl.h" 49#endif 50 51namespace WebCore { 52 53using namespace HTMLNames; 54 55HTMLPlugInElement::HTMLPlugInElement(const QualifiedName& tagName, Document* doc) 56 : HTMLFrameOwnerElement(tagName, doc) 57 , m_inBeforeLoadEventHandler(false) 58#if ENABLE(NETSCAPE_PLUGIN_API) 59 , m_NPObject(0) 60#endif 61 , m_isCapturingMouseEvents(false) 62 , m_displayState(Playing) 63{ 64} 65 66HTMLPlugInElement::~HTMLPlugInElement() 67{ 68 ASSERT(!m_instance); // cleared in detach() 69 70#if ENABLE(NETSCAPE_PLUGIN_API) 71 if (m_NPObject) { 72 _NPN_ReleaseObject(m_NPObject); 73 m_NPObject = 0; 74 } 75#endif 76} 77 78bool HTMLPlugInElement::canProcessDrag() const 79{ 80 const PluginViewBase* plugin = pluginWidget() && pluginWidget()->isPluginViewBase() ? static_cast<const PluginViewBase*>(pluginWidget()) : 0; 81 return plugin ? plugin->canProcessDrag() : false; 82} 83 84bool HTMLPlugInElement::willRespondToMouseClickEvents() 85{ 86 if (isDisabledFormControl()) 87 return false; 88 RenderObject* r = renderer(); 89 if (!r) 90 return false; 91 if (!r->isEmbeddedObject() && !r->isWidget()) 92 return false; 93 return true; 94} 95 96void HTMLPlugInElement::detach(const AttachContext& context) 97{ 98 m_instance.clear(); 99 100 if (m_isCapturingMouseEvents) { 101 if (Frame* frame = document()->frame()) 102 frame->eventHandler()->setCapturingMouseEventsNode(0); 103 m_isCapturingMouseEvents = false; 104 } 105 106#if ENABLE(NETSCAPE_PLUGIN_API) 107 if (m_NPObject) { 108 _NPN_ReleaseObject(m_NPObject); 109 m_NPObject = 0; 110 } 111#endif 112 113 HTMLFrameOwnerElement::detach(context); 114} 115 116void HTMLPlugInElement::resetInstance() 117{ 118 m_instance.clear(); 119} 120 121PassRefPtr<JSC::Bindings::Instance> HTMLPlugInElement::getInstance() 122{ 123 Frame* frame = document()->frame(); 124 if (!frame) 125 return 0; 126 127 // If the host dynamically turns off JavaScript (or Java) we will still return 128 // the cached allocated Bindings::Instance. Not supporting this edge-case is OK. 129 if (m_instance) 130 return m_instance; 131 132 if (Widget* widget = pluginWidget()) 133 m_instance = frame->script()->createScriptInstanceForWidget(widget); 134 135 return m_instance; 136} 137 138bool HTMLPlugInElement::guardedDispatchBeforeLoadEvent(const String& sourceURL) 139{ 140 // FIXME: Our current plug-in loading design can't guarantee the following 141 // assertion is true, since plug-in loading can be initiated during layout, 142 // and synchronous layout can be initiated in a beforeload event handler! 143 // See <http://webkit.org/b/71264>. 144 // ASSERT(!m_inBeforeLoadEventHandler); 145 m_inBeforeLoadEventHandler = true; 146 // static_cast is used to avoid a compile error since dispatchBeforeLoadEvent 147 // is intentionally undefined on this class. 148 bool beforeLoadAllowedLoad = static_cast<HTMLFrameOwnerElement*>(this)->dispatchBeforeLoadEvent(sourceURL); 149 m_inBeforeLoadEventHandler = false; 150 return beforeLoadAllowedLoad; 151} 152 153Widget* HTMLPlugInElement::pluginWidget() const 154{ 155 if (m_inBeforeLoadEventHandler) { 156 // 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. 157 // That would recursively call beforeload for the same element. 158 return 0; 159 } 160 161 RenderWidget* renderWidget = renderWidgetForJSBindings(); 162 if (!renderWidget) 163 return 0; 164 165 return renderWidget->widget(); 166} 167 168bool HTMLPlugInElement::isPresentationAttribute(const QualifiedName& name) const 169{ 170 if (name == widthAttr || name == heightAttr || name == vspaceAttr || name == hspaceAttr || name == alignAttr) 171 return true; 172 return HTMLFrameOwnerElement::isPresentationAttribute(name); 173} 174 175void HTMLPlugInElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style) 176{ 177 if (name == widthAttr) 178 addHTMLLengthToStyle(style, CSSPropertyWidth, value); 179 else if (name == heightAttr) 180 addHTMLLengthToStyle(style, CSSPropertyHeight, value); 181 else if (name == vspaceAttr) { 182 addHTMLLengthToStyle(style, CSSPropertyMarginTop, value); 183 addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value); 184 } else if (name == hspaceAttr) { 185 addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value); 186 addHTMLLengthToStyle(style, CSSPropertyMarginRight, value); 187 } else if (name == alignAttr) 188 applyAlignmentAttributeToStyle(value, style); 189 else 190 HTMLFrameOwnerElement::collectStyleForPresentationAttribute(name, value, style); 191} 192 193void HTMLPlugInElement::defaultEventHandler(Event* event) 194{ 195 // Firefox seems to use a fake event listener to dispatch events to plug-in (tested with mouse events only). 196 // This is observable via different order of events - in Firefox, event listeners specified in HTML attributes fires first, then an event 197 // gets dispatched to plug-in, and only then other event listeners fire. Hopefully, this difference does not matter in practice. 198 199 // FIXME: Mouse down and scroll events are passed down to plug-in via custom code in EventHandler; these code paths should be united. 200 201 RenderObject* r = renderer(); 202 if (r && r->isEmbeddedObject()) { 203 if (toRenderEmbeddedObject(r)->isPluginUnavailable()) { 204 toRenderEmbeddedObject(r)->handleUnavailablePluginIndicatorEvent(event); 205 return; 206 } 207 208 if (r->isSnapshottedPlugIn() && displayState() < Restarting) { 209 toRenderSnapshottedPlugIn(r)->handleEvent(event); 210 HTMLFrameOwnerElement::defaultEventHandler(event); 211 return; 212 } 213 214 if (displayState() < Playing) 215 return; 216 } 217 218 if (!r || !r->isWidget()) 219 return; 220 RefPtr<Widget> widget = toRenderWidget(r)->widget(); 221 if (!widget) 222 return; 223 widget->handleEvent(event); 224 if (event->defaultHandled()) 225 return; 226 HTMLFrameOwnerElement::defaultEventHandler(event); 227} 228 229bool HTMLPlugInElement::isKeyboardFocusable(KeyboardEvent* event) const 230{ 231 UNUSED_PARAM(event); 232 if (!document()->page()) 233 return false; 234 235 const PluginViewBase* plugin = pluginWidget() && pluginWidget()->isPluginViewBase() ? static_cast<const PluginViewBase*>(pluginWidget()) : 0; 236 if (plugin) 237 return plugin->supportsKeyboardFocus(); 238 239 return false; 240} 241 242bool HTMLPlugInElement::isPluginElement() const 243{ 244 return true; 245} 246 247bool HTMLPlugInElement::supportsFocus() const 248{ 249 if (HTMLFrameOwnerElement::supportsFocus()) 250 return true; 251 252 if (useFallbackContent() || !renderer() || !renderer()->isEmbeddedObject()) 253 return false; 254 return !toRenderEmbeddedObject(renderer())->isPluginUnavailable(); 255} 256 257#if ENABLE(NETSCAPE_PLUGIN_API) 258 259NPObject* HTMLPlugInElement::getNPObject() 260{ 261 ASSERT(document()->frame()); 262 if (!m_NPObject) 263 m_NPObject = document()->frame()->script()->createScriptObjectForPluginElement(this); 264 return m_NPObject; 265} 266 267#endif /* ENABLE(NETSCAPE_PLUGIN_API) */ 268 269} 270