4245644080d3bb9391e88907ceab79a67702d9a0
[WebKit-https.git] / WebCore / html / HTMLObjectElement.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 #include "config.h"
25 #include "HTMLObjectElement.h"
26
27 #include "EventNames.h"
28 #include "Frame.h"
29 #include "HTMLFormElement.h"
30 #include "HTMLDocument.h"
31 #include "HTMLImageLoader.h"
32 #include "HTMLNames.h"
33 #include "Image.h"
34 #include "RenderImage.h"
35 #include "RenderPartObject.h"
36 #include "RenderWidget.h"
37 #include "Text.h"
38 #include "csshelper.h"
39
40 namespace WebCore {
41
42 using namespace EventNames;
43 using namespace HTMLNames;
44
45 HTMLObjectElement::HTMLObjectElement(Document *doc) 
46 : HTMLPlugInElement(objectTag, doc)
47 , m_imageLoader(0)
48 {
49     needWidgetUpdate = false;
50     m_useFallbackContent = false;
51     m_complete = false;
52     m_docNamedItem = true;
53 }
54
55 HTMLObjectElement::~HTMLObjectElement()
56 {
57 #if PLATFORM(MAC)
58     // m_instance should have been cleaned up in detach().
59     assert(!m_instance);
60 #endif
61     
62     delete m_imageLoader;
63 }
64
65 #if PLATFORM(MAC)
66 KJS::Bindings::Instance *HTMLObjectElement::getInstance() const
67 {
68     Frame* frame = document()->frame();
69     if (!frame)
70         return 0;
71
72     if (m_instance)
73         return m_instance.get();
74
75     if (RenderObject *r = renderer()) {
76         if (r->isWidget()) {
77             if (Widget* widget = static_cast<RenderWidget*>(r)->widget()) {
78                 // Call into the frame (and over the bridge) to pull the Bindings::Instance
79                 // from the guts of the plugin.
80                 m_instance = frame->getObjectInstanceForWidget(widget);
81                 // Applet may specified with <object> tag.
82                 if (!m_instance)
83                     m_instance = frame->getAppletInstanceForWidget(widget);
84             }
85         }
86     }
87
88     return m_instance.get();
89 }
90 #endif
91
92 HTMLFormElement* HTMLObjectElement::form() const
93 {
94     for (Node* p = parentNode(); p != 0; p = p->parentNode()) {
95         if (p->hasTagName(formTag))
96             return static_cast<HTMLFormElement*>(p);
97     }
98     
99     return 0;
100 }
101
102 void HTMLObjectElement::parseMappedAttribute(MappedAttribute *attr)
103 {
104     String val = attr->value();
105     int pos;
106     if (attr->name() == typeAttr) {
107         serviceType = val.deprecatedString().lower();
108         pos = serviceType.find( ";" );
109         if ( pos!=-1 )
110           serviceType = serviceType.left( pos );
111         if (renderer())
112           needWidgetUpdate = true;
113         if (!isImageType() && m_imageLoader) {
114           delete m_imageLoader;
115           m_imageLoader = 0;
116         }
117     } else if (attr->name() == dataAttr) {
118         url = parseURL(val).deprecatedString();
119         if (renderer())
120           needWidgetUpdate = true;
121         if (renderer() && isImageType()) {
122           if (!m_imageLoader)
123               m_imageLoader = new HTMLImageLoader(this);
124           m_imageLoader->updateFromElement();
125         }
126     } else if (attr->name() == classidAttr) {
127         classId = val;
128         if (renderer())
129           needWidgetUpdate = true;
130     } else if (attr->name() == onloadAttr) {
131         setHTMLEventListener(loadEvent, attr);
132     } else if (attr->name() == onunloadAttr) {
133         setHTMLEventListener(unloadEvent, attr);
134     } else if (attr->name() == nameAttr) {
135             String newNameAttr = attr->value();
136             if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) {
137                 HTMLDocument *doc = static_cast<HTMLDocument *>(document());
138                 doc->removeNamedItem(oldNameAttr);
139                 doc->addNamedItem(newNameAttr);
140             }
141             oldNameAttr = newNameAttr;
142     } else if (attr->name() == idAttr) {
143         String newIdAttr = attr->value();
144         if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) {
145             HTMLDocument* doc = static_cast<HTMLDocument*>(document());
146             doc->removeDocExtraNamedItem(oldIdAttr);
147             doc->addDocExtraNamedItem(newIdAttr);
148         }
149         oldIdAttr = newIdAttr;
150         // also call superclass
151         HTMLPlugInElement::parseMappedAttribute(attr);
152     } else
153         HTMLPlugInElement::parseMappedAttribute(attr);
154 }
155
156 Document* HTMLObjectElement::contentDocument() const
157 {
158     // ###
159     return 0;
160 }
161
162 bool HTMLObjectElement::rendererIsNeeded(RenderStyle *style)
163 {
164     if (m_useFallbackContent || isImageType())
165         return HTMLPlugInElement::rendererIsNeeded(style);
166
167     Frame *frame = document()->frame();
168     if (!frame || !frame->pluginsEnabled())
169         return false;
170     
171     return true;
172 }
173
174 RenderObject *HTMLObjectElement::createRenderer(RenderArena *arena, RenderStyle *style)
175 {
176     if (m_useFallbackContent)
177         return RenderObject::createObject(this, style);
178     if (isImageType())
179         return new (arena) RenderImage(this);
180     return new (arena) RenderPartObject(this);
181 }
182
183 void HTMLObjectElement::attach()
184 {
185     HTMLPlugInElement::attach();
186
187     if (renderer() && !m_useFallbackContent) {
188         if (isImageType()) {
189             if (!m_imageLoader)
190                 m_imageLoader = new HTMLImageLoader(this);
191             m_imageLoader->updateFromElement();
192             if (renderer()) {
193                 RenderImage* imageObj = static_cast<RenderImage*>(renderer());
194                 imageObj->setCachedImage(m_imageLoader->image());
195             }
196         } else {
197             if (needWidgetUpdate) {
198                 // Set needWidgetUpdate to false before calling updateWidget because updateWidget may cause
199                 // this method or recalcStyle (which also calls updateWidget) to be called.
200                 needWidgetUpdate = false;
201                 static_cast<RenderPartObject*>(renderer())->updateWidget();
202             } else {
203                 needWidgetUpdate = true;
204                 setChanged();
205             }
206         }
207     }
208 }
209
210 void HTMLObjectElement::closeRenderer()
211 {
212     // The parser just reached </object>.
213     setComplete(true);
214     
215     HTMLPlugInElement::closeRenderer();
216 }
217
218 void HTMLObjectElement::setComplete(bool complete)
219 {
220     if (complete != m_complete) {
221         m_complete = complete;
222         if (complete && !m_useFallbackContent) {
223             needWidgetUpdate = true;
224             if (inDocument())
225                 setChanged();
226         }
227     }
228 }
229
230 void HTMLObjectElement::detach()
231 {
232     if (attached() && renderer() && !m_useFallbackContent) {
233         // Update the widget the next time we attach (detaching destroys the plugin).
234         needWidgetUpdate = true;
235     }
236
237 #if PLATFORM(MAC)
238     m_instance = 0;
239 #endif
240     HTMLPlugInElement::detach();
241 }
242
243 void HTMLObjectElement::insertedIntoDocument()
244 {
245     if (isDocNamedItem() && document()->isHTMLDocument()) {
246         HTMLDocument *doc = static_cast<HTMLDocument *>(document());
247         doc->addNamedItem(oldNameAttr);
248         doc->addDocExtraNamedItem(oldIdAttr);
249     }
250
251     HTMLPlugInElement::insertedIntoDocument();
252 }
253
254 void HTMLObjectElement::removedFromDocument()
255 {
256     if (isDocNamedItem() && document()->isHTMLDocument()) {
257         HTMLDocument *doc = static_cast<HTMLDocument *>(document());
258         doc->removeNamedItem(oldNameAttr);
259         doc->removeDocExtraNamedItem(oldIdAttr);
260     }
261
262     HTMLPlugInElement::removedFromDocument();
263 }
264
265 void HTMLObjectElement::recalcStyle(StyleChange ch)
266 {
267     if (!m_useFallbackContent && needWidgetUpdate && renderer() && !isImageType()) {
268         detach();
269         attach();
270     }
271     HTMLPlugInElement::recalcStyle(ch);
272 }
273
274 void HTMLObjectElement::childrenChanged()
275 {
276     updateDocNamedItem();
277     if (inDocument() && !m_useFallbackContent) {
278         needWidgetUpdate = true;
279         setChanged();
280     }
281 }
282
283 bool HTMLObjectElement::isURLAttribute(Attribute *attr) const
284 {
285     return (attr->name() == dataAttr || (attr->name() == usemapAttr && attr->value().domString()[0] != '#'));
286 }
287
288 bool HTMLObjectElement::isImageType()
289 {
290     if (serviceType.isEmpty() && url.startsWith("data:")) {
291         // Extract the MIME type from the data URL.
292         int index = url.find(';');
293         if (index == -1)
294             index = url.find(',');
295         if (index != -1) {
296             int len = index - 5;
297             if (len > 0)
298                 serviceType = url.mid(5, len);
299             else
300                 serviceType = "text/plain"; // Data URLs with no MIME type are considered text/plain.
301         }
302     }
303     
304     return Image::supportsType(serviceType);
305 }
306
307 void HTMLObjectElement::renderFallbackContent()
308 {
309     if (m_useFallbackContent)
310         return;
311
312     // Mark ourselves as using the fallback content.
313     m_useFallbackContent = true;
314
315     // Now do a detach and reattach.    
316     // FIXME: Style gets recalculated which is suboptimal.
317     detach();
318     attach();
319 }
320
321 void HTMLObjectElement::updateDocNamedItem()
322 {
323     // The rule is "<object> elements with no children other than
324     // <param> elements and whitespace can be found by name in a
325     // document, and other <object> elements cannot."
326     bool wasNamedItem = m_docNamedItem;
327     bool isNamedItem = true;
328     Node* child = firstChild();
329     while (child && isNamedItem) {
330         if (child->isElementNode()) {
331             if (!static_cast<Element*>(child)->hasTagName(paramTag))
332                 isNamedItem = false;
333         } else if (child->isTextNode()) {
334             if (!static_cast<Text*>(child)->containsOnlyWhitespace())
335                 isNamedItem = false;
336         } else
337             isNamedItem = false;
338         child = child->nextSibling();
339     }
340     if (isNamedItem != wasNamedItem && document()->isHTMLDocument()) {
341         HTMLDocument* doc = static_cast<HTMLDocument*>(document());
342         if (isNamedItem) {
343             doc->addNamedItem(oldNameAttr);
344             doc->addDocExtraNamedItem(oldIdAttr);
345         } else {
346             doc->removeNamedItem(oldNameAttr);
347             doc->removeDocExtraNamedItem(oldIdAttr);
348         }
349     }
350     m_docNamedItem = isNamedItem;
351 }
352
353 String HTMLObjectElement::code() const
354 {
355     return getAttribute(codeAttr);
356 }
357
358 void HTMLObjectElement::setCode(const String &value)
359 {
360     setAttribute(codeAttr, value);
361 }
362
363 String HTMLObjectElement::archive() const
364 {
365     return getAttribute(archiveAttr);
366 }
367
368 void HTMLObjectElement::setArchive(const String &value)
369 {
370     setAttribute(archiveAttr, value);
371 }
372
373 String HTMLObjectElement::border() const
374 {
375     return getAttribute(borderAttr);
376 }
377
378 void HTMLObjectElement::setBorder(const String &value)
379 {
380     setAttribute(borderAttr, value);
381 }
382
383 String HTMLObjectElement::codeBase() const
384 {
385     return getAttribute(codebaseAttr);
386 }
387
388 void HTMLObjectElement::setCodeBase(const String &value)
389 {
390     setAttribute(codebaseAttr, value);
391 }
392
393 String HTMLObjectElement::codeType() const
394 {
395     return getAttribute(codetypeAttr);
396 }
397
398 void HTMLObjectElement::setCodeType(const String &value)
399 {
400     setAttribute(codetypeAttr, value);
401 }
402
403 String HTMLObjectElement::data() const
404 {
405     return getAttribute(dataAttr);
406 }
407
408 void HTMLObjectElement::setData(const String &value)
409 {
410     setAttribute(dataAttr, value);
411 }
412
413 bool HTMLObjectElement::declare() const
414 {
415     return !getAttribute(declareAttr).isNull();
416 }
417
418 void HTMLObjectElement::setDeclare(bool declare)
419 {
420     setAttribute(declareAttr, declare ? "" : 0);
421 }
422
423 String HTMLObjectElement::hspace() const
424 {
425     return getAttribute(hspaceAttr);
426 }
427
428 void HTMLObjectElement::setHspace(const String &value)
429 {
430     setAttribute(hspaceAttr, value);
431 }
432
433 String HTMLObjectElement::standby() const
434 {
435     return getAttribute(standbyAttr);
436 }
437
438 void HTMLObjectElement::setStandby(const String &value)
439 {
440     setAttribute(standbyAttr, value);
441 }
442
443 int HTMLObjectElement::tabIndex() const
444 {
445     return getAttribute(tabindexAttr).toInt();
446 }
447
448 void HTMLObjectElement::setTabIndex(int tabIndex)
449 {
450     setAttribute(tabindexAttr, String::number(tabIndex));
451 }
452
453 String HTMLObjectElement::type() const
454 {
455     return getAttribute(typeAttr);
456 }
457
458 void HTMLObjectElement::setType(const String &value)
459 {
460     setAttribute(typeAttr, value);
461 }
462
463 String HTMLObjectElement::useMap() const
464 {
465     return getAttribute(usemapAttr);
466 }
467
468 void HTMLObjectElement::setUseMap(const String &value)
469 {
470     setAttribute(usemapAttr, value);
471 }
472
473 String HTMLObjectElement::vspace() const
474 {
475     return getAttribute(vspaceAttr);
476 }
477
478 void HTMLObjectElement::setVspace(const String &value)
479 {
480     setAttribute(vspaceAttr, value);
481 }
482
483 }