Reviewed by Eric.
[WebKit-https.git] / WebCore / html / html_objectimpl.cpp
1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
6  *           (C) 2000 Stefan Schimanski (1Stein@gmx.de)
7  * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #include "config.h"
26 #include "html_objectimpl.h"
27
28 #include "CSSPropertyNames.h"
29 #include "CSSValueKeywords.h"
30 #include "DeprecatedString.h"
31 #include "EventNames.h"
32 #include "Frame.h"
33 #include "HTMLDocument.h"
34 #include "HTMLFormElement.h"
35 #include "HTMLNames.h"
36 #include "PlatformString.h"
37 #include "RenderApplet.h"
38 #include "RenderEmptyApplet.h"
39 #include "RenderImage.h"
40 #include "Text.h"
41 #include "csshelper.h"
42 #include "cssstyleselector.h"
43 #include "dom2_eventsimpl.h"
44 #include "html_imageimpl.h"
45 #include "render_frames.h"
46
47 namespace WebCore {
48
49 using namespace EventNames;
50 using namespace HTMLNames;
51
52 // -------------------------------------------------------------------------
53
54 HTMLAppletElement::HTMLAppletElement(Document *doc)
55 : HTMLElement(appletTag, doc)
56 , m_allParamsAvailable(false)
57 {
58 }
59
60 HTMLAppletElement::~HTMLAppletElement()
61 {
62 #if __APPLE__
63     // m_appletInstance should have been cleaned up in detach().
64     assert(!m_appletInstance);
65 #endif
66 }
67
68 bool HTMLAppletElement::checkDTD(const Node* newChild)
69 {
70     return newChild->hasTagName(paramTag) || HTMLElement::checkDTD(newChild);
71 }
72
73 bool HTMLAppletElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
74 {
75     if (attrName == widthAttr ||
76         attrName == heightAttr ||
77         attrName == vspaceAttr ||
78         attrName == hspaceAttr) {
79             result = eUniversal;
80             return false;
81     }
82     
83     if (attrName == alignAttr) {
84         result = eReplaced; // Share with <img> since the alignment behavior is the same.
85         return false;
86     }
87     
88     return HTMLElement::mapToEntry(attrName, result);
89 }
90
91 void HTMLAppletElement::parseMappedAttribute(MappedAttribute *attr)
92 {
93     if (attr->name() == altAttr ||
94         attr->name() == archiveAttr ||
95         attr->name() == codeAttr ||
96         attr->name() == codebaseAttr ||
97         attr->name() == mayscriptAttr ||
98         attr->name() == objectAttr) {
99         // Do nothing.
100     } else if (attr->name() == widthAttr) {
101         addCSSLength(attr, CSS_PROP_WIDTH, attr->value());
102     } else if (attr->name() == heightAttr) {
103         addCSSLength(attr, CSS_PROP_HEIGHT, attr->value());
104     } else if (attr->name() == vspaceAttr) {
105         addCSSLength(attr, CSS_PROP_MARGIN_TOP, attr->value());
106         addCSSLength(attr, CSS_PROP_MARGIN_BOTTOM, attr->value());
107     } else if (attr->name() == hspaceAttr) {
108         addCSSLength(attr, CSS_PROP_MARGIN_LEFT, attr->value());
109         addCSSLength(attr, CSS_PROP_MARGIN_RIGHT, attr->value());
110     } else if (attr->name() == alignAttr) {
111         addHTMLAlignment(attr);
112     } else if (attr->name() == nameAttr) {
113         String newNameAttr = attr->value();
114         if (inDocument() && document()->isHTMLDocument()) {
115             HTMLDocument *doc = static_cast<HTMLDocument *>(document());
116             doc->removeNamedItem(oldNameAttr);
117             doc->addNamedItem(newNameAttr);
118         }
119         oldNameAttr = newNameAttr;
120     } else if (attr->name() == idAttr) {
121         String newIdAttr = attr->value();
122         if (inDocument() && document()->isHTMLDocument()) {
123             HTMLDocument *doc = static_cast<HTMLDocument *>(document());
124             doc->removeDocExtraNamedItem(oldIdAttr);
125             doc->addDocExtraNamedItem(newIdAttr);
126         }
127         oldIdAttr = newIdAttr;
128         // also call superclass
129         HTMLElement::parseMappedAttribute(attr);
130     } else
131         HTMLElement::parseMappedAttribute(attr);
132 }
133
134 void HTMLAppletElement::insertedIntoDocument()
135 {
136     if (document()->isHTMLDocument()) {
137         HTMLDocument *doc = static_cast<HTMLDocument *>(document());
138         doc->addNamedItem(oldNameAttr);
139         doc->addDocExtraNamedItem(oldIdAttr);
140     }
141
142     HTMLElement::insertedIntoDocument();
143 }
144
145 void HTMLAppletElement::removedFromDocument()
146 {
147     if (document()->isHTMLDocument()) {
148         HTMLDocument *doc = static_cast<HTMLDocument *>(document());
149         doc->removeNamedItem(oldNameAttr);
150         doc->removeDocExtraNamedItem(oldIdAttr);
151     }
152
153     HTMLElement::removedFromDocument();
154 }
155
156 bool HTMLAppletElement::rendererIsNeeded(RenderStyle *style)
157 {
158     return !getAttribute(codeAttr).isNull();
159 }
160
161 RenderObject *HTMLAppletElement::createRenderer(RenderArena *arena, RenderStyle *style)
162 {
163     Frame *frame = document()->frame();
164
165     if (frame && frame->javaEnabled()) {
166         HashMap<String, String> args;
167
168         args.set("code", getAttribute(codeAttr));
169         const AtomicString& codeBase = getAttribute(codebaseAttr);
170         if(!codeBase.isNull())
171             args.set("codeBase", codeBase);
172         const AtomicString& name = getAttribute(document()->htmlMode() != Document::XHtml ? nameAttr : idAttr);
173         if (!name.isNull())
174             args.set("name", name);
175         const AtomicString& archive = getAttribute(archiveAttr);
176         if (!archive.isNull())
177             args.set("archive", archive);
178
179         args.set("baseURL", document()->baseURL());
180
181         const AtomicString& mayScript = getAttribute(mayscriptAttr);
182         if (!mayScript.isNull())
183             args.set("mayScript", mayScript);
184
185         // Other arguments (from <PARAM> tags) are added later.
186         
187         return new (document()->renderArena()) RenderApplet(this, args);
188     }
189
190     // ### remove me. we should never show an empty applet, instead
191     // render the alternative content given by the webpage
192     return new (document()->renderArena()) RenderEmptyApplet(this);
193 }
194
195 #if __APPLE__
196 KJS::Bindings::Instance *HTMLAppletElement::getAppletInstance() const
197 {
198     Frame *frame = document()->frame();
199     if (!frame || !frame->javaEnabled())
200         return 0;
201
202     if (m_appletInstance)
203         return m_appletInstance.get();
204     
205     RenderApplet *r = static_cast<RenderApplet*>(renderer());
206     if (r) {
207         r->createWidgetIfNecessary();
208         if (r->widget())
209             // Call into the frame (and over the bridge) to pull the Bindings::Instance
210             // from the guts of the plugin.
211             m_appletInstance = frame->getAppletInstanceForWidget(r->widget());
212     }
213     return m_appletInstance.get();
214 }
215 #endif
216
217 void HTMLAppletElement::closeRenderer()
218 {
219     // The parser just reached </applet>, so all the params are available now.
220     m_allParamsAvailable = true;
221     if (renderer())
222         renderer()->setNeedsLayout(true); // This will cause it to create its widget & the Java applet
223     HTMLElement::closeRenderer();
224 }
225
226 void HTMLAppletElement::detach()
227 {
228 #if __APPLE__
229     m_appletInstance = 0;
230 #endif
231     HTMLElement::detach();
232 }
233
234 bool HTMLAppletElement::allParamsAvailable()
235 {
236     return m_allParamsAvailable;
237 }
238
239 String HTMLAppletElement::align() const
240 {
241     return getAttribute(alignAttr);
242 }
243
244 void HTMLAppletElement::setAlign(const String &value)
245 {
246     setAttribute(alignAttr, value);
247 }
248
249 String HTMLAppletElement::alt() const
250 {
251     return getAttribute(altAttr);
252 }
253
254 void HTMLAppletElement::setAlt(const String &value)
255 {
256     setAttribute(altAttr, value);
257 }
258
259 String HTMLAppletElement::archive() const
260 {
261     return getAttribute(archiveAttr);
262 }
263
264 void HTMLAppletElement::setArchive(const String &value)
265 {
266     setAttribute(archiveAttr, value);
267 }
268
269 String HTMLAppletElement::code() const
270 {
271     return getAttribute(codeAttr);
272 }
273
274 void HTMLAppletElement::setCode(const String &value)
275 {
276     setAttribute(codeAttr, value);
277 }
278
279 String HTMLAppletElement::codeBase() const
280 {
281     return getAttribute(codebaseAttr);
282 }
283
284 void HTMLAppletElement::setCodeBase(const String &value)
285 {
286     setAttribute(codebaseAttr, value);
287 }
288
289 String HTMLAppletElement::height() const
290 {
291     return getAttribute(heightAttr);
292 }
293
294 void HTMLAppletElement::setHeight(const String &value)
295 {
296     setAttribute(heightAttr, value);
297 }
298
299 String HTMLAppletElement::hspace() const
300 {
301     return getAttribute(hspaceAttr);
302 }
303
304 void HTMLAppletElement::setHspace(const String &value)
305 {
306     setAttribute(hspaceAttr, value);
307 }
308
309 String HTMLAppletElement::name() const
310 {
311     return getAttribute(nameAttr);
312 }
313
314 void HTMLAppletElement::setName(const String &value)
315 {
316     setAttribute(nameAttr, value);
317 }
318
319 String HTMLAppletElement::object() const
320 {
321     return getAttribute(objectAttr);
322 }
323
324 void HTMLAppletElement::setObject(const String &value)
325 {
326     setAttribute(objectAttr, value);
327 }
328
329 String HTMLAppletElement::vspace() const
330 {
331     return getAttribute(vspaceAttr);
332 }
333
334 void HTMLAppletElement::setVspace(const String &value)
335 {
336     setAttribute(vspaceAttr, value);
337 }
338
339 String HTMLAppletElement::width() const
340 {
341     return getAttribute(widthAttr);
342 }
343
344 void HTMLAppletElement::setWidth(const String &value)
345 {
346     setAttribute(widthAttr, value);
347 }
348
349 // -------------------------------------------------------------------------
350
351 HTMLEmbedElement::HTMLEmbedElement(Document *doc)
352 : HTMLElement(embedTag, doc)
353 {
354 }
355
356 HTMLEmbedElement::~HTMLEmbedElement()
357 {
358 #if __APPLE__
359     // m_embedInstance should have been cleaned up in detach().
360     assert(!m_embedInstance);
361 #endif
362 }
363
364 bool HTMLEmbedElement::checkDTD(const Node* newChild)
365 {
366     return newChild->hasTagName(paramTag) || HTMLElement::checkDTD(newChild);
367 }
368
369 #if __APPLE__
370 KJS::Bindings::Instance *HTMLEmbedElement::getEmbedInstance() const
371 {
372     Frame *frame = document()->frame();
373     if (!frame)
374         return 0;
375
376     if (m_embedInstance)
377         return m_embedInstance.get();
378     
379     RenderObject *r = renderer();
380     if (!r) {
381         Node *p = parentNode();
382         if (p && p->hasTagName(objectTag))
383             r = p->renderer();
384     }
385
386     if (r && r->isWidget()){
387         if (Widget *widget = static_cast<RenderWidget *>(r)->widget()) {
388             // Call into the frame (and over the bridge) to pull the Bindings::Instance
389             // from the guts of the Java VM.
390             m_embedInstance = frame->getEmbedInstanceForWidget(widget);
391             // Applet may specified with <embed> tag.
392             if (!m_embedInstance)
393                 m_embedInstance = frame->getAppletInstanceForWidget(widget);
394         }
395     }
396     return m_embedInstance.get();
397 }
398 #endif
399
400 bool HTMLEmbedElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
401 {
402     if (attrName == widthAttr ||
403         attrName == heightAttr ||
404         attrName == borderAttr ||
405         attrName == vspaceAttr ||
406         attrName == hspaceAttr ||
407         attrName == valignAttr ||
408         attrName == hiddenAttr) {
409         result = eUniversal;
410         return false;
411     }
412         
413     if (attrName == alignAttr) {
414         result = eReplaced; // Share with <img> since the alignment behavior is the same.
415         return false;
416     }
417     
418     return HTMLElement::mapToEntry(attrName, result);
419 }
420
421 void HTMLEmbedElement::parseMappedAttribute(MappedAttribute *attr)
422 {
423     DeprecatedString val = attr->value().deprecatedString();
424   
425     int pos;
426     if (attr->name() == typeAttr) {
427         serviceType = val.lower();
428         pos = serviceType.find( ";" );
429         if ( pos!=-1 )
430             serviceType = serviceType.left( pos );
431     } else if (attr->name() == codeAttr ||
432                attr->name() == srcAttr) {
433          url = WebCore::parseURL(attr->value()).deprecatedString();
434     } else if (attr->name() == widthAttr) {
435         addCSSLength( attr, CSS_PROP_WIDTH, attr->value() );
436     } else if (attr->name() == heightAttr) {
437         addCSSLength( attr, CSS_PROP_HEIGHT, attr->value());
438     } else if (attr->name() == borderAttr) {
439         addCSSLength(attr, CSS_PROP_BORDER_WIDTH, attr->value());
440         addCSSProperty( attr, CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_SOLID );
441         addCSSProperty( attr, CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_SOLID );
442         addCSSProperty( attr, CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_SOLID );
443         addCSSProperty( attr, CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_SOLID );
444     } else if (attr->name() == vspaceAttr) {
445         addCSSLength(attr, CSS_PROP_MARGIN_TOP, attr->value());
446         addCSSLength(attr, CSS_PROP_MARGIN_BOTTOM, attr->value());
447     } else if (attr->name() == hspaceAttr) {
448         addCSSLength(attr, CSS_PROP_MARGIN_LEFT, attr->value());
449         addCSSLength(attr, CSS_PROP_MARGIN_RIGHT, attr->value());
450     } else if (attr->name() == alignAttr) {
451         addHTMLAlignment(attr);
452     } else if (attr->name() == valignAttr) {
453         addCSSProperty(attr, CSS_PROP_VERTICAL_ALIGN, attr->value());
454     } else if (attr->name() == pluginpageAttr ||
455                attr->name() == pluginspageAttr) {
456         pluginPage = val;
457     } else if (attr->name() == hiddenAttr) {
458         if (val.lower()=="yes" || val.lower()=="true") {
459             // FIXME: Not dynamic, but it's not really important that such a rarely-used
460             // feature work dynamically.
461             addCSSLength( attr, CSS_PROP_WIDTH, "0" );
462             addCSSLength( attr, CSS_PROP_HEIGHT, "0" );
463         }
464     } else if (attr->name() == nameAttr) {
465         String newNameAttr = attr->value();
466         if (inDocument() && document()->isHTMLDocument()) {
467             HTMLDocument *doc = static_cast<HTMLDocument *>(document());
468             doc->removeNamedItem(oldNameAttr);
469             doc->addNamedItem(newNameAttr);
470         }
471         oldNameAttr = newNameAttr;
472     } else
473         HTMLElement::parseMappedAttribute(attr);
474 }
475
476 bool HTMLEmbedElement::rendererIsNeeded(RenderStyle *style)
477 {
478     Frame *frame = document()->frame();
479     if (!frame || !frame->pluginsEnabled())
480         return false;
481
482     Node *p = parentNode();
483     if (p && p->hasTagName(objectTag)) {
484         assert(p->renderer());
485         return false;
486     }
487
488     return true;
489 }
490
491 RenderObject *HTMLEmbedElement::createRenderer(RenderArena *arena, RenderStyle *style)
492 {
493     return new (arena) RenderPartObject(this);
494 }
495
496 void HTMLEmbedElement::attach()
497 {
498     HTMLElement::attach();
499
500     if (renderer())
501         static_cast<RenderPartObject*>(renderer())->updateWidget();
502 }
503
504 void HTMLEmbedElement::detach()
505 {
506 #if __APPLE__
507     m_embedInstance = 0;
508 #endif
509     HTMLElement::detach();
510 }
511
512 void HTMLEmbedElement::insertedIntoDocument()
513 {
514     if (document()->isHTMLDocument()) {
515         HTMLDocument *doc = static_cast<HTMLDocument *>(document());
516         doc->addNamedItem(oldNameAttr);
517     }
518
519     HTMLElement::insertedIntoDocument();
520 }
521
522 void HTMLEmbedElement::removedFromDocument()
523 {
524     if (document()->isHTMLDocument()) {
525         HTMLDocument *doc = static_cast<HTMLDocument *>(document());
526         doc->removeNamedItem(oldNameAttr);
527     }
528
529     HTMLElement::removedFromDocument();
530 }
531
532 bool HTMLEmbedElement::isURLAttribute(Attribute *attr) const
533 {
534     return attr->name() == srcAttr;
535 }
536
537 // -------------------------------------------------------------------------
538
539 HTMLObjectElement::HTMLObjectElement(Document *doc) 
540 : HTMLElement(objectTag, doc)
541 , m_imageLoader(0)
542 {
543     needWidgetUpdate = false;
544     m_useFallbackContent = false;
545     m_complete = false;
546     m_docNamedItem = true;
547 }
548
549 HTMLObjectElement::~HTMLObjectElement()
550 {
551 #if __APPLE__
552     // m_objectInstance should have been cleaned up in detach().
553     assert(!m_objectInstance);
554 #endif
555     
556     delete m_imageLoader;
557 }
558
559 bool HTMLObjectElement::checkDTD(const Node* newChild)
560 {
561     return newChild->hasTagName(paramTag) || HTMLElement::checkDTD(newChild);
562 }
563
564 #if __APPLE__
565 KJS::Bindings::Instance *HTMLObjectElement::getObjectInstance() const
566 {
567     Frame *frame = document()->frame();
568     if (!frame)
569         return 0;
570
571     if (m_objectInstance)
572         return m_objectInstance.get();
573
574     if (RenderObject *r = renderer()) {
575         if (r->isWidget()) {
576             if (Widget *widget = static_cast<RenderWidget *>(r)->widget()) {
577                 // Call into the frame (and over the bridge) to pull the Bindings::Instance
578                 // from the guts of the plugin.
579                 m_objectInstance = frame->getObjectInstanceForWidget(widget);
580                 // Applet may specified with <object> tag.
581                 if (!m_objectInstance)
582                     m_objectInstance = frame->getAppletInstanceForWidget(widget);
583             }
584         }
585     }
586
587     return m_objectInstance.get();
588 }
589 #endif
590
591 HTMLFormElement *HTMLObjectElement::form() const
592 {
593     for (Node *p = parentNode(); p != 0; p = p->parentNode()) {
594         if (p->hasTagName(formTag))
595             return static_cast<HTMLFormElement *>(p);
596     }
597     
598     return 0;
599 }
600
601 bool HTMLObjectElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
602 {
603     if (attrName == widthAttr ||
604         attrName == heightAttr ||
605         attrName == vspaceAttr ||
606         attrName == hspaceAttr) {
607         result = eUniversal;
608         return false;
609     }
610     
611     if (attrName == alignAttr) {
612         result = eReplaced; // Share with <img> since the alignment behavior is the same.
613         return false;
614     }
615     
616     return HTMLElement::mapToEntry(attrName, result);
617 }
618
619 void HTMLObjectElement::parseMappedAttribute(MappedAttribute *attr)
620 {
621     String val = attr->value();
622     int pos;
623     if (attr->name() == typeAttr) {
624         serviceType = val.deprecatedString().lower();
625         pos = serviceType.find( ";" );
626         if ( pos!=-1 )
627           serviceType = serviceType.left( pos );
628         if (renderer())
629           needWidgetUpdate = true;
630         if (!isImageType() && m_imageLoader) {
631           delete m_imageLoader;
632           m_imageLoader = 0;
633         }
634     } else if (attr->name() == dataAttr) {
635         url = WebCore::parseURL(val).deprecatedString();
636         if (renderer())
637           needWidgetUpdate = true;
638         if (renderer() && isImageType()) {
639           if (!m_imageLoader)
640               m_imageLoader = new HTMLImageLoader(this);
641           m_imageLoader->updateFromElement();
642         }
643     } else if (attr->name() == widthAttr) {
644         addCSSLength( attr, CSS_PROP_WIDTH, attr->value());
645     } else if (attr->name() == heightAttr) {
646         addCSSLength( attr, CSS_PROP_HEIGHT, attr->value());
647     } else if (attr->name() == vspaceAttr) {
648         addCSSLength(attr, CSS_PROP_MARGIN_TOP, attr->value());
649         addCSSLength(attr, CSS_PROP_MARGIN_BOTTOM, attr->value());
650     } else if (attr->name() == hspaceAttr) {
651         addCSSLength(attr, CSS_PROP_MARGIN_LEFT, attr->value());
652         addCSSLength(attr, CSS_PROP_MARGIN_RIGHT, attr->value());
653     } else if (attr->name() == alignAttr) {
654         addHTMLAlignment(attr);
655     } else if (attr->name() == classidAttr) {
656         classId = val;
657         if (renderer())
658           needWidgetUpdate = true;
659     } else if (attr->name() == onloadAttr) {
660         setHTMLEventListener(loadEvent, attr);
661     } else if (attr->name() == onunloadAttr) {
662         setHTMLEventListener(unloadEvent, attr);
663     } else if (attr->name() == nameAttr) {
664             String newNameAttr = attr->value();
665             if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) {
666                 HTMLDocument *doc = static_cast<HTMLDocument *>(document());
667                 doc->removeNamedItem(oldNameAttr);
668                 doc->addNamedItem(newNameAttr);
669             }
670             oldNameAttr = newNameAttr;
671     } else if (attr->name() == idAttr) {
672         String newIdAttr = attr->value();
673         if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) {
674             HTMLDocument *doc = static_cast<HTMLDocument *>(document());
675             doc->removeDocExtraNamedItem(oldIdAttr);
676             doc->addDocExtraNamedItem(newIdAttr);
677         }
678         oldIdAttr = newIdAttr;
679         // also call superclass
680         HTMLElement::parseMappedAttribute(attr);
681     } else
682         HTMLElement::parseMappedAttribute(attr);
683 }
684
685 Document* HTMLObjectElement::contentDocument() const
686 {
687     // ###
688     return 0;
689 }
690
691 bool HTMLObjectElement::rendererIsNeeded(RenderStyle *style)
692 {
693     if (m_useFallbackContent || isImageType())
694         return HTMLElement::rendererIsNeeded(style);
695
696     Frame *frame = document()->frame();
697     if (!frame || !frame->pluginsEnabled())
698         return false;
699     
700     return true;
701 }
702
703 RenderObject *HTMLObjectElement::createRenderer(RenderArena *arena, RenderStyle *style)
704 {
705     if (m_useFallbackContent)
706         return RenderObject::createObject(this, style);
707     if (isImageType())
708         return new (arena) RenderImage(this);
709     return new (arena) RenderPartObject(this);
710 }
711
712 void HTMLObjectElement::attach()
713 {
714     HTMLElement::attach();
715
716     if (renderer() && !m_useFallbackContent) {
717         if (isImageType()) {
718             if (!m_imageLoader)
719                 m_imageLoader = new HTMLImageLoader(this);
720             m_imageLoader->updateFromElement();
721             if (renderer()) {
722                 RenderImage* imageObj = static_cast<RenderImage*>(renderer());
723                 imageObj->setCachedImage(m_imageLoader->image());
724             }
725         } else {
726             if (needWidgetUpdate) {
727                 // Set needWidgetUpdate to false before calling updateWidget because updateWidget may cause
728                 // this method or recalcStyle (which also calls updateWidget) to be called.
729                 needWidgetUpdate = false;
730                 static_cast<RenderPartObject*>(renderer())->updateWidget();
731             } else {
732                 needWidgetUpdate = true;
733                 setChanged();
734             }
735         }
736     }
737 }
738
739 void HTMLObjectElement::closeRenderer()
740 {
741     // The parser just reached </object>.
742     setComplete(true);
743     
744     HTMLElement::closeRenderer();
745 }
746
747 void HTMLObjectElement::setComplete(bool complete)
748 {
749     if (complete != m_complete) {
750         m_complete = complete;
751         if (complete && inDocument() && !m_useFallbackContent) {
752             needWidgetUpdate = true;
753             setChanged();
754         }
755     }
756 }
757
758 void HTMLObjectElement::detach()
759 {
760     if (attached() && renderer() && !m_useFallbackContent) {
761         // Update the widget the next time we attach (detaching destroys the plugin).
762         needWidgetUpdate = true;
763     }
764
765 #if __APPLE__
766     m_objectInstance = 0;
767 #endif
768     HTMLElement::detach();
769 }
770
771 void HTMLObjectElement::insertedIntoDocument()
772 {
773     if (isDocNamedItem() && document()->isHTMLDocument()) {
774         HTMLDocument *doc = static_cast<HTMLDocument *>(document());
775         doc->addNamedItem(oldNameAttr);
776         doc->addDocExtraNamedItem(oldIdAttr);
777     }
778
779     HTMLElement::insertedIntoDocument();
780 }
781
782 void HTMLObjectElement::removedFromDocument()
783 {
784     if (isDocNamedItem() && document()->isHTMLDocument()) {
785         HTMLDocument *doc = static_cast<HTMLDocument *>(document());
786         doc->removeNamedItem(oldNameAttr);
787         doc->removeDocExtraNamedItem(oldIdAttr);
788     }
789
790     HTMLElement::removedFromDocument();
791 }
792
793 void HTMLObjectElement::recalcStyle(StyleChange ch)
794 {
795     if (!m_useFallbackContent && needWidgetUpdate && renderer() && !isImageType()) {
796         detach();
797         attach();
798     }
799     HTMLElement::recalcStyle(ch);
800 }
801
802 void HTMLObjectElement::childrenChanged()
803 {
804     updateDocNamedItem();
805     if (inDocument() && !m_useFallbackContent) {
806         needWidgetUpdate = true;
807         setChanged();
808     }
809 }
810
811 bool HTMLObjectElement::isURLAttribute(Attribute *attr) const
812 {
813     return (attr->name() == dataAttr || (attr->name() == usemapAttr && attr->value().domString()[0] != '#'));
814 }
815
816 bool HTMLObjectElement::isImageType()
817 {
818     if (serviceType.isEmpty() && url.startsWith("data:")) {
819         // Extract the MIME type from the data URL.
820         int index = url.find(';');
821         if (index == -1)
822             index = url.find(',');
823         if (index != -1) {
824             int len = index - 5;
825             if (len > 0)
826                 serviceType = url.mid(5, len);
827             else
828                 serviceType = "text/plain"; // Data URLs with no MIME type are considered text/plain.
829         }
830     }
831     
832     return Image::supportsType(serviceType);
833 }
834
835 void HTMLObjectElement::renderFallbackContent()
836 {
837     if (m_useFallbackContent)
838         return;
839
840     // Mark ourselves as using the fallback content.
841     m_useFallbackContent = true;
842
843     // Now do a detach and reattach.    
844     // FIXME: Style gets recalculated which is suboptimal.
845     detach();
846     attach();
847 }
848
849 void HTMLObjectElement::updateDocNamedItem()
850 {
851     // The rule is "<object> elements with no children other than
852     // <param> elements and whitespace can be found by name in a
853     // document, and other <object> elements cannot."
854     bool wasNamedItem = m_docNamedItem;
855     bool isNamedItem = true;
856     Node *child = firstChild();
857     while (child && isNamedItem) {
858         if (child->isElementNode()) {
859             if (!static_cast<Element *>(child)->hasTagName(paramTag))
860                 isNamedItem = false;
861         } else if (child->isTextNode()) {
862             if (!static_cast<Text *>(child)->containsOnlyWhitespace())
863                 isNamedItem = false;
864         } else
865             isNamedItem = false;
866         child = child->nextSibling();
867     }
868     if (isNamedItem != wasNamedItem && document()->isHTMLDocument()) {
869         HTMLDocument *doc = static_cast<HTMLDocument *>(document());
870         if (isNamedItem) {
871             doc->addNamedItem(oldNameAttr);
872             doc->addDocExtraNamedItem(oldIdAttr);
873         } else {
874             doc->removeNamedItem(oldNameAttr);
875             doc->removeDocExtraNamedItem(oldIdAttr);
876         }
877     }
878     m_docNamedItem = isNamedItem;
879 }
880
881 String HTMLObjectElement::code() const
882 {
883     return getAttribute(codeAttr);
884 }
885
886 void HTMLObjectElement::setCode(const String &value)
887 {
888     setAttribute(codeAttr, value);
889 }
890
891 String HTMLObjectElement::align() const
892 {
893     return getAttribute(alignAttr);
894 }
895
896 void HTMLObjectElement::setAlign(const String &value)
897 {
898     setAttribute(alignAttr, value);
899 }
900
901 String HTMLObjectElement::archive() const
902 {
903     return getAttribute(archiveAttr);
904 }
905
906 void HTMLObjectElement::setArchive(const String &value)
907 {
908     setAttribute(archiveAttr, value);
909 }
910
911 String HTMLObjectElement::border() const
912 {
913     return getAttribute(borderAttr);
914 }
915
916 void HTMLObjectElement::setBorder(const String &value)
917 {
918     setAttribute(borderAttr, value);
919 }
920
921 String HTMLObjectElement::codeBase() const
922 {
923     return getAttribute(codebaseAttr);
924 }
925
926 void HTMLObjectElement::setCodeBase(const String &value)
927 {
928     setAttribute(codebaseAttr, value);
929 }
930
931 String HTMLObjectElement::codeType() const
932 {
933     return getAttribute(codetypeAttr);
934 }
935
936 void HTMLObjectElement::setCodeType(const String &value)
937 {
938     setAttribute(codetypeAttr, value);
939 }
940
941 String HTMLObjectElement::data() const
942 {
943     return getAttribute(dataAttr);
944 }
945
946 void HTMLObjectElement::setData(const String &value)
947 {
948     setAttribute(dataAttr, value);
949 }
950
951 bool HTMLObjectElement::declare() const
952 {
953     return !getAttribute(declareAttr).isNull();
954 }
955
956 void HTMLObjectElement::setDeclare(bool declare)
957 {
958     setAttribute(declareAttr, declare ? "" : 0);
959 }
960
961 String HTMLObjectElement::height() const
962 {
963     return getAttribute(heightAttr);
964 }
965
966 void HTMLObjectElement::setHeight(const String &value)
967 {
968     setAttribute(heightAttr, value);
969 }
970
971 String HTMLObjectElement::hspace() const
972 {
973     return getAttribute(hspaceAttr);
974 }
975
976 void HTMLObjectElement::setHspace(const String &value)
977 {
978     setAttribute(hspaceAttr, value);
979 }
980
981 String HTMLObjectElement::name() const
982 {
983     return getAttribute(nameAttr);
984 }
985
986 void HTMLObjectElement::setName(const String &value)
987 {
988     setAttribute(nameAttr, value);
989 }
990
991 String HTMLObjectElement::standby() const
992 {
993     return getAttribute(standbyAttr);
994 }
995
996 void HTMLObjectElement::setStandby(const String &value)
997 {
998     setAttribute(standbyAttr, value);
999 }
1000
1001 int HTMLObjectElement::tabIndex() const
1002 {
1003     return getAttribute(tabindexAttr).toInt();
1004 }
1005
1006 void HTMLObjectElement::setTabIndex(int tabIndex)
1007 {
1008     setAttribute(tabindexAttr, String::number(tabIndex));
1009 }
1010
1011 String HTMLObjectElement::type() const
1012 {
1013     return getAttribute(typeAttr);
1014 }
1015
1016 void HTMLObjectElement::setType(const String &value)
1017 {
1018     setAttribute(typeAttr, value);
1019 }
1020
1021 String HTMLObjectElement::useMap() const
1022 {
1023     return getAttribute(usemapAttr);
1024 }
1025
1026 void HTMLObjectElement::setUseMap(const String &value)
1027 {
1028     setAttribute(usemapAttr, value);
1029 }
1030
1031 String HTMLObjectElement::vspace() const
1032 {
1033     return getAttribute(vspaceAttr);
1034 }
1035
1036 void HTMLObjectElement::setVspace(const String &value)
1037 {
1038     setAttribute(vspaceAttr, value);
1039 }
1040
1041 String HTMLObjectElement::width() const
1042 {
1043     return getAttribute(widthAttr);
1044 }
1045
1046 void HTMLObjectElement::setWidth(const String &value)
1047 {
1048     setAttribute(widthAttr, value);
1049 }
1050
1051 // -------------------------------------------------------------------------
1052
1053 HTMLParamElement::HTMLParamElement(Document *doc)
1054     : HTMLElement(paramTag, doc)
1055 {
1056 }
1057
1058 HTMLParamElement::~HTMLParamElement()
1059 {
1060 }
1061
1062 void HTMLParamElement::parseMappedAttribute(MappedAttribute *attr)
1063 {
1064     if (attr->name() == idAttr) {
1065         // Must call base class so that hasID bit gets set.
1066         HTMLElement::parseMappedAttribute(attr);
1067         if (document()->htmlMode() != Document::XHtml)
1068             return;
1069         m_name = attr->value();
1070     } else if (attr->name() == nameAttr) {
1071         m_name = attr->value();
1072     } else if (attr->name() == valueAttr) {
1073         m_value = attr->value();
1074     } else
1075         HTMLElement::parseMappedAttribute(attr);
1076 }
1077
1078 bool HTMLParamElement::isURLAttribute(Attribute *attr) const
1079 {
1080     if (attr->name() == valueAttr) {
1081         Attribute *attr = attributes()->getAttributeItem(nameAttr);
1082         if (attr) {
1083             String value = attr->value().domString().lower();
1084             if (value == "src" || value == "movie" || value == "data")
1085                 return true;
1086         }
1087     }
1088     return false;
1089 }
1090
1091 void HTMLParamElement::setName(const String &value)
1092 {
1093     setAttribute(nameAttr, value);
1094 }
1095
1096 String HTMLParamElement::type() const
1097 {
1098     return getAttribute(typeAttr);
1099 }
1100
1101 void HTMLParamElement::setType(const String &value)
1102 {
1103     setAttribute(typeAttr, value);
1104 }
1105
1106 void HTMLParamElement::setValue(const String &value)
1107 {
1108     setAttribute(valueAttr, value);
1109 }
1110
1111 String HTMLParamElement::valueType() const
1112 {
1113     return getAttribute(valuetypeAttr);
1114 }
1115
1116 void HTMLParamElement::setValueType(const String &value)
1117 {
1118     setAttribute(valuetypeAttr, value);
1119 }
1120
1121 }