Home | History | Annotate | Download | only in html
      1 /**
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2000 Stefan Schimanski (1Stein (at) 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 "core/html/HTMLPlugInElement.h"
     25 
     26 #include "CSSPropertyNames.h"
     27 #include "HTMLNames.h"
     28 #include "bindings/v8/ScriptController.h"
     29 #include "bindings/v8/npruntime_impl.h"
     30 #include "core/dom/Document.h"
     31 #include "core/dom/Event.h"
     32 #include "core/page/EventHandler.h"
     33 #include "core/page/Frame.h"
     34 #include "core/platform/Widget.h"
     35 #include "core/plugins/PluginView.h"
     36 #include "core/rendering/RenderEmbeddedObject.h"
     37 #include "core/rendering/RenderWidget.h"
     38 #include "wtf/UnusedParam.h"
     39 
     40 
     41 namespace WebCore {
     42 
     43 using namespace HTMLNames;
     44 
     45 HTMLPlugInElement::HTMLPlugInElement(const QualifiedName& tagName, Document* doc)
     46     : HTMLFrameOwnerElement(tagName, doc)
     47     , m_NPObject(0)
     48     , m_isCapturingMouseEvents(false)
     49     , m_inBeforeLoadEventHandler(false)
     50     , m_displayState(Playing)
     51 {
     52 }
     53 
     54 HTMLPlugInElement::~HTMLPlugInElement()
     55 {
     56     ASSERT(!m_instance); // cleared in detach()
     57 
     58     if (m_NPObject) {
     59         _NPN_ReleaseObject(m_NPObject);
     60         m_NPObject = 0;
     61     }
     62 }
     63 
     64 bool HTMLPlugInElement::canProcessDrag() const
     65 {
     66     const PluginView* plugin = pluginWidget() && pluginWidget()->isPluginView() ? static_cast<const PluginView*>(pluginWidget()) : 0;
     67     return plugin ? plugin->canProcessDrag() : false;
     68 }
     69 
     70 bool HTMLPlugInElement::willRespondToMouseClickEvents()
     71 {
     72     if (isDisabledFormControl())
     73         return false;
     74     RenderObject* r = renderer();
     75     if (!r)
     76         return false;
     77     if (!r->isEmbeddedObject() && !r->isWidget())
     78         return false;
     79     return true;
     80 }
     81 
     82 void HTMLPlugInElement::detach(const AttachContext& context)
     83 {
     84     m_instance.clear();
     85 
     86     if (m_isCapturingMouseEvents) {
     87         if (Frame* frame = document()->frame())
     88             frame->eventHandler()->setCapturingMouseEventsNode(0);
     89         m_isCapturingMouseEvents = false;
     90     }
     91 
     92     if (m_NPObject) {
     93         _NPN_ReleaseObject(m_NPObject);
     94         m_NPObject = 0;
     95     }
     96 
     97     HTMLFrameOwnerElement::detach(context);
     98 }
     99 
    100 void HTMLPlugInElement::resetInstance()
    101 {
    102     m_instance.clear();
    103 }
    104 
    105 PassScriptInstance HTMLPlugInElement::getInstance()
    106 {
    107     Frame* frame = document()->frame();
    108     if (!frame)
    109         return 0;
    110 
    111     // If the host dynamically turns off JavaScript (or Java) we will still return
    112     // the cached allocated Bindings::Instance.  Not supporting this edge-case is OK.
    113     if (m_instance)
    114         return m_instance;
    115 
    116     if (Widget* widget = pluginWidget())
    117         m_instance = frame->script()->createScriptInstanceForWidget(widget);
    118 
    119     return m_instance;
    120 }
    121 
    122 bool HTMLPlugInElement::dispatchBeforeLoadEvent(const String& sourceURL)
    123 {
    124     // FIXME: Our current plug-in loading design can't guarantee the following
    125     // assertion is true, since plug-in loading can be initiated during layout,
    126     // and synchronous layout can be initiated in a beforeload event handler!
    127     // See <http://webkit.org/b/71264>.
    128     // ASSERT(!m_inBeforeLoadEventHandler);
    129     m_inBeforeLoadEventHandler = true;
    130     bool beforeLoadAllowedLoad = HTMLFrameOwnerElement::dispatchBeforeLoadEvent(sourceURL);
    131     m_inBeforeLoadEventHandler = false;
    132     return beforeLoadAllowedLoad;
    133 }
    134 
    135 Widget* HTMLPlugInElement::pluginWidget() const
    136 {
    137     if (m_inBeforeLoadEventHandler) {
    138         // 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.
    139         // That would recursively call beforeload for the same element.
    140         return 0;
    141     }
    142 
    143     RenderWidget* renderWidget = renderWidgetForJSBindings();
    144     if (!renderWidget)
    145         return 0;
    146 
    147     return renderWidget->widget();
    148 }
    149 
    150 bool HTMLPlugInElement::isPresentationAttribute(const QualifiedName& name) const
    151 {
    152     if (name == widthAttr || name == heightAttr || name == vspaceAttr || name == hspaceAttr || name == alignAttr)
    153         return true;
    154     return HTMLFrameOwnerElement::isPresentationAttribute(name);
    155 }
    156 
    157 void HTMLPlugInElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
    158 {
    159     if (name == widthAttr)
    160         addHTMLLengthToStyle(style, CSSPropertyWidth, value);
    161     else if (name == heightAttr)
    162         addHTMLLengthToStyle(style, CSSPropertyHeight, value);
    163     else if (name == vspaceAttr) {
    164         addHTMLLengthToStyle(style, CSSPropertyMarginTop, value);
    165         addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value);
    166     } else if (name == hspaceAttr) {
    167         addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value);
    168         addHTMLLengthToStyle(style, CSSPropertyMarginRight, value);
    169     } else if (name == alignAttr)
    170         applyAlignmentAttributeToStyle(value, style);
    171     else
    172         HTMLFrameOwnerElement::collectStyleForPresentationAttribute(name, value, style);
    173 }
    174 
    175 void HTMLPlugInElement::defaultEventHandler(Event* event)
    176 {
    177     // Firefox seems to use a fake event listener to dispatch events to plug-in (tested with mouse events only).
    178     // This is observable via different order of events - in Firefox, event listeners specified in HTML attributes fires first, then an event
    179     // gets dispatched to plug-in, and only then other event listeners fire. Hopefully, this difference does not matter in practice.
    180 
    181     // FIXME: Mouse down and scroll events are passed down to plug-in via custom code in EventHandler; these code paths should be united.
    182 
    183     RenderObject* r = renderer();
    184     if (r && r->isEmbeddedObject()) {
    185         if (toRenderEmbeddedObject(r)->showsUnavailablePluginIndicator())
    186             return;
    187 
    188         if (displayState() < Playing)
    189             return;
    190     }
    191 
    192     if (!r || !r->isWidget())
    193         return;
    194     RefPtr<Widget> widget = toRenderWidget(r)->widget();
    195     if (!widget)
    196         return;
    197     widget->handleEvent(event);
    198     if (event->defaultHandled())
    199         return;
    200     HTMLFrameOwnerElement::defaultEventHandler(event);
    201 }
    202 
    203 bool HTMLPlugInElement::isKeyboardFocusable() const
    204 {
    205     if (!document()->page())
    206         return false;
    207 
    208     const PluginView* plugin = pluginWidget() && pluginWidget()->isPluginView() ? static_cast<const PluginView*>(pluginWidget()) : 0;
    209     if (plugin)
    210         return plugin->supportsKeyboardFocus();
    211 
    212     return false;
    213 }
    214 
    215 bool HTMLPlugInElement::isPluginElement() const
    216 {
    217     return true;
    218 }
    219 
    220 bool HTMLPlugInElement::rendererIsFocusable() const
    221 {
    222     if (HTMLFrameOwnerElement::supportsFocus() && HTMLFrameOwnerElement::rendererIsFocusable())
    223         return true;
    224 
    225     if (useFallbackContent() || !renderer() || !renderer()->isEmbeddedObject())
    226         return false;
    227     return !toRenderEmbeddedObject(renderer())->showsUnavailablePluginIndicator();
    228 }
    229 
    230 NPObject* HTMLPlugInElement::getNPObject()
    231 {
    232     ASSERT(document()->frame());
    233     if (!m_NPObject)
    234         m_NPObject = document()->frame()->script()->createScriptObjectForPluginElement(this);
    235     return m_NPObject;
    236 }
    237 
    238 }
    239