File indexing completed on 2024-05-05 16:10:14

0001 /**
0002  * This file is part of the DOM implementation for KDE.
0003  *
0004  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
0005  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
0006  *           (C) 2000 Stefan Schimanski (1Stein@gmx.de)
0007  *           (C) 2007, 2008 Maks Orlovich (maksim@kde.org)
0008  *
0009  * This library is free software; you can redistribute it and/or
0010  * modify it under the terms of the GNU Library General Public
0011  * License as published by the Free Software Foundation; either
0012  * version 2 of the License, or (at your option) any later version.
0013  *
0014  * This library is distributed in the hope that it will be useful,
0015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0017  * Library General Public License for more details.
0018  *
0019  * You should have received a copy of the GNU Library General Public License
0020  * along with this library; see the file COPYING.LIB.  If not, write to
0021  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0022  * Boston, MA 02110-1301, USA.
0023  */
0024 #include "html/html_objectimpl.h"
0025 
0026 #include "khtml_part.h"
0027 #include "dom/dom_string.h"
0028 #include "imload/imagemanager.h"
0029 #include "khtmlview.h"
0030 #include <QCharRef>
0031 #include <QVariant>
0032 #include <QMap>
0033 #include <QTimer>
0034 #include <QImageReader>
0035 
0036 #include "khtml_debug.h"
0037 #include <kmessagebox.h>
0038 #include <qmimedatabase.h>
0039 
0040 #include "xml/dom_docimpl.h"
0041 #include "css/cssstyleselector.h"
0042 #include "css/cssproperties.h"
0043 #include "css/cssvalues.h"
0044 #include "rendering/render_frames.h"
0045 #include "rendering/render_image.h"
0046 #include "xml/dom2_eventsimpl.h"
0047 
0048 using namespace DOM;
0049 using namespace khtml;
0050 
0051 HTMLPartContainerElementImpl::HTMLPartContainerElementImpl(DocumentImpl *doc)
0052     : HTMLElementImpl(doc)
0053 {
0054     m_needToComputeContent = true;
0055     m_childWidget          = nullptr;
0056 }
0057 
0058 HTMLPartContainerElementImpl::~HTMLPartContainerElementImpl()
0059 {
0060     // Kill the renderer here, since we are asking for a widget to be deleted
0061     if (m_render) {
0062         detach();
0063     }
0064 
0065     if (m_childWidget) {
0066         m_childWidget->deleteLater();
0067     }
0068 }
0069 
0070 void HTMLPartContainerElementImpl::recalcStyle(StyleChange ch)
0071 {
0072     computeContentIfNeeded();
0073 
0074     HTMLElementImpl::recalcStyle(ch);
0075 }
0076 
0077 void HTMLPartContainerElementImpl::close()
0078 {
0079     HTMLElementImpl::close(); // Do it first, to make sure closed() is set.
0080     computeContentIfNeeded();
0081 }
0082 
0083 void HTMLPartContainerElementImpl::computeContentIfNeeded()
0084 {
0085     if (!m_needToComputeContent) {
0086         return;
0087     }
0088 
0089     m_needToComputeContent = false;
0090     computeContent();
0091 }
0092 
0093 void HTMLPartContainerElementImpl::setNeedComputeContent()
0094 {
0095     m_needToComputeContent = true;
0096     if (closed()) {
0097         setChanged();    //React quickly when not in the middle of parsing..
0098     }
0099 }
0100 
0101 void HTMLPartContainerElementImpl::setWidget(QWidget *widget)
0102 {
0103     if (widget == m_childWidget) {
0104         return;    // The same part got navigated. Don't do anything
0105     }
0106 
0107     QWidget *oldWidget = m_childWidget;
0108     m_childWidget = widget;
0109     if (m_childWidget) {
0110         m_childWidget->hide();
0111     }
0112 
0113     setWidgetNotify(m_childWidget);
0114     if (oldWidget) {
0115         oldWidget->hide();
0116         oldWidget->deleteLater();
0117     }
0118 }
0119 
0120 void HTMLPartContainerElementImpl::partLoadingErrorNotify()
0121 {
0122     clearChildWidget();
0123 }
0124 
0125 void HTMLPartContainerElementImpl::clearChildWidget()
0126 {
0127     setWidget(nullptr);
0128 }
0129 
0130 bool HTMLPartContainerElementImpl::mimetypeHandledInternally(const QString &)
0131 {
0132     return false;
0133 }
0134 
0135 void HTMLPartContainerElementImpl::slotEmitLoadEvent()
0136 {
0137     dispatchHTMLEvent(EventImpl::LOAD_EVENT, false, false);
0138 }
0139 
0140 void HTMLPartContainerElementImpl::postResizeEvent()
0141 {
0142     QApplication::postEvent(this, new QEvent(static_cast<QEvent::Type>(DOMCFResizeEvent)));
0143 }
0144 
0145 void HTMLPartContainerElementImpl::sendPostedResizeEvents()
0146 {
0147     QApplication::sendPostedEvents(nullptr, DOMCFResizeEvent);
0148 }
0149 
0150 bool HTMLPartContainerElementImpl::event(QEvent *e)
0151 {
0152     if (e->type() == static_cast<QEvent::Type>(DOMCFResizeEvent)) {
0153         dispatchWindowEvent(EventImpl::RESIZE_EVENT, false, false);
0154         e->accept();
0155         return true;
0156     }
0157     return QObject::event(e);
0158 }
0159 
0160 // -------------------------------------------------------------------------
0161 HTMLObjectBaseElementImpl::HTMLObjectBaseElementImpl(DocumentImpl *doc)
0162     : HTMLPartContainerElementImpl(doc)
0163 {
0164     m_renderAlternative    = false;
0165     m_imageLike            = false;
0166     m_rerender             = false;
0167 }
0168 
0169 void HTMLObjectBaseElementImpl::setServiceType(const QString &val)
0170 {
0171     serviceType = val.toLower();
0172     int pos = serviceType.indexOf(";");
0173     if (pos != -1) {
0174         serviceType.truncate(pos);
0175     }
0176 }
0177 
0178 void HTMLObjectBaseElementImpl::parseAttribute(AttributeImpl *attr)
0179 {
0180     switch (attr->id()) {
0181     case ATTR_TYPE:
0182     case ATTR_CODETYPE:
0183         if (attr->val()) {
0184             setServiceType(attr->val()->string());
0185             setNeedComputeContent();
0186         }
0187         break;
0188     case ATTR_WIDTH:
0189         if (!attr->value().isEmpty()) {
0190             addCSSLength(CSS_PROP_WIDTH, attr->value());
0191         } else {
0192             removeCSSProperty(CSS_PROP_WIDTH);
0193         }
0194         break;
0195     case ATTR_HEIGHT:
0196         if (!attr->value().isEmpty()) {
0197             addCSSLength(CSS_PROP_HEIGHT, attr->value());
0198         } else {
0199             removeCSSProperty(CSS_PROP_HEIGHT);
0200         }
0201         break;
0202     case ATTR_NAME:
0203         if (inDocument() && m_name != attr->value()) {
0204             document()->underDocNamedCache().remove(m_name,        this);
0205             document()->underDocNamedCache().add(attr->value(), this);
0206         }
0207         m_name = attr->value();
0208     //fallthrough
0209     default:
0210         HTMLElementImpl::parseAttribute(attr);
0211     }
0212 }
0213 
0214 void HTMLObjectBaseElementImpl::defaultEventHandler(EventImpl *e)
0215 {
0216     // ### duplicated in HTMLIFrameElementImpl
0217     if (e->target() == this && m_render && m_render->isWidget()
0218             && static_cast<RenderWidget *>(m_render)->isRedirectedWidget()
0219             && qobject_cast<KHTMLView *>(static_cast<RenderWidget *>(m_render)->widget())) {
0220         switch (e->id())  {
0221         case EventImpl::MOUSEDOWN_EVENT:
0222         case EventImpl::MOUSEUP_EVENT:
0223         case EventImpl::MOUSEMOVE_EVENT:
0224         case EventImpl::MOUSEOUT_EVENT:
0225         case EventImpl::MOUSEOVER_EVENT:
0226         case EventImpl::KHTML_MOUSEWHEEL_EVENT:
0227         case EventImpl::KEYDOWN_EVENT:
0228         case EventImpl::KEYUP_EVENT:
0229         case EventImpl::KEYPRESS_EVENT:
0230         case EventImpl::DOMFOCUSIN_EVENT:
0231         case EventImpl::DOMFOCUSOUT_EVENT:
0232             if (static_cast<RenderWidget *>(m_render)->handleEvent(*e)) {
0233                 e->setDefaultHandled();
0234             }
0235         default:
0236             break;
0237         }
0238     }
0239     HTMLElementImpl::defaultEventHandler(e);
0240 }
0241 
0242 void HTMLObjectBaseElementImpl::removedFromDocument()
0243 {
0244     document()->underDocNamedCache().remove(m_name, this);
0245 
0246     // When removed from document, we destroy the widget/plugin.
0247     // We have to do it here and not just call setNeedComputeContent(),
0248     // since khtml will not try to restyle changed() things not in document.
0249     clearChildWidget();
0250 
0251     HTMLPartContainerElementImpl::removedFromDocument();
0252 }
0253 
0254 void HTMLObjectBaseElementImpl::insertedIntoDocument()
0255 {
0256     document()->underDocNamedCache().add(m_name, this);
0257     setNeedComputeContent();
0258     HTMLPartContainerElementImpl::insertedIntoDocument();
0259 }
0260 
0261 void HTMLObjectBaseElementImpl::removeId(const DOMString &id)
0262 {
0263     document()->underDocNamedCache().remove(id, this);
0264     HTMLElementImpl::removeId(id);
0265 }
0266 
0267 void HTMLObjectBaseElementImpl::addId(const DOMString &id)
0268 {
0269     document()->underDocNamedCache().add(id, this);
0270     HTMLElementImpl::addId(id);
0271 }
0272 
0273 void HTMLObjectBaseElementImpl::requestRerender()
0274 {
0275     if (m_rerender) {
0276         return;
0277     }
0278     m_rerender = true;
0279     QTimer::singleShot(0, this, SLOT(slotRerender()));
0280 }
0281 
0282 void HTMLObjectBaseElementImpl::slotRerender()
0283 {
0284     // the singleshot timer might have fired after we're removed
0285     // from the document, but not yet deleted due to references
0286     if (!inDocument() || !m_rerender) {
0287         return;
0288     }
0289 
0290     // ### there can be a m_render if this is called from our attach indirectly
0291     if (attached() || m_render) {
0292         detach();
0293         attach();
0294     }
0295 
0296     m_rerender = false;
0297 }
0298 
0299 void HTMLObjectBaseElementImpl::attach()
0300 {
0301     assert(!attached());
0302     assert(!m_render);
0303 
0304     computeContentIfNeeded();
0305     m_rerender = false;
0306 
0307     if (m_renderAlternative && !m_imageLike) {
0308         // render alternative content
0309         ElementImpl::attach();
0310         return;
0311     }
0312 
0313     if (!parentNode()->renderer()) {
0314         NodeBaseImpl::attach();
0315         return;
0316     }
0317 
0318     RenderStyle *_style = document()->styleSelector()->styleForElement(this);
0319     _style->ref();
0320 
0321     if (parentNode()->renderer() && parentNode()->renderer()->childAllowed() &&
0322             _style->display() != NONE) {
0323         if (m_imageLike) {
0324             m_render = new(document()->renderArena()) RenderImage(this);
0325         } else {
0326             m_render = new(document()->renderArena()) RenderPartObject(this);
0327             // If we already have a widget, set it.
0328             if (childWidget()) {
0329                 static_cast<RenderFrame *>(m_render)->setWidget(childWidget());
0330             }
0331         }
0332 
0333         m_render->setStyle(_style);
0334         parentNode()->renderer()->addChild(m_render, nextRenderer());
0335         if (m_imageLike) {
0336             m_render->updateFromElement();
0337         }
0338     }
0339 
0340     _style->deref();
0341     NodeBaseImpl::attach();
0342 }
0343 
0344 HTMLEmbedElementImpl *HTMLObjectBaseElementImpl::relevantEmbed()
0345 {
0346     for (NodeImpl *child = firstChild(); child; child = child->nextSibling()) {
0347         if (child->id() == ID_EMBED) {
0348             return static_cast<HTMLEmbedElementImpl *>(child);
0349         }
0350     }
0351 
0352     return nullptr;
0353 }
0354 
0355 bool HTMLObjectBaseElementImpl::mimetypeHandledInternally(const QString &mime)
0356 {
0357     QStringList supportedImageTypes = khtmlImLoad::ImageManager::loaderDatabase()->supportedMimeTypes();
0358 
0359     bool newImageLike = supportedImageTypes.contains(mime);
0360 
0361     if (newImageLike != m_imageLike) {
0362         m_imageLike = newImageLike;
0363         requestRerender();
0364     }
0365 
0366     return newImageLike; // No need for kpart for that.
0367 }
0368 
0369 void HTMLObjectBaseElementImpl::computeContent()
0370 {
0371     QStringList params;
0372     QString     effectiveURL = url; // May be overwritten by some of the <params>
0373     // if the URL isn't there
0374     QString     effectiveServiceType = serviceType;
0375 
0376     // We need to wait until everything has parsed, since we need the <param>s,
0377     // and the embedded <embed>
0378     if (!closed()) {
0379         setNeedComputeContent();
0380         return;
0381     }
0382 
0383     // Not in document => no plugin.
0384     if (!inDocument()) {
0385         clearChildWidget();
0386         return;
0387     }
0388 
0389     // Collect information from <param> children for ...
0390     // It also sometimes supplements or replaces some of the element's attributes
0391     for (NodeImpl *child = firstChild(); child; child = child->nextSibling()) {
0392         if (child->id() == ID_PARAM) {
0393             HTMLParamElementImpl *p = static_cast<HTMLParamElementImpl *>(child);
0394 
0395             QString aStr = p->name();
0396             aStr += QLatin1String("=\"");
0397             aStr += p->value();
0398             aStr += QLatin1String("\"");
0399             QString name_lower = p->name().toLower();
0400             if (name_lower == QLatin1String("type") && id() != ID_APPLET) {
0401                 setServiceType(p->value());
0402                 effectiveServiceType = serviceType;
0403             } else if (effectiveURL.isEmpty() &&
0404                        (name_lower == QLatin1String("src") ||
0405                         name_lower == QLatin1String("movie") ||
0406                         name_lower == QLatin1String("code"))) {
0407                 effectiveURL = p->value();
0408             }
0409             params.append(aStr);
0410         }
0411     }
0412 
0413     // For <applet>(?) and <embed> we also make each attribute a part parameter
0414     if (id() != ID_OBJECT) {
0415         NamedAttrMapImpl *a = attributes();
0416         if (a) {
0417             for (unsigned i = 0; i < a->length(); ++i) {
0418                 NodeImpl::Id id = a->idAt(i);
0419                 DOMString value = a->valueAt(i);
0420                 params.append(LocalName::fromId(localNamePart(id)).toString().string() + "=\"" + value.string() + "\"");
0421             }
0422         }
0423     }
0424 
0425     params.append(QLatin1String("__KHTML__PLUGINEMBED=\"YES\""));
0426     params.append(QString::fromLatin1("__KHTML__PLUGINBASEURL=\"%1\"").arg(document()->baseURL().url()));
0427     params.append(QString::fromLatin1("__KHTML__PLUGINPAGEURL=\"%1\"").arg(document()->URL().url()));
0428 
0429     // Non-embed elements parse a bunch of attributes and inherit things off <embed>, if any
0430     HTMLEmbedElementImpl *embed = relevantEmbed();
0431     if (id() != ID_EMBED) {
0432         params.append(QString::fromLatin1("__KHTML__CLASSID=\"%1\"").arg(classId));
0433         params.append(QString::fromLatin1("__KHTML__CODEBASE=\"%1\"").arg(getAttribute(ATTR_CODEBASE).string()));
0434 
0435         if (embed && !embed->getAttribute(ATTR_WIDTH).isEmpty()) {
0436             setAttribute(ATTR_WIDTH, embed->getAttribute(ATTR_WIDTH));
0437         }
0438 
0439         if (embed && !embed->getAttribute(ATTR_HEIGHT).isEmpty()) {
0440             setAttribute(ATTR_HEIGHT, embed->getAttribute(ATTR_HEIGHT));
0441         }
0442 
0443         if (!getAttribute(ATTR_WIDTH).isEmpty()) {
0444             params.append(QString::fromLatin1("WIDTH=\"%1\"").arg(getAttribute(ATTR_WIDTH).string()));
0445         }
0446 
0447         if (!getAttribute(ATTR_HEIGHT).isEmpty()) {
0448             params.append(QString::fromLatin1("HEIGHT=\"%1\"").arg(getAttribute(ATTR_HEIGHT).string()));
0449         }
0450 
0451         // Fix up the serviceType from embed, or applet info..
0452         if (embed) {
0453             effectiveURL = embed->url;
0454             if (!embed->serviceType.isEmpty()) {
0455                 effectiveServiceType = embed->serviceType;
0456             }
0457         } else if (effectiveURL.isEmpty() &&
0458                    classId.startsWith(QLatin1String("java:"))) {
0459             effectiveServiceType = "application/x-java-applet";
0460             effectiveURL         = classId.mid(5);
0461         }
0462 
0463         // Translate ActiveX gibberish into mimetypes
0464         if ((effectiveServiceType.isEmpty() || serviceType == "application/x-oleobject") && !classId.isEmpty()) {
0465             if (classId.indexOf(QString::fromLatin1("D27CDB6E-AE6D-11cf-96B8-444553540000")) >= 0) {
0466                 effectiveServiceType = "application/x-shockwave-flash";
0467             } else if (classId.indexOf(QLatin1String("CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA")) >= 0) {
0468                 effectiveServiceType = "audio/x-pn-realaudio-plugin";
0469             } else if (classId.indexOf(QLatin1String("8AD9C840-044E-11D1-B3E9-00805F499D93")) >= 0 ||
0470                        classId.indexOf(QLatin1String("CAFEEFAC-0014-0000-0000-ABCDEFFEDCBA")) >= 0) {
0471                 effectiveServiceType = "application/x-java-applet";
0472             }
0473             // http://www.apple.com/quicktime/tools_tips/tutorials/activex.html
0474             else if (classId.indexOf(QLatin1String("02BF25D5-8C17-4B23-BC80-D3488ABDDC6B")) >= 0) {
0475                 effectiveServiceType = "video/quicktime";
0476             }
0477             // http://msdn.microsoft.com/library/en-us/dnwmt/html/adding_windows_media_to_web_pages__etse.asp?frame=true
0478             else if (classId.indexOf(QString::fromLatin1("6BF52A52-394A-11d3-B153-00C04F79FAA6")) >= 0 ||
0479                      classId.indexOf(QString::fromLatin1("22D6f312-B0F6-11D0-94AB-0080C74C7E95")) >= 0) {
0480                 effectiveServiceType = "video/x-msvideo";
0481             } else {
0482                 // qCDebug(KHTML_LOG) << "ActiveX classId " << classId;
0483             }
0484             // TODO: add more plugins here
0485         }
0486     }
0487 
0488     if (effectiveServiceType.isEmpty() &&
0489             effectiveURL.startsWith(QLatin1String("data:"))) {
0490         // Extract the MIME type from the data URL.
0491         int index = effectiveURL.indexOf(';');
0492         if (index == -1) {
0493             index = effectiveURL.indexOf(',');
0494         }
0495         if (index != -1) {
0496             int len = index - 5;
0497             if (len > 0) {
0498                 effectiveServiceType = effectiveURL.mid(5, len);
0499             } else {
0500                 effectiveServiceType = "text/plain";    // Data URLs with no MIME type are considered text/plain.
0501             }
0502         }
0503     }
0504 
0505     // Figure out if may be we're image-like. In this case, we don't need to load anything,
0506     // but may need to do a detach/attach
0507     QStringList supportedImageTypes = khtmlImLoad::ImageManager::loaderDatabase()->supportedMimeTypes();
0508 
0509     bool newImageLike = effectiveServiceType.startsWith(QLatin1String("image/")) && supportedImageTypes.contains(effectiveServiceType);
0510 
0511     if (newImageLike != m_imageLike) {
0512         m_imageLike = newImageLike;
0513         requestRerender();
0514     }
0515 
0516     if (m_imageLike) {
0517         return;
0518     }
0519 
0520     // Now see if we have to render alternate content.
0521     bool newRenderAlternative = false;
0522 
0523     // If we aren't permitted to load this by security policy, render alternative content instead.
0524     if (!document()->isURLAllowed(effectiveURL)) {
0525         newRenderAlternative = true;
0526     }
0527 
0528     // If Java is off, render alternative as well...
0529     if (effectiveServiceType == "application/x-java-applet") {
0530         KHTMLPart *p = document()->part();
0531         if (!p || !p->javaEnabled()) {
0532             newRenderAlternative = true;
0533         }
0534     }
0535 
0536     // If there is no <embed> (here or as a child), and we don't have a type + url to go on,
0537     // we need to render alternative as well
0538     if (!embed && effectiveURL.isEmpty() && effectiveServiceType.isEmpty()) {
0539         newRenderAlternative = true;
0540     }
0541 
0542     if (newRenderAlternative != m_renderAlternative) {
0543         m_renderAlternative = newRenderAlternative;
0544         requestRerender();
0545     }
0546 
0547     if (m_renderAlternative) {
0548         return;
0549     }
0550 
0551     KHTMLPart *part = document()->part();
0552     clearChildWidget();
0553 
0554     // qCDebug(KHTML_LOG) << effectiveURL << effectiveServiceType << params;
0555 
0556     if (!part->loadObjectElement(this, effectiveURL, effectiveServiceType, params)) {
0557         // Looks like we are gonna need alternative content after all...
0558         m_renderAlternative = true;
0559     }
0560 
0561     // Either way, we need to re-attach, either for alternative content, or because
0562     // we got the part..
0563     requestRerender();
0564 }
0565 
0566 void HTMLObjectBaseElementImpl::setWidgetNotify(QWidget *widget)
0567 {
0568     // Ick.
0569     if (m_render && strcmp(m_render->renderName(),  "RenderPartObject") == 0) {
0570         static_cast<RenderPartObject *>(m_render)->setWidget(widget);
0571     }
0572 }
0573 
0574 void HTMLObjectBaseElementImpl::renderAlternative()
0575 {
0576     if (m_renderAlternative) {
0577         return;
0578     }
0579 
0580     m_renderAlternative = true;
0581     requestRerender();
0582 }
0583 
0584 void HTMLObjectBaseElementImpl::partLoadingErrorNotify()
0585 {
0586     // Defer ourselves from the current event loop (to prevent crashes due to the message box staying up)
0587     QTimer::singleShot(0, this, SLOT(slotPartLoadingErrorNotify()));
0588 
0589     // Either way, we don't have stuff to display, so have to render alternative content.
0590     if (!m_renderAlternative) {
0591         m_renderAlternative = true;
0592         requestRerender();
0593     }
0594 
0595     clearChildWidget();
0596 }
0597 
0598 void HTMLObjectBaseElementImpl::slotPartLoadingErrorNotify()
0599 {
0600     // If we have an embed, we may be able to tell the user where to
0601     // download the plugin.
0602 
0603     HTMLEmbedElementImpl *embed = relevantEmbed();
0604     QString serviceType; // shadows ours, but we don't care.
0605 
0606     if (!embed) {
0607         return;
0608     }
0609 
0610     serviceType = embed->serviceType;
0611 
0612     KHTMLPart *part = document()->part();
0613     KParts::BrowserExtension *ext = part->browserExtension();
0614 
0615     if (!embed->pluginPage.isEmpty() && ext) {
0616         // Prepare the mimetype to show in the question (comment if available, name as fallback)
0617         QString mimeName = serviceType;
0618         QMimeDatabase db;
0619         QMimeType mime = db.mimeTypeForName(serviceType);
0620         if (mime.isValid()) {
0621             mimeName = mime.comment();
0622         }
0623 
0624         // Check if we already asked the user, for this page
0625         if (!mimeName.isEmpty() && !part->pluginPageQuestionAsked(serviceType)) {
0626             part->setPluginPageQuestionAsked(serviceType);
0627 
0628             // Prepare the URL to show in the question (host only if http, to make it short)
0629             QUrl pluginPageURL(embed->pluginPage);
0630             QString shortURL = pluginPageURL.scheme() == "http" ? pluginPageURL.host() : pluginPageURL.toDisplayString();
0631             int res = KMessageBox::questionTwoActions(part->view(),
0632                                                       i18n("No plugin found for '%1'.\nDo you want to download one from %2?", mimeName, shortURL),
0633                                                       i18n("Missing Plugin"), KGuiItem(i18n("Download")), KGuiItem(i18n("Do Not Download")), QString("plugin-") + serviceType);
0634             if (res == KMessageBox::PrimaryAction) {
0635                 // Display vendor download page
0636                 ext->createNewWindow(pluginPageURL);
0637                 return;
0638             }
0639         }
0640     }
0641 }
0642 
0643 // -------------------------------------------------------------------------
0644 
0645 HTMLAppletElementImpl::HTMLAppletElementImpl(DocumentImpl *doc)
0646     : HTMLObjectBaseElementImpl(doc)
0647 {
0648     serviceType = "application/x-java-applet";
0649 }
0650 
0651 HTMLAppletElementImpl::~HTMLAppletElementImpl()
0652 {
0653 }
0654 
0655 NodeImpl::Id HTMLAppletElementImpl::id() const
0656 {
0657     return ID_APPLET;
0658 }
0659 
0660 void HTMLAppletElementImpl::parseAttribute(AttributeImpl *attr)
0661 {
0662     switch (attr->id()) {
0663     case ATTR_CODEBASE:
0664     case ATTR_ARCHIVE:
0665     case ATTR_CODE:
0666     case ATTR_OBJECT:
0667     case ATTR_ALT:
0668         break;
0669     case ATTR_ALIGN:
0670         addHTMLAlignment(attr->value());
0671         break;
0672     case ATTR_VSPACE:
0673         addCSSLength(CSS_PROP_MARGIN_TOP, attr->value());
0674         addCSSLength(CSS_PROP_MARGIN_BOTTOM, attr->value());
0675         break;
0676     case ATTR_HSPACE:
0677         addCSSLength(CSS_PROP_MARGIN_LEFT, attr->value());
0678         addCSSLength(CSS_PROP_MARGIN_RIGHT, attr->value());
0679         break;
0680     case ATTR_VALIGN:
0681         addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower());
0682         break;
0683     default:
0684         HTMLObjectBaseElementImpl::parseAttribute(attr);
0685     }
0686 }
0687 
0688 void HTMLAppletElementImpl::computeContent()
0689 {
0690     DOMString codeBase = getAttribute(ATTR_CODEBASE);
0691     DOMString code = getAttribute(ATTR_CODE);
0692     if (!codeBase.isEmpty()) {
0693         url = codeBase.string();
0694     }
0695     if (!code.isEmpty()) {
0696         url = code.string();
0697     }
0698     HTMLObjectBaseElementImpl::computeContent();
0699 }
0700 
0701 // -------------------------------------------------------------------------
0702 
0703 HTMLEmbedElementImpl::HTMLEmbedElementImpl(DocumentImpl *doc)
0704     : HTMLObjectBaseElementImpl(doc)
0705 {
0706 }
0707 
0708 HTMLEmbedElementImpl::~HTMLEmbedElementImpl()
0709 {
0710 }
0711 
0712 NodeImpl::Id HTMLEmbedElementImpl::id() const
0713 {
0714     return ID_EMBED;
0715 }
0716 
0717 HTMLEmbedElementImpl *HTMLEmbedElementImpl::relevantEmbed()
0718 {
0719     return this;
0720 }
0721 
0722 void HTMLEmbedElementImpl::parseAttribute(AttributeImpl *attr)
0723 {
0724     switch (attr->id()) {
0725     case ATTR_CODE:
0726     case ATTR_SRC:
0727         url = attr->value().trimSpaces().string();
0728         setNeedComputeContent();
0729         break;
0730     case ATTR_BORDER:
0731         addCSSLength(CSS_PROP_BORDER_WIDTH, attr->value());
0732         addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_SOLID);
0733         addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_SOLID);
0734         addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_SOLID);
0735         addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_SOLID);
0736         break;
0737     case ATTR_VSPACE:
0738         addCSSLength(CSS_PROP_MARGIN_TOP, attr->value());
0739         addCSSLength(CSS_PROP_MARGIN_BOTTOM, attr->value());
0740         break;
0741     case ATTR_HSPACE:
0742         addCSSLength(CSS_PROP_MARGIN_LEFT, attr->value());
0743         addCSSLength(CSS_PROP_MARGIN_RIGHT, attr->value());
0744         break;
0745     case ATTR_ALIGN:
0746         addHTMLAlignment(attr->value());
0747         break;
0748     case ATTR_VALIGN:
0749         addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower());
0750         break;
0751     case ATTR_PLUGINPAGE:
0752     case ATTR_PLUGINSPAGE: {
0753         pluginPage = attr->value().string();
0754         break;
0755     }
0756     case ATTR_HIDDEN:
0757         if (strcasecmp(attr->value(), "yes") == 0 || strcasecmp(attr->value(), "true") == 0) {
0758             hidden = true;
0759         } else {
0760             hidden = false;
0761         }
0762         break;
0763     default:
0764         HTMLObjectBaseElementImpl::parseAttribute(attr);
0765     }
0766 }
0767 
0768 void HTMLEmbedElementImpl::attach()
0769 {
0770     if (parentNode()->id() == ID_OBJECT) {
0771         NodeBaseImpl::attach();
0772     } else {
0773         HTMLObjectBaseElementImpl::attach();
0774     }
0775 }
0776 
0777 void HTMLEmbedElementImpl::computeContent()
0778 {
0779     if (parentNode()->id() != ID_OBJECT) {
0780         HTMLObjectBaseElementImpl::computeContent();
0781     }
0782 }
0783 
0784 // -------------------------------------------------------------------------
0785 
0786 HTMLObjectElementImpl::HTMLObjectElementImpl(DocumentImpl *doc)
0787     : HTMLObjectBaseElementImpl(doc)
0788 {
0789 }
0790 
0791 HTMLObjectElementImpl::~HTMLObjectElementImpl()
0792 {
0793 }
0794 
0795 NodeImpl::Id HTMLObjectElementImpl::id() const
0796 {
0797     return ID_OBJECT;
0798 }
0799 
0800 HTMLFormElementImpl *HTMLObjectElementImpl::form() const
0801 {
0802     return nullptr;
0803 }
0804 
0805 void HTMLObjectElementImpl::parseAttribute(AttributeImpl *attr)
0806 {
0807     switch (attr->id()) {
0808     case ATTR_DATA:
0809         url = attr->value().trimSpaces().string();
0810         setNeedComputeContent();
0811         break;
0812     case ATTR_CLASSID:
0813         classId = attr->value().string();
0814         setNeedComputeContent();
0815         break;
0816     case ATTR_ONLOAD: // ### support load/unload on object elements
0817         setHTMLEventListener(EventImpl::LOAD_EVENT,
0818                              document()->createHTMLEventListener(attr->value().string(), "onload", this));
0819         break;
0820     case ATTR_ONUNLOAD:
0821         setHTMLEventListener(EventImpl::UNLOAD_EVENT,
0822                              document()->createHTMLEventListener(attr->value().string(), "onunload", this));
0823         break;
0824     case ATTR_VSPACE:
0825         addCSSLength(CSS_PROP_MARGIN_TOP, attr->value());
0826         addCSSLength(CSS_PROP_MARGIN_BOTTOM, attr->value());
0827         break;
0828     case ATTR_HSPACE:
0829         addCSSLength(CSS_PROP_MARGIN_LEFT, attr->value());
0830         addCSSLength(CSS_PROP_MARGIN_RIGHT, attr->value());
0831         break;
0832     case ATTR_ALIGN:
0833         addHTMLAlignment(attr->value());
0834         break;
0835     case ATTR_VALIGN:
0836         addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower());
0837         break;
0838     default:
0839         HTMLObjectBaseElementImpl::parseAttribute(attr);
0840     }
0841 }
0842 
0843 DocumentImpl *HTMLObjectElementImpl::contentDocument() const
0844 {
0845     QWidget *widget = childWidget();
0846     if (widget && qobject_cast<KHTMLView *>(widget)) {
0847         return static_cast<KHTMLView *>(widget)->part()->xmlDocImpl();
0848     }
0849     return nullptr;
0850 }
0851 
0852 void HTMLObjectElementImpl::attach()
0853 {
0854     HTMLObjectBaseElementImpl::attach();
0855 }
0856 
0857 // -------------------------------------------------------------------------
0858 
0859 NodeImpl::Id HTMLParamElementImpl::id() const
0860 {
0861     return ID_PARAM;
0862 }
0863 
0864 void HTMLParamElementImpl::parseAttribute(AttributeImpl *attr)
0865 {
0866     switch (attr->id()) {
0867     case ATTR_VALUE:
0868         m_value = attr->value().string();
0869         break;
0870     case ATTR_ID:
0871         if (document()->htmlMode() != DocumentImpl::XHtml) {
0872             break;
0873         }
0874     // fall through
0875     case ATTR_NAME:
0876         m_name = attr->value().string();
0877     // fall through
0878     default:
0879         HTMLElementImpl::parseAttribute(attr);
0880     }
0881 }
0882 
0883 #include "moc_html_objectimpl.cpp"