• 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 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