Remove debug code.
[vuplus_webkit] / Source / WebCore / html / HTMLObjectElement.cpp
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, 2011 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 "Attribute.h"
28 #include "CSSValueKeywords.h"
29 #include "EventNames.h"
30 #include "ExceptionCode.h"
31 #include "FormDataList.h"
32 #include "Frame.h"
33 #include "HTMLDocument.h"
34 #include "HTMLFormElement.h"
35 #include "HTMLImageLoader.h"
36 #include "HTMLMetaElement.h"
37 #include "HTMLNames.h"
38 #include "HTMLParamElement.h"
39 #include "HTMLParserIdioms.h"
40 #include "MIMETypeRegistry.h"
41 #include "NodeList.h"
42 #include "Page.h"
43 #include "PluginViewBase.h"
44 #include "RenderEmbeddedObject.h"
45 #include "RenderImage.h"
46 #include "RenderWidget.h"
47 #include "ScriptEventListener.h"
48 #include "Settings.h"
49 #include "Text.h"
50 #include "Widget.h"
51 #include "FrameView.h"
52
53 namespace WebCore {
54
55 using namespace HTMLNames;
56
57 inline HTMLObjectElement::HTMLObjectElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser) 
58     : HTMLPlugInImageElement(tagName, document, createdByParser, ShouldNotPreferPlugInsForImages)
59     , FormAssociatedElement(form)
60     , m_docNamedItem(true)
61     , m_useFallbackContent(false)
62     , m_widget( 0 )
63     , m_oipfType( NO_OIPF_OBJ )
64 {
65
66         fprintf( stderr, "HTMLObject Constructor this %x\n", this );
67
68     ASSERT(hasTagName(objectTag));
69     if (!this->form())
70         setForm(findFormAncestor());
71     if (this->form())
72         this->form()->registerFormElement(this);
73 }
74
75 inline HTMLObjectElement::~HTMLObjectElement()
76 {
77     if (form())
78         form()->removeFormElement(this);
79
80         fprintf( stderr, "HTMLObject Destructor %x\n", ( m_widget == 0 ) );
81         if( m_widget )
82         {
83                 if( document() && document()->view() )
84                 {
85                         document()->view()->removeChild( m_widget.get() );
86                 }
87                 else
88                 {
89                         m_widget->setParent( NULL );
90                 }
91                 
92                 m_widget = 0;
93         }
94 }
95
96 PassRefPtr<HTMLObjectElement> HTMLObjectElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form, bool createdByParser)
97 {
98     return adoptRef(new HTMLObjectElement(tagName, document, form, createdByParser));
99 }
100
101 RenderWidget* HTMLObjectElement::renderWidgetForJSBindings()
102 {
103     document()->updateLayoutIgnorePendingStylesheets();
104     return renderPart(); // This will return 0 if the renderer is not a RenderPart.
105 }
106
107 void HTMLObjectElement::parseMappedAttribute(Attribute* attr)
108 {
109     if (attr->name() == formAttr)
110         formAttributeChanged();
111     else if (attr->name() == typeAttr) {
112         m_serviceType = attr->value().lower();
113         size_t pos = m_serviceType.find(";");
114         if (pos != notFound)
115             m_serviceType = m_serviceType.left(pos);
116         if (renderer())
117             setNeedsWidgetUpdate(true);
118         if (!isImageType() && m_imageLoader)
119             m_imageLoader.clear();
120
121                 /* oipfType */
122                 
123                 if (equalIgnoringCase( m_serviceType, "application/oipfobjectfactory") )
124                 {
125                         m_oipfType = OIPF_OBJ_FACTORY;
126                 }
127                 else if( equalIgnoringCase(serviceType(), "application/oipfapplicationmanager" ) )
128                 {
129                         m_oipfType = OIPF_APP_MANANGER;
130                 }
131                 else if( equalIgnoringCase(serviceType(), "application/oipfconfiguration"))
132                 {
133                         m_oipfType = OIPF_CONFIGURATION;
134                 }
135                 else if( equalIgnoringCase(serviceType(), "application/oipfcapabilities"))
136                 {
137                         m_oipfType = OIPF_CAPABILITIES;
138                 }
139                 else if( equalIgnoringCase(serviceType(), "application/oipfdrmagent"))
140                 {
141                         m_oipfType = OIPF_DRMAGENT;
142                 }
143                 else if( equalIgnoringCase(serviceType(), "video/broadcast") )
144                 {
145                         m_oipfType = OIPF_VIDEO_BC;
146                 }
147                 else if( equalIgnoringCase(serviceType(), "valups/system") )
148                 {
149                         m_oipfType = VALUPS_SYSTEM;
150                 }
151                 else if( equalIgnoringCase(serviceType(), "humax/portalprofile") )
152                 {
153                         m_oipfType = H_PORTAL_PROFILE;
154                 }
155                 else if( equalIgnoringCase(serviceType(), "video/mp4")
156                         || equalIgnoringCase(serviceType(), "video/mpeg")
157                         || equalIgnoringCase(serviceType(), "video/mpeg4")
158                         || equalIgnoringCase(serviceType(), "application/x-mpegURL"))
159                 {
160                         m_oipfType = OIPF_VIDEO_MPEG;
161                 }               
162     } else if (attr->name() == dataAttr) {
163         m_url = stripLeadingAndTrailingHTMLSpaces(attr->value());
164         if (renderer()) {
165             setNeedsWidgetUpdate(true);
166             if (isImageType()) {
167                 if (!m_imageLoader)
168                     m_imageLoader = adoptPtr(new HTMLImageLoader(this));
169                 m_imageLoader->updateFromElementIgnoringPreviousError();
170             }
171         }
172     } else if (attr->name() == classidAttr) {
173         m_classId = attr->value();
174         if (renderer())
175             setNeedsWidgetUpdate(true);
176     } else if (attr->name() == onloadAttr)
177         setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr));
178     else if (attr->name() == onbeforeloadAttr)
179         setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, attr));
180     else if (attr->name() == nameAttr) {
181         const AtomicString& newName = attr->value();
182         if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) {
183             HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
184             document->removeNamedItem(m_name);
185             document->addNamedItem(newName);
186         }
187         m_name = newName;
188     } else if (attr->name() == borderAttr)
189         applyBorderAttribute(attr);
190     else if (isIdAttributeName(attr->name())) {
191         const AtomicString& newId = attr->value();
192         if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) {
193             HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
194             document->removeExtraNamedItem(m_id);
195             document->addExtraNamedItem(newId);
196         }
197         m_id = newId;
198         // also call superclass
199         HTMLPlugInImageElement::parseMappedAttribute(attr);
200     } else
201         HTMLPlugInImageElement::parseMappedAttribute(attr);
202 }
203
204 static void mapDataParamToSrc(Vector<String>* paramNames, Vector<String>* paramValues)
205 {
206     // Some plugins don't understand the "data" attribute of the OBJECT tag (i.e. Real and WMP
207     // require "src" attribute).
208     int srcIndex = -1, dataIndex = -1;
209     for (unsigned int i = 0; i < paramNames->size(); ++i) {
210         if (equalIgnoringCase((*paramNames)[i], "src"))
211             srcIndex = i;
212         else if (equalIgnoringCase((*paramNames)[i], "data"))
213             dataIndex = i;
214     }
215     
216     if (srcIndex == -1 && dataIndex != -1) {
217         paramNames->append("src");
218         paramValues->append((*paramValues)[dataIndex]);
219     }
220 }
221
222 // FIXME: This function should not deal with url or serviceType!
223 void HTMLObjectElement::parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues, String& url, String& serviceType)
224 {
225     HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames;
226     String urlParameter;
227     
228     // Scan the PARAM children and store their name/value pairs.
229     // Get the URL and type from the params if we don't already have them.
230     for (Node* child = firstChild(); child; child = child->nextSibling()) {
231         if (!child->hasTagName(paramTag))
232             continue;
233
234         HTMLParamElement* p = static_cast<HTMLParamElement*>(child);
235         String name = p->name();
236         if (name.isEmpty())
237             continue;
238
239         uniqueParamNames.add(name.impl());
240         paramNames.append(p->name());
241         paramValues.append(p->value());
242
243         // FIXME: url adjustment does not belong in this function.
244         if (url.isEmpty() && urlParameter.isEmpty() && (equalIgnoringCase(name, "src") || 
245                         equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url")|| equalIgnoringCase(name, "FileName")))
246             urlParameter = stripLeadingAndTrailingHTMLSpaces(p->value());
247         // FIXME: serviceType calculation does not belong in this function.
248         if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) {
249             serviceType = p->value();
250             size_t pos = serviceType.find(";");
251             if (pos != notFound)
252                 serviceType = serviceType.left(pos);
253         }
254     }
255     
256     // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag
257     // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is
258     // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means
259     // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM,
260     // else our Java plugin will misinterpret it. [4004531]
261     String codebase;
262     if (MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) {
263         codebase = "codebase";
264         uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already
265     }
266     
267     // Turn the attributes of the <object> element into arrays, but don't override <param> values.
268     NamedNodeMap* attributes = this->attributes(true);
269     if (attributes) {
270         for (unsigned i = 0; i < attributes->length(); ++i) {
271             Attribute* it = attributes->attributeItem(i);
272             const AtomicString& name = it->name().localName();
273             if (!uniqueParamNames.contains(name.impl())) {
274                 paramNames.append(name.string());
275                 paramValues.append(it->value().string());
276             }
277         }
278     }
279     
280     mapDataParamToSrc(&paramNames, &paramValues);
281     
282     // HTML5 says that an object resource's URL is specified by the object's data
283     // attribute, not by a param element. However, for compatibility, allow the
284     // resource's URL to be given by a param named "src", "movie", "code" or "url"
285     // if we know that resource points to a plug-in.
286     if (url.isEmpty() && !urlParameter.isEmpty()) {
287         SubframeLoader* loader = document()->frame()->loader()->subframeLoader();
288         if (loader->resourceWillUsePlugin(urlParameter, serviceType, shouldPreferPlugInsForImages()))
289             url = urlParameter;
290     }
291 }
292
293     
294 bool HTMLObjectElement::hasFallbackContent() const
295 {
296     for (Node* child = firstChild(); child; child = child->nextSibling()) {
297         // Ignore whitespace-only text, and <param> tags, any other content is fallback content.
298         if (child->isTextNode()) {
299             if (!static_cast<Text*>(child)->containsOnlyWhitespace())
300                 return true;
301         } else if (!child->hasTagName(paramTag))
302             return true;
303     }
304     return false;
305 }
306     
307 bool HTMLObjectElement::shouldAllowQuickTimeClassIdQuirk()
308 {
309     // This site-specific hack maintains compatibility with Mac OS X Wiki Server,
310     // which embeds QuickTime movies using an object tag containing QuickTime's
311     // ActiveX classid. Treat this classid as valid only if OS X Server's unique
312     // 'generator' meta tag is present. Only apply this quirk if there is no
313     // fallback content, which ensures the quirk will disable itself if Wiki
314     // Server is updated to generate an alternate embed tag as fallback content.
315     if (!document()->page()
316         || !document()->page()->settings()->needsSiteSpecificQuirks()
317         || hasFallbackContent()
318         || !equalIgnoringCase(classId(), "clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"))
319         return false;
320
321     RefPtr<NodeList> metaElements = document()->getElementsByTagName(HTMLNames::metaTag.localName());
322     unsigned length = metaElements->length();
323     for (unsigned i = 0; i < length; ++i) {
324         ASSERT(metaElements->item(i)->isHTMLElement());
325         HTMLMetaElement* metaElement = static_cast<HTMLMetaElement*>(metaElements->item(i));
326         if (equalIgnoringCase(metaElement->name(), "generator") && metaElement->content().startsWith("Mac OS X Server Web Services Server", false))
327             return true;
328     }
329     
330     return false;
331 }
332     
333 bool HTMLObjectElement::hasValidClassId()
334 {
335 #if PLATFORM(QT)
336     if (equalIgnoringCase(serviceType(), "application/x-qt-plugin") || equalIgnoringCase(serviceType(), "application/x-qt-styled-widget"))
337         return true;
338 #endif
339
340     if (MIMETypeRegistry::isJavaAppletMIMEType(serviceType()) && classId().startsWith("java:", false))
341         return true;
342     
343     if (shouldAllowQuickTimeClassIdQuirk())
344         return true;
345
346     if (equalIgnoringCase(serviceType(), "application/x-oleobject")&&
347                 equalIgnoringCase( classId(), "CLSID:22d6f312-b0f6-11d0-94ab-0080c74c7e95" ))
348     {
349         return true;    
350     }
351
352         
353
354     // HTML5 says that fallback content should be rendered if a non-empty
355     // classid is specified for which the UA can't find a suitable plug-in.
356     return classId().isEmpty();
357 }
358
359 Widget* HTMLObjectElement::pluginWidget()
360 {
361         if( m_widget && m_widget.get() )
362         {
363                 return m_widget.get();
364         }
365         
366     return HTMLPlugInImageElement::pluginWidget();
367 }
368
369
370 void HTMLObjectElement::setWidget(PassRefPtr<Widget> widget)
371 {       
372         if( m_oipfType == NO_OIPF_OBJ )
373         {
374                 fprintf( stderr, "!!!!!! NO_OIPF_OBJ!!!!!!!\n" );
375                 return;
376         }
377         
378     if ( widget == m_widget )
379         return;
380
381         m_widget = widget;
382 }
383
384 #define OIPF_HAS_NO_DISPLAY( a ) (( a == OIPF_APP_MANANGER ) ||\
385                                                                         ( a == OIPF_CONFIGURATION ) || \
386                                                                         ( a == OIPF_CAPABILITIES ) || \
387                                                                         ( a == OIPF_DRMAGENT ) || \
388                                                                         ( a == OIPF_OBJ_FACTORY ) || \
389                                                                         ( a == VALUPS_SYSTEM ) || \
390                                                                         ( a == H_PORTAL_PROFILE ) )
391
392 void HTMLObjectElement::updateWidgetIfNecessary()
393 {
394     document()->updateStyleIfNeeded();
395         
396 //      fprintf( stderr, "serviceType = %s\n", m_serviceType.ascii().data() );
397
398     if ((!needsWidgetUpdate() || useFallbackContent() || isImageType()) &&
399                 ( m_oipfType == NO_OIPF_OBJ ) )
400     {
401         return;
402     }
403
404         if( m_oipfType != NO_OIPF_OBJ ) //( renderEmbeddedObject() == NULL && m_oipfType != NO_OIPF_OBJ ) || ( OIPF_HAS_NO_DISPLAY( m_oipfType ) ) )
405         {               
406                 if( m_widget == 0 )
407                 {
408                         setNeedsWidgetUpdate(false);
409                         // FIXME: This should ASSERT isFinishedParsingChildren() instead.
410                         if (!isFinishedParsingChildren() && !OIPF_HAS_NO_DISPLAY( m_oipfType ) )
411                         {
412                                 return;
413                         }
414                         
415                         String url = this->url();
416                         String serviceType = this->serviceType();
417                         
418                         // FIXME: These should be joined into a PluginParameters class.
419                         Vector<String> paramNames;
420                         Vector<String> paramValues;
421                         parametersForPlugin(paramNames, paramValues, url, serviceType);
422                         
423                         // Note: url is modified above by parametersForPlugin.
424                         if (!allowedToLoadFrameURL(url))
425                         {
426                                 return;
427                         }
428                                                         
429                         ASSERT(!m_inBeforeLoadEventHandler);
430                         m_inBeforeLoadEventHandler = true;
431                         bool beforeLoadAllowedLoad = dispatchBeforeLoadEvent(url);
432                         m_inBeforeLoadEventHandler = false;
433                         
434                         // beforeload events can modify the DOM, potentially causing
435                         // RenderWidget::destroy() to be called.  Ensure we haven't been
436                         // destroyed before continuing.
437                         // FIXME: Should this render fallback content?
438         //              if (!renderer())
439                 //              return;
440                         
441                         RefPtr<HTMLObjectElement> protect(this); // Loading the plugin might remove us from the document.
442                         SubframeLoader* loader = document()->frame()->loader()->subframeLoader();
443                         
444                         if( beforeLoadAllowedLoad && hasValidClassId() )
445                                 loader->requestObjectWithoutRenderer(this, url, getAttribute(nameAttr), serviceType, paramNames, paramValues);
446
447                         if( m_widget )
448                         {
449                                 if( document() && document()->view() )
450                                 {
451                                         document()->view()->addChild( m_widget );
452                                 }
453                         }
454                 }
455                                 
456                 return;         
457         }
458
459     if (!needsWidgetUpdate() || useFallbackContent() || isImageType())
460     {
461         return;
462     }
463
464         return HTMLPlugInImageElement::updateWidgetIfNecessary();
465  }
466
467
468 // FIXME: This should be unified with HTMLEmbedElement::updateWidget and
469 // moved down into HTMLPluginImageElement.cpp
470 void HTMLObjectElement::updateWidget(PluginCreationOption pluginCreationOption)
471 {
472 //      if(( m_oipfType != NO_OIPF_OBJ ))// OIPF_HAS_NO_DISPLAY( m_oipfType ) )
473 //      {
474 //              fprintf( stderr, "ERROR>>>>>>>>>>>>>>>>> oipfType = %d\n", m_oipfType );
475 //              return;
476 //      }
477         
478     ASSERT(!renderEmbeddedObject()->pluginCrashedOrWasMissing());
479     // FIXME: We should ASSERT(needsWidgetUpdate()), but currently
480     // FrameView::updateWidget() calls updateWidget(false) without checking if
481     // the widget actually needs updating!
482     setNeedsWidgetUpdate(false);
483     // FIXME: This should ASSERT isFinishedParsingChildren() instead.
484     if (!isFinishedParsingChildren())
485         return;
486     
487     String url = this->url();
488     String serviceType = this->serviceType();
489
490     // FIXME: These should be joined into a PluginParameters class.
491     Vector<String> paramNames;
492     Vector<String> paramValues;
493     parametersForPlugin(paramNames, paramValues, url, serviceType);
494
495     // Note: url is modified above by parametersForPlugin.
496     if (!allowedToLoadFrameURL(url))
497         return;
498
499     bool fallbackContent = hasFallbackContent();
500     renderEmbeddedObject()->setHasFallbackContent(fallbackContent);
501
502     if (pluginCreationOption == CreateOnlyNonNetscapePlugins && wouldLoadAsNetscapePlugin(url, serviceType))
503         return;
504
505     ASSERT(!m_inBeforeLoadEventHandler);
506     m_inBeforeLoadEventHandler = true;
507     bool beforeLoadAllowedLoad = dispatchBeforeLoadEvent(url);
508     m_inBeforeLoadEventHandler = false;
509
510     // beforeload events can modify the DOM, potentially causing
511     // RenderWidget::destroy() to be called.  Ensure we haven't been
512     // destroyed before continuing.
513     // FIXME: Should this render fallback content?
514     if (!renderer())
515         return;
516
517     RefPtr<HTMLObjectElement> protect(this); // Loading the plugin might remove us from the document.
518     SubframeLoader* loader = document()->frame()->loader()->subframeLoader();
519     bool success = beforeLoadAllowedLoad && hasValidClassId() && loader->requestObject(this, url, getAttribute(nameAttr), serviceType, paramNames, paramValues);
520
521     if (!success && fallbackContent)
522         renderFallbackContent();
523 }
524
525 bool HTMLObjectElement::rendererIsNeeded(const NodeRenderingContext& context)
526 {
527     // FIXME: This check should not be needed, detached documents never render!
528     Frame* frame = document()->frame();
529     if (!frame)
530         return false;
531
532         /* hbbtv Object for OIPF will be always rendered 
533     if (equalIgnoringCase(serviceType(), "application/oipfobjectfactory") 
534                 || equalIgnoringCase(serviceType(), "application/oipfapplicationmanager")
535                 || equalIgnoringCase(serviceType(), "application/oipfconfiguration")
536                 || equalIgnoringCase(serviceType(), "video/broadcast")
537                 || equalIgnoringCase(serviceType(), "video/mp4")
538                 || equalIgnoringCase(serviceType(), "video/mpeg")
539                 || equalIgnoringCase(serviceType(), "video/mpeg4")              
540                 )
541     {
542                 fprintf( stderr, "%s %s %d\n", __FILE__, __func__, __LINE__ );
543                 return true;
544     }
545         /* hbbtv Object for OIPF will be always rendered */
546
547 //      if( m_oipfType != NO_OIPF_OBJ &&
548 //              m_widget )
549 //      {
550 //              fprintf( stderr, "Do not render - m_widget exists\n" );
551 //              return false;
552 //      }
553
554     return HTMLPlugInImageElement::rendererIsNeeded(context);
555 }
556
557 PassRefPtr<Widget> HTMLObjectElement::getPredefinedWidget()
558 {
559         return m_widget;
560 }
561
562 #if ENABLE(NETSCAPE_PLUGIN_API)
563
564 NPObject* HTMLObjectElement::getNPObject()
565 {
566         if( !document() || !document()->frame() )
567                 return NULL;
568         
569         return HTMLPlugInElement::getNPObject();
570 }
571
572 #endif /* ENABLE(NETSCAPE_PLUGIN_API) */
573
574
575 void HTMLObjectElement::insertedIntoDocument()
576 {
577     HTMLPlugInImageElement::insertedIntoDocument();
578     if (!inDocument())
579         return;
580
581     if (isDocNamedItem() && document()->isHTMLDocument()) {
582         HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
583         document->addNamedItem(m_name);
584         document->addExtraNamedItem(m_id);
585     }
586
587     FormAssociatedElement::insertedIntoDocument();
588 }
589
590 void HTMLObjectElement::removedFromDocument()
591 {
592     if (isDocNamedItem() && document()->isHTMLDocument()) {
593         HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
594         document->removeNamedItem(m_name);
595         document->removeExtraNamedItem(m_id);
596     }
597
598     HTMLPlugInImageElement::removedFromDocument();
599     FormAssociatedElement::removedFromDocument();
600 }
601
602 void HTMLObjectElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
603 {
604     updateDocNamedItem();
605     if (inDocument() && !useFallbackContent()) {
606         setNeedsWidgetUpdate(true);
607         setNeedsStyleRecalc();
608     }
609     HTMLPlugInImageElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
610 }
611
612 bool HTMLObjectElement::isURLAttribute(Attribute *attr) const
613 {
614     return (attr->name() == dataAttr || (attr->name() == usemapAttr && attr->value().string()[0] != '#'));
615 }
616
617 const QualifiedName& HTMLObjectElement::imageSourceAttributeName() const
618 {
619     return dataAttr;
620 }
621
622 void HTMLObjectElement::renderFallbackContent()
623 {
624     if (useFallbackContent())
625         return;
626     
627     if (!inDocument())
628         return;
629
630     // Before we give up and use fallback content, check to see if this is a MIME type issue.
631     if (m_imageLoader && m_imageLoader->image() && m_imageLoader->image()->status() != CachedResource::LoadError) {
632         m_serviceType = m_imageLoader->image()->response().mimeType();
633         if (!isImageType()) {
634             // If we don't think we have an image type anymore, then clear the image from the loader.
635             m_imageLoader->setImage(0);
636             reattach();
637             return;
638         }
639     }
640
641     m_useFallbackContent = true;
642
643     // FIXME: Style gets recalculated which is suboptimal.
644     detach();
645     attach();
646 }
647
648 // FIXME: This should be removed, all callers are almost certainly wrong.
649 static bool isRecognizedTagName(const QualifiedName& tagName)
650 {
651     DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, tagList, ());
652     if (tagList.isEmpty()) {
653         size_t tagCount = 0;
654         QualifiedName** tags = HTMLNames::getHTMLTags(&tagCount);
655         for (size_t i = 0; i < tagCount; i++) {
656             if (*tags[i] == bgsoundTag
657                 || *tags[i] == commandTag
658                 || *tags[i] == detailsTag
659                 || *tags[i] == figcaptionTag
660                 || *tags[i] == figureTag
661                 || *tags[i] == summaryTag
662                 || *tags[i] == trackTag) {
663                 // Even though we have atoms for these tags, we don't want to
664                 // treat them as "recognized tags" for the purpose of parsing
665                 // because that changes how we parse documents.
666                 continue;
667             }
668             tagList.add(tags[i]->localName().impl());
669         }
670     }
671     return tagList.contains(tagName.localName().impl());
672 }
673
674 void HTMLObjectElement::updateDocNamedItem()
675 {
676     // The rule is "<object> elements with no children other than
677     // <param> elements, unknown elements and whitespace can be
678     // found by name in a document, and other <object> elements cannot."
679     bool wasNamedItem = m_docNamedItem;
680     bool isNamedItem = true;
681     Node* child = firstChild();
682     while (child && isNamedItem) {
683         if (child->isElementNode()) {
684             Element* element = static_cast<Element*>(child);
685             // FIXME: Use of isRecognizedTagName is almost certainly wrong here.
686             if (isRecognizedTagName(element->tagQName()) && !element->hasTagName(paramTag))
687                 isNamedItem = false;
688         } else if (child->isTextNode()) {
689             if (!static_cast<Text*>(child)->containsOnlyWhitespace())
690                 isNamedItem = false;
691         } else
692             isNamedItem = false;
693         child = child->nextSibling();
694     }
695     if (isNamedItem != wasNamedItem && document()->isHTMLDocument()) {
696         HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
697         if (isNamedItem) {
698             document->addNamedItem(m_name);
699             document->addExtraNamedItem(m_id);
700         } else {
701             document->removeNamedItem(m_name);
702             document->removeExtraNamedItem(m_id);
703         }
704     }
705     m_docNamedItem = isNamedItem;
706 }
707
708 bool HTMLObjectElement::containsJavaApplet() const
709 {
710     if (MIMETypeRegistry::isJavaAppletMIMEType(getAttribute(typeAttr)))
711         return true;
712         
713     for (Element* child = firstElementChild(); child; child = child->nextElementSibling()) {
714         if (child->hasTagName(paramTag)
715                 && equalIgnoringCase(child->getAttribute(nameAttr), "type")
716                 && MIMETypeRegistry::isJavaAppletMIMEType(child->getAttribute(valueAttr).string()))
717             return true;
718         if (child->hasTagName(objectTag)
719                 && static_cast<HTMLObjectElement*>(child)->containsJavaApplet())
720             return true;
721         if (child->hasTagName(appletTag))
722             return true;
723     }
724     
725     return false;
726 }
727
728 void HTMLObjectElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
729 {
730     HTMLPlugInImageElement::addSubresourceAttributeURLs(urls);
731
732     addSubresourceURL(urls, document()->completeURL(getAttribute(dataAttr)));
733
734     // FIXME: Passing a string that starts with "#" to the completeURL function does
735     // not seem like it would work. The image element has similar but not identical code.
736     const AtomicString& useMap = getAttribute(usemapAttr);
737     if (useMap.startsWith("#"))
738         addSubresourceURL(urls, document()->completeURL(useMap));
739 }
740
741 void HTMLObjectElement::willMoveToNewOwnerDocument()
742 {
743     FormAssociatedElement::willMoveToNewOwnerDocument();
744     HTMLPlugInImageElement::willMoveToNewOwnerDocument();
745 }
746
747 void HTMLObjectElement::insertedIntoTree(bool deep)
748 {
749     FormAssociatedElement::insertedIntoTree();
750     HTMLPlugInImageElement::insertedIntoTree(deep);
751 }
752
753 void HTMLObjectElement::removedFromTree(bool deep)
754 {
755     FormAssociatedElement::removedFromTree();
756     HTMLPlugInImageElement::removedFromTree(deep);
757 }
758
759 bool HTMLObjectElement::appendFormData(FormDataList& encoding, bool)
760 {
761     if (name().isEmpty())
762         return false;
763
764     Widget* widget = pluginWidget();
765     if (!widget || !widget->isPluginViewBase())
766         return false;
767     String value;
768     if (!static_cast<PluginViewBase*>(widget)->getFormValue(value))
769         return false;
770     encoding.appendData(name(), value);
771     return true;
772 }
773
774 const AtomicString& HTMLObjectElement::formControlName() const
775 {
776     return m_name.isNull() ? emptyAtom : m_name;
777 }
778
779 HTMLFormElement* HTMLObjectElement::virtualForm() const
780 {
781     return FormAssociatedElement::form();
782 }
783
784 }