CTTE: ImageLoader is always owned by an Element.
[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 "Frame.h"
30 #include "FrameLoader.h"
31 #include "FrameView.h"
32 #include "HTMLImageLoader.h"
33 #include "HTMLNames.h"
34 #include "HTMLObjectElement.h"
35 #include "HTMLParserIdioms.h"
36 #include "PluginDocument.h"
37 #include "RenderEmbeddedObject.h"
38 #include "RenderWidget.h"
39 #include "Settings.h"
40 #include "SubframeLoader.h"
41 #include <wtf/Ref.h>
42
43 namespace WebCore {
44
45 using namespace HTMLNames;
46
47 inline HTMLEmbedElement::HTMLEmbedElement(const QualifiedName& tagName, Document& document, bool createdByParser)
48     : HTMLPlugInImageElement(tagName, document, createdByParser, ShouldPreferPlugInsForImages)
49 {
50     ASSERT(hasTagName(embedTag));
51 }
52
53 PassRefPtr<HTMLEmbedElement> HTMLEmbedElement::create(const QualifiedName& tagName, Document& document, bool createdByParser)
54 {
55     return adoptRef(new HTMLEmbedElement(tagName, document, createdByParser));
56 }
57
58 static inline RenderWidget* findWidgetRenderer(const Node* n) 
59 {
60     if (!n->renderer())
61         do
62             n = n->parentNode();
63         while (n && !n->hasTagName(objectTag));
64
65     if (n && n->renderer() && n->renderer()->isWidget())
66         return toRenderWidget(n->renderer());
67
68     return 0;
69 }
70
71 RenderWidget* HTMLEmbedElement::renderWidgetForJSBindings() const
72 {
73     FrameView* view = document().view();
74     if (!view || (!view->isInLayout() && !view->isPainting()))
75         document().updateLayoutIgnorePendingStylesheets();
76     return findWidgetRenderer(this);
77 }
78
79 bool HTMLEmbedElement::isPresentationAttribute(const QualifiedName& name) const
80 {
81     if (name == hiddenAttr)
82         return true;
83     return HTMLPlugInImageElement::isPresentationAttribute(name);
84 }
85
86 void HTMLEmbedElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStyleProperties& style)
87 {
88     if (name == hiddenAttr) {
89         if (equalIgnoringCase(value, "yes") || equalIgnoringCase(value, "true")) {
90             addPropertyToPresentationAttributeStyle(style, CSSPropertyWidth, 0, CSSPrimitiveValue::CSS_PX);
91             addPropertyToPresentationAttributeStyle(style, CSSPropertyHeight, 0, CSSPrimitiveValue::CSS_PX);
92         }
93     } else
94         HTMLPlugInImageElement::collectStyleForPresentationAttribute(name, value, style);
95 }
96
97 void HTMLEmbedElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
98 {
99     if (name == typeAttr) {
100         m_serviceType = value.string().lower();
101         size_t pos = m_serviceType.find(";");
102         if (pos != notFound)
103             m_serviceType = m_serviceType.left(pos);
104     } else if (name == codeAttr)
105         m_url = stripLeadingAndTrailingHTMLSpaces(value);
106     else if (name == srcAttr) {
107         m_url = stripLeadingAndTrailingHTMLSpaces(value);
108         document().updateStyleIfNeeded();
109         if (renderer() && isImageType()) {
110             if (!m_imageLoader)
111                 m_imageLoader = adoptPtr(new HTMLImageLoader(*this));
112             m_imageLoader->updateFromElementIgnoringPreviousError();
113         }
114     } else
115         HTMLPlugInImageElement::parseAttribute(name, value);
116 }
117
118 void HTMLEmbedElement::parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues)
119 {
120     if (!hasAttributes())
121         return;
122
123     for (const Attribute& attribute : attributesIterator()) {
124         paramNames.append(attribute.localName().string());
125         paramValues.append(attribute.value().string());
126     }
127 }
128
129 // FIXME: This should be unified with HTMLObjectElement::updateWidget and
130 // moved down into HTMLPluginImageElement.cpp
131 void HTMLEmbedElement::updateWidget(PluginCreationOption pluginCreationOption)
132 {
133     ASSERT(!renderEmbeddedObject()->isPluginUnavailable());
134     ASSERT(needsWidgetUpdate());
135     setNeedsWidgetUpdate(false);
136
137     if (m_url.isEmpty() && m_serviceType.isEmpty())
138         return;
139
140     // Note these pass m_url and m_serviceType to allow better code sharing with
141     // <object> which modifies url and serviceType before calling these.
142     if (!allowedToLoadFrameURL(m_url))
143         return;
144
145     // FIXME: It's sadness that we have this special case here.
146     //        See http://trac.webkit.org/changeset/25128 and
147     //        plugins/netscape-plugin-setwindow-size.html
148     if (pluginCreationOption == CreateOnlyNonNetscapePlugins && wouldLoadAsNetscapePlugin(m_url, m_serviceType)) {
149         // Ensure updateWidget() is called again during layout to create the Netscape plug-in.
150         setNeedsWidgetUpdate(true);
151         return;
152     }
153
154     // FIXME: These should be joined into a PluginParameters class.
155     Vector<String> paramNames;
156     Vector<String> paramValues;
157     parametersForPlugin(paramNames, paramValues);
158
159     Ref<HTMLEmbedElement> protect(*this); // Loading the plugin might remove us from the document.
160     bool beforeLoadAllowedLoad = guardedDispatchBeforeLoadEvent(m_url);
161     if (!beforeLoadAllowedLoad) {
162         if (document().isPluginDocument()) {
163             // Plugins inside plugin documents load differently than other plugins. By the time
164             // we are here in a plugin document, the load of the plugin (which is the plugin document's
165             // main resource) has already started. We need to explicitly cancel the main resource load here.
166             toPluginDocument(&document())->cancelManualPluginLoad();
167         }
168         return;
169     }
170     if (!renderer()) // Do not load the plugin if beforeload removed this element or its renderer.
171         return;
172
173     // FIXME: beforeLoad could have detached the renderer!  Just like in the <object> case above.
174     requestObject(m_url, m_serviceType, paramNames, paramValues);
175 }
176
177 bool HTMLEmbedElement::rendererIsNeeded(const RenderStyle& style)
178 {
179     if (isImageType())
180         return HTMLPlugInImageElement::rendererIsNeeded(style);
181
182     // If my parent is an <object> and is not set to use fallback content, I
183     // should be ignored and not get a renderer.
184     ContainerNode* p = parentNode();
185     if (p && p->hasTagName(objectTag)) {
186         if (!p->renderer())
187             return false;
188         if (!toHTMLObjectElement(p)->useFallbackContent()) {
189             ASSERT(!p->renderer()->isEmbeddedObject());
190             return false;
191         }
192     }
193
194 #if ENABLE(DASHBOARD_SUPPORT)
195     // Workaround for <rdar://problem/6642221>.
196     if (document().frame()->settings().usesDashboardBackwardCompatibilityMode())
197         return true;
198 #endif
199
200     return HTMLPlugInImageElement::rendererIsNeeded(style);
201 }
202
203 bool HTMLEmbedElement::isURLAttribute(const Attribute& attribute) const
204 {
205     return attribute.name() == srcAttr || HTMLPlugInImageElement::isURLAttribute(attribute);
206 }
207
208 const AtomicString& HTMLEmbedElement::imageSourceURL() const
209 {
210     return getAttribute(srcAttr);
211 }
212
213 void HTMLEmbedElement::addSubresourceAttributeURLs(ListHashSet<URL>& urls) const
214 {
215     HTMLPlugInImageElement::addSubresourceAttributeURLs(urls);
216
217     addSubresourceURL(urls, document().completeURL(getAttribute(srcAttr)));
218 }
219
220 }