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 "HTMLPlugInElement.h" 25 26 #include "Attribute.h" 27 #include "Chrome.h" 28 #include "ChromeClient.h" 29 #include "CSSPropertyNames.h" 30 #include "Document.h" 31 #include "Frame.h" 32 #include "FrameLoader.h" 33 #include "FrameTree.h" 34 #include "HTMLNames.h" 35 #include "Page.h" 36 #include "RenderEmbeddedObject.h" 37 #include "RenderWidget.h" 38 #include "ScriptController.h" 39 #include "Settings.h" 40 #include "Widget.h" 41 42 #if ENABLE(NETSCAPE_PLUGIN_API) 43 #include "npruntime_impl.h" 44 #endif 45 46 namespace WebCore { 47 48 using namespace HTMLNames; 49 50 HTMLPlugInElement::HTMLPlugInElement(const QualifiedName& tagName, Document* doc) 51 : HTMLFrameOwnerElement(tagName, doc) 52 , m_inBeforeLoadEventHandler(false) 53 #if ENABLE(NETSCAPE_PLUGIN_API) 54 , m_NPObject(0) 55 #endif 56 , m_isCapturingMouseEvents(false) 57 { 58 } 59 60 HTMLPlugInElement::~HTMLPlugInElement() 61 { 62 ASSERT(!m_instance); // cleared in detach() 63 64 #if ENABLE(NETSCAPE_PLUGIN_API) 65 if (m_NPObject) { 66 _NPN_ReleaseObject(m_NPObject); 67 m_NPObject = 0; 68 } 69 #endif 70 } 71 72 void HTMLPlugInElement::detach() 73 { 74 m_instance.clear(); 75 76 if (m_isCapturingMouseEvents) { 77 if (Frame* frame = document()->frame()) 78 frame->eventHandler()->setCapturingMouseEventsNode(0); 79 m_isCapturingMouseEvents = false; 80 } 81 82 HTMLFrameOwnerElement::detach(); 83 } 84 85 PassScriptInstance HTMLPlugInElement::getInstance() const 86 { 87 Frame* frame = document()->frame(); 88 if (!frame) 89 return 0; 90 91 // If the host dynamically turns off JavaScript (or Java) we will still return 92 // the cached allocated Bindings::Instance. Not supporting this edge-case is OK. 93 if (m_instance) 94 return m_instance; 95 96 if (Widget* widget = pluginWidget()) 97 m_instance = frame->script()->createScriptInstanceForWidget(widget); 98 99 return m_instance; 100 } 101 102 Widget* HTMLPlugInElement::pluginWidget() const 103 { 104 if (m_inBeforeLoadEventHandler) { 105 // 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. 106 // That would recursively call beforeload for the same element. 107 return 0; 108 } 109 110 RenderWidget* renderWidget = renderWidgetForJSBindings(); 111 if (!renderWidget) 112 return 0; 113 114 return renderWidget->widget(); 115 } 116 117 bool HTMLPlugInElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const 118 { 119 if (attrName == widthAttr || 120 attrName == heightAttr || 121 attrName == vspaceAttr || 122 attrName == hspaceAttr) { 123 result = eUniversal; 124 return false; 125 } 126 127 if (attrName == alignAttr) { 128 result = eReplaced; // Share with <img> since the alignment behavior is the same. 129 return false; 130 } 131 132 return HTMLFrameOwnerElement::mapToEntry(attrName, result); 133 } 134 135 void HTMLPlugInElement::parseMappedAttribute(Attribute* attr) 136 { 137 if (attr->name() == widthAttr) 138 addCSSLength(attr, CSSPropertyWidth, attr->value()); 139 else if (attr->name() == heightAttr) 140 addCSSLength(attr, CSSPropertyHeight, attr->value()); 141 else if (attr->name() == vspaceAttr) { 142 addCSSLength(attr, CSSPropertyMarginTop, attr->value()); 143 addCSSLength(attr, CSSPropertyMarginBottom, attr->value()); 144 } else if (attr->name() == hspaceAttr) { 145 addCSSLength(attr, CSSPropertyMarginLeft, attr->value()); 146 addCSSLength(attr, CSSPropertyMarginRight, attr->value()); 147 } else if (attr->name() == alignAttr) 148 addHTMLAlignment(attr); 149 else 150 HTMLFrameOwnerElement::parseMappedAttribute(attr); 151 } 152 153 void HTMLPlugInElement::defaultEventHandler(Event* event) 154 { 155 // Firefox seems to use a fake event listener to dispatch events to plug-in (tested with mouse events only). 156 // This is observable via different order of events - in Firefox, event listeners specified in HTML attributes fires first, then an event 157 // gets dispatched to plug-in, and only then other event listeners fire. Hopefully, this difference does not matter in practice. 158 159 // FIXME: Mouse down and scroll events are passed down to plug-in via custom code in EventHandler; these code paths should be united. 160 161 RenderObject* r = renderer(); 162 if (r && r->isEmbeddedObject() && toRenderEmbeddedObject(r)->showsMissingPluginIndicator()) { 163 toRenderEmbeddedObject(r)->handleMissingPluginIndicatorEvent(event); 164 return; 165 } 166 167 if (!r || !r->isWidget()) 168 return; 169 RefPtr<Widget> widget = toRenderWidget(r)->widget(); 170 if (!widget) 171 return; 172 widget->handleEvent(event); 173 } 174 175 #if ENABLE(NETSCAPE_PLUGIN_API) 176 177 NPObject* HTMLPlugInElement::getNPObject() 178 { 179 ASSERT(document()->frame()); 180 if (!m_NPObject) 181 m_NPObject = document()->frame()->script()->createScriptObjectForPluginElement(this); 182 return m_NPObject; 183 } 184 185 #endif /* ENABLE(NETSCAPE_PLUGIN_API) */ 186 187 #if PLATFORM(ANDROID) 188 bool HTMLPlugInElement::supportsFocus() const 189 { 190 return true; 191 } 192 #endif 193 194 } 195