2010-08-24 Adam Barth <abarth@webkit.org>
[WebKit-https.git] / 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 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 "CSSHelper.h"
29 #include "CSSPropertyNames.h"
30 #include "Frame.h"
31 #include "HTMLDocument.h"
32 #include "HTMLImageLoader.h"
33 #include "HTMLNames.h"
34 #include "HTMLObjectElement.h"
35 #include "RenderEmbeddedObject.h"
36 #include "RenderImage.h"
37 #include "RenderWidget.h"
38 #include "ScriptController.h"
39 #include "Settings.h"
40
41 namespace WebCore {
42
43 using namespace HTMLNames;
44
45 inline HTMLEmbedElement::HTMLEmbedElement(const QualifiedName& tagName, Document* document)
46     : HTMLPlugInImageElement(tagName, document)
47     , m_needWidgetUpdate(false)
48 {
49     ASSERT(hasTagName(embedTag));
50 }
51
52 PassRefPtr<HTMLEmbedElement> HTMLEmbedElement::create(const QualifiedName& tagName, Document* document)
53 {
54     return adoptRef(new HTMLEmbedElement(tagName, document));
55 }
56
57 static inline RenderWidget* findWidgetRenderer(const Node* n) 
58 {
59     if (!n->renderer())
60         do
61             n = n->parentNode();
62         while (n && !n->hasTagName(objectTag));
63
64     if (n && n->renderer() && n->renderer()->isWidget())
65         return toRenderWidget(n->renderer());
66
67     return 0;
68 }
69
70 RenderWidget* HTMLEmbedElement::renderWidgetForJSBindings() const
71 {
72     document()->updateLayoutIgnorePendingStylesheets();
73     return findWidgetRenderer(this);
74 }
75
76 bool HTMLEmbedElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
77 {
78     if (attrName == hiddenAttr) {
79         result = eUniversal;
80         return false;
81     }
82         
83     return HTMLPlugInElement::mapToEntry(attrName, result);
84 }
85
86 void HTMLEmbedElement::parseMappedAttribute(Attribute* attr)
87 {
88     const AtomicString& value = attr->value();
89   
90     if (attr->name() == typeAttr) {
91         m_serviceType = value.string().lower();
92         size_t pos = m_serviceType.find(";");
93         if (pos != notFound)
94             m_serviceType = m_serviceType.left(pos);
95         if (!isImageType() && m_imageLoader)
96             m_imageLoader.clear();
97     } else if (attr->name() == codeAttr)
98         m_url = deprecatedParseURL(value.string());
99     else if (attr->name() == srcAttr) {
100         m_url = deprecatedParseURL(value.string());
101         if (renderer() && isImageType()) {
102             if (!m_imageLoader)
103                 m_imageLoader = adoptPtr(new HTMLImageLoader(this));
104             m_imageLoader->updateFromElementIgnoringPreviousError();
105         }
106     } else if (attr->name() == hiddenAttr) {
107         if (equalIgnoringCase(value.string(), "yes") || equalIgnoringCase(value.string(), "true")) {
108             // FIXME: Not dynamic, since we add this but don't remove it, but it may be OK for now
109             // that this rarely-used attribute won't work properly if you remove it.
110             addCSSLength(attr, CSSPropertyWidth, "0");
111             addCSSLength(attr, CSSPropertyHeight, "0");
112         }
113     } else if (attr->name() == nameAttr) {
114         if (inDocument() && document()->isHTMLDocument()) {
115             HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
116             document->removeNamedItem(m_name);
117             document->addNamedItem(value);
118         }
119         m_name = value;
120     } else
121         HTMLPlugInElement::parseMappedAttribute(attr);
122 }
123
124 bool HTMLEmbedElement::rendererIsNeeded(RenderStyle* style)
125 {
126     if (isImageType())
127         return HTMLPlugInElement::rendererIsNeeded(style);
128
129     Frame* frame = document()->frame();
130     if (!frame)
131         return false;
132
133     Node* p = parentNode();
134     if (p && p->hasTagName(objectTag)) {
135         ASSERT(p->renderer());
136         return false;
137     }
138
139 #if ENABLE(DASHBOARD_SUPPORT)
140     // Workaround for <rdar://problem/6642221>. 
141     if (Settings* settings = frame->settings()) {
142         if (settings->usesDashboardBackwardCompatibilityMode())
143             return true;
144     }
145 #endif
146
147     return HTMLPlugInElement::rendererIsNeeded(style);
148 }
149
150 RenderObject* HTMLEmbedElement::createRenderer(RenderArena* arena, RenderStyle*)
151 {
152     if (isImageType())
153         return new (arena) RenderImage(this);
154     return new (arena) RenderEmbeddedObject(this);
155 }
156
157 void HTMLEmbedElement::attach()
158 {
159     m_needWidgetUpdate = true;
160
161     bool isImage = isImageType();
162
163     if (!isImage)
164         queuePostAttachCallback(&HTMLPlugInElement::updateWidgetCallback, this);
165
166     HTMLPlugInElement::attach();
167
168     if (isImage && renderer()) {
169         if (!m_imageLoader)
170             m_imageLoader = adoptPtr(new HTMLImageLoader(this));
171         m_imageLoader->updateFromElement();
172
173         if (renderer())
174             toRenderImage(renderer())->setCachedImage(m_imageLoader->image());
175     }
176 }
177
178 void HTMLEmbedElement::updateWidget()
179 {
180     document()->updateStyleIfNeeded();
181     if (m_needWidgetUpdate && renderer() && !isImageType())
182         toRenderEmbeddedObject(renderer())->updateWidget(true);
183 }
184
185 void HTMLEmbedElement::insertedIntoDocument()
186 {
187     if (document()->isHTMLDocument())
188         static_cast<HTMLDocument*>(document())->addNamedItem(m_name);
189
190     String width = getAttribute(widthAttr);
191     String height = getAttribute(heightAttr);
192     if (!width.isEmpty() || !height.isEmpty()) {
193         Node* n = parent();
194         while (n && !n->hasTagName(objectTag))
195             n = n->parent();
196         if (n) {
197             if (!width.isEmpty())
198                 static_cast<HTMLObjectElement*>(n)->setAttribute(widthAttr, width);
199             if (!height.isEmpty())
200                 static_cast<HTMLObjectElement*>(n)->setAttribute(heightAttr, height);
201         }
202     }
203
204     HTMLPlugInElement::insertedIntoDocument();
205 }
206
207 void HTMLEmbedElement::removedFromDocument()
208 {
209     if (document()->isHTMLDocument())
210         static_cast<HTMLDocument*>(document())->removeNamedItem(m_name);
211
212     HTMLPlugInElement::removedFromDocument();
213 }
214
215 void HTMLEmbedElement::attributeChanged(Attribute* attr, bool preserveDecls)
216 {
217     HTMLPlugInElement::attributeChanged(attr, preserveDecls);
218
219     if ((attr->name() == widthAttr || attr->name() == heightAttr) && !attr->isEmpty()) {
220         Node* n = parent();
221         while (n && !n->hasTagName(objectTag))
222             n = n->parent();
223         if (n)
224             static_cast<HTMLObjectElement*>(n)->setAttribute(attr->name(), attr->value());
225     }
226 }
227
228 bool HTMLEmbedElement::isURLAttribute(Attribute* attr) const
229 {
230     return attr->name() == srcAttr;
231 }
232
233 const QualifiedName& HTMLEmbedElement::imageSourceAttributeName() const
234 {
235     return srcAttr;
236 }
237
238 void HTMLEmbedElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
239 {
240     HTMLPlugInImageElement::addSubresourceAttributeURLs(urls);
241
242     addSubresourceURL(urls, document()->completeURL(getAttribute(srcAttr)));
243 }
244
245 }