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)
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.
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.
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.
25 #include "HTMLObjectElement.h"
27 #include "CSSHelper.h"
28 #include "EventNames.h"
29 #include "ExceptionCode.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 "RenderImage.h"
39 #include "RenderPartObject.h"
40 #include "RenderWidget.h"
41 #include "ScriptController.h"
46 using namespace HTMLNames
;
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)
54 ASSERT(hasTagName(objectTag
));
57 PassRefPtr
<HTMLObjectElement
> HTMLObjectElement::create(const QualifiedName
& tagName
, Document
* document
, bool createdByParser
)
59 return adoptRef(new HTMLObjectElement(tagName
, document
, createdByParser
));
62 RenderWidget
* HTMLObjectElement::renderWidgetForJSBindings() const
64 RenderWidget
* renderWidget
= (renderer() && renderer()->isWidget()) ? toRenderWidget(renderer()) : 0;
65 if (renderWidget
&& !renderWidget
->widget()) {
66 document()->updateLayoutIgnorePendingStylesheets();
67 renderWidget
= (renderer() && renderer()->isWidget()) ? toRenderWidget(renderer()) : 0;
72 void HTMLObjectElement::parseMappedAttribute(MappedAttribute
*attr
)
74 String val
= attr
->value();
76 if (attr
->name() == typeAttr
) {
77 m_serviceType
= val
.lower();
78 pos
= m_serviceType
.find(";");
80 m_serviceType
= m_serviceType
.left(pos
);
82 m_needWidgetUpdate
= true;
83 if (!isImageType() && m_imageLoader
)
84 m_imageLoader
.clear();
85 } else if (attr
->name() == dataAttr
) {
86 m_url
= deprecatedParseURL(val
);
88 m_needWidgetUpdate
= true;
89 if (renderer() && isImageType()) {
91 m_imageLoader
.set(new HTMLImageLoader(this));
92 m_imageLoader
->updateFromElementIgnoringPreviousError();
94 } else if (attr
->name() == classidAttr
) {
97 m_needWidgetUpdate
= true;
98 } else if (attr
->name() == onloadAttr
)
99 setAttributeEventListener(eventNames().loadEvent
, createAttributeEventListener(this, attr
));
100 else if (attr
->name() == onbeforeloadAttr
)
101 setAttributeEventListener(eventNames().beforeloadEvent
, createAttributeEventListener(this, attr
));
102 else if (attr
->name() == nameAttr
) {
103 const AtomicString
& newName
= attr
->value();
104 if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) {
105 HTMLDocument
* document
= static_cast<HTMLDocument
*>(this->document());
106 document
->removeNamedItem(m_name
);
107 document
->addNamedItem(newName
);
110 } else if (attr
->name() == idAttr
) {
111 const AtomicString
& newId
= attr
->value();
112 if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) {
113 HTMLDocument
* document
= static_cast<HTMLDocument
*>(this->document());
114 document
->removeExtraNamedItem(m_id
);
115 document
->addExtraNamedItem(newId
);
118 // also call superclass
119 HTMLPlugInElement::parseMappedAttribute(attr
);
121 HTMLPlugInElement::parseMappedAttribute(attr
);
124 bool HTMLObjectElement::rendererIsNeeded(RenderStyle
* style
)
126 Frame
* frame
= document()->frame();
130 // Temporary Workaround for Gears plugin - see bug 24215 for details and bug 24346 to track removal.
131 // Gears expects the plugin to be instantiated even if display:none is set
132 // for the object element.
133 bool isGearsPlugin
= equalIgnoringCase(getAttribute(typeAttr
), "application/x-googlegears");
134 return isGearsPlugin
|| HTMLPlugInElement::rendererIsNeeded(style
);
137 RenderObject
*HTMLObjectElement::createRenderer(RenderArena
* arena
, RenderStyle
* style
)
139 if (m_useFallbackContent
)
140 return RenderObject::createObject(this, style
);
142 return new (arena
) RenderImage(this);
143 return new (arena
) RenderPartObject(this);
146 void HTMLObjectElement::attach()
148 bool isImage
= isImageType();
151 queuePostAttachCallback(&HTMLPlugInElement::updateWidgetCallback
, this);
153 HTMLPlugInElement::attach();
155 if (isImage
&& renderer() && !m_useFallbackContent
) {
157 m_imageLoader
.set(new HTMLImageLoader(this));
158 m_imageLoader
->updateFromElement();
159 // updateForElement() may have changed us to use fallback content and called detach() and attach().
160 if (m_useFallbackContent
)
164 toRenderImage(renderer())->setCachedImage(m_imageLoader
->image());
168 void HTMLObjectElement::updateWidget()
170 document()->updateStyleIfNeeded();
171 if (m_needWidgetUpdate
&& renderer() && !m_useFallbackContent
&& !isImageType())
172 toRenderPartObject(renderer())->updateWidget(true);
175 void HTMLObjectElement::finishParsingChildren()
177 HTMLPlugInElement::finishParsingChildren();
178 if (!m_useFallbackContent
) {
179 m_needWidgetUpdate
= true;
181 setNeedsStyleRecalc();
185 void HTMLObjectElement::detach()
187 if (attached() && renderer() && !m_useFallbackContent
)
188 // Update the widget the next time we attach (detaching destroys the plugin).
189 m_needWidgetUpdate
= true;
190 HTMLPlugInElement::detach();
193 void HTMLObjectElement::insertedIntoDocument()
195 if (isDocNamedItem() && document()->isHTMLDocument()) {
196 HTMLDocument
* document
= static_cast<HTMLDocument
*>(this->document());
197 document
->addNamedItem(m_name
);
198 document
->addExtraNamedItem(m_id
);
201 HTMLPlugInElement::insertedIntoDocument();
204 void HTMLObjectElement::removedFromDocument()
206 if (isDocNamedItem() && document()->isHTMLDocument()) {
207 HTMLDocument
* document
= static_cast<HTMLDocument
*>(this->document());
208 document
->removeNamedItem(m_name
);
209 document
->removeExtraNamedItem(m_id
);
212 HTMLPlugInElement::removedFromDocument();
215 void HTMLObjectElement::recalcStyle(StyleChange ch
)
217 if (!m_useFallbackContent
&& m_needWidgetUpdate
&& renderer() && !isImageType()) {
221 HTMLPlugInElement::recalcStyle(ch
);
224 void HTMLObjectElement::childrenChanged(bool changedByParser
, Node
* beforeChange
, Node
* afterChange
, int childCountDelta
)
226 updateDocNamedItem();
227 if (inDocument() && !m_useFallbackContent
) {
228 m_needWidgetUpdate
= true;
229 setNeedsStyleRecalc();
231 HTMLPlugInElement::childrenChanged(changedByParser
, beforeChange
, afterChange
, childCountDelta
);
234 bool HTMLObjectElement::isURLAttribute(Attribute
*attr
) const
236 return (attr
->name() == dataAttr
|| (attr
->name() == usemapAttr
&& attr
->value().string()[0] != '#'));
239 const QualifiedName
& HTMLObjectElement::imageSourceAttributeName() const
244 void HTMLObjectElement::renderFallbackContent()
246 if (m_useFallbackContent
)
249 // Before we give up and use fallback content, check to see if this is a MIME type issue.
250 if (m_imageLoader
&& m_imageLoader
->image()) {
251 m_serviceType
= m_imageLoader
->image()->response().mimeType();
252 if (!isImageType()) {
253 // If we don't think we have an image type anymore, then ditch the image loader.
254 m_imageLoader
.clear();
261 // Mark ourselves as using the fallback content.
262 m_useFallbackContent
= true;
264 // Now do a detach and reattach.
265 // FIXME: Style gets recalculated which is suboptimal.
270 void HTMLObjectElement::updateDocNamedItem()
272 // The rule is "<object> elements with no children other than
273 // <param> elements, unknown elements and whitespace can be
274 // found by name in a document, and other <object> elements cannot."
275 bool wasNamedItem
= m_docNamedItem
;
276 bool isNamedItem
= true;
277 Node
* child
= firstChild();
278 while (child
&& isNamedItem
) {
279 if (child
->isElementNode()) {
280 Element
* element
= static_cast<Element
*>(child
);
281 if (HTMLElement::isRecognizedTagName(element
->tagQName()) && !element
->hasTagName(paramTag
))
283 } else if (child
->isTextNode()) {
284 if (!static_cast<Text
*>(child
)->containsOnlyWhitespace())
288 child
= child
->nextSibling();
290 if (isNamedItem
!= wasNamedItem
&& document()->isHTMLDocument()) {
291 HTMLDocument
* document
= static_cast<HTMLDocument
*>(this->document());
293 document
->addNamedItem(m_name
);
294 document
->addExtraNamedItem(m_id
);
296 document
->removeNamedItem(m_name
);
297 document
->removeExtraNamedItem(m_id
);
300 m_docNamedItem
= isNamedItem
;
303 bool HTMLObjectElement::declare() const
305 return !getAttribute(declareAttr
).isNull();
308 void HTMLObjectElement::setDeclare(bool declare
)
310 setAttribute(declareAttr
, declare
? "" : 0);
313 int HTMLObjectElement::hspace() const
315 return getAttribute(hspaceAttr
).toInt();
318 void HTMLObjectElement::setHspace(int value
)
320 setAttribute(hspaceAttr
, String::number(value
));
323 int HTMLObjectElement::vspace() const
325 return getAttribute(vspaceAttr
).toInt();
328 void HTMLObjectElement::setVspace(int value
)
330 setAttribute(vspaceAttr
, String::number(value
));
333 bool HTMLObjectElement::containsJavaApplet() const
335 if (MIMETypeRegistry::isJavaAppletMIMEType(getAttribute(typeAttr
)))
338 for (Element
* child
= firstElementChild(); child
; child
= child
->nextElementSibling()) {
339 if (child
->hasTagName(paramTag
)
340 && equalIgnoringCase(child
->getAttribute(nameAttr
), "type")
341 && MIMETypeRegistry::isJavaAppletMIMEType(child
->getAttribute(valueAttr
).string()))
343 if (child
->hasTagName(objectTag
)
344 && static_cast<HTMLObjectElement
*>(child
)->containsJavaApplet())
346 if (child
->hasTagName(appletTag
))
353 void HTMLObjectElement::addSubresourceAttributeURLs(ListHashSet
<KURL
>& urls
) const
355 HTMLPlugInImageElement::addSubresourceAttributeURLs(urls
);
357 addSubresourceURL(urls
, document()->completeURL(getAttribute(dataAttr
)));
359 // FIXME: Passing a string that starts with "#" to the completeURL function does
360 // not seem like it would work. The image element has similar but not identical code.
361 const AtomicString
& useMap
= getAttribute(usemapAttr
);
362 if (useMap
.startsWith("#"))
363 addSubresourceURL(urls
, document()->completeURL(useMap
));