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