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  *           (C) 2007, 2008 Maks Orlovich (maksim@kde.org)
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., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24 #include "html/html_objectimpl.h"
25 
26 #include "khtml_part.h"
27 #include "dom/dom_string.h"
28 #include "imload/imagemanager.h"
29 #include "khtmlview.h"
30 #include <QCharRef>
31 #include <QVariant>
32 #include <QMap>
33 #include <QTimer>
34 #include <QImageReader>
35 
36 #include "khtml_debug.h"
37 #include <kmessagebox.h>
38 #include <qmimedatabase.h>
39 
40 #include "xml/dom_docimpl.h"
41 #include "css/cssstyleselector.h"
42 #include "css/cssproperties.h"
43 #include "css/cssvalues.h"
44 #include "rendering/render_frames.h"
45 #include "rendering/render_image.h"
46 #include "xml/dom2_eventsimpl.h"
47 
48 using namespace DOM;
49 using namespace khtml;
50 
HTMLPartContainerElementImpl(DocumentImpl * doc)51 HTMLPartContainerElementImpl::HTMLPartContainerElementImpl(DocumentImpl *doc)
52     : HTMLElementImpl(doc)
53 {
54     m_needToComputeContent = true;
55     m_childWidget          = nullptr;
56 }
57 
~HTMLPartContainerElementImpl()58 HTMLPartContainerElementImpl::~HTMLPartContainerElementImpl()
59 {
60     // Kill the renderer here, since we are asking for a widget to be deleted
61     if (m_render) {
62         detach();
63     }
64 
65     if (m_childWidget) {
66         m_childWidget->deleteLater();
67     }
68 }
69 
recalcStyle(StyleChange ch)70 void HTMLPartContainerElementImpl::recalcStyle(StyleChange ch)
71 {
72     computeContentIfNeeded();
73 
74     HTMLElementImpl::recalcStyle(ch);
75 }
76 
close()77 void HTMLPartContainerElementImpl::close()
78 {
79     HTMLElementImpl::close(); // Do it first, to make sure closed() is set.
80     computeContentIfNeeded();
81 }
82 
computeContentIfNeeded()83 void HTMLPartContainerElementImpl::computeContentIfNeeded()
84 {
85     if (!m_needToComputeContent) {
86         return;
87     }
88 
89     m_needToComputeContent = false;
90     computeContent();
91 }
92 
setNeedComputeContent()93 void HTMLPartContainerElementImpl::setNeedComputeContent()
94 {
95     m_needToComputeContent = true;
96     if (closed()) {
97         setChanged();    //React quickly when not in the middle of parsing..
98     }
99 }
100 
setWidget(QWidget * widget)101 void HTMLPartContainerElementImpl::setWidget(QWidget *widget)
102 {
103     if (widget == m_childWidget) {
104         return;    // The same part got navigated. Don't do anything
105     }
106 
107     QWidget *oldWidget = m_childWidget;
108     m_childWidget = widget;
109     if (m_childWidget) {
110         m_childWidget->hide();
111     }
112 
113     setWidgetNotify(m_childWidget);
114     if (oldWidget) {
115         oldWidget->hide();
116         oldWidget->deleteLater();
117     }
118 }
119 
partLoadingErrorNotify()120 void HTMLPartContainerElementImpl::partLoadingErrorNotify()
121 {
122     clearChildWidget();
123 }
124 
clearChildWidget()125 void HTMLPartContainerElementImpl::clearChildWidget()
126 {
127     setWidget(nullptr);
128 }
129 
mimetypeHandledInternally(const QString &)130 bool HTMLPartContainerElementImpl::mimetypeHandledInternally(const QString &)
131 {
132     return false;
133 }
134 
slotEmitLoadEvent()135 void HTMLPartContainerElementImpl::slotEmitLoadEvent()
136 {
137     dispatchHTMLEvent(EventImpl::LOAD_EVENT, false, false);
138 }
139 
postResizeEvent()140 void HTMLPartContainerElementImpl::postResizeEvent()
141 {
142     QApplication::postEvent(this, new QEvent(static_cast<QEvent::Type>(DOMCFResizeEvent)));
143 }
144 
sendPostedResizeEvents()145 void HTMLPartContainerElementImpl::sendPostedResizeEvents()
146 {
147     QApplication::sendPostedEvents(nullptr, DOMCFResizeEvent);
148 }
149 
event(QEvent * e)150 bool HTMLPartContainerElementImpl::event(QEvent *e)
151 {
152     if (e->type() == static_cast<QEvent::Type>(DOMCFResizeEvent)) {
153         dispatchWindowEvent(EventImpl::RESIZE_EVENT, false, false);
154         e->accept();
155         return true;
156     }
157     return QObject::event(e);
158 }
159 
160 // -------------------------------------------------------------------------
HTMLObjectBaseElementImpl(DocumentImpl * doc)161 HTMLObjectBaseElementImpl::HTMLObjectBaseElementImpl(DocumentImpl *doc)
162     : HTMLPartContainerElementImpl(doc)
163 {
164     m_renderAlternative    = false;
165     m_imageLike            = false;
166     m_rerender             = false;
167 }
168 
setServiceType(const QString & val)169 void HTMLObjectBaseElementImpl::setServiceType(const QString &val)
170 {
171     serviceType = val.toLower();
172     int pos = serviceType.indexOf(";");
173     if (pos != -1) {
174         serviceType.truncate(pos);
175     }
176 }
177 
parseAttribute(AttributeImpl * attr)178 void HTMLObjectBaseElementImpl::parseAttribute(AttributeImpl *attr)
179 {
180     switch (attr->id()) {
181     case ATTR_TYPE:
182     case ATTR_CODETYPE:
183         if (attr->val()) {
184             setServiceType(attr->val()->string());
185             setNeedComputeContent();
186         }
187         break;
188     case ATTR_WIDTH:
189         if (!attr->value().isEmpty()) {
190             addCSSLength(CSS_PROP_WIDTH, attr->value());
191         } else {
192             removeCSSProperty(CSS_PROP_WIDTH);
193         }
194         break;
195     case ATTR_HEIGHT:
196         if (!attr->value().isEmpty()) {
197             addCSSLength(CSS_PROP_HEIGHT, attr->value());
198         } else {
199             removeCSSProperty(CSS_PROP_HEIGHT);
200         }
201         break;
202     case ATTR_NAME:
203         if (inDocument() && m_name != attr->value()) {
204             document()->underDocNamedCache().remove(m_name,        this);
205             document()->underDocNamedCache().add(attr->value(), this);
206         }
207         m_name = attr->value();
208     //fallthrough
209     default:
210         HTMLElementImpl::parseAttribute(attr);
211     }
212 }
213 
defaultEventHandler(EventImpl * e)214 void HTMLObjectBaseElementImpl::defaultEventHandler(EventImpl *e)
215 {
216     // ### duplicated in HTMLIFrameElementImpl
217     if (e->target() == this && m_render && m_render->isWidget()
218             && static_cast<RenderWidget *>(m_render)->isRedirectedWidget()
219             && qobject_cast<KHTMLView *>(static_cast<RenderWidget *>(m_render)->widget())) {
220         switch (e->id())  {
221         case EventImpl::MOUSEDOWN_EVENT:
222         case EventImpl::MOUSEUP_EVENT:
223         case EventImpl::MOUSEMOVE_EVENT:
224         case EventImpl::MOUSEOUT_EVENT:
225         case EventImpl::MOUSEOVER_EVENT:
226         case EventImpl::KHTML_MOUSEWHEEL_EVENT:
227         case EventImpl::KEYDOWN_EVENT:
228         case EventImpl::KEYUP_EVENT:
229         case EventImpl::KEYPRESS_EVENT:
230         case EventImpl::DOMFOCUSIN_EVENT:
231         case EventImpl::DOMFOCUSOUT_EVENT:
232             if (static_cast<RenderWidget *>(m_render)->handleEvent(*e)) {
233                 e->setDefaultHandled();
234             }
235         default:
236             break;
237         }
238     }
239     HTMLElementImpl::defaultEventHandler(e);
240 }
241 
removedFromDocument()242 void HTMLObjectBaseElementImpl::removedFromDocument()
243 {
244     document()->underDocNamedCache().remove(m_name, this);
245 
246     // When removed from document, we destroy the widget/plugin.
247     // We have to do it here and not just call setNeedComputeContent(),
248     // since khtml will not try to restyle changed() things not in document.
249     clearChildWidget();
250 
251     HTMLPartContainerElementImpl::removedFromDocument();
252 }
253 
insertedIntoDocument()254 void HTMLObjectBaseElementImpl::insertedIntoDocument()
255 {
256     document()->underDocNamedCache().add(m_name, this);
257     setNeedComputeContent();
258     HTMLPartContainerElementImpl::insertedIntoDocument();
259 }
260 
removeId(const DOMString & id)261 void HTMLObjectBaseElementImpl::removeId(const DOMString &id)
262 {
263     document()->underDocNamedCache().remove(id, this);
264     HTMLElementImpl::removeId(id);
265 }
266 
addId(const DOMString & id)267 void HTMLObjectBaseElementImpl::addId(const DOMString &id)
268 {
269     document()->underDocNamedCache().add(id, this);
270     HTMLElementImpl::addId(id);
271 }
272 
requestRerender()273 void HTMLObjectBaseElementImpl::requestRerender()
274 {
275     if (m_rerender) {
276         return;
277     }
278     m_rerender = true;
279     QTimer::singleShot(0, this, SLOT(slotRerender()));
280 }
281 
slotRerender()282 void HTMLObjectBaseElementImpl::slotRerender()
283 {
284     // the singleshot timer might have fired after we're removed
285     // from the document, but not yet deleted due to references
286     if (!inDocument() || !m_rerender) {
287         return;
288     }
289 
290     // ### there can be a m_render if this is called from our attach indirectly
291     if (attached() || m_render) {
292         detach();
293         attach();
294     }
295 
296     m_rerender = false;
297 }
298 
attach()299 void HTMLObjectBaseElementImpl::attach()
300 {
301     assert(!attached());
302     assert(!m_render);
303 
304     computeContentIfNeeded();
305     m_rerender = false;
306 
307     if (m_renderAlternative && !m_imageLike) {
308         // render alternative content
309         ElementImpl::attach();
310         return;
311     }
312 
313     if (!parentNode()->renderer()) {
314         NodeBaseImpl::attach();
315         return;
316     }
317 
318     RenderStyle *_style = document()->styleSelector()->styleForElement(this);
319     _style->ref();
320 
321     if (parentNode()->renderer() && parentNode()->renderer()->childAllowed() &&
322             _style->display() != NONE) {
323         if (m_imageLike) {
324             m_render = new(document()->renderArena()) RenderImage(this);
325         } else {
326             m_render = new(document()->renderArena()) RenderPartObject(this);
327             // If we already have a widget, set it.
328             if (childWidget()) {
329                 static_cast<RenderFrame *>(m_render)->setWidget(childWidget());
330             }
331         }
332 
333         m_render->setStyle(_style);
334         parentNode()->renderer()->addChild(m_render, nextRenderer());
335         if (m_imageLike) {
336             m_render->updateFromElement();
337         }
338     }
339 
340     _style->deref();
341     NodeBaseImpl::attach();
342 }
343 
relevantEmbed()344 HTMLEmbedElementImpl *HTMLObjectBaseElementImpl::relevantEmbed()
345 {
346     for (NodeImpl *child = firstChild(); child; child = child->nextSibling()) {
347         if (child->id() == ID_EMBED) {
348             return static_cast<HTMLEmbedElementImpl *>(child);
349         }
350     }
351 
352     return nullptr;
353 }
354 
mimetypeHandledInternally(const QString & mime)355 bool HTMLObjectBaseElementImpl::mimetypeHandledInternally(const QString &mime)
356 {
357     QStringList supportedImageTypes = khtmlImLoad::ImageManager::loaderDatabase()->supportedMimeTypes();
358 
359     bool newImageLike = supportedImageTypes.contains(mime);
360 
361     if (newImageLike != m_imageLike) {
362         m_imageLike = newImageLike;
363         requestRerender();
364     }
365 
366     return newImageLike; // No need for kpart for that.
367 }
368 
computeContent()369 void HTMLObjectBaseElementImpl::computeContent()
370 {
371     QStringList params;
372     QString     effectiveURL = url; // May be overwritten by some of the <params>
373     // if the URL isn't there
374     QString     effectiveServiceType = serviceType;
375 
376     // We need to wait until everything has parsed, since we need the <param>s,
377     // and the embedded <embed>
378     if (!closed()) {
379         setNeedComputeContent();
380         return;
381     }
382 
383     // Not in document => no plugin.
384     if (!inDocument()) {
385         clearChildWidget();
386         return;
387     }
388 
389     // Collect information from <param> children for ...
390     // It also sometimes supplements or replaces some of the element's attributes
391     for (NodeImpl *child = firstChild(); child; child = child->nextSibling()) {
392         if (child->id() == ID_PARAM) {
393             HTMLParamElementImpl *p = static_cast<HTMLParamElementImpl *>(child);
394 
395             QString aStr = p->name();
396             aStr += QLatin1String("=\"");
397             aStr += p->value();
398             aStr += QLatin1String("\"");
399             QString name_lower = p->name().toLower();
400             if (name_lower == QLatin1String("type") && id() != ID_APPLET) {
401                 setServiceType(p->value());
402                 effectiveServiceType = serviceType;
403             } else if (effectiveURL.isEmpty() &&
404                        (name_lower == QLatin1String("src") ||
405                         name_lower == QLatin1String("movie") ||
406                         name_lower == QLatin1String("code"))) {
407                 effectiveURL = p->value();
408             }
409             params.append(aStr);
410         }
411     }
412 
413     // For <applet>(?) and <embed> we also make each attribute a part parameter
414     if (id() != ID_OBJECT) {
415         NamedAttrMapImpl *a = attributes();
416         if (a) {
417             for (unsigned i = 0; i < a->length(); ++i) {
418                 NodeImpl::Id id = a->idAt(i);
419                 DOMString value = a->valueAt(i);
420                 params.append(LocalName::fromId(localNamePart(id)).toString().string() + "=\"" + value.string() + "\"");
421             }
422         }
423     }
424 
425     params.append(QLatin1String("__KHTML__PLUGINEMBED=\"YES\""));
426     params.append(QString::fromLatin1("__KHTML__PLUGINBASEURL=\"%1\"").arg(document()->baseURL().url()));
427     params.append(QString::fromLatin1("__KHTML__PLUGINPAGEURL=\"%1\"").arg(document()->URL().url()));
428 
429     // Non-embed elements parse a bunch of attributes and inherit things off <embed>, if any
430     HTMLEmbedElementImpl *embed = relevantEmbed();
431     if (id() != ID_EMBED) {
432         params.append(QString::fromLatin1("__KHTML__CLASSID=\"%1\"").arg(classId));
433         params.append(QString::fromLatin1("__KHTML__CODEBASE=\"%1\"").arg(getAttribute(ATTR_CODEBASE).string()));
434 
435         if (embed && !embed->getAttribute(ATTR_WIDTH).isEmpty()) {
436             setAttribute(ATTR_WIDTH, embed->getAttribute(ATTR_WIDTH));
437         }
438 
439         if (embed && !embed->getAttribute(ATTR_HEIGHT).isEmpty()) {
440             setAttribute(ATTR_HEIGHT, embed->getAttribute(ATTR_HEIGHT));
441         }
442 
443         if (!getAttribute(ATTR_WIDTH).isEmpty()) {
444             params.append(QString::fromLatin1("WIDTH=\"%1\"").arg(getAttribute(ATTR_WIDTH).string()));
445         }
446 
447         if (!getAttribute(ATTR_HEIGHT).isEmpty()) {
448             params.append(QString::fromLatin1("HEIGHT=\"%1\"").arg(getAttribute(ATTR_HEIGHT).string()));
449         }
450 
451         // Fix up the serviceType from embed, or applet info..
452         if (embed) {
453             effectiveURL = embed->url;
454             if (!embed->serviceType.isEmpty()) {
455                 effectiveServiceType = embed->serviceType;
456             }
457         } else if (effectiveURL.isEmpty() &&
458                    classId.startsWith(QLatin1String("java:"))) {
459             effectiveServiceType = "application/x-java-applet";
460             effectiveURL         = classId.mid(5);
461         }
462 
463         // Translate ActiveX gibberish into mimetypes
464         if ((effectiveServiceType.isEmpty() || serviceType == "application/x-oleobject") && !classId.isEmpty()) {
465             if (classId.indexOf(QString::fromLatin1("D27CDB6E-AE6D-11cf-96B8-444553540000")) >= 0) {
466                 effectiveServiceType = "application/x-shockwave-flash";
467             } else if (classId.indexOf(QLatin1String("CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA")) >= 0) {
468                 effectiveServiceType = "audio/x-pn-realaudio-plugin";
469             } else if (classId.indexOf(QLatin1String("8AD9C840-044E-11D1-B3E9-00805F499D93")) >= 0 ||
470                        classId.indexOf(QLatin1String("CAFEEFAC-0014-0000-0000-ABCDEFFEDCBA")) >= 0) {
471                 effectiveServiceType = "application/x-java-applet";
472             }
473             // http://www.apple.com/quicktime/tools_tips/tutorials/activex.html
474             else if (classId.indexOf(QLatin1String("02BF25D5-8C17-4B23-BC80-D3488ABDDC6B")) >= 0) {
475                 effectiveServiceType = "video/quicktime";
476             }
477             // http://msdn.microsoft.com/library/en-us/dnwmt/html/adding_windows_media_to_web_pages__etse.asp?frame=true
478             else if (classId.indexOf(QString::fromLatin1("6BF52A52-394A-11d3-B153-00C04F79FAA6")) >= 0 ||
479                      classId.indexOf(QString::fromLatin1("22D6f312-B0F6-11D0-94AB-0080C74C7E95")) >= 0) {
480                 effectiveServiceType = "video/x-msvideo";
481             } else {
482                 // qCDebug(KHTML_LOG) << "ActiveX classId " << classId;
483             }
484             // TODO: add more plugins here
485         }
486     }
487 
488     if (effectiveServiceType.isEmpty() &&
489             effectiveURL.startsWith(QLatin1String("data:"))) {
490         // Extract the MIME type from the data URL.
491         int index = effectiveURL.indexOf(';');
492         if (index == -1) {
493             index = effectiveURL.indexOf(',');
494         }
495         if (index != -1) {
496             int len = index - 5;
497             if (len > 0) {
498                 effectiveServiceType = effectiveURL.mid(5, len);
499             } else {
500                 effectiveServiceType = "text/plain";    // Data URLs with no MIME type are considered text/plain.
501             }
502         }
503     }
504 
505     // Figure out if may be we're image-like. In this case, we don't need to load anything,
506     // but may need to do a detach/attach
507     QStringList supportedImageTypes = khtmlImLoad::ImageManager::loaderDatabase()->supportedMimeTypes();
508 
509     bool newImageLike = effectiveServiceType.startsWith(QLatin1String("image/")) && supportedImageTypes.contains(effectiveServiceType);
510 
511     if (newImageLike != m_imageLike) {
512         m_imageLike = newImageLike;
513         requestRerender();
514     }
515 
516     if (m_imageLike) {
517         return;
518     }
519 
520     // Now see if we have to render alternate content.
521     bool newRenderAlternative = false;
522 
523     // If we aren't permitted to load this by security policy, render alternative content instead.
524     if (!document()->isURLAllowed(effectiveURL)) {
525         newRenderAlternative = true;
526     }
527 
528     // If Java is off, render alternative as well...
529     if (effectiveServiceType == "application/x-java-applet") {
530         KHTMLPart *p = document()->part();
531         if (!p || !p->javaEnabled()) {
532             newRenderAlternative = true;
533         }
534     }
535 
536     // If there is no <embed> (here or as a child), and we don't have a type + url to go on,
537     // we need to render alternative as well
538     if (!embed && effectiveURL.isEmpty() && effectiveServiceType.isEmpty()) {
539         newRenderAlternative = true;
540     }
541 
542     if (newRenderAlternative != m_renderAlternative) {
543         m_renderAlternative = newRenderAlternative;
544         requestRerender();
545     }
546 
547     if (m_renderAlternative) {
548         return;
549     }
550 
551     KHTMLPart *part = document()->part();
552     clearChildWidget();
553 
554     // qCDebug(KHTML_LOG) << effectiveURL << effectiveServiceType << params;
555 
556     if (!part->loadObjectElement(this, effectiveURL, effectiveServiceType, params)) {
557         // Looks like we are gonna need alternative content after all...
558         m_renderAlternative = true;
559     }
560 
561     // Either way, we need to re-attach, either for alternative content, or because
562     // we got the part..
563     requestRerender();
564 }
565 
setWidgetNotify(QWidget * widget)566 void HTMLObjectBaseElementImpl::setWidgetNotify(QWidget *widget)
567 {
568     // Ick.
569     if (m_render && strcmp(m_render->renderName(),  "RenderPartObject") == 0) {
570         static_cast<RenderPartObject *>(m_render)->setWidget(widget);
571     }
572 }
573 
renderAlternative()574 void HTMLObjectBaseElementImpl::renderAlternative()
575 {
576     if (m_renderAlternative) {
577         return;
578     }
579 
580     m_renderAlternative = true;
581     requestRerender();
582 }
583 
partLoadingErrorNotify()584 void HTMLObjectBaseElementImpl::partLoadingErrorNotify()
585 {
586     // Defer ourselves from the current event loop (to prevent crashes due to the message box staying up)
587     QTimer::singleShot(0, this, SLOT(slotPartLoadingErrorNotify()));
588 
589     // Either way, we don't have stuff to display, so have to render alternative content.
590     if (!m_renderAlternative) {
591         m_renderAlternative = true;
592         requestRerender();
593     }
594 
595     clearChildWidget();
596 }
597 
slotPartLoadingErrorNotify()598 void HTMLObjectBaseElementImpl::slotPartLoadingErrorNotify()
599 {
600     // If we have an embed, we may be able to tell the user where to
601     // download the plugin.
602 
603     HTMLEmbedElementImpl *embed = relevantEmbed();
604     QString serviceType; // shadows ours, but we don't care.
605 
606     if (!embed) {
607         return;
608     }
609 
610     serviceType = embed->serviceType;
611 
612     KHTMLPart *part = document()->part();
613     KParts::BrowserExtension *ext = part->browserExtension();
614 
615     if (!embed->pluginPage.isEmpty() && ext) {
616         // Prepare the mimetype to show in the question (comment if available, name as fallback)
617         QString mimeName = serviceType;
618         QMimeDatabase db;
619         QMimeType mime = db.mimeTypeForName(serviceType);
620         if (mime.isValid()) {
621             mimeName = mime.comment();
622         }
623 
624         // Check if we already asked the user, for this page
625         if (!mimeName.isEmpty() && !part->pluginPageQuestionAsked(serviceType)) {
626             part->setPluginPageQuestionAsked(serviceType);
627 
628             // Prepare the URL to show in the question (host only if http, to make it short)
629             QUrl pluginPageURL(embed->pluginPage);
630             QString shortURL = pluginPageURL.scheme() == "http" ? pluginPageURL.host() : pluginPageURL.toDisplayString();
631             int res = KMessageBox::questionYesNo(part->view(),
632                                                  i18n("No plugin found for '%1'.\nDo you want to download one from %2?", mimeName, shortURL),
633                                                  i18n("Missing Plugin"), KGuiItem(i18n("Download")), KGuiItem(i18n("Do Not Download")), QString("plugin-") + serviceType);
634             if (res == KMessageBox::Yes) {
635                 // Display vendor download page
636                 ext->createNewWindow(pluginPageURL);
637                 return;
638             }
639         }
640     }
641 }
642 
643 // -------------------------------------------------------------------------
644 
HTMLAppletElementImpl(DocumentImpl * doc)645 HTMLAppletElementImpl::HTMLAppletElementImpl(DocumentImpl *doc)
646     : HTMLObjectBaseElementImpl(doc)
647 {
648     serviceType = "application/x-java-applet";
649 }
650 
~HTMLAppletElementImpl()651 HTMLAppletElementImpl::~HTMLAppletElementImpl()
652 {
653 }
654 
id() const655 NodeImpl::Id HTMLAppletElementImpl::id() const
656 {
657     return ID_APPLET;
658 }
659 
parseAttribute(AttributeImpl * attr)660 void HTMLAppletElementImpl::parseAttribute(AttributeImpl *attr)
661 {
662     switch (attr->id()) {
663     case ATTR_CODEBASE:
664     case ATTR_ARCHIVE:
665     case ATTR_CODE:
666     case ATTR_OBJECT:
667     case ATTR_ALT:
668         break;
669     case ATTR_ALIGN:
670         addHTMLAlignment(attr->value());
671         break;
672     case ATTR_VSPACE:
673         addCSSLength(CSS_PROP_MARGIN_TOP, attr->value());
674         addCSSLength(CSS_PROP_MARGIN_BOTTOM, attr->value());
675         break;
676     case ATTR_HSPACE:
677         addCSSLength(CSS_PROP_MARGIN_LEFT, attr->value());
678         addCSSLength(CSS_PROP_MARGIN_RIGHT, attr->value());
679         break;
680     case ATTR_VALIGN:
681         addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower());
682         break;
683     default:
684         HTMLObjectBaseElementImpl::parseAttribute(attr);
685     }
686 }
687 
computeContent()688 void HTMLAppletElementImpl::computeContent()
689 {
690     DOMString codeBase = getAttribute(ATTR_CODEBASE);
691     DOMString code = getAttribute(ATTR_CODE);
692     if (!codeBase.isEmpty()) {
693         url = codeBase.string();
694     }
695     if (!code.isEmpty()) {
696         url = code.string();
697     }
698     HTMLObjectBaseElementImpl::computeContent();
699 }
700 
701 // -------------------------------------------------------------------------
702 
HTMLEmbedElementImpl(DocumentImpl * doc)703 HTMLEmbedElementImpl::HTMLEmbedElementImpl(DocumentImpl *doc)
704     : HTMLObjectBaseElementImpl(doc)
705 {
706 }
707 
~HTMLEmbedElementImpl()708 HTMLEmbedElementImpl::~HTMLEmbedElementImpl()
709 {
710 }
711 
id() const712 NodeImpl::Id HTMLEmbedElementImpl::id() const
713 {
714     return ID_EMBED;
715 }
716 
relevantEmbed()717 HTMLEmbedElementImpl *HTMLEmbedElementImpl::relevantEmbed()
718 {
719     return this;
720 }
721 
parseAttribute(AttributeImpl * attr)722 void HTMLEmbedElementImpl::parseAttribute(AttributeImpl *attr)
723 {
724     switch (attr->id()) {
725     case ATTR_CODE:
726     case ATTR_SRC:
727         url = attr->value().trimSpaces().string();
728         setNeedComputeContent();
729         break;
730     case ATTR_BORDER:
731         addCSSLength(CSS_PROP_BORDER_WIDTH, attr->value());
732         addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_SOLID);
733         addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_SOLID);
734         addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_SOLID);
735         addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_SOLID);
736         break;
737     case ATTR_VSPACE:
738         addCSSLength(CSS_PROP_MARGIN_TOP, attr->value());
739         addCSSLength(CSS_PROP_MARGIN_BOTTOM, attr->value());
740         break;
741     case ATTR_HSPACE:
742         addCSSLength(CSS_PROP_MARGIN_LEFT, attr->value());
743         addCSSLength(CSS_PROP_MARGIN_RIGHT, attr->value());
744         break;
745     case ATTR_ALIGN:
746         addHTMLAlignment(attr->value());
747         break;
748     case ATTR_VALIGN:
749         addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower());
750         break;
751     case ATTR_PLUGINPAGE:
752     case ATTR_PLUGINSPAGE: {
753         pluginPage = attr->value().string();
754         break;
755     }
756     case ATTR_HIDDEN:
757         if (strcasecmp(attr->value(), "yes") == 0 || strcasecmp(attr->value(), "true") == 0) {
758             hidden = true;
759         } else {
760             hidden = false;
761         }
762         break;
763     default:
764         HTMLObjectBaseElementImpl::parseAttribute(attr);
765     }
766 }
767 
attach()768 void HTMLEmbedElementImpl::attach()
769 {
770     if (parentNode()->id() == ID_OBJECT) {
771         NodeBaseImpl::attach();
772     } else {
773         HTMLObjectBaseElementImpl::attach();
774     }
775 }
776 
computeContent()777 void HTMLEmbedElementImpl::computeContent()
778 {
779     if (parentNode()->id() != ID_OBJECT) {
780         HTMLObjectBaseElementImpl::computeContent();
781     }
782 }
783 
784 // -------------------------------------------------------------------------
785 
HTMLObjectElementImpl(DocumentImpl * doc)786 HTMLObjectElementImpl::HTMLObjectElementImpl(DocumentImpl *doc)
787     : HTMLObjectBaseElementImpl(doc)
788 {
789 }
790 
~HTMLObjectElementImpl()791 HTMLObjectElementImpl::~HTMLObjectElementImpl()
792 {
793 }
794 
id() const795 NodeImpl::Id HTMLObjectElementImpl::id() const
796 {
797     return ID_OBJECT;
798 }
799 
form() const800 HTMLFormElementImpl *HTMLObjectElementImpl::form() const
801 {
802     return nullptr;
803 }
804 
parseAttribute(AttributeImpl * attr)805 void HTMLObjectElementImpl::parseAttribute(AttributeImpl *attr)
806 {
807     switch (attr->id()) {
808     case ATTR_DATA:
809         url = attr->value().trimSpaces().string();
810         setNeedComputeContent();
811         break;
812     case ATTR_CLASSID:
813         classId = attr->value().string();
814         setNeedComputeContent();
815         break;
816     case ATTR_ONLOAD: // ### support load/unload on object elements
817         setHTMLEventListener(EventImpl::LOAD_EVENT,
818                              document()->createHTMLEventListener(attr->value().string(), "onload", this));
819         break;
820     case ATTR_ONUNLOAD:
821         setHTMLEventListener(EventImpl::UNLOAD_EVENT,
822                              document()->createHTMLEventListener(attr->value().string(), "onunload", this));
823         break;
824     case ATTR_VSPACE:
825         addCSSLength(CSS_PROP_MARGIN_TOP, attr->value());
826         addCSSLength(CSS_PROP_MARGIN_BOTTOM, attr->value());
827         break;
828     case ATTR_HSPACE:
829         addCSSLength(CSS_PROP_MARGIN_LEFT, attr->value());
830         addCSSLength(CSS_PROP_MARGIN_RIGHT, attr->value());
831         break;
832     case ATTR_ALIGN:
833         addHTMLAlignment(attr->value());
834         break;
835     case ATTR_VALIGN:
836         addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower());
837         break;
838     default:
839         HTMLObjectBaseElementImpl::parseAttribute(attr);
840     }
841 }
842 
contentDocument() const843 DocumentImpl *HTMLObjectElementImpl::contentDocument() const
844 {
845     QWidget *widget = childWidget();
846     if (widget && qobject_cast<KHTMLView *>(widget)) {
847         return static_cast<KHTMLView *>(widget)->part()->xmlDocImpl();
848     }
849     return nullptr;
850 }
851 
attach()852 void HTMLObjectElementImpl::attach()
853 {
854     HTMLObjectBaseElementImpl::attach();
855 }
856 
857 // -------------------------------------------------------------------------
858 
id() const859 NodeImpl::Id HTMLParamElementImpl::id() const
860 {
861     return ID_PARAM;
862 }
863 
parseAttribute(AttributeImpl * attr)864 void HTMLParamElementImpl::parseAttribute(AttributeImpl *attr)
865 {
866     switch (attr->id()) {
867     case ATTR_VALUE:
868         m_value = attr->value().string();
869         break;
870     case ATTR_ID:
871         if (document()->htmlMode() != DocumentImpl::XHtml) {
872             break;
873         }
874     // fall through
875     case ATTR_NAME:
876         m_name = attr->value().string();
877     // fall through
878     default:
879         HTMLElementImpl::parseAttribute(attr);
880     }
881 }
882 
883