c33e2f8b9c0d4d9b3fe995d40683a7299e0902f5
[WebKit-https.git] / Source / WebCore / html / HTMLEmbedElement.cpp
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, 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 "FrameLoader.h"
32 #include "HTMLDocument.h"
33 #include "HTMLImageLoader.h"
34 #include "HTMLNames.h"
35 #include "HTMLObjectElement.h"
36 #include "HTMLParserIdioms.h"
37 #include "MainResourceLoader.h"
38 #include "PluginDocument.h"
39 #include "RenderEmbeddedObject.h"
40 #include "RenderImage.h"
41 #include "RenderWidget.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::isPresentationAttribute(const QualifiedName& name) const
79 {
80     if (name == hiddenAttr)
81         return true;
82     return HTMLPlugInImageElement::isPresentationAttribute(name);
83 }
84
85 void HTMLEmbedElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
86 {
87     if (name == hiddenAttr) {
88         if (equalIgnoringCase(value, "yes") || equalIgnoringCase(value, "true")) {
89             addPropertyToPresentationAttributeStyle(style, CSSPropertyWidth, 0, CSSPrimitiveValue::CSS_PX);
90             addPropertyToPresentationAttributeStyle(style, CSSPropertyHeight, 0, CSSPrimitiveValue::CSS_PX);
91         }
92     } else
93         HTMLPlugInImageElement::collectStyleForPresentationAttribute(name, value, style);
94 }
95
96 void HTMLEmbedElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
97 {
98     if (name == typeAttr) {
99         m_serviceType = value.string().lower();
100         size_t pos = m_serviceType.find(";");
101         if (pos != notFound)
102             m_serviceType = m_serviceType.left(pos);
103     } else if (name == codeAttr)
104         m_url = stripLeadingAndTrailingHTMLSpaces(value);
105     else if (name == srcAttr) {
106         m_url = stripLeadingAndTrailingHTMLSpaces(value);
107         if (renderer() && isImageType()) {
108             if (!m_imageLoader)
109                 m_imageLoader = adoptPtr(new HTMLImageLoader(this));
110             m_imageLoader->updateFromElementIgnoringPreviousError();
111         }
112     } else
113         HTMLPlugInImageElement::parseAttribute(name, value);
114 }
115
116 void HTMLEmbedElement::parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues)
117 {
118     if (!hasAttributes())
119         return;
120
121     for (unsigned i = 0; i < attributeCount(); ++i) {
122         const Attribute* attribute = attributeItem(i);
123         paramNames.append(attribute->localName().string());
124         paramValues.append(attribute->value().string());
125     }
126 }
127
128 // FIXME: This should be unified with HTMLObjectElement::updateWidget and
129 // moved down into HTMLPluginImageElement.cpp
130 void HTMLEmbedElement::updateWidget(PluginCreationOption pluginCreationOption)
131 {
132     ASSERT(!renderEmbeddedObject()->showsUnavailablePluginIndicator());
133     ASSERT(needsWidgetUpdate());
134     setNeedsWidgetUpdate(false);
135
136     if (m_url.isEmpty() && m_serviceType.isEmpty())
137         return;
138
139     // Note these pass m_url and m_serviceType to allow better code sharing with
140     // <object> which modifies url and serviceType before calling these.
141     if (!allowedToLoadFrameURL(m_url))
142         return;
143
144     // FIXME: It's sadness that we have this special case here.
145     //        See http://trac.webkit.org/changeset/25128 and
146     //        plugins/netscape-plugin-setwindow-size.html
147     if (pluginCreationOption == CreateOnlyNonNetscapePlugins && wouldLoadAsNetscapePlugin(m_url, m_serviceType)) {
148         // Ensure updateWidget() is called again during layout to create the Netscape plug-in.
149         setNeedsWidgetUpdate(true);
150         return;
151     }
152
153     // FIXME: These should be joined into a PluginParameters class.
154     Vector<String> paramNames;
155     Vector<String> paramValues;
156     parametersForPlugin(paramNames, paramValues);
157
158     RefPtr<HTMLEmbedElement> protect(this); // Loading the plugin might remove us from the document.
159     bool beforeLoadAllowedLoad = guardedDispatchBeforeLoadEvent(m_url);
160     if (!beforeLoadAllowedLoad) {
161         if (document()->isPluginDocument()) {
162             // Plugins inside plugin documents load differently than other plugins. By the time
163             // we are here in a plugin document, the load of the plugin (which is the plugin document's
164             // main resource) has already started. We need to explicitly cancel the main resource load here.
165             toPluginDocument(document())->cancelManualPluginLoad();
166         }
167         return;
168     }
169     if (!renderer()) // Do not load the plugin if beforeload removed this element or its renderer.
170         return;
171
172     SubframeLoader* loader = document()->frame()->loader()->subframeLoader();
173     // FIXME: beforeLoad could have detached the renderer!  Just like in the <object> case above.
174     loader->requestObject(this, m_url, getNameAttribute(), m_serviceType, paramNames, paramValues);
175 }
176
177 bool HTMLEmbedElement::rendererIsNeeded(const NodeRenderingContext& context)
178 {
179     if (isImageType())
180         return HTMLPlugInImageElement::rendererIsNeeded(context);
181
182     Frame* frame = document()->frame();
183     if (!frame)
184         return false;
185
186     // If my parent is an <object> and is not set to use fallback content, I
187     // should be ignored and not get a renderer.
188     ContainerNode* p = parentNode();
189     if (p && p->hasTagName(objectTag)) {
190         ASSERT(p->renderer());
191         if (!static_cast<HTMLObjectElement*>(p)->useFallbackContent()) {
192             ASSERT(!p->renderer()->isEmbeddedObject());
193             return false;
194         }
195     }
196
197 #if ENABLE(DASHBOARD_SUPPORT)
198     // Workaround for <rdar://problem/6642221>. 
199     if (Settings* settings = frame->settings()) {
200         if (settings->usesDashboardBackwardCompatibilityMode())
201             return true;
202     }
203 #endif
204
205     return HTMLPlugInImageElement::rendererIsNeeded(context);
206 }
207
208 bool HTMLEmbedElement::isURLAttribute(const Attribute& attribute) const
209 {
210     return attribute.name() == srcAttr || HTMLPlugInImageElement::isURLAttribute(attribute);
211 }
212
213 const QualifiedName& HTMLEmbedElement::imageSourceAttributeName() const
214 {
215     return srcAttr;
216 }
217
218 void HTMLEmbedElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
219 {
220     HTMLPlugInImageElement::addSubresourceAttributeURLs(urls);
221
222     addSubresourceURL(urls, document()->completeURL(getAttribute(srcAttr)));
223 }
224
225 #if ENABLE(MICRODATA)
226 String HTMLEmbedElement::itemValueText() const
227 {
228     return getURLAttribute(srcAttr);
229 }
230
231 void HTMLEmbedElement::setItemValueText(const String& value, ExceptionCode&)
232 {
233     setAttribute(srcAttr, value);
234 }
235 #endif
236
237 }