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