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 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 "RenderImage.h"
39 #include "RenderPartObject.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 * doc,bool createdByParser)48 HTMLObjectElement::HTMLObjectElement(const QualifiedName& tagName, Document* doc, bool createdByParser)
49 : HTMLPlugInImageElement(tagName, doc)
50 , m_docNamedItem(true)
51 , m_needWidgetUpdate(!createdByParser)
52 , m_useFallbackContent(false)
53 {
54 ASSERT(hasTagName(objectTag));
55 }
56
~HTMLObjectElement()57 HTMLObjectElement::~HTMLObjectElement()
58 {
59 }
60
renderWidgetForJSBindings() const61 RenderWidget* HTMLObjectElement::renderWidgetForJSBindings() const
62 {
63 RenderWidget* renderWidget = (renderer() && renderer()->isWidget()) ? toRenderWidget(renderer()) : 0;
64 if (renderWidget && !renderWidget->widget()) {
65 document()->updateLayoutIgnorePendingStylesheets();
66 renderWidget = (renderer() && renderer()->isWidget()) ? toRenderWidget(renderer()) : 0;
67 }
68 return renderWidget;
69 }
70
parseMappedAttribute(MappedAttribute * attr)71 void HTMLObjectElement::parseMappedAttribute(MappedAttribute *attr)
72 {
73 String val = attr->value();
74 int pos;
75 if (attr->name() == typeAttr) {
76 m_serviceType = val.lower();
77 pos = m_serviceType.find(";");
78 if (pos != -1)
79 m_serviceType = m_serviceType.left(pos);
80 if (renderer())
81 m_needWidgetUpdate = true;
82 if (!isImageType() && m_imageLoader)
83 m_imageLoader.clear();
84 } else if (attr->name() == dataAttr) {
85 m_url = deprecatedParseURL(val);
86 if (renderer())
87 m_needWidgetUpdate = true;
88 if (renderer() && isImageType()) {
89 if (!m_imageLoader)
90 m_imageLoader.set(new HTMLImageLoader(this));
91 m_imageLoader->updateFromElementIgnoringPreviousError();
92 }
93 } else if (attr->name() == classidAttr) {
94 m_classId = val;
95 if (renderer())
96 m_needWidgetUpdate = true;
97 } else if (attr->name() == onloadAttr) {
98 setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr));
99 } else if (attr->name() == nameAttr) {
100 const AtomicString& newName = attr->value();
101 if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) {
102 HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
103 document->removeNamedItem(m_name);
104 document->addNamedItem(newName);
105 }
106 m_name = newName;
107 } else if (attr->name() == idAttr) {
108 const AtomicString& newId = attr->value();
109 if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) {
110 HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
111 document->removeExtraNamedItem(m_id);
112 document->addExtraNamedItem(newId);
113 }
114 m_id = newId;
115 // also call superclass
116 HTMLPlugInElement::parseMappedAttribute(attr);
117 } else
118 HTMLPlugInElement::parseMappedAttribute(attr);
119 }
120
rendererIsNeeded(RenderStyle * style)121 bool HTMLObjectElement::rendererIsNeeded(RenderStyle* style)
122 {
123 Frame* frame = document()->frame();
124 if (!frame)
125 return false;
126
127 // Temporary Workaround for Gears plugin - see bug 24215 for details and bug 24346 to track removal.
128 // Gears expects the plugin to be instantiated even if display:none is set
129 // for the object element.
130 bool isGearsPlugin = equalIgnoringCase(getAttribute(typeAttr), "application/x-googlegears");
131 return isGearsPlugin || HTMLPlugInElement::rendererIsNeeded(style);
132 }
133
createRenderer(RenderArena * arena,RenderStyle * style)134 RenderObject *HTMLObjectElement::createRenderer(RenderArena* arena, RenderStyle* style)
135 {
136 if (m_useFallbackContent)
137 return RenderObject::createObject(this, style);
138 if (isImageType())
139 return new (arena) RenderImage(this);
140 return new (arena) RenderPartObject(this);
141 }
142
attach()143 void HTMLObjectElement::attach()
144 {
145 bool isImage = isImageType();
146
147 if (!isImage)
148 queuePostAttachCallback(&HTMLPlugInElement::updateWidgetCallback, this);
149
150 HTMLPlugInElement::attach();
151
152 if (isImage && renderer() && !m_useFallbackContent) {
153 if (!m_imageLoader)
154 m_imageLoader.set(new HTMLImageLoader(this));
155 m_imageLoader->updateFromElement();
156 // updateForElement() may have changed us to use fallback content and called detach() and attach().
157 if (m_useFallbackContent)
158 return;
159
160 if (renderer())
161 toRenderImage(renderer())->setCachedImage(m_imageLoader->image());
162 }
163 }
164
updateWidget()165 void HTMLObjectElement::updateWidget()
166 {
167 document()->updateStyleIfNeeded();
168 if (m_needWidgetUpdate && renderer() && !m_useFallbackContent && !isImageType())
169 toRenderPartObject(renderer())->updateWidget(true);
170 }
171
finishParsingChildren()172 void HTMLObjectElement::finishParsingChildren()
173 {
174 HTMLPlugInElement::finishParsingChildren();
175 if (!m_useFallbackContent) {
176 m_needWidgetUpdate = true;
177 if (inDocument())
178 setNeedsStyleRecalc();
179 }
180 }
181
detach()182 void HTMLObjectElement::detach()
183 {
184 if (attached() && renderer() && !m_useFallbackContent)
185 // Update the widget the next time we attach (detaching destroys the plugin).
186 m_needWidgetUpdate = true;
187 HTMLPlugInElement::detach();
188 }
189
insertedIntoDocument()190 void HTMLObjectElement::insertedIntoDocument()
191 {
192 if (isDocNamedItem() && document()->isHTMLDocument()) {
193 HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
194 document->addNamedItem(m_name);
195 document->addExtraNamedItem(m_id);
196 }
197
198 HTMLPlugInElement::insertedIntoDocument();
199 }
200
removedFromDocument()201 void HTMLObjectElement::removedFromDocument()
202 {
203 if (isDocNamedItem() && document()->isHTMLDocument()) {
204 HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
205 document->removeNamedItem(m_name);
206 document->removeExtraNamedItem(m_id);
207 }
208
209 HTMLPlugInElement::removedFromDocument();
210 }
211
recalcStyle(StyleChange ch)212 void HTMLObjectElement::recalcStyle(StyleChange ch)
213 {
214 if (!m_useFallbackContent && m_needWidgetUpdate && renderer() && !isImageType()) {
215 detach();
216 attach();
217 }
218 HTMLPlugInElement::recalcStyle(ch);
219 }
220
childrenChanged(bool changedByParser,Node * beforeChange,Node * afterChange,int childCountDelta)221 void HTMLObjectElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
222 {
223 updateDocNamedItem();
224 if (inDocument() && !m_useFallbackContent) {
225 m_needWidgetUpdate = true;
226 setNeedsStyleRecalc();
227 }
228 HTMLPlugInElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
229 }
230
isURLAttribute(Attribute * attr) const231 bool HTMLObjectElement::isURLAttribute(Attribute *attr) const
232 {
233 return (attr->name() == dataAttr || (attr->name() == usemapAttr && attr->value().string()[0] != '#'));
234 }
235
imageSourceAttributeName() const236 const QualifiedName& HTMLObjectElement::imageSourceAttributeName() const
237 {
238 return dataAttr;
239 }
240
renderFallbackContent()241 void HTMLObjectElement::renderFallbackContent()
242 {
243 if (m_useFallbackContent)
244 return;
245
246 // Before we give up and use fallback content, check to see if this is a MIME type issue.
247 if (m_imageLoader && m_imageLoader->image()) {
248 m_serviceType = m_imageLoader->image()->response().mimeType();
249 if (!isImageType()) {
250 // If we don't think we have an image type anymore, then ditch the image loader.
251 m_imageLoader.clear();
252 detach();
253 attach();
254 return;
255 }
256 }
257
258 // Mark ourselves as using the fallback content.
259 m_useFallbackContent = true;
260
261 // Now do a detach and reattach.
262 // FIXME: Style gets recalculated which is suboptimal.
263 detach();
264 attach();
265 }
266
updateDocNamedItem()267 void HTMLObjectElement::updateDocNamedItem()
268 {
269 // The rule is "<object> elements with no children other than
270 // <param> elements, unknown elements and whitespace can be
271 // found by name in a document, and other <object> elements cannot."
272 bool wasNamedItem = m_docNamedItem;
273 bool isNamedItem = true;
274 Node* child = firstChild();
275 while (child && isNamedItem) {
276 if (child->isElementNode()) {
277 Element* element = static_cast<Element*>(child);
278 if (HTMLElement::isRecognizedTagName(element->tagQName()) && !element->hasTagName(paramTag))
279 isNamedItem = false;
280 } else if (child->isTextNode()) {
281 if (!static_cast<Text*>(child)->containsOnlyWhitespace())
282 isNamedItem = false;
283 } else
284 isNamedItem = false;
285 child = child->nextSibling();
286 }
287 if (isNamedItem != wasNamedItem && document()->isHTMLDocument()) {
288 HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
289 if (isNamedItem) {
290 document->addNamedItem(m_name);
291 document->addExtraNamedItem(m_id);
292 } else {
293 document->removeNamedItem(m_name);
294 document->removeExtraNamedItem(m_id);
295 }
296 }
297 m_docNamedItem = isNamedItem;
298 }
299
code() const300 String HTMLObjectElement::code() const
301 {
302 return getAttribute(codeAttr);
303 }
304
setCode(const String & value)305 void HTMLObjectElement::setCode(const String& value)
306 {
307 setAttribute(codeAttr, value);
308 }
309
archive() const310 String HTMLObjectElement::archive() const
311 {
312 return getAttribute(archiveAttr);
313 }
314
setArchive(const String & value)315 void HTMLObjectElement::setArchive(const String& value)
316 {
317 setAttribute(archiveAttr, value);
318 }
319
border() const320 String HTMLObjectElement::border() const
321 {
322 return getAttribute(borderAttr);
323 }
324
setBorder(const String & value)325 void HTMLObjectElement::setBorder(const String& value)
326 {
327 setAttribute(borderAttr, value);
328 }
329
codeBase() const330 String HTMLObjectElement::codeBase() const
331 {
332 return getAttribute(codebaseAttr);
333 }
334
setCodeBase(const String & value)335 void HTMLObjectElement::setCodeBase(const String& value)
336 {
337 setAttribute(codebaseAttr, value);
338 }
339
codeType() const340 String HTMLObjectElement::codeType() const
341 {
342 return getAttribute(codetypeAttr);
343 }
344
setCodeType(const String & value)345 void HTMLObjectElement::setCodeType(const String& value)
346 {
347 setAttribute(codetypeAttr, value);
348 }
349
data() const350 KURL HTMLObjectElement::data() const
351 {
352 return document()->completeURL(getAttribute(dataAttr));
353 }
354
setData(const String & value)355 void HTMLObjectElement::setData(const String& value)
356 {
357 setAttribute(dataAttr, value);
358 }
359
declare() const360 bool HTMLObjectElement::declare() const
361 {
362 return !getAttribute(declareAttr).isNull();
363 }
364
setDeclare(bool declare)365 void HTMLObjectElement::setDeclare(bool declare)
366 {
367 setAttribute(declareAttr, declare ? "" : 0);
368 }
369
hspace() const370 int HTMLObjectElement::hspace() const
371 {
372 return getAttribute(hspaceAttr).toInt();
373 }
374
setHspace(int value)375 void HTMLObjectElement::setHspace(int value)
376 {
377 setAttribute(hspaceAttr, String::number(value));
378 }
379
standby() const380 String HTMLObjectElement::standby() const
381 {
382 return getAttribute(standbyAttr);
383 }
384
setStandby(const String & value)385 void HTMLObjectElement::setStandby(const String& value)
386 {
387 setAttribute(standbyAttr, value);
388 }
389
type() const390 String HTMLObjectElement::type() const
391 {
392 return getAttribute(typeAttr);
393 }
394
setType(const String & value)395 void HTMLObjectElement::setType(const String& value)
396 {
397 setAttribute(typeAttr, value);
398 }
399
useMap() const400 String HTMLObjectElement::useMap() const
401 {
402 return getAttribute(usemapAttr);
403 }
404
setUseMap(const String & value)405 void HTMLObjectElement::setUseMap(const String& value)
406 {
407 setAttribute(usemapAttr, value);
408 }
409
vspace() const410 int HTMLObjectElement::vspace() const
411 {
412 return getAttribute(vspaceAttr).toInt();
413 }
414
setVspace(int value)415 void HTMLObjectElement::setVspace(int value)
416 {
417 setAttribute(vspaceAttr, String::number(value));
418 }
419
containsJavaApplet() const420 bool HTMLObjectElement::containsJavaApplet() const
421 {
422 if (MIMETypeRegistry::isJavaAppletMIMEType(type()))
423 return true;
424
425 Node* child = firstChild();
426 while (child) {
427 if (child->isElementNode()) {
428 Element* e = static_cast<Element*>(child);
429 if (e->hasTagName(paramTag) && equalIgnoringCase(e->getAttribute(nameAttr), "type") && MIMETypeRegistry::isJavaAppletMIMEType(e->getAttribute(valueAttr).string()))
430 return true;
431 else if (e->hasTagName(objectTag) && static_cast<HTMLObjectElement*>(e)->containsJavaApplet())
432 return true;
433 else if (e->hasTagName(appletTag))
434 return true;
435 }
436 child = child->nextSibling();
437 }
438
439 return false;
440 }
441
addSubresourceAttributeURLs(ListHashSet<KURL> & urls) const442 void HTMLObjectElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
443 {
444 HTMLPlugInImageElement::addSubresourceAttributeURLs(urls);
445
446 addSubresourceURL(urls, data());
447 if (useMap().startsWith("#"))
448 addSubresourceURL(urls, document()->completeURL(useMap()));
449 }
450
451 }
452