[3603191] REGRESSION: Applets not receiving all of the Applet Parameters in Java...
[WebKit-https.git] / WebCore / khtml / 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 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 "html/html_objectimpl.h"
25
26 #include "khtml_part.h"
27 #include "dom/dom_string.h"
28 #include "misc/htmlhashes.h"
29 #include "khtmlview.h"
30 #include <qstring.h>
31 #include <qmap.h>
32 #include <kdebug.h>
33
34 #include "xml/dom_docimpl.h"
35 #include "css/cssstyleselector.h"
36 #include "css/csshelper.h"
37 #include "css/cssproperties.h"
38 #include "css/cssvalues.h"
39 #include "rendering/render_applet.h"
40 #include "rendering/render_frames.h"
41 #include "rendering/render_image.h"
42 #include "xml/dom2_eventsimpl.h"
43
44 #ifndef Q_WS_QWS // We don't have Java in Qt Embedded
45 #include "java/kjavaappletwidget.h"
46 #include "java/kjavaappletcontext.h"
47 #endif
48
49 #if APPLE_CHANGES
50 #include "KWQKHTMLPart.h"
51 #endif
52
53 using namespace DOM;
54 using namespace khtml;
55
56 // -------------------------------------------------------------------------
57
58 HTMLAppletElementImpl::HTMLAppletElementImpl(DocumentPtr *doc)
59   : HTMLElementImpl(doc)
60 {
61     appletInstance = 0;
62     m_allParamsAvailable = false;
63 }
64
65 HTMLAppletElementImpl::~HTMLAppletElementImpl()
66 {
67     delete appletInstance;
68 }
69
70 NodeImpl::Id HTMLAppletElementImpl::id() const
71 {
72     return ID_APPLET;
73 }
74
75 bool HTMLAppletElementImpl::mapToEntry(NodeImpl::Id attr, MappedAttributeEntry& result) const
76 {
77     switch (attr) {
78         case ATTR_WIDTH:
79         case ATTR_HEIGHT:
80             result = eUniversal;
81             return false;
82         case ATTR_ALIGN:
83             result = eReplaced; // Share with <img> since the alignment behavior is the same.
84             return false;
85         default:
86             break;
87     }
88     
89     return HTMLElementImpl::mapToEntry(attr, result);
90 }
91
92 void HTMLAppletElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
93 {
94     switch (attr->id()) {
95     case ATTR_ALT:
96     case ATTR_ARCHIVE:
97     case ATTR_CODE:
98     case ATTR_CODEBASE:
99     case ATTR_MAYSCRIPT:
100     case ATTR_NAME:
101     case ATTR_OBJECT:
102         break;
103     case ATTR_WIDTH:
104         addCSSLength(attr, CSS_PROP_WIDTH, attr->value());
105         break;
106     case ATTR_HEIGHT:
107         addCSSLength(attr, CSS_PROP_HEIGHT, attr->value());
108         break;
109     case ATTR_ALIGN:
110         addHTMLAlignment(attr);
111         break;
112     default:
113         HTMLElementImpl::parseHTMLAttribute(attr);
114     }
115 }
116
117 bool HTMLAppletElementImpl::rendererIsNeeded(RenderStyle *style)
118 {
119     return !getAttribute(ATTR_CODE).isNull();
120 }
121
122 RenderObject *HTMLAppletElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
123 {
124 #ifndef Q_WS_QWS // FIXME(E)? I don't think this is possible with Qt Embedded...
125     KHTMLPart *part = getDocument()->part();
126
127     if( part && part->javaEnabled() )
128     {
129         QMap<QString, QString> args;
130
131         args.insert( "code", getAttribute(ATTR_CODE).string());
132         DOMString codeBase = getAttribute(ATTR_CODEBASE);
133         if(!codeBase.isNull())
134             args.insert( "codeBase", codeBase.string() );
135         DOMString name = getDocument()->htmlMode() != DocumentImpl::XHtml ?
136                          getAttribute(ATTR_NAME) : getAttribute(ATTR_ID);
137         if(!name.isNull())
138             args.insert( "name", name.string() );
139         DOMString archive = getAttribute(ATTR_ARCHIVE);
140         if(!archive.isNull())
141             args.insert( "archive", archive.string() );
142
143         args.insert( "baseURL", getDocument()->baseURL() );
144
145         DOMString mayScript = getAttribute(ATTR_MAYSCRIPT);
146         if (!mayScript.isNull())
147             args.insert("mayScript", mayScript.string());
148
149         // Other arguments (from <PARAM> tags) are added later.
150         
151         return new (getDocument()->renderArena()) RenderApplet(this, args);
152     }
153
154     // ### remove me. we should never show an empty applet, instead
155     // render the alternative content given by the webpage
156     return new (getDocument()->renderArena()) RenderEmptyApplet(this);
157 #else
158     return 0;
159 #endif
160 }
161
162 bool HTMLAppletElementImpl::getMember(const QString & name, JType & type, QString & val) {
163 #if APPLE_CHANGES
164     return false;
165 #else
166 #ifndef Q_WS_QWS // We don't have Java in Qt Embedded
167     if ( !m_render || !m_render->isApplet() )
168         return false;
169     KJavaAppletWidget *w = static_cast<KJavaAppletWidget*>(static_cast<RenderApplet*>(m_render)->widget());
170     return (w && w->applet() && w->applet()->getMember(name, type, val));
171 #else
172     return false;
173 #endif
174 #endif
175 }
176
177 bool HTMLAppletElementImpl::callMember(const QString & name, const QStringList & args, JType & type, QString & val) {
178 #if APPLE_CHANGES
179     return false;
180 #else
181 #ifndef Q_WS_QWS // We don't have Java in Qt Embedded
182     if ( !m_render || !m_render->isApplet() )
183         return false;
184     KJavaAppletWidget *w = static_cast<KJavaAppletWidget*>(static_cast<RenderApplet*>(m_render)->widget());
185     return (w && w->applet() && w->applet()->callMember(name, args, type, val));
186 #else
187     return false;
188 #endif
189 #endif
190 }
191
192 #if APPLE_CHANGES
193 KJS::Bindings::Instance *HTMLAppletElementImpl::getAppletInstance() const
194 {
195     KHTMLPart* part = getDocument()->part();
196     if (!part || !part->javaEnabled())
197         return 0;
198
199     if (appletInstance)
200         return appletInstance;
201     
202     RenderApplet *r = static_cast<RenderApplet*>(m_render);
203     if (r) {
204         r->createWidgetIfNecessary();
205         if (r->widget()){
206             // Call into the part (and over the bridge) to pull the Bindings::Instance
207             // from the guts of the plugin.
208             void *_view = r->widget()->getView();
209             appletInstance = KWQ(part)->getAppletInstanceForView((NSView *)_view);
210         }
211     }
212     return appletInstance;
213 }
214
215 void HTMLAppletElementImpl::setAllParamsAvailable()
216 {
217     // The parser just reached </applet>, so all the params are available now.
218     m_allParamsAvailable = true;
219     if( m_render )
220         m_render->setNeedsLayout(); // This will cause it to create its widget & the Java applet
221 }
222
223 bool HTMLAppletElementImpl::allParamsAvailable()
224 {
225     return m_allParamsAvailable;
226 }
227 #endif
228
229 // -------------------------------------------------------------------------
230
231 HTMLEmbedElementImpl::HTMLEmbedElementImpl(DocumentPtr *doc)
232     : HTMLElementImpl(doc), embedInstance(0)
233 {}
234
235 HTMLEmbedElementImpl::~HTMLEmbedElementImpl()
236 {
237 }
238
239 NodeImpl::Id HTMLEmbedElementImpl::id() const
240 {
241     return ID_EMBED;
242 }
243
244 #if APPLE_CHANGES
245 KJS::Bindings::Instance *HTMLEmbedElementImpl::getEmbedInstance() const
246 {
247     KHTMLPart* part = getDocument()->part();
248     if (!part)
249         return 0;
250
251     if (embedInstance)
252         return embedInstance;
253     
254     RenderPartObject *r = static_cast<RenderPartObject*>(m_render);
255     if (r) {
256         if (r->widget()){
257             // Call into the part (and over the bridge) to pull the Bindings::Instance
258             // from the guts of the Java VM.
259             void *_view = r->widget()->getView();
260             embedInstance = KWQ(part)->getEmbedInstanceForView((NSView *)_view);
261             // Applet may specified with <embed> tag.
262             if (!embedInstance)
263                 embedInstance = KWQ(part)->getAppletInstanceForView((NSView *)_view);
264         }
265     }
266     return embedInstance;
267 }
268 #endif
269
270 bool HTMLEmbedElementImpl::mapToEntry(NodeImpl::Id attr, MappedAttributeEntry& result) const
271 {
272     switch (attr) {
273         case ATTR_WIDTH:
274         case ATTR_HEIGHT:
275         case ATTR_BORDER:
276         case ATTR_VSPACE:
277         case ATTR_HSPACE:
278         case ATTR_VALIGN:
279         case ATTR_HIDDEN:
280             result = eUniversal;
281             return false;
282         case ATTR_ALIGN:
283             result = eReplaced; // Share with <img> since the alignment behavior is the same.
284             return false;
285         default:
286             break;
287     }
288     
289     return HTMLElementImpl::mapToEntry(attr, result);
290 }
291
292 void HTMLEmbedElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
293 {
294   QString val = attr->value().string();
295   
296   int pos;
297   switch ( attr->id() )
298   {
299      case ATTR_TYPE:
300         serviceType = val.lower();
301         pos = serviceType.find( ";" );
302         if ( pos!=-1 )
303             serviceType = serviceType.left( pos );
304         break;
305      case ATTR_CODE:
306      case ATTR_SRC:
307          url = khtml::parseURL(attr->value()).string();
308          break;
309      case ATTR_WIDTH:
310         addCSSLength( attr, CSS_PROP_WIDTH, attr->value() );
311         break;
312      case ATTR_HEIGHT:
313         addCSSLength( attr, CSS_PROP_HEIGHT, attr->value());
314         break;
315      case ATTR_BORDER:
316         addCSSLength(attr, CSS_PROP_BORDER_WIDTH, attr->value());
317         addCSSProperty( attr, CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_SOLID );
318         addCSSProperty( attr, CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_SOLID );
319         addCSSProperty( attr, CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_SOLID );
320         addCSSProperty( attr, CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_SOLID );
321         break;
322      case ATTR_VSPACE:
323         addCSSLength(attr, CSS_PROP_MARGIN_TOP, attr->value());
324         addCSSLength(attr, CSS_PROP_MARGIN_BOTTOM, attr->value());
325         break;
326      case ATTR_HSPACE:
327         addCSSLength(attr, CSS_PROP_MARGIN_LEFT, attr->value());
328         addCSSLength(attr, CSS_PROP_MARGIN_RIGHT, attr->value());
329         break;
330      case ATTR_ALIGN:
331         addHTMLAlignment(attr);
332         break;
333      case ATTR_VALIGN:
334         addCSSProperty(attr, CSS_PROP_VERTICAL_ALIGN, attr->value());
335         break;
336      case ATTR_PLUGINPAGE:
337      case ATTR_PLUGINSPAGE:
338         pluginPage = val;
339         break;
340      case ATTR_HIDDEN:
341         if (val.lower()=="yes" || val.lower()=="true") {
342             // FIXME: Not dynamic, but it's not really important that such a rarely-used
343             // feature work dynamically.
344             addCSSLength( attr, CSS_PROP_WIDTH, "0" );
345             addCSSLength( attr, CSS_PROP_HEIGHT, "0" );
346         }
347         break;
348      default:
349         HTMLElementImpl::parseHTMLAttribute( attr );
350   }
351 }
352
353 bool HTMLEmbedElementImpl::rendererIsNeeded(RenderStyle *style)
354 {
355     KHTMLPart *part = getDocument()->part();
356     if (!part)
357         return false;
358     return part->pluginsEnabled() && parentNode()->id() != ID_OBJECT;
359 }
360
361 RenderObject *HTMLEmbedElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
362 {
363     return new (arena) RenderPartObject(this);
364 }
365
366 void HTMLEmbedElementImpl::attach()
367 {
368     HTMLElementImpl::attach();
369     if (m_render) {
370         static_cast<RenderPartObject*>(m_render)->updateWidget();
371     }
372 }
373
374 bool HTMLEmbedElementImpl::isURLAttribute(AttributeImpl *attr) const
375 {
376     return attr->id() == ATTR_SRC;
377 }
378
379 // -------------------------------------------------------------------------
380
381 HTMLObjectElementImpl::HTMLObjectElementImpl(DocumentPtr *doc) 
382 #if APPLE_CHANGES
383 : HTMLElementImpl(doc), m_imageLoader(0), objectInstance(0)
384 #else
385 : HTMLElementImpl(doc), m_imageLoader(0)
386 #endif
387 {
388     needWidgetUpdate = false;
389 }
390
391 HTMLObjectElementImpl::~HTMLObjectElementImpl()
392 {
393     delete m_imageLoader;
394 }
395
396 NodeImpl::Id HTMLObjectElementImpl::id() const
397 {
398     return ID_OBJECT;
399 }
400
401 #if APPLE_CHANGES
402 KJS::Bindings::Instance *HTMLObjectElementImpl::getObjectInstance() const
403 {
404     KHTMLPart* part = getDocument()->part();
405     if (!part)
406         return 0;
407
408     if (objectInstance)
409         return objectInstance;
410     
411     RenderPartObject *r = static_cast<RenderPartObject*>(m_render);
412     if (r) {
413         if (r->widget()){
414             // Call into the part (and over the bridge) to pull the Bindings::Instance
415             // from the guts of the plugin.
416             void *_view = r->widget()->getView();
417             objectInstance = KWQ(part)->getObjectInstanceForView((NSView *)_view);
418             // Applet may specified with <object> tag.
419             if (!objectInstance)
420                 objectInstance = KWQ(part)->getAppletInstanceForView((NSView *)_view);
421         }
422     }
423     return objectInstance;
424 }
425 #endif
426
427 HTMLFormElementImpl *HTMLObjectElementImpl::form() const
428 {
429   return 0;
430 }
431
432 bool HTMLObjectElementImpl::mapToEntry(NodeImpl::Id attr, MappedAttributeEntry& result) const
433 {
434     switch (attr) {
435         case ATTR_WIDTH:
436         case ATTR_HEIGHT:
437             result = eUniversal;
438             return false;
439         default:
440             break;
441     }
442     
443     return HTMLElementImpl::mapToEntry(attr, result);
444 }
445
446 void HTMLObjectElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
447 {
448   QString val = attr->value().string();
449   int pos;
450   switch ( attr->id() )
451   {
452     case ATTR_TYPE:
453       serviceType = val.lower();
454       pos = serviceType.find( ";" );
455       if ( pos!=-1 )
456           serviceType = serviceType.left( pos );
457       if (m_render)
458           needWidgetUpdate = true;
459       if (!canRenderImageType(serviceType) && m_imageLoader) {
460           delete m_imageLoader;
461           m_imageLoader = 0;
462       }
463       break;
464     case ATTR_DATA:
465       url = khtml::parseURL(  val ).string();
466       if (m_render)
467           needWidgetUpdate = true;
468       if (m_render && canRenderImageType(serviceType)) {
469           if (!m_imageLoader)
470               m_imageLoader = new HTMLImageLoader(this);
471           m_imageLoader->updateFromElement();
472       }
473       break;
474     case ATTR_WIDTH:
475       addCSSLength( attr, CSS_PROP_WIDTH, attr->value());
476       break;
477     case ATTR_HEIGHT:
478       addCSSLength( attr, CSS_PROP_HEIGHT, attr->value());
479       break;
480     case ATTR_CLASSID:
481       classId = val;
482       if (m_render)
483           needWidgetUpdate = true;
484       break;
485     case ATTR_ONLOAD: // ### support load/unload on object elements
486         setHTMLEventListener(EventImpl::LOAD_EVENT,
487             getDocument()->createHTMLEventListener(attr->value().string()));
488         break;
489     case ATTR_ONUNLOAD:
490         setHTMLEventListener(EventImpl::UNLOAD_EVENT,
491             getDocument()->createHTMLEventListener(attr->value().string()));
492         break;
493     default:
494       HTMLElementImpl::parseHTMLAttribute( attr );
495   }
496 }
497
498 DocumentImpl* HTMLObjectElementImpl::contentDocument() const
499 {
500     // ###
501     return 0;
502 }
503
504 bool HTMLObjectElementImpl::rendererIsNeeded(RenderStyle *style)
505 {
506     if (canRenderImageType(serviceType)) {
507         return HTMLElementImpl::rendererIsNeeded(style);
508     }
509
510     KHTMLPart* part = getDocument()->part();
511     if (!part || !part->pluginsEnabled()) {
512         return false;
513     }
514 #if APPLE_CHANGES
515     // Eventually we will merge with the better version of this check on the tip of tree.
516     // Until then, just leave it out.
517 #else
518     KURL u = getDocument()->completeURL(url);
519     for (KHTMLPart* part = w->part()->parentPart(); part; part = part->parentPart())
520         if (part->url() == u) {
521             return false;
522         }
523 #endif
524     return true;
525 }
526
527 RenderObject *HTMLObjectElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
528 {
529     if (canRenderImageType(serviceType)) {
530         return new (arena) RenderImage(this);
531     }
532     return new (arena) RenderPartObject(this);
533 }
534
535 void HTMLObjectElementImpl::attach()
536 {
537     HTMLElementImpl::attach();
538
539     if (m_render) {
540         if (canRenderImageType(serviceType)) {
541             if (!m_imageLoader)
542                 m_imageLoader = new HTMLImageLoader(this);
543             m_imageLoader->updateFromElement();
544             if (renderer()) {
545                 RenderImage* imageObj = static_cast<RenderImage*>(renderer());
546                 imageObj->setImage(m_imageLoader->image());
547             }
548         } else {
549             if (needWidgetUpdate) {
550                 // Set needWidgetUpdate to false before calling updateWidget because updateWidget may cause
551                 // this method or recalcStyle (which also calls updateWidget) to be called.
552                 needWidgetUpdate = false;
553                 static_cast<RenderPartObject*>(m_render)->updateWidget();
554                 dispatchHTMLEvent(EventImpl::LOAD_EVENT,false,false);
555             } else {
556                 needWidgetUpdate = true;
557                 setChanged();
558             }
559         }
560     }
561 }
562
563 void HTMLObjectElementImpl::detach()
564 {
565     // Only bother with an unload event if we had a render object.  - dwh
566     if (attached() && m_render)
567         // ### do this when we are actualy removed from document instead
568         dispatchHTMLEvent(EventImpl::UNLOAD_EVENT,false,false);
569
570   HTMLElementImpl::detach();
571 }
572
573 void HTMLObjectElementImpl::recalcStyle(StyleChange ch)
574 {
575     if (needWidgetUpdate && m_render && !canRenderImageType(serviceType)) {
576         // Set needWidgetUpdate to false before calling updateWidget because updateWidget may cause
577         // this method or attach (which also calls updateWidget) to be called.
578         needWidgetUpdate = false;
579         static_cast<RenderPartObject*>(m_render)->updateWidget();
580         dispatchHTMLEvent(EventImpl::LOAD_EVENT,false,false);
581     }
582     HTMLElementImpl::recalcStyle(ch);
583 }
584
585 void HTMLObjectElementImpl::childrenChanged()
586 {
587     if (inDocument()) {
588         needWidgetUpdate = true;
589         setChanged();
590     }
591 }
592
593 bool HTMLObjectElementImpl::isURLAttribute(AttributeImpl *attr) const
594 {
595     return (attr->id() == ATTR_DATA || (attr->id() == ATTR_USEMAP && attr->value().domString()[0] != '#'));
596 }
597
598 // -------------------------------------------------------------------------
599
600 HTMLParamElementImpl::HTMLParamElementImpl(DocumentPtr *doc)
601     : HTMLElementImpl(doc)
602 {
603 }
604
605 HTMLParamElementImpl::~HTMLParamElementImpl()
606 {
607 }
608
609 NodeImpl::Id HTMLParamElementImpl::id() const
610 {
611     return ID_PARAM;
612 }
613
614 void HTMLParamElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
615 {
616     switch( attr->id() )
617     {
618     case ATTR_ID:
619         // Must call base class so that hasID bit gets set.
620         HTMLElementImpl::parseHTMLAttribute(attr);
621         if (getDocument()->htmlMode() != DocumentImpl::XHtml) break;
622         // fall through
623     case ATTR_NAME:
624         m_name = attr->value();
625         break;
626     case ATTR_VALUE:
627         m_value = attr->value();
628         break;
629     }
630 }
631
632 bool HTMLParamElementImpl::isURLAttribute(AttributeImpl *attr) const
633 {
634     if (attr->id() == ATTR_VALUE) {
635         AttributeImpl *attr = attributes()->getAttributeItem(ATTR_NAME);
636         if (attr) {
637             DOMString value = attr->value().string().lower();
638             if (value == "src" || value == "movie" || value == "data") {
639                 return true;
640             }
641         }
642     }
643     return false;
644 }