Rubber-stamped by Brady Eidson.
[webbrowser.git] / WebCore / html / HTMLObjectElement.cpp
blobd3ccfa4b8a2edd2466e304a8c6939cad7a4d89ae
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)
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.
24 #include "config.h"
25 #include "HTMLObjectElement.h"
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 "RenderImage.h"
39 #include "RenderPartObject.h"
40 #include "RenderWidget.h"
41 #include "ScriptController.h"
42 #include "Text.h"
44 namespace WebCore {
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;
69 return renderWidget;
72 void HTMLObjectElement::parseMappedAttribute(MappedAttribute *attr)
74 String val = attr->value();
75 int pos;
76 if (attr->name() == typeAttr) {
77 m_serviceType = val.lower();
78 pos = m_serviceType.find(";");
79 if (pos != -1)
80 m_serviceType = m_serviceType.left(pos);
81 if (renderer())
82 m_needWidgetUpdate = true;
83 if (!isImageType() && m_imageLoader)
84 m_imageLoader.clear();
85 } else if (attr->name() == dataAttr) {
86 m_url = deprecatedParseURL(val);
87 if (renderer())
88 m_needWidgetUpdate = true;
89 if (renderer() && isImageType()) {
90 if (!m_imageLoader)
91 m_imageLoader.set(new HTMLImageLoader(this));
92 m_imageLoader->updateFromElementIgnoringPreviousError();
94 } else if (attr->name() == classidAttr) {
95 m_classId = val;
96 if (renderer())
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);
109 m_name = 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);
117 m_id = newId;
118 // also call superclass
119 HTMLPlugInElement::parseMappedAttribute(attr);
120 } else
121 HTMLPlugInElement::parseMappedAttribute(attr);
124 bool HTMLObjectElement::rendererIsNeeded(RenderStyle* style)
126 Frame* frame = document()->frame();
127 if (!frame)
128 return false;
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);
141 if (isImageType())
142 return new (arena) RenderImage(this);
143 return new (arena) RenderPartObject(this);
146 void HTMLObjectElement::attach()
148 bool isImage = isImageType();
150 if (!isImage)
151 queuePostAttachCallback(&HTMLPlugInElement::updateWidgetCallback, this);
153 HTMLPlugInElement::attach();
155 if (isImage && renderer() && !m_useFallbackContent) {
156 if (!m_imageLoader)
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)
161 return;
163 if (renderer())
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;
180 if (inDocument())
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()) {
218 detach();
219 attach();
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
241 return dataAttr;
244 void HTMLObjectElement::renderFallbackContent()
246 if (m_useFallbackContent)
247 return;
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();
255 detach();
256 attach();
257 return;
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.
266 detach();
267 attach();
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))
282 isNamedItem = false;
283 } else if (child->isTextNode()) {
284 if (!static_cast<Text*>(child)->containsOnlyWhitespace())
285 isNamedItem = false;
286 } else
287 isNamedItem = false;
288 child = child->nextSibling();
290 if (isNamedItem != wasNamedItem && document()->isHTMLDocument()) {
291 HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
292 if (isNamedItem) {
293 document->addNamedItem(m_name);
294 document->addExtraNamedItem(m_id);
295 } else {
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)))
336 return true;
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()))
342 return true;
343 if (child->hasTagName(objectTag)
344 && static_cast<HTMLObjectElement*>(child)->containsJavaApplet())
345 return true;
346 if (child->hasTagName(appletTag))
347 return true;
350 return false;
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));