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, 2008, 2009, 2011 Apple Inc. All rights reserved. 6 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public License 19 * along with this library; see the file COPYING.LIB. If not, write to 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301, USA. 22 */ 23 24 #include "config.h" 25 #include "HTMLEmbedElement.h" 26 27 #include "Attribute.h" 28 #include "CSSPropertyNames.h" 29 #include "DocumentLoader.h" 30 #include "Frame.h" 31 #include "HTMLDocument.h" 32 #include "HTMLImageLoader.h" 33 #include "HTMLNames.h" 34 #include "HTMLObjectElement.h" 35 #include "HTMLParserIdioms.h" 36 #include "MainResourceLoader.h" 37 #include "PluginDocument.h" 38 #include "RenderEmbeddedObject.h" 39 #include "RenderImage.h" 40 #include "RenderWidget.h" 41 #include "ScriptController.h" 42 #include "Settings.h" 43 44 namespace WebCore { 45 46 using namespace HTMLNames; 47 48 inline HTMLEmbedElement::HTMLEmbedElement(const QualifiedName& tagName, Document* document, bool createdByParser) 49 : HTMLPlugInImageElement(tagName, document, createdByParser, ShouldPreferPlugInsForImages) 50 { 51 ASSERT(hasTagName(embedTag)); 52 } 53 54 PassRefPtr<HTMLEmbedElement> HTMLEmbedElement::create(const QualifiedName& tagName, Document* document, bool createdByParser) 55 { 56 return adoptRef(new HTMLEmbedElement(tagName, document, createdByParser)); 57 } 58 59 static inline RenderWidget* findWidgetRenderer(const Node* n) 60 { 61 if (!n->renderer()) 62 do 63 n = n->parentNode(); 64 while (n && !n->hasTagName(objectTag)); 65 66 if (n && n->renderer() && n->renderer()->isWidget()) 67 return toRenderWidget(n->renderer()); 68 69 return 0; 70 } 71 72 RenderWidget* HTMLEmbedElement::renderWidgetForJSBindings() const 73 { 74 document()->updateLayoutIgnorePendingStylesheets(); 75 return findWidgetRenderer(this); 76 } 77 78 bool HTMLEmbedElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const 79 { 80 if (attrName == hiddenAttr) { 81 result = eUniversal; 82 return false; 83 } 84 85 return HTMLPlugInImageElement::mapToEntry(attrName, result); 86 } 87 88 void HTMLEmbedElement::parseMappedAttribute(Attribute* attr) 89 { 90 const AtomicString& value = attr->value(); 91 92 if (attr->name() == typeAttr) { 93 m_serviceType = value.string().lower(); 94 size_t pos = m_serviceType.find(";"); 95 if (pos != notFound) 96 m_serviceType = m_serviceType.left(pos); 97 if (!isImageType() && m_imageLoader) 98 m_imageLoader.clear(); 99 } else if (attr->name() == codeAttr) 100 m_url = stripLeadingAndTrailingHTMLSpaces(value.string()); 101 else if (attr->name() == srcAttr) { 102 m_url = stripLeadingAndTrailingHTMLSpaces(value.string()); 103 if (renderer() && isImageType()) { 104 if (!m_imageLoader) 105 m_imageLoader = adoptPtr(new HTMLImageLoader(this)); 106 m_imageLoader->updateFromElementIgnoringPreviousError(); 107 } 108 } else if (attr->name() == hiddenAttr) { 109 if (equalIgnoringCase(value.string(), "yes") || equalIgnoringCase(value.string(), "true")) { 110 // FIXME: Not dynamic, since we add this but don't remove it, but it may be OK for now 111 // that this rarely-used attribute won't work properly if you remove it. 112 addCSSLength(attr, CSSPropertyWidth, "0"); 113 addCSSLength(attr, CSSPropertyHeight, "0"); 114 } 115 } else if (attr->name() == nameAttr) { 116 if (inDocument() && document()->isHTMLDocument()) { 117 HTMLDocument* document = static_cast<HTMLDocument*>(this->document()); 118 document->removeNamedItem(m_name); 119 document->addNamedItem(value); 120 } 121 m_name = value; 122 } else 123 HTMLPlugInImageElement::parseMappedAttribute(attr); 124 } 125 126 void HTMLEmbedElement::parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues) 127 { 128 NamedNodeMap* attributes = this->attributes(true); 129 if (!attributes) 130 return; 131 132 for (unsigned i = 0; i < attributes->length(); ++i) { 133 Attribute* it = attributes->attributeItem(i); 134 paramNames.append(it->localName().string()); 135 paramValues.append(it->value().string()); 136 } 137 } 138 139 // FIXME: This should be unified with HTMLObjectElement::updateWidget and 140 // moved down into HTMLPluginImageElement.cpp 141 void HTMLEmbedElement::updateWidget(PluginCreationOption pluginCreationOption) 142 { 143 ASSERT(!renderEmbeddedObject()->pluginCrashedOrWasMissing()); 144 // FIXME: We should ASSERT(needsWidgetUpdate()), but currently 145 // FrameView::updateWidget() calls updateWidget(false) without checking if 146 // the widget actually needs updating! 147 setNeedsWidgetUpdate(false); 148 149 if (m_url.isEmpty() && m_serviceType.isEmpty()) 150 return; 151 152 // Note these pass m_url and m_serviceType to allow better code sharing with 153 // <object> which modifies url and serviceType before calling these. 154 if (!allowedToLoadFrameURL(m_url)) 155 return; 156 // FIXME: It's sadness that we have this special case here. 157 // See http://trac.webkit.org/changeset/25128 and 158 // plugins/netscape-plugin-setwindow-size.html 159 if (pluginCreationOption == CreateOnlyNonNetscapePlugins && wouldLoadAsNetscapePlugin(m_url, m_serviceType)) 160 return; 161 162 // FIXME: These should be joined into a PluginParameters class. 163 Vector<String> paramNames; 164 Vector<String> paramValues; 165 parametersForPlugin(paramNames, paramValues); 166 167 ASSERT(!m_inBeforeLoadEventHandler); 168 m_inBeforeLoadEventHandler = true; 169 bool beforeLoadAllowedLoad = dispatchBeforeLoadEvent(m_url); 170 m_inBeforeLoadEventHandler = false; 171 172 if (!beforeLoadAllowedLoad) { 173 if (document()->isPluginDocument()) { 174 // Plugins inside plugin documents load differently than other plugins. By the time 175 // we are here in a plugin document, the load of the plugin (which is the plugin document's 176 // main resource) has already started. We need to explicitly cancel the main resource load here. 177 toPluginDocument(document())->cancelManualPluginLoad(); 178 } 179 return; 180 } 181 182 SubframeLoader* loader = document()->frame()->loader()->subframeLoader(); 183 // FIXME: beforeLoad could have detached the renderer! Just like in the <object> case above. 184 loader->requestObject(this, m_url, getAttribute(nameAttr), m_serviceType, paramNames, paramValues); 185 } 186 187 bool HTMLEmbedElement::rendererIsNeeded(RenderStyle* style) 188 { 189 if (isImageType()) 190 return HTMLPlugInImageElement::rendererIsNeeded(style); 191 192 Frame* frame = document()->frame(); 193 if (!frame) 194 return false; 195 196 // If my parent is an <object> and is not set to use fallback content, I 197 // should be ignored and not get a renderer. 198 ContainerNode* p = parentNode(); 199 if (p && p->hasTagName(objectTag)) { 200 ASSERT(p->renderer()); 201 if (!static_cast<HTMLObjectElement*>(p)->useFallbackContent()) { 202 ASSERT(!p->renderer()->isEmbeddedObject()); 203 return false; 204 } 205 } 206 207 #if ENABLE(DASHBOARD_SUPPORT) 208 // Workaround for <rdar://problem/6642221>. 209 if (Settings* settings = frame->settings()) { 210 if (settings->usesDashboardBackwardCompatibilityMode()) 211 return true; 212 } 213 #endif 214 215 return HTMLPlugInImageElement::rendererIsNeeded(style); 216 } 217 218 void HTMLEmbedElement::insertedIntoDocument() 219 { 220 HTMLPlugInImageElement::insertedIntoDocument(); 221 if (!inDocument()) 222 return; 223 224 if (document()->isHTMLDocument()) 225 static_cast<HTMLDocument*>(document())->addNamedItem(m_name); 226 227 String width = getAttribute(widthAttr); 228 String height = getAttribute(heightAttr); 229 if (!width.isEmpty() || !height.isEmpty()) { 230 Node* n = parentNode(); 231 while (n && !n->hasTagName(objectTag)) 232 n = n->parentNode(); 233 if (n) { 234 if (!width.isEmpty()) 235 static_cast<HTMLObjectElement*>(n)->setAttribute(widthAttr, width); 236 if (!height.isEmpty()) 237 static_cast<HTMLObjectElement*>(n)->setAttribute(heightAttr, height); 238 } 239 } 240 } 241 242 void HTMLEmbedElement::removedFromDocument() 243 { 244 if (document()->isHTMLDocument()) 245 static_cast<HTMLDocument*>(document())->removeNamedItem(m_name); 246 247 HTMLPlugInImageElement::removedFromDocument(); 248 } 249 250 void HTMLEmbedElement::attributeChanged(Attribute* attr, bool preserveDecls) 251 { 252 HTMLPlugInImageElement::attributeChanged(attr, preserveDecls); 253 254 if ((attr->name() == widthAttr || attr->name() == heightAttr) && !attr->isEmpty()) { 255 ContainerNode* n = parentNode(); 256 while (n && !n->hasTagName(objectTag)) 257 n = n->parentNode(); 258 if (n) 259 static_cast<HTMLObjectElement*>(n)->setAttribute(attr->name(), attr->value()); 260 } 261 } 262 263 bool HTMLEmbedElement::isURLAttribute(Attribute* attr) const 264 { 265 return attr->name() == srcAttr; 266 } 267 268 const QualifiedName& HTMLEmbedElement::imageSourceAttributeName() const 269 { 270 return srcAttr; 271 } 272 273 void HTMLEmbedElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const 274 { 275 HTMLPlugInImageElement::addSubresourceAttributeURLs(urls); 276 277 addSubresourceURL(urls, document()->completeURL(getAttribute(srcAttr))); 278 } 279 280 } 281