• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, 2007, 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 "HTMLObjectElement.h"
26 
27 #include "CSSHelper.h"
28 #include "EventNames.h"
29 #include "ExceptionCode.h"
30 #include "Frame.h"
31 #include "HTMLDocument.h"
32 #include "HTMLFormElement.h"
33 #include "HTMLImageLoader.h"
34 #include "HTMLNames.h"
35 #include "ScriptEventListener.h"
36 #include "MIMETypeRegistry.h"
37 #include "MappedAttribute.h"
38 #include "RenderEmbeddedObject.h"
39 #include "RenderImage.h"
40 #include "RenderWidget.h"
41 #include "ScriptController.h"
42 #include "Text.h"
43 
44 namespace WebCore {
45 
46 using namespace HTMLNames;
47 
HTMLObjectElement(const QualifiedName & tagName,Document * document,bool createdByParser)48 inline HTMLObjectElement::HTMLObjectElement(const QualifiedName& tagName, Document* document, bool createdByParser)
49     : HTMLPlugInImageElement(tagName, document)
50     , m_docNamedItem(true)
51     , m_needWidgetUpdate(!createdByParser)
52     , m_useFallbackContent(false)
53 {
54     ASSERT(hasTagName(objectTag));
55 }
56 
create(const QualifiedName & tagName,Document * document,bool createdByParser)57 PassRefPtr<HTMLObjectElement> HTMLObjectElement::create(const QualifiedName& tagName, Document* document, bool createdByParser)
58 {
59     return adoptRef(new HTMLObjectElement(tagName, document, createdByParser));
60 }
61 
renderWidgetForJSBindings() const62 RenderWidget* HTMLObjectElement::renderWidgetForJSBindings() const
63 {
64     document()->updateLayoutIgnorePendingStylesheets();
65     if (!renderer() || !renderer()->isWidget())
66         return 0;
67     return toRenderWidget(renderer());
68 }
69 
parseMappedAttribute(MappedAttribute * attr)70 void HTMLObjectElement::parseMappedAttribute(MappedAttribute *attr)
71 {
72     String val = attr->value();
73     int pos;
74     if (attr->name() == typeAttr) {
75         m_serviceType = val.lower();
76         pos = m_serviceType.find(";");
77         if (pos != -1)
78           m_serviceType = m_serviceType.left(pos);
79         if (renderer())
80           m_needWidgetUpdate = true;
81         if (!isImageType() && m_imageLoader)
82           m_imageLoader.clear();
83     } else if (attr->name() == dataAttr) {
84         m_url = deprecatedParseURL(val);
85         if (renderer())
86           m_needWidgetUpdate = true;
87         if (renderer() && isImageType()) {
88           if (!m_imageLoader)
89               m_imageLoader.set(new HTMLImageLoader(this));
90           m_imageLoader->updateFromElementIgnoringPreviousError();
91         }
92     } else if (attr->name() == classidAttr) {
93         m_classId = val;
94         if (renderer())
95           m_needWidgetUpdate = true;
96     } else if (attr->name() == onloadAttr)
97         setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr));
98     else if (attr->name() == onbeforeloadAttr)
99         setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, attr));
100     else if (attr->name() == nameAttr) {
101         const AtomicString& newName = attr->value();
102         if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) {
103             HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
104             document->removeNamedItem(m_name);
105             document->addNamedItem(newName);
106         }
107         m_name = newName;
108     } else if (attr->name() == idAttributeName()) {
109         const AtomicString& newId = attr->value();
110         if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) {
111             HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
112             document->removeExtraNamedItem(m_id);
113             document->addExtraNamedItem(newId);
114         }
115         m_id = newId;
116         // also call superclass
117         HTMLPlugInElement::parseMappedAttribute(attr);
118     } else
119         HTMLPlugInElement::parseMappedAttribute(attr);
120 }
121 
rendererIsNeeded(RenderStyle * style)122 bool HTMLObjectElement::rendererIsNeeded(RenderStyle* style)
123 {
124     Frame* frame = document()->frame();
125     if (!frame)
126         return false;
127 
128     // Temporary Workaround for Gears plugin - see bug 24215 for details and bug 24346 to track removal.
129     // Gears expects the plugin to be instantiated even if display:none is set
130     // for the object element.
131     bool isGearsPlugin = equalIgnoringCase(getAttribute(typeAttr), "application/x-googlegears");
132     return isGearsPlugin || HTMLPlugInElement::rendererIsNeeded(style);
133 }
134 
createRenderer(RenderArena * arena,RenderStyle * style)135 RenderObject *HTMLObjectElement::createRenderer(RenderArena* arena, RenderStyle* style)
136 {
137     if (m_useFallbackContent)
138         return RenderObject::createObject(this, style);
139     if (isImageType())
140         return new (arena) RenderImage(this);
141     return new (arena) RenderEmbeddedObject(this);
142 }
143 
attach()144 void HTMLObjectElement::attach()
145 {
146     bool isImage = isImageType();
147 
148     if (!isImage)
149         queuePostAttachCallback(&HTMLPlugInElement::updateWidgetCallback, this);
150 
151     HTMLPlugInElement::attach();
152 
153     if (isImage && renderer() && !m_useFallbackContent) {
154         if (!m_imageLoader)
155             m_imageLoader.set(new HTMLImageLoader(this));
156         m_imageLoader->updateFromElement();
157         // updateForElement() may have changed us to use fallback content and called detach() and attach().
158         if (m_useFallbackContent)
159             return;
160 
161         if (renderer())
162             toRenderImage(renderer())->setCachedImage(m_imageLoader->image());
163     }
164 }
165 
updateWidget()166 void HTMLObjectElement::updateWidget()
167 {
168     document()->updateStyleIfNeeded();
169     if (m_needWidgetUpdate && renderer() && !m_useFallbackContent && !isImageType())
170         toRenderEmbeddedObject(renderer())->updateWidget(true);
171 }
172 
finishParsingChildren()173 void HTMLObjectElement::finishParsingChildren()
174 {
175     HTMLPlugInElement::finishParsingChildren();
176     if (!m_useFallbackContent) {
177         m_needWidgetUpdate = true;
178         if (inDocument())
179             setNeedsStyleRecalc();
180     }
181 }
182 
detach()183 void HTMLObjectElement::detach()
184 {
185     if (attached() && renderer() && !m_useFallbackContent)
186         // Update the widget the next time we attach (detaching destroys the plugin).
187         m_needWidgetUpdate = true;
188     HTMLPlugInElement::detach();
189 }
190 
insertedIntoDocument()191 void HTMLObjectElement::insertedIntoDocument()
192 {
193     if (isDocNamedItem() && document()->isHTMLDocument()) {
194         HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
195         document->addNamedItem(m_name);
196         document->addExtraNamedItem(m_id);
197     }
198 
199     HTMLPlugInElement::insertedIntoDocument();
200 }
201 
removedFromDocument()202 void HTMLObjectElement::removedFromDocument()
203 {
204     if (isDocNamedItem() && document()->isHTMLDocument()) {
205         HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
206         document->removeNamedItem(m_name);
207         document->removeExtraNamedItem(m_id);
208     }
209 
210     HTMLPlugInElement::removedFromDocument();
211 }
212 
recalcStyle(StyleChange ch)213 void HTMLObjectElement::recalcStyle(StyleChange ch)
214 {
215     if (!m_useFallbackContent && m_needWidgetUpdate && renderer() && !isImageType()) {
216         detach();
217         attach();
218     }
219     HTMLPlugInElement::recalcStyle(ch);
220 }
221 
childrenChanged(bool changedByParser,Node * beforeChange,Node * afterChange,int childCountDelta)222 void HTMLObjectElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
223 {
224     updateDocNamedItem();
225     if (inDocument() && !m_useFallbackContent) {
226         m_needWidgetUpdate = true;
227         setNeedsStyleRecalc();
228     }
229     HTMLPlugInElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
230 }
231 
isURLAttribute(Attribute * attr) const232 bool HTMLObjectElement::isURLAttribute(Attribute *attr) const
233 {
234     return (attr->name() == dataAttr || (attr->name() == usemapAttr && attr->value().string()[0] != '#'));
235 }
236 
imageSourceAttributeName() const237 const QualifiedName& HTMLObjectElement::imageSourceAttributeName() const
238 {
239     return dataAttr;
240 }
241 
renderFallbackContent()242 void HTMLObjectElement::renderFallbackContent()
243 {
244     if (m_useFallbackContent)
245         return;
246 
247     // Before we give up and use fallback content, check to see if this is a MIME type issue.
248     if (m_imageLoader && m_imageLoader->image()) {
249         m_serviceType = m_imageLoader->image()->response().mimeType();
250         if (!isImageType()) {
251             // If we don't think we have an image type anymore, then ditch the image loader.
252             m_imageLoader.clear();
253             detach();
254             attach();
255             return;
256         }
257     }
258 
259     // Mark ourselves as using the fallback content.
260     m_useFallbackContent = true;
261 
262     // Now do a detach and reattach.
263     // FIXME: Style gets recalculated which is suboptimal.
264     detach();
265     attach();
266 }
267 
updateDocNamedItem()268 void HTMLObjectElement::updateDocNamedItem()
269 {
270     // The rule is "<object> elements with no children other than
271     // <param> elements, unknown elements and whitespace can be
272     // found by name in a document, and other <object> elements cannot."
273     bool wasNamedItem = m_docNamedItem;
274     bool isNamedItem = true;
275     Node* child = firstChild();
276     while (child && isNamedItem) {
277         if (child->isElementNode()) {
278             Element* element = static_cast<Element*>(child);
279             if (HTMLElement::isRecognizedTagName(element->tagQName()) && !element->hasTagName(paramTag))
280                 isNamedItem = false;
281         } else if (child->isTextNode()) {
282             if (!static_cast<Text*>(child)->containsOnlyWhitespace())
283                 isNamedItem = false;
284         } else
285             isNamedItem = false;
286         child = child->nextSibling();
287     }
288     if (isNamedItem != wasNamedItem && document()->isHTMLDocument()) {
289         HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
290         if (isNamedItem) {
291             document->addNamedItem(m_name);
292             document->addExtraNamedItem(m_id);
293         } else {
294             document->removeNamedItem(m_name);
295             document->removeExtraNamedItem(m_id);
296         }
297     }
298     m_docNamedItem = isNamedItem;
299 }
300 
declare() const301 bool HTMLObjectElement::declare() const
302 {
303     return !getAttribute(declareAttr).isNull();
304 }
305 
setDeclare(bool declare)306 void HTMLObjectElement::setDeclare(bool declare)
307 {
308     setAttribute(declareAttr, declare ? "" : 0);
309 }
310 
hspace() const311 int HTMLObjectElement::hspace() const
312 {
313     return getAttribute(hspaceAttr).toInt();
314 }
315 
setHspace(int value)316 void HTMLObjectElement::setHspace(int value)
317 {
318     setAttribute(hspaceAttr, String::number(value));
319 }
320 
vspace() const321 int HTMLObjectElement::vspace() const
322 {
323     return getAttribute(vspaceAttr).toInt();
324 }
325 
setVspace(int value)326 void HTMLObjectElement::setVspace(int value)
327 {
328     setAttribute(vspaceAttr, String::number(value));
329 }
330 
containsJavaApplet() const331 bool HTMLObjectElement::containsJavaApplet() const
332 {
333     if (MIMETypeRegistry::isJavaAppletMIMEType(getAttribute(typeAttr)))
334         return true;
335 
336     for (Element* child = firstElementChild(); child; child = child->nextElementSibling()) {
337         if (child->hasTagName(paramTag)
338                 && equalIgnoringCase(child->getAttribute(nameAttr), "type")
339                 && MIMETypeRegistry::isJavaAppletMIMEType(child->getAttribute(valueAttr).string()))
340             return true;
341         if (child->hasTagName(objectTag)
342                 && static_cast<HTMLObjectElement*>(child)->containsJavaApplet())
343             return true;
344         if (child->hasTagName(appletTag))
345             return true;
346     }
347 
348     return false;
349 }
350 
addSubresourceAttributeURLs(ListHashSet<KURL> & urls) const351 void HTMLObjectElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
352 {
353     HTMLPlugInImageElement::addSubresourceAttributeURLs(urls);
354 
355     addSubresourceURL(urls, document()->completeURL(getAttribute(dataAttr)));
356 
357     // FIXME: Passing a string that starts with "#" to the completeURL function does
358     // not seem like it would work. The image element has similar but not identical code.
359     const AtomicString& useMap = getAttribute(usemapAttr);
360     if (useMap.startsWith("#"))
361         addSubresourceURL(urls, document()->completeURL(useMap));
362 }
363 
364 }
365