File indexing completed on 2024-04-28 15:24:48

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) 2001 Dirk Mueller (mueller@kde.org)
0007  *           (C) 2002-2006 Apple Computer, Inc.
0008  *           (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com)
0009  *           (C) 2005 Frerich Raabe <raabe@kde.org>
0010  *           (C) 2010 Maksim Orlovich <maksim@kde.org>
0011  *
0012  * This library is free software; you can redistribute it and/or
0013  * modify it under the terms of the GNU Library General Public
0014  * License as published by the Free Software Foundation; either
0015  * version 2 of the License, or (at your option) any later version.
0016  *
0017  * This library is distributed in the hope that it will be useful,
0018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0020  * Library General Public License for more details.
0021  *
0022  * You should have received a copy of the GNU Library General Public License
0023  * along with this library; see the file COPYING.LIB.  If not, write to
0024  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0025  * Boston, MA 02110-1301, USA.
0026  */
0027 
0028 #include "dom_docimpl.h"
0029 
0030 #include <dom/dom_exception.h>
0031 
0032 #include "dom_textimpl.h"
0033 #include "dom_xmlimpl.h"
0034 #include "dom2_rangeimpl.h"
0035 #include "dom2_eventsimpl.h"
0036 #include "xml_tokenizer.h"
0037 #include <html/htmltokenizer.h>
0038 #include "dom_restyler.h"
0039 
0040 #include <css/cssstyleselector.h>
0041 #include <css/css_stylesheetimpl.h>
0042 #include <misc/seed.h>
0043 #include <misc/loader.h>
0044 #include <ecma/kjs_proxy.h>
0045 #include <ecma/kjs_binding.h>
0046 
0047 #include <QStack>
0048 //Added by qt3to4:
0049 #include "khtml_debug.h"
0050 #include <klocalizedstring.h>
0051 
0052 #include <rendering/counter_tree.h>
0053 #include <rendering/render_canvas.h>
0054 #include <rendering/render_replaced.h>
0055 #include <rendering/render_arena.h>
0056 #include <rendering/render_layer.h>
0057 #include <rendering/render_frames.h>
0058 #include <rendering/render_image.h>
0059 
0060 #include <khtmlview.h>
0061 #include <khtml_part.h>
0062 #include <kurlauthorized.h>
0063 #include <khtml_settings.h>
0064 #include <khtmlpart_p.h>
0065 
0066 #include <xml/dom3_xpathimpl.h>
0067 #include <html/html_baseimpl.h>
0068 #include <html/html_blockimpl.h>
0069 #include <html/html_canvasimpl.h>
0070 #include <html/html_documentimpl.h>
0071 #include <html/html_formimpl.h>
0072 #include <html/html_headimpl.h>
0073 #include <html/html_imageimpl.h>
0074 #include <html/html_listimpl.h>
0075 #include <html/html_miscimpl.h>
0076 #include <html/html_tableimpl.h>
0077 #include <html/html_objectimpl.h>
0078 #include <html/HTMLAudioElement.h>
0079 #include <html/HTMLVideoElement.h>
0080 #include <html/HTMLSourceElement.h>
0081 #include <editing/jsediting.h>
0082 
0083 #include <ecma/kjs_window.h>
0084 
0085 // SVG (WebCore)
0086 #include <svg/SVGElement.h>
0087 #include <svg/SVGSVGElement.h>
0088 #include <svg/SVGNames.h>
0089 #include <svg/SVGDocumentExtensions.h>
0090 #include <svg/SVGRectElement.h>
0091 #include <svg/SVGDocument.h>
0092 #include <svg/SVGCircleElement.h>
0093 #include <svg/SVGStyleElement.h>
0094 #include <svg/SVGEllipseElement.h>
0095 #include <svg/SVGPolygonElement.h>
0096 #include <svg/SVGPolylineElement.h>
0097 #include <svg/SVGPathElement.h>
0098 #include <svg/SVGDefsElement.h>
0099 #include <svg/SVGLinearGradientElement.h>
0100 #include <svg/SVGRadialGradientElement.h>
0101 #include <svg/SVGStopElement.h>
0102 #include <svg/SVGClipPathElement.h>
0103 #include <svg/SVGGElement.h>
0104 #include <svg/SVGUseElement.h>
0105 #include <svg/SVGLineElement.h>
0106 #include <svg/SVGTextElement.h>
0107 #include <svg/SVGAElement.h>
0108 #include <svg/SVGScriptElement.h>
0109 #include <svg/SVGDescElement.h>
0110 #include <svg/SVGTitleElement.h>
0111 #include <svg/SVGTextPathElement.h>
0112 #include <svg/SVGTSpanElement.h>
0113 #include <svg/SVGHKernElement.h>
0114 #include <svg/SVGAltGlyphElement.h>
0115 #include <svg/SVGFontElement.h>
0116 
0117 #include <kio/job.h>
0118 #include <QFontDatabase>
0119 
0120 #include <stdlib.h>
0121 #include <limits.h>
0122 
0123 #undef FOCUS_EVENT  // for win32, MinGW
0124 
0125 template class QStack<DOM::NodeImpl *>;
0126 
0127 using namespace DOM;
0128 using namespace khtml;
0129 
0130 // ------------------------------------------------------------------------
0131 
0132 DOMImplementationImpl::DOMImplementationImpl()
0133 {
0134 }
0135 
0136 DOMImplementationImpl::~DOMImplementationImpl()
0137 {
0138 }
0139 
0140 bool DOMImplementationImpl::hasFeature(const DOMString &feature, const DOMString &version)
0141 {
0142     // ### update when we (fully) support the relevant features
0143     QString lower = feature.string().toLower();
0144     if ((lower == "html" || lower == "xml") &&
0145             (version.isEmpty() || version == "1.0" || version == "2.0")) {
0146         return true;
0147     }
0148 
0149     // ## Do we support Core Level 3 ?
0150     if ((lower == "core") &&
0151             (version.isEmpty() || version == "2.0")) {
0152         return true;
0153     }
0154 
0155     if ((lower == "traversal") &&
0156             (version.isEmpty() || version == "2.0")) {
0157         return true;
0158     }
0159 
0160     if ((lower == "css") &&
0161             (version.isEmpty() || version == "2.0")) {
0162         return true;
0163     }
0164 
0165     if ((lower == "events" || lower == "uievents" ||
0166             lower == "mouseevents" || lower == "mutationevents" ||
0167             lower == "htmlevents" || lower == "textevents") &&
0168             (version.isEmpty() || version == "2.0" || version == "3.0")) {
0169         return true;
0170     }
0171 
0172     if (lower == "selectors-api" && version == "1.0") {
0173         return true;
0174     }
0175 
0176     return false;
0177 }
0178 
0179 DocumentTypeImpl *DOMImplementationImpl::createDocumentType(const DOMString &qualifiedName, const DOMString &publicId,
0180         const DOMString &systemId, int &exceptioncode)
0181 {
0182     // Not mentioned in spec: throw NAMESPACE_ERR if no qualifiedName supplied
0183     if (qualifiedName.isNull()) {
0184         exceptioncode = DOMException::NAMESPACE_ERR;
0185         return nullptr;
0186     }
0187 
0188     // INVALID_CHARACTER_ERR: Raised if the specified qualified name contains an illegal character.
0189     if (!Element::khtmlValidQualifiedName(qualifiedName)) {
0190         exceptioncode = DOMException::INVALID_CHARACTER_ERR;
0191         return nullptr;
0192     }
0193 
0194     // NAMESPACE_ERR: Raised if the qualifiedName is malformed.
0195     // Added special case for the empty string, which seems to be a common pre-DOM2 misuse
0196     if (!qualifiedName.isEmpty() && Element::khtmlMalformedQualifiedName(qualifiedName)) {
0197         exceptioncode = DOMException::NAMESPACE_ERR;
0198         return nullptr;
0199     }
0200 
0201     return new DocumentTypeImpl(this, nullptr, qualifiedName, publicId, systemId);
0202 }
0203 
0204 DocumentImpl *DOMImplementationImpl::createDocument(const DOMString &namespaceURI, const DOMString &qualifiedName,
0205         DocumentTypeImpl *dtype,
0206         KHTMLView *v,
0207         int &exceptioncode)
0208 {
0209     exceptioncode = 0;
0210 
0211     if (!checkQualifiedName(qualifiedName, namespaceURI, nullptr, true/*nameCanBeNull*/,
0212                             true /*nameCanBeEmpty, see #61650*/, &exceptioncode)) {
0213         return nullptr;
0214     }
0215 
0216     // WRONG_DOCUMENT_ERR: Raised if doctype has already been used with a different document or was
0217     // created from a different implementation.
0218     // We elide the "different implementation" case here, since we're not doing interop
0219     // of different implementations, and different impl objects exist only for
0220     // isolation  reasons
0221     if (dtype && dtype->document()) {
0222         exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
0223         return nullptr;
0224     }
0225 
0226     // ### view can be 0 which can cause problems
0227     DocumentImpl *doc;
0228     if (namespaceURI == XHTML_NAMESPACE) {
0229         doc = new HTMLDocumentImpl(v);
0230     } else {
0231         doc = new DocumentImpl(v);
0232     }
0233 
0234     if (dtype) {
0235         dtype->setDocument(doc);
0236         doc->appendChild(dtype, exceptioncode);
0237     }
0238 
0239     // the document must be created empty if all parameters are null
0240     // (or empty for qName/nsURI as a tolerance) - see DOM 3 Core.
0241     if (dtype || !qualifiedName.isEmpty() || !namespaceURI.isEmpty()) {
0242         ElementImpl *element = doc->createElementNS(namespaceURI, qualifiedName);
0243         doc->appendChild(element, exceptioncode);
0244         if (exceptioncode) {
0245             delete element;
0246             delete doc;
0247             return nullptr;
0248         }
0249     }
0250     return doc;
0251 }
0252 
0253 CSSStyleSheetImpl *DOMImplementationImpl::createCSSStyleSheet(DOMStringImpl *title, DOMStringImpl *media,
0254         int &/*exceptioncode*/)
0255 {
0256     // ### TODO : media could have wrong syntax, in which case we should
0257     // generate an exception.
0258     CSSStyleSheetImpl *parent = nullptr;
0259     CSSStyleSheetImpl *sheet = new CSSStyleSheetImpl(parent, DOMString());
0260     sheet->setMedia(new MediaListImpl(sheet, media, true /*fallbackToDescriptor*/));
0261     sheet->setTitle(DOMString(title));
0262     return sheet;
0263 }
0264 
0265 DocumentImpl *DOMImplementationImpl::createDocument(KHTMLView *v)
0266 {
0267     DocumentImpl *doc = new DocumentImpl(v);
0268 
0269     return doc;
0270 }
0271 
0272 XMLDocumentImpl *DOMImplementationImpl::createXMLDocument(KHTMLView *v)
0273 {
0274     XMLDocumentImpl *doc = new XMLDocumentImpl(v);
0275 
0276     return doc;
0277 }
0278 
0279 HTMLDocumentImpl *DOMImplementationImpl::createHTMLDocument(KHTMLView *v)
0280 {
0281     HTMLDocumentImpl *doc = new HTMLDocumentImpl(v);
0282 
0283     return doc;
0284 }
0285 
0286 // create SVG document
0287 WebCore::SVGDocument *DOMImplementationImpl::createSVGDocument(KHTMLView *v)
0288 {
0289     WebCore::SVGDocument *doc = new WebCore::SVGDocument(v);
0290 
0291     return doc;
0292 }
0293 
0294 HTMLDocumentImpl *DOMImplementationImpl::createHTMLDocument(const DOMString &title)
0295 {
0296     HTMLDocumentImpl *r = createHTMLDocument(nullptr /* ### create a view otherwise it doesn't work */);
0297 
0298     r->open();
0299 
0300     r->write(QLatin1String("<HTML><HEAD><TITLE>") + title.string() +
0301              QLatin1String("</TITLE></HEAD>"));
0302 
0303     return r;
0304 }
0305 
0306 // ------------------------------------------------------------------------
0307 
0308 ElementMappingCache::ElementMappingCache(): m_dict()
0309 {
0310 }
0311 
0312 ElementMappingCache::~ElementMappingCache()
0313 {
0314     qDeleteAll(m_dict);
0315 }
0316 
0317 void ElementMappingCache::add(const DOMString &id, ElementImpl *nd)
0318 {
0319     if (id.isEmpty()) {
0320         return;
0321     }
0322 
0323     ItemInfo *info = m_dict.value(id);
0324     if (info) {
0325         info->ref++;
0326         info->nd = nullptr; //Now ambigous
0327     } else {
0328         ItemInfo *info = new ItemInfo();
0329         info->ref = 1;
0330         info->nd  = nd;
0331         m_dict.insert(id, info);
0332     }
0333 }
0334 
0335 void ElementMappingCache::set(const DOMString &id, ElementImpl *nd)
0336 {
0337     if (id.isEmpty()) {
0338         return;
0339     }
0340 
0341     assert(m_dict.contains(id));
0342     ItemInfo *info = m_dict.value(id);
0343     info->nd = nd;
0344 }
0345 
0346 void ElementMappingCache::remove(const DOMString &id, ElementImpl *nd)
0347 {
0348     if (id.isEmpty()) {
0349         return;
0350     }
0351 
0352     assert(m_dict.contains(id));
0353     ItemInfo *info = m_dict.value(id);
0354     info->ref--;
0355     if (info->ref == 0) {
0356         m_dict.take(id);
0357         delete info;
0358     } else {
0359         if (info->nd == nd) {
0360             info->nd = nullptr;
0361         }
0362     }
0363 }
0364 
0365 bool ElementMappingCache::contains(const DOMString &id)
0366 {
0367     if (id.isEmpty()) {
0368         return false;
0369     }
0370     return m_dict.contains(id);
0371 }
0372 
0373 ElementMappingCache::ItemInfo *ElementMappingCache::get(const DOMString &id)
0374 {
0375     if (id.isEmpty()) {
0376         return nullptr;
0377     }
0378     return m_dict.value(id);
0379 }
0380 
0381 typedef QList<DocumentImpl *> ChangedDocuments;
0382 Q_GLOBAL_STATIC(ChangedDocuments, s_changedDocuments)
0383 
0384 // KHTMLView might be 0
0385 DocumentImpl::DocumentImpl(KHTMLView *v)
0386     : NodeBaseImpl(nullptr), m_svgExtensions(nullptr), m_counterDict(),
0387       m_imageLoadEventTimer(0)
0388 {
0389     m_document.resetSkippingRef(this); //Make document return us..
0390     m_selfOnlyRefCount = 0;
0391 
0392     m_paintDevice = nullptr;
0393     //m_decoderMibEnum = 0;
0394     m_textColor = Qt::black;
0395 
0396     m_view = v;
0397     m_renderArena.reset();
0398 
0399     KHTMLGlobal::registerDocumentImpl(this);
0400 
0401     if (v) {
0402         m_docLoader = new DocLoader(v->part(), this);
0403         setPaintDevice(m_view);
0404     } else {
0405         m_docLoader = new DocLoader(nullptr, this);
0406     }
0407 
0408     visuallyOrdered = false;
0409     m_bParsing = false;
0410     m_docChanged = false;
0411     m_elemSheet = nullptr;
0412     m_tokenizer = nullptr;
0413     m_decoder = nullptr;
0414     m_doctype = nullptr;
0415     m_implementation = nullptr;
0416     pMode = Strict;
0417     hMode = XHtml;
0418     m_htmlCompat = false;
0419     m_textColor = "#000000";
0420     m_focusNode = nullptr;
0421     m_hoverNode = nullptr;
0422     m_activeNode = nullptr;
0423     m_defaultView = new AbstractViewImpl(this);
0424     m_defaultView->ref();
0425     m_listenerTypes = 0;
0426     m_styleSheets = new StyleSheetListImpl(this);
0427     m_styleSheets->ref();
0428     m_addedStyleSheets = nullptr;
0429     m_inDocument = true;
0430     m_styleSelectorDirty = false;
0431     m_styleSelector = nullptr;
0432     m_styleSheetListDirty = true;
0433 
0434     m_inStyleRecalc = false;
0435     m_pendingStylesheets = 0;
0436     m_ignorePendingStylesheets = false;
0437     m_async = true;
0438     m_hadLoadError = false;
0439     m_docLoading = false;
0440     m_bVariableLength = false;
0441     m_inSyncLoad = nullptr;
0442     m_loadingXMLDoc = nullptr;
0443     m_documentElement = nullptr;
0444     m_cssTarget = nullptr;
0445     m_jsEditor = nullptr;
0446     m_dynamicDomRestyler = new khtml::DynamicDomRestyler();
0447     m_stateRestorePos = 0;
0448     m_windowEventTarget = new WindowEventTargetImpl(this);
0449     m_windowEventTarget->ref();
0450 
0451     for (int c = 0; c < NumTreeVersions; ++c) {
0452         m_domTreeVersions[c] = 0;
0453     }
0454 }
0455 
0456 void DocumentImpl::removedLastRef()
0457 {
0458     if (m_selfOnlyRefCount) {
0459         /* In this case, the only references to us are from children,
0460            so we have a cycle. We'll try to break it by disconnecting the
0461            children from us; this sucks/is wrong, but it's pretty much
0462            the best we can do without tracing.
0463 
0464            Of course, if dumping the children causes the refcount from them to
0465            drop to 0 we can get killed right here, so better hold
0466            a temporary reference, too
0467         */
0468         DocPtr<DocumentImpl> guard(this);
0469 
0470         // we must make sure not to be retaining any of our children through
0471         // these extra pointers or we will create a reference cycle
0472         if (m_doctype) {
0473             m_doctype->deref();
0474             m_doctype = nullptr;
0475         }
0476 
0477         if (m_cssTarget) {
0478             m_cssTarget->deref();
0479             m_cssTarget = nullptr;
0480         }
0481 
0482         if (m_focusNode) {
0483             m_focusNode->deref();
0484             m_focusNode = nullptr;
0485         }
0486 
0487         if (m_hoverNode) {
0488             m_hoverNode->deref();
0489             m_hoverNode = nullptr;
0490         }
0491 
0492         if (m_activeNode) {
0493             m_activeNode->deref();
0494             m_activeNode = nullptr;
0495         }
0496 
0497         if (m_documentElement) {
0498             m_documentElement->deref();
0499             m_documentElement = nullptr;
0500         }
0501 
0502         removeChildren();
0503 
0504         delete m_tokenizer;
0505         m_tokenizer = nullptr;
0506     } else {
0507         delete this;
0508     }
0509 }
0510 
0511 DocumentImpl::~DocumentImpl()
0512 {
0513     //Important: if you need to remove stuff here,
0514     //you may also have to fix removedLastRef() above - M.O.
0515     assert(!m_render);
0516 
0517     QHashIterator<long, DynamicNodeListImpl::Cache *> it(m_nodeListCache);
0518     while (it.hasNext()) {
0519         it.next().value()->deref();
0520     }
0521 
0522     if (m_loadingXMLDoc) {
0523         m_loadingXMLDoc->deref(this);
0524     }
0525     if (s_changedDocuments() && m_docChanged) {
0526         s_changedDocuments()->removeAll(this);
0527     }
0528     delete m_tokenizer;
0529     m_document.resetSkippingRef(nullptr);
0530     delete m_styleSelector;
0531     delete m_docLoader;
0532     if (m_elemSheet) {
0533         m_elemSheet->deref();
0534     }
0535     if (m_doctype) {
0536         m_doctype->deref();
0537     }
0538     if (m_implementation) {
0539         m_implementation->deref();
0540     }
0541     delete m_dynamicDomRestyler;
0542     delete m_jsEditor;
0543     m_defaultView->deref();
0544     m_styleSheets->deref();
0545     if (m_addedStyleSheets) {
0546         m_addedStyleSheets->deref();
0547     }
0548     if (m_cssTarget) {
0549         m_cssTarget->deref();
0550     }
0551     if (m_focusNode) {
0552         m_focusNode->deref();
0553     }
0554     if (m_hoverNode) {
0555         m_hoverNode->deref();
0556     }
0557     if (m_activeNode) {
0558         m_activeNode->deref();
0559     }
0560     if (m_documentElement) {
0561         m_documentElement->deref();
0562     }
0563     m_windowEventTarget->deref();
0564     qDeleteAll(m_counterDict);
0565 
0566     m_renderArena.reset();
0567 
0568     KHTMLGlobal::deregisterDocumentImpl(this);
0569 }
0570 
0571 DOMImplementationImpl *DocumentImpl::implementation() const
0572 {
0573     if (!m_implementation) {
0574         m_implementation = new DOMImplementationImpl();
0575         m_implementation->ref();
0576     }
0577     return m_implementation;
0578 }
0579 
0580 void DocumentImpl::childrenChanged()
0581 {
0582     // invalidate the document element we have cached in case it was replaced
0583     if (m_documentElement) {
0584         m_documentElement->deref();
0585     }
0586     m_documentElement = nullptr;
0587 
0588     // same for m_docType
0589     if (m_doctype) {
0590         m_doctype->deref();
0591     }
0592     m_doctype = nullptr;
0593 }
0594 
0595 ElementImpl *DocumentImpl::documentElement() const
0596 {
0597     if (!m_documentElement) {
0598         NodeImpl *n = firstChild();
0599         while (n && n->nodeType() != Node::ELEMENT_NODE) {
0600             n = n->nextSibling();
0601         }
0602         m_documentElement = static_cast<ElementImpl *>(n);
0603         if (m_documentElement) {
0604             m_documentElement->ref();
0605         }
0606     }
0607     return m_documentElement;
0608 }
0609 
0610 DocumentTypeImpl *DocumentImpl::doctype() const
0611 {
0612     if (!m_doctype) {
0613         NodeImpl *n = firstChild();
0614         while (n && n->nodeType() != Node::DOCUMENT_TYPE_NODE) {
0615             n = n->nextSibling();
0616         }
0617         m_doctype = static_cast<DocumentTypeImpl *>(n);
0618         if (m_doctype) {
0619             m_doctype->ref();
0620         }
0621     }
0622     return m_doctype;
0623 }
0624 
0625 ElementImpl *DocumentImpl::createElement(const DOMString &name, int *pExceptioncode)
0626 {
0627     if (pExceptioncode && !Element::khtmlValidQualifiedName(name)) {
0628         *pExceptioncode = DOMException::INVALID_CHARACTER_ERR;
0629         return nullptr;
0630     }
0631 
0632     PrefixName prefix;
0633     LocalName  localName;
0634     bool htmlCompat = htmlMode() != XHtml;
0635     splitPrefixLocalName(name, prefix, localName, htmlCompat);
0636     XMLElementImpl *e = new XMLElementImpl(document(), emptyNamespaceName, localName, prefix);
0637     e->setHTMLCompat(htmlCompat); // Not a real HTML element, but inside an html-compat doc all tags are uppercase.
0638     return e;
0639 }
0640 
0641 AttrImpl *DocumentImpl::createAttribute(const DOMString &tagName, int *pExceptioncode)
0642 {
0643     if (pExceptioncode && !Element::khtmlValidAttrName(tagName)) {
0644         *pExceptioncode = DOMException::INVALID_CHARACTER_ERR;
0645         return nullptr;
0646     }
0647 
0648     PrefixName prefix;
0649     LocalName  localName;
0650     bool htmlCompat = (htmlMode() != XHtml);
0651     splitPrefixLocalName(tagName, prefix, localName, htmlCompat);
0652 
0653     AttrImpl *attr = new AttrImpl(nullptr, document(), NamespaceName::fromId(emptyNamespace),
0654                                   localName, prefix, DOMString("").implementation());
0655     attr->setHTMLCompat(htmlCompat);
0656     return attr;
0657 }
0658 
0659 DocumentFragmentImpl *DocumentImpl::createDocumentFragment()
0660 {
0661     return new DocumentFragmentImpl(docPtr());
0662 }
0663 
0664 CommentImpl *DocumentImpl::createComment(DOMStringImpl *data)
0665 {
0666     return new CommentImpl(docPtr(), data);
0667 }
0668 
0669 CDATASectionImpl *DocumentImpl::createCDATASection(DOMStringImpl *data, int &exceptioncode)
0670 {
0671     if (isHTMLDocument()) {
0672         exceptioncode = DOMException::NOT_SUPPORTED_ERR;
0673         return nullptr;
0674     }
0675     return new CDATASectionImpl(docPtr(), data);
0676 }
0677 
0678 ProcessingInstructionImpl *DocumentImpl::createProcessingInstruction(const DOMString &target, DOMStringImpl *data)
0679 {
0680     return new ProcessingInstructionImpl(docPtr(), target, data);
0681 }
0682 
0683 EntityReferenceImpl *DocumentImpl::createEntityReference(const DOMString &name, int &exceptioncode)
0684 {
0685     if (isHTMLDocument()) {
0686         exceptioncode = DOMException::NOT_SUPPORTED_ERR;
0687         return nullptr;
0688     }
0689     return new EntityReferenceImpl(docPtr(), name.implementation());
0690 }
0691 
0692 EditingTextImpl *DocumentImpl::createEditingTextNode(const DOMString &text)
0693 {
0694     return new EditingTextImpl(docPtr(), text);
0695 }
0696 
0697 NodeImpl *DocumentImpl::importNode(NodeImpl *importedNode, bool deep, int &exceptioncode)
0698 {
0699     NodeImpl *result = nullptr;
0700 
0701     // Not mentioned in spec: throw NOT_FOUND_ERR if evt is null
0702     if (!importedNode) {
0703         exceptioncode = DOMException::NOT_FOUND_ERR;
0704         return nullptr;
0705     }
0706 
0707     if (importedNode->nodeType() == Node::ELEMENT_NODE) {
0708         // Why not use cloneNode?
0709         ElementImpl *otherElem = static_cast<ElementImpl *>(importedNode);
0710         NamedAttrMapImpl *otherMap = static_cast<ElementImpl *>(importedNode)->attributes(true);
0711 
0712         ElementImpl *tempElementImpl;
0713         tempElementImpl = createElementNS(otherElem->namespaceURI(), otherElem->nonCaseFoldedTagName());
0714         tempElementImpl->setHTMLCompat(htmlMode() != XHtml && otherElem->htmlCompat());
0715         result = tempElementImpl;
0716 
0717         if (otherMap) {
0718             for (unsigned i = 0; i < otherMap->length(); i++) {
0719                 AttrImpl *otherAttr = otherMap->attributeAt(i).createAttr(otherElem, otherElem->docPtr());
0720 
0721                 tempElementImpl->setAttributeNS(otherAttr->namespaceURI(),
0722                                                 otherAttr->name(),
0723                                                 otherAttr->nodeValue(),
0724                                                 exceptioncode);
0725 
0726                 if (exceptioncode != 0) {
0727                     break;    // ### properly cleanup here
0728                 }
0729             }
0730         }
0731     } else if (importedNode->nodeType() == Node::TEXT_NODE) {
0732         result = createTextNode(static_cast<TextImpl *>(importedNode)->string());
0733         deep = false;
0734     } else if (importedNode->nodeType() == Node::CDATA_SECTION_NODE) {
0735         result = createCDATASection(static_cast<CDATASectionImpl *>(importedNode)->string(), exceptioncode);
0736         deep = false;
0737     } else if (importedNode->nodeType() == Node::ENTITY_REFERENCE_NODE) {
0738         result = createEntityReference(importedNode->nodeName(), exceptioncode);
0739     } else if (importedNode->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) {
0740         result = createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue().implementation());
0741         deep = false;
0742     } else if (importedNode->nodeType() == Node::COMMENT_NODE) {
0743         result = createComment(static_cast<CommentImpl *>(importedNode)->string());
0744         deep = false;
0745     } else if (importedNode->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) {
0746         result = createDocumentFragment();
0747     } else {
0748         exceptioncode = DOMException::NOT_SUPPORTED_ERR;
0749     }
0750 
0751     //### FIXME: This should handle Attributes, and a few other things
0752 
0753     if (deep && result) {
0754         for (Node n = importedNode->firstChild(); !n.isNull(); n = n.nextSibling()) {
0755             result->appendChild(importNode(n.handle(), true, exceptioncode), exceptioncode);
0756         }
0757     }
0758 
0759     return result;
0760 }
0761 
0762 ElementImpl *DocumentImpl::createElementNS(const DOMString &_namespaceURI, const DOMString &_qualifiedName, int *pExceptioncode)
0763 {
0764     ElementImpl *e = nullptr;
0765     int colonPos = -2;
0766     // check NAMESPACE_ERR/INVALID_CHARACTER_ERR
0767     if (pExceptioncode && !checkQualifiedName(_qualifiedName, _namespaceURI, &colonPos,
0768             false/*nameCanBeNull*/, false/*nameCanBeEmpty*/,
0769             pExceptioncode)) {
0770         return nullptr;
0771     }
0772     DOMString prefix, localName;
0773     splitPrefixLocalName(_qualifiedName.implementation(), prefix, localName, colonPos);
0774 
0775     if (_namespaceURI == SVG_NAMESPACE) {
0776         e = createSVGElement(QualifiedName(prefix, localName, _namespaceURI));
0777         if (e) {
0778             return e;
0779         }
0780         if (!e) {
0781             qCWarning(KHTML_LOG) << "svg element" << localName << "either is not supported by khtml or it's not a proper svg element";
0782         }
0783     }
0784 
0785     // Regardless of document type (even for HTML), this method will only create HTML
0786     // elements if given the namespace explicitly. Further, this method is always
0787     // case sensitive, again, even in HTML; however .tagName will case-normalize
0788     // in HTML regardless
0789     if (_namespaceURI == XHTML_NAMESPACE) {
0790         e = createHTMLElement(localName, false /* case sensitive */);
0791         int _exceptioncode = 0;
0792         if (!prefix.isNull()) {
0793             e->setPrefix(prefix, _exceptioncode);
0794         }
0795         if (_exceptioncode) {
0796             if (pExceptioncode) {
0797                 *pExceptioncode = _exceptioncode;
0798             }
0799             delete e;
0800             return nullptr;
0801         }
0802     }
0803     if (!e) {
0804         e = new XMLElementImpl(document(), NamespaceName::fromString(_namespaceURI),
0805                                LocalName::fromString(localName), PrefixName::fromString(prefix));
0806     }
0807 
0808     return e;
0809 }
0810 
0811 AttrImpl *DocumentImpl::createAttributeNS(const DOMString &_namespaceURI,
0812         const DOMString &_qualifiedName, int *pExceptioncode)
0813 {
0814     int colonPos = -2;
0815     // check NAMESPACE_ERR/INVALID_CHARACTER_ERR
0816     if (pExceptioncode && !checkQualifiedName(_qualifiedName, _namespaceURI, &colonPos,
0817             false/*nameCanBeNull*/, false/*nameCanBeEmpty*/,
0818             pExceptioncode)) {
0819         return nullptr;
0820     }
0821     PrefixName prefix;
0822     LocalName  localName;
0823     bool htmlCompat =  _namespaceURI.isNull() && htmlMode() != XHtml;
0824     splitPrefixLocalName(_qualifiedName, prefix, localName, false, colonPos);
0825     AttrImpl *attr = new AttrImpl(nullptr, document(), NamespaceName::fromString(_namespaceURI),
0826                                   localName, prefix, DOMString("").implementation());
0827     attr->setHTMLCompat(htmlCompat);
0828     return attr;
0829 }
0830 
0831 ElementImpl *DocumentImpl::getElementById(const DOMString &elementId) const
0832 {
0833     ElementMappingCache::ItemInfo *info = m_getElementByIdCache.get(elementId);
0834 
0835     if (!info) {
0836         return nullptr;
0837     }
0838 
0839     //See if cache has an unambiguous answer.
0840     if (info->nd) {
0841         return info->nd;
0842     }
0843 
0844     //Now we actually have to walk.
0845     QStack<NodeImpl *> nodeStack;
0846     NodeImpl *current = _first;
0847 
0848     while (1) {
0849         if (!current) {
0850             if (nodeStack.isEmpty()) {
0851                 break;
0852             }
0853             current = nodeStack.pop();
0854             current = current->nextSibling();
0855         } else {
0856             if (current->isElementNode()) {
0857                 ElementImpl *e = static_cast<ElementImpl *>(current);
0858                 if (e->getAttribute(ATTR_ID) == elementId) {
0859                     info->nd = e;
0860                     return e;
0861                 }
0862             }
0863 
0864             NodeImpl *child = current->firstChild();
0865             if (child) {
0866                 nodeStack.push(current);
0867                 current = child;
0868             } else {
0869                 current = current->nextSibling();
0870             }
0871         }
0872     }
0873 
0874     assert(0); //If there is no item with such an ID, we should never get here
0875 
0876     //qCDebug(KHTML_LOG) << "WARNING: *DocumentImpl::getElementById not found " << elementId.string();
0877 
0878     return nullptr;
0879 }
0880 
0881 void DocumentImpl::setTitle(const DOMString &_title)
0882 {
0883     if (_title == m_title && !m_title.isNull()) {
0884         return;
0885     }
0886 
0887     m_title = _title;
0888 
0889     QString titleStr = m_title.string();
0890     for (int i = 0; i < titleStr.length(); ++i)
0891         if (titleStr[i] < ' ') {
0892             titleStr[i] = ' ';
0893         }
0894     titleStr = titleStr.simplified();
0895     if (view() && !view()->part()->parentPart()) {
0896         if (titleStr.isEmpty()) {
0897             // empty title... set window caption as the URL
0898             QUrl url = m_url;
0899             url.setFragment(QString());
0900             url.setQuery(QString());
0901             titleStr = url.toDisplayString();
0902         }
0903 
0904         emit view()->part()->setWindowCaption(titleStr);
0905     }
0906 }
0907 
0908 DOMString DocumentImpl::nodeName() const
0909 {
0910     return "#document";
0911 }
0912 
0913 unsigned short DocumentImpl::nodeType() const
0914 {
0915     return Node::DOCUMENT_NODE;
0916 }
0917 
0918 ElementImpl *DocumentImpl::createHTMLElement(const DOMString &name, bool caseInsensitive)
0919 {
0920     LocalName localname = LocalName::fromString(name,
0921                           caseInsensitive ? IDS_NormalizeLower : IDS_CaseSensitive);
0922     uint id = localname.id();
0923 
0924     ElementImpl *n = nullptr;
0925     switch (id) {
0926     case ID_HTML:
0927         n = new HTMLHtmlElementImpl(docPtr());
0928         break;
0929     case ID_HEAD:
0930         n = new HTMLHeadElementImpl(docPtr());
0931         break;
0932     case ID_BODY:
0933         n = new HTMLBodyElementImpl(docPtr());
0934         break;
0935 
0936 // head elements
0937     case ID_BASE:
0938         n = new HTMLBaseElementImpl(docPtr());
0939         break;
0940     case ID_LINK:
0941         n = new HTMLLinkElementImpl(docPtr());
0942         break;
0943     case ID_META:
0944         n = new HTMLMetaElementImpl(docPtr());
0945         break;
0946     case ID_STYLE:
0947         n = new HTMLStyleElementImpl(docPtr());
0948         break;
0949     case ID_TITLE:
0950         n = new HTMLTitleElementImpl(docPtr());
0951         break;
0952 
0953 // frames
0954     case ID_FRAME:
0955         n = new HTMLFrameElementImpl(docPtr());
0956         break;
0957     case ID_FRAMESET:
0958         n = new HTMLFrameSetElementImpl(docPtr());
0959         break;
0960     case ID_IFRAME:
0961         n = new HTMLIFrameElementImpl(docPtr());
0962         break;
0963 
0964 // form elements
0965 // ### FIXME: we need a way to set form dependency after we have made the form elements
0966     case ID_FORM:
0967         n = new HTMLFormElementImpl(docPtr(), false);
0968         break;
0969     case ID_BUTTON:
0970         n = new HTMLButtonElementImpl(docPtr());
0971         break;
0972     case ID_FIELDSET:
0973         n = new HTMLFieldSetElementImpl(docPtr());
0974         break;
0975     case ID_INPUT:
0976         n = new HTMLInputElementImpl(docPtr());
0977         break;
0978     case ID_ISINDEX:
0979         n = new HTMLIsIndexElementImpl(docPtr());
0980         break;
0981     case ID_LABEL:
0982         n = new HTMLLabelElementImpl(docPtr());
0983         break;
0984     case ID_LEGEND:
0985         n = new HTMLLegendElementImpl(docPtr());
0986         break;
0987     case ID_OPTGROUP:
0988         n = new HTMLOptGroupElementImpl(docPtr());
0989         break;
0990     case ID_OPTION:
0991         n = new HTMLOptionElementImpl(docPtr());
0992         break;
0993     case ID_SELECT:
0994         n = new HTMLSelectElementImpl(docPtr());
0995         break;
0996     case ID_TEXTAREA:
0997         n = new HTMLTextAreaElementImpl(docPtr());
0998         break;
0999 
1000 // lists
1001     case ID_DL:
1002         n = new HTMLDListElementImpl(docPtr());
1003         break;
1004     case ID_DD:
1005         n = new HTMLGenericElementImpl(docPtr(), id);
1006         break;
1007     case ID_DT:
1008         n = new HTMLGenericElementImpl(docPtr(), id);
1009         break;
1010     case ID_UL:
1011         n = new HTMLUListElementImpl(docPtr());
1012         break;
1013     case ID_OL:
1014         n = new HTMLOListElementImpl(docPtr());
1015         break;
1016     case ID_DIR:
1017         n = new HTMLDirectoryElementImpl(docPtr());
1018         break;
1019     case ID_MENU:
1020         n = new HTMLMenuElementImpl(docPtr());
1021         break;
1022     case ID_LI:
1023         n = new HTMLLIElementImpl(docPtr());
1024         break;
1025 
1026 // formatting elements (block)
1027     case ID_DIV:
1028     case ID_P:
1029         n = new HTMLDivElementImpl(docPtr(), id);
1030         break;
1031     case ID_BLOCKQUOTE:
1032     case ID_H1:
1033     case ID_H2:
1034     case ID_H3:
1035     case ID_H4:
1036     case ID_H5:
1037     case ID_H6:
1038         n = new HTMLGenericElementImpl(docPtr(), id);
1039         break;
1040     case ID_HR:
1041         n = new HTMLHRElementImpl(docPtr());
1042         break;
1043     case ID_PLAINTEXT:
1044     case ID_XMP:
1045     case ID_PRE:
1046     case ID_LISTING:
1047         n = new HTMLPreElementImpl(docPtr(), id);
1048         break;
1049 
1050 // font stuff
1051     case ID_BASEFONT:
1052         n = new HTMLBaseFontElementImpl(docPtr());
1053         break;
1054     case ID_FONT:
1055         n = new HTMLFontElementImpl(docPtr());
1056         break;
1057 
1058 // ins/del
1059     case ID_DEL:
1060     case ID_INS:
1061         n = new HTMLGenericElementImpl(docPtr(), id);
1062         break;
1063 
1064 // anchor
1065     case ID_A:
1066         n = new HTMLAnchorElementImpl(docPtr());
1067         break;
1068 
1069 // images
1070     case ID_IMG:
1071     case ID_IMAGE: // legacy name
1072         n = new HTMLImageElementImpl(docPtr());
1073         break;
1074     case ID_CANVAS:
1075         n = new HTMLCanvasElementImpl(docPtr());
1076         break;
1077     case ID_MAP:
1078         n = new HTMLMapElementImpl(docPtr());
1079         /*n = map;*/
1080         break;
1081     case ID_AREA:
1082         n = new HTMLAreaElementImpl(docPtr());
1083         break;
1084 
1085 // objects, applets and scripts
1086     case ID_APPLET:
1087         n = new HTMLAppletElementImpl(docPtr());
1088         break;
1089     case ID_OBJECT:
1090         n = new HTMLObjectElementImpl(docPtr());
1091         break;
1092     case ID_EMBED:
1093         n = new HTMLEmbedElementImpl(docPtr());
1094         break;
1095     case ID_PARAM:
1096         n = new HTMLParamElementImpl(docPtr());
1097         break;
1098     case ID_SCRIPT:
1099         n = new HTMLScriptElementImpl(docPtr());
1100         break;
1101 
1102 // media
1103     case ID_AUDIO:
1104         n = new HTMLAudioElement(docPtr());
1105         break;
1106     case ID_VIDEO:
1107         n = new HTMLVideoElement(docPtr());
1108         break;
1109     case ID_SOURCE:
1110         n = new HTMLSourceElement(docPtr());
1111         break;
1112 
1113 // tables
1114     case ID_TABLE:
1115         n = new HTMLTableElementImpl(docPtr());
1116         break;
1117     case ID_CAPTION:
1118         n = new HTMLTableCaptionElementImpl(docPtr());
1119         break;
1120     case ID_COLGROUP:
1121     case ID_COL:
1122         n = new HTMLTableColElementImpl(docPtr(), id);
1123         break;
1124     case ID_TR:
1125         n = new HTMLTableRowElementImpl(docPtr());
1126         break;
1127     case ID_TD:
1128     case ID_TH:
1129         n = new HTMLTableCellElementImpl(docPtr(), id);
1130         break;
1131     case ID_THEAD:
1132     case ID_TBODY:
1133     case ID_TFOOT:
1134         n = new HTMLTableSectionElementImpl(docPtr(), id, false);
1135         break;
1136 
1137 // inline elements
1138     case ID_BR:
1139         n = new HTMLBRElementImpl(docPtr());
1140         break;
1141     case ID_WBR:
1142         n = new HTMLWBRElementImpl(docPtr());
1143         break;
1144     case ID_Q:
1145         n = new HTMLGenericElementImpl(docPtr(), id);
1146         break;
1147 
1148 // elements with no special representation in the DOM
1149 
1150 // block:
1151     case ID_ADDRESS:
1152     case ID_CENTER:
1153         n = new HTMLGenericElementImpl(docPtr(), id);
1154         break;
1155 // inline
1156     // %fontstyle
1157     case ID_TT:
1158     case ID_U:
1159     case ID_B:
1160     case ID_I:
1161     case ID_S:
1162     case ID_STRIKE:
1163     case ID_BIG:
1164     case ID_SMALL:
1165 
1166     // %phrase
1167     case ID_EM:
1168     case ID_STRONG:
1169     case ID_DFN:
1170     case ID_CODE:
1171     case ID_SAMP:
1172     case ID_KBD:
1173     case ID_VAR:
1174     case ID_CITE:
1175     case ID_ABBR:
1176     case ID_ACRONYM:
1177 
1178     // %special
1179     case ID_SUB:
1180     case ID_SUP:
1181     case ID_SPAN:
1182     case ID_NOBR:
1183     case ID_BDO:
1184     case ID_NOFRAMES:
1185     case ID_NOSCRIPT:
1186     case ID_NOEMBED:
1187     case ID_NOLAYER:
1188         n = new HTMLGenericElementImpl(docPtr(), id);
1189         break;
1190 
1191     case ID_MARQUEE:
1192         n = new HTMLMarqueeElementImpl(docPtr());
1193         break;
1194 // text
1195     case ID_TEXT:
1196         // qCDebug(KHTML_LOG) << "Use document->createTextNode()";
1197         break;
1198 
1199     default:
1200         n = new HTMLGenericElementImpl(docPtr(), localname);
1201         break;
1202     }
1203     assert(n);
1204     return n;
1205 }
1206 
1207 // SVG
1208 ElementImpl *DocumentImpl::createSVGElement(const QualifiedName &name)
1209 {
1210     uint id = name.localNameId().id();
1211     // qCDebug(KHTML_LOG) << getPrintableName(name.id());
1212     // qCDebug(KHTML_LOG) << "svg text:   " << getPrintableName(WebCore::SVGNames::textTag.id());
1213 
1214     ElementImpl *n = nullptr;
1215     switch (id) {
1216     case ID_TEXTPATH:
1217         n = new WebCore::SVGTextPathElement(name, docPtr());
1218         break;
1219     case ID_TSPAN:
1220         n = new WebCore::SVGTSpanElement(name, docPtr());
1221         break;
1222     case ID_HKERN:
1223         n = new WebCore::SVGHKernElement(name, docPtr());
1224         break;
1225     case ID_ALTGLYPH:
1226         n = new WebCore::SVGAltGlyphElement(name, docPtr());
1227         break;
1228     case ID_FONT:
1229         n = new WebCore::SVGFontElement(name, docPtr());
1230         break;
1231     }
1232 
1233     if (id == WebCore::SVGNames::svgTag.localNameId().id()) {
1234         n = new WebCore::SVGSVGElement(name, docPtr());
1235     }
1236 
1237     if (id == WebCore::SVGNames::rectTag.localNameId().id()) {
1238         n = new WebCore::SVGRectElement(name, docPtr());
1239     }
1240 
1241     if (id == WebCore::SVGNames::circleTag.localNameId().id()) {
1242         n = new WebCore::SVGCircleElement(name, docPtr());
1243     }
1244 
1245     if (id == WebCore::SVGNames::ellipseTag.localNameId().id()) {
1246         n = new WebCore::SVGEllipseElement(name, docPtr());
1247     }
1248 
1249     if (id == WebCore::SVGNames::polylineTag.localNameId().id()) {
1250         n = new WebCore::SVGPolylineElement(name, docPtr());
1251     }
1252 
1253     if (id == WebCore::SVGNames::polygonTag.localNameId().id()) {
1254         n = new WebCore::SVGPolygonElement(name, docPtr());
1255     }
1256 
1257     if (id == WebCore::SVGNames::pathTag.localNameId().id()) {
1258         n = new WebCore::SVGPathElement(name, docPtr());
1259     }
1260 
1261     if (id == WebCore::SVGNames::defsTag.localNameId().id()) {
1262         n = new WebCore::SVGDefsElement(name, docPtr());
1263     }
1264 
1265     if (id == WebCore::SVGNames::linearGradientTag.localNameId().id()) {
1266         n = new WebCore::SVGLinearGradientElement(name, docPtr());
1267     }
1268 
1269     if (id == WebCore::SVGNames::radialGradientTag.localNameId().id()) {
1270         n = new WebCore::SVGRadialGradientElement(name, docPtr());
1271     }
1272 
1273     if (id == WebCore::SVGNames::stopTag.localNameId().id()) {
1274         n = new WebCore::SVGStopElement(name, docPtr());
1275     }
1276 
1277     if (id == WebCore::SVGNames::clipPathTag.localNameId().id()) {
1278         n = new WebCore::SVGClipPathElement(name, docPtr());
1279     }
1280 
1281     if (id == WebCore::SVGNames::gTag.localNameId().id()) {
1282         n = new WebCore::SVGGElement(name, docPtr());
1283     }
1284 
1285     if (id == WebCore::SVGNames::useTag.localNameId().id()) {
1286         n = new WebCore::SVGUseElement(name, docPtr());
1287     }
1288 
1289     if (id == WebCore::SVGNames::lineTag.localNameId().id()) {
1290         n = new WebCore::SVGLineElement(name, docPtr());
1291     }
1292 
1293     if (id == WebCore::SVGNames::textTag.localNameId().id()) {
1294         n = new WebCore::SVGTextElement(name, docPtr());
1295     }
1296 
1297     if (id == WebCore::SVGNames::aTag.localNameId().id()) {
1298         n = new WebCore::SVGAElement(name, docPtr());
1299     }
1300 
1301     if (id == WebCore::SVGNames::scriptTag.localNameId().id()) {
1302         n = new WebCore::SVGScriptElement(name, docPtr());
1303     }
1304 
1305     if (id == WebCore::SVGNames::descTag.localNameId().id()) {
1306         n = new WebCore::SVGDescElement(name, docPtr());
1307     }
1308 
1309     if (id == WebCore::SVGNames::titleTag.localNameId().id()) {
1310         n = new WebCore::SVGTitleElement(name, docPtr());
1311     }
1312 
1313     if (id == makeId(svgNamespace, ID_STYLE)) {
1314         n = new WebCore::SVGStyleElement(name, docPtr());
1315     }
1316 
1317     return n;
1318 }
1319 
1320 void DocumentImpl::attemptRestoreState(NodeImpl *n)
1321 {
1322     if (!n->isElementNode()) {
1323         return;
1324     }
1325 
1326     ElementImpl *el = static_cast<ElementImpl *>(n);
1327 
1328     if (m_stateRestorePos >= m_state.size()) {
1329         return;
1330     }
1331 
1332     // Grab the state and element info..
1333     QString idStr = m_state[m_stateRestorePos];
1334     QString nmStr = m_state[m_stateRestorePos + 1];
1335     QString tpStr = m_state[m_stateRestorePos + 2];
1336     QString stStr = m_state[m_stateRestorePos + 3];
1337 
1338     // Make sure it matches!
1339     if (idStr.toUInt() != el->id()) {
1340         return;
1341     }
1342     if (nmStr != el->getAttribute(ATTR_NAME).string()) {
1343         return;
1344     }
1345     if (tpStr != el->getAttribute(ATTR_TYPE).string()) {
1346         return;
1347     }
1348 
1349     m_stateRestorePos += 4;
1350     if (!stStr.isNull()) {
1351         el->restoreState(stStr);
1352     }
1353 }
1354 
1355 QStringList DocumentImpl::docState()
1356 {
1357     QStringList s;
1358     for (QListIterator<NodeImpl *> it(m_maintainsState); it.hasNext();) {
1359         NodeImpl *n = it.next();
1360         if (!n->isElementNode()) {
1361             continue;
1362         }
1363 
1364         ElementImpl *el = static_cast<ElementImpl *>(n);
1365         // Encode the element ID, as well as the name and type attributes
1366         s.append(QString::number(el->id()));
1367         s.append(el->getAttribute(ATTR_NAME).string());
1368         s.append(el->getAttribute(ATTR_TYPE).string());
1369         s.append(el->state());
1370     }
1371 
1372     return s;
1373 }
1374 
1375 bool DocumentImpl::unsubmittedFormChanges()
1376 {
1377     for (QListIterator<NodeImpl *> it(m_maintainsState); it.hasNext();) {
1378         NodeImpl *node = it.next();
1379         if (node->isGenericFormElement() && static_cast<HTMLGenericFormElementImpl *>(node)->unsubmittedFormChanges()) {
1380             return true;
1381         }
1382     }
1383 
1384     return false;
1385 }
1386 
1387 RangeImpl *DocumentImpl::createRange()
1388 {
1389     return new RangeImpl(docPtr());
1390 }
1391 
1392 NodeIteratorImpl *DocumentImpl::createNodeIterator(NodeImpl *root, unsigned long whatToShow,
1393         NodeFilterImpl *filter, bool entityReferenceExpansion,
1394         int &exceptioncode)
1395 {
1396     if (!root) {
1397         exceptioncode = DOMException::NOT_SUPPORTED_ERR;
1398         return nullptr;
1399     }
1400 
1401     return new NodeIteratorImpl(root, whatToShow, filter, entityReferenceExpansion);
1402 }
1403 
1404 TreeWalkerImpl *DocumentImpl::createTreeWalker(NodeImpl *root, unsigned long whatToShow, NodeFilterImpl *filter,
1405         bool entityReferenceExpansion, int &exceptioncode)
1406 {
1407     if (!root) {
1408         exceptioncode = DOMException::NOT_SUPPORTED_ERR;
1409         return nullptr;
1410     }
1411 
1412     return new TreeWalkerImpl(root, whatToShow, filter, entityReferenceExpansion);
1413 }
1414 
1415 void DocumentImpl::setDocumentChanged(bool b)
1416 {
1417     if (b && !m_docChanged) {
1418         s_changedDocuments()->append(this);
1419     } else if (!b && m_docChanged) {
1420         s_changedDocuments()->removeAll(this);
1421     }
1422     m_docChanged = b;
1423 }
1424 
1425 void DocumentImpl::recalcStyle(StyleChange change)
1426 {
1427 //     qDebug("recalcStyle(%p)", this);
1428 //     QTime qt;
1429 //     qt.start();
1430     if (m_inStyleRecalc) {
1431         return;    // Guard against re-entrancy. -dwh
1432     }
1433 
1434     m_inStyleRecalc = true;
1435 
1436     if (!m_render) {
1437         goto bail_out;
1438     }
1439 
1440     if (change == Force) {
1441         RenderStyle *oldStyle = m_render->style();
1442         if (oldStyle) {
1443             oldStyle->ref();
1444         }
1445         RenderStyle *_style = new RenderStyle();
1446         _style->setDisplay(BLOCK);
1447         _style->setVisuallyOrdered(visuallyOrdered);
1448         // ### make the font stuff _really_ work!!!! (??)
1449 
1450         FontDef fontDef = FontDef();
1451         // Initial fontDef.size is 0
1452         fontDef.size = m_styleSelector->fontSizes()[3];
1453         _style->setFontDef(fontDef);
1454         _style->htmlFont().update(0);
1455 
1456         if (inCompatMode()) {
1457             _style->setHtmlHacks(true);    // enable html specific rendering tricks
1458         }
1459 
1460         StyleChange ch = diff(_style, oldStyle);
1461         if (m_render && ch != NoChange) {
1462             m_render->setStyle(_style);
1463         } else {
1464             delete _style;
1465         }
1466 
1467         if (oldStyle) {
1468             oldStyle->deref();
1469         }
1470     }
1471 
1472     NodeImpl *n;
1473     for (n = _first; n; n = n->nextSibling())
1474         if (change >= Inherit || n->hasChangedChild() || n->changed()) {
1475             n->recalcStyle(change);
1476         }
1477     //qCDebug(KHTML_LOG) << "TIME: recalcStyle() dt=" << qt.elapsed();
1478 
1479     if (changed() && m_view) {
1480         m_view->layout();
1481     }
1482 
1483 bail_out:
1484     setChanged(false);
1485     setHasChangedChild(false);
1486     setDocumentChanged(false);
1487 
1488     m_inStyleRecalc = false;
1489 }
1490 
1491 void DocumentImpl::updateRendering()
1492 {
1493     if (!hasChangedChild()) {
1494         return;
1495     }
1496 
1497 //     QTime time;
1498 //     time.start();
1499 //     qCDebug(KHTML_LOG) << "UPDATERENDERING: ";
1500 
1501     StyleChange change = NoChange;
1502 #if 0
1503     if (m_styleSelectorDirty) {
1504         recalcStyleSelector();
1505         change = Force;
1506     }
1507 #endif
1508     recalcStyle(change);
1509 
1510 //    qCDebug(KHTML_LOG) << "UPDATERENDERING time used="<<time.elapsed();
1511 }
1512 
1513 void DocumentImpl::updateDocumentsRendering()
1514 {
1515     if (!s_changedDocuments()) {
1516         return;
1517     }
1518 
1519     while (!s_changedDocuments()->isEmpty()) {
1520         DocumentImpl *it = s_changedDocuments()->takeFirst();
1521         if (it->isDocumentChanged()) {
1522             it->updateRendering();
1523         }
1524     }
1525 }
1526 
1527 void DocumentImpl::updateLayout()
1528 {
1529     if (ElementImpl *oe = ownerElement()) {
1530         oe->document()->updateLayout();
1531     }
1532 
1533     bool oldIgnore = m_ignorePendingStylesheets;
1534 
1535     if (!haveStylesheetsLoaded()) {
1536         m_ignorePendingStylesheets = true;
1537         updateStyleSelector();
1538     }
1539 
1540     updateRendering();
1541 
1542     // Only do a layout if changes have occurred that make it necessary.
1543     if (m_view && renderer() && renderer()->needsLayout()) {
1544         m_view->layout();
1545     }
1546 
1547     m_ignorePendingStylesheets = oldIgnore;
1548 }
1549 
1550 void DocumentImpl::attach()
1551 {
1552     assert(!attached());
1553 
1554     if (m_view) {
1555         setPaintDevice(m_view);
1556     }
1557 
1558     if (!m_renderArena) {
1559         m_renderArena.reset(new RenderArena());
1560     }
1561 
1562     // Create the rendering tree
1563     assert(!m_styleSelector);
1564     m_styleSelector = new CSSStyleSelector(this, m_usersheet, m_styleSheets, m_url,
1565                                            !inCompatMode());
1566     m_render = new(m_renderArena.get()) RenderCanvas(this, m_view);
1567     m_styleSelector->computeFontSizes(m_paintDevice->logicalDpiY(), m_view ? m_view->part()->fontScaleFactor() : 100);
1568     recalcStyle(Force);
1569 
1570     RenderObject *render = m_render;
1571     m_render = nullptr;
1572 
1573     NodeBaseImpl::attach();
1574     m_render = render;
1575 }
1576 
1577 void DocumentImpl::detach()
1578 {
1579     RenderObject *render = m_render;
1580 
1581     // indicate destruction mode,  i.e. attached() but m_render == 0
1582     m_render = nullptr;
1583 
1584     delete m_tokenizer;
1585     m_tokenizer = nullptr;
1586 
1587     // Empty out these lists as a performance optimization
1588     m_imageLoadEventDispatchSoonList.clear();
1589     m_imageLoadEventDispatchingList.clear();
1590     NodeBaseImpl::detach();
1591 
1592     if (render) {
1593         render->detach();
1594     }
1595 
1596     m_view = nullptr;
1597 
1598     m_renderArena.reset();
1599 }
1600 
1601 void DocumentImpl::setVisuallyOrdered()
1602 {
1603     visuallyOrdered = true;
1604     if (m_render) {
1605         m_render->style()->setVisuallyOrdered(true);
1606     }
1607 }
1608 
1609 void DocumentImpl::setSelection(NodeImpl *s, int sp, NodeImpl *e, int ep)
1610 {
1611     if (m_render) {
1612         static_cast<RenderCanvas *>(m_render)->setSelection(s->renderer(), sp, e->renderer(), ep);
1613     }
1614 }
1615 
1616 void DocumentImpl::clearSelection()
1617 {
1618     if (m_render) {
1619         static_cast<RenderCanvas *>(m_render)->clearSelection();
1620     }
1621 }
1622 
1623 void DocumentImpl::updateSelection()
1624 {
1625     if (!m_render) {
1626         return;
1627     }
1628 
1629     RenderCanvas *canvas = static_cast<RenderCanvas *>(m_render);
1630     Selection s = part()->caret();
1631     if (s.isEmpty() || s.state() == Selection::CARET) {
1632         canvas->clearSelection();
1633     } else {
1634         RenderObject *startRenderer = s.start().node() ? s.start().node()->renderer() : nullptr;
1635         RenderObject *endRenderer = s.end().node() ? s.end().node()->renderer() : nullptr;
1636         RenderPosition renderedStart = RenderPosition::fromDOMPosition(s.start());
1637         RenderPosition renderedEnd   = RenderPosition::fromDOMPosition(s.end());
1638         static_cast<RenderCanvas *>(m_render)->setSelection(startRenderer, renderedStart.renderedOffset(), endRenderer, renderedEnd.renderedOffset());
1639     }
1640 }
1641 
1642 khtml::Tokenizer *DocumentImpl::createTokenizer()
1643 {
1644     return new khtml::XMLTokenizer(docPtr(), m_view);
1645 }
1646 
1647 int DocumentImpl::logicalDpiY()
1648 {
1649     return m_paintDevice->logicalDpiY();
1650 }
1651 
1652 void DocumentImpl::open(bool clearEventListeners)
1653 {
1654     if (parsing()) {
1655         return;
1656     }
1657 
1658     if (m_tokenizer) {
1659         close();
1660     }
1661 
1662     delete m_tokenizer;
1663     m_tokenizer = nullptr;
1664 
1665     KHTMLView *view = m_view;
1666     bool was_attached = attached();
1667     if (was_attached) {
1668         detach();
1669     }
1670 
1671     removeChildren();
1672     childrenChanged(); // Reset m_documentElement, m_doctype
1673     delete m_styleSelector;
1674     m_styleSelector = nullptr;
1675     m_view = view;
1676     if (was_attached) {
1677         attach();
1678     }
1679 
1680     if (clearEventListeners) {
1681         windowEventTarget()->listenerList().clear();
1682     }
1683 
1684     m_tokenizer = createTokenizer();
1685     //m_decoderMibEnum = 0;
1686     connect(m_tokenizer, SIGNAL(finishedParsing()), this, SIGNAL(finishedParsing()));
1687     m_tokenizer->begin();
1688 }
1689 
1690 HTMLElementImpl *DocumentImpl::body() const
1691 {
1692     NodeImpl *de = documentElement();
1693     if (!de) {
1694         return nullptr;
1695     }
1696 
1697     // try to prefer a FRAMESET element over BODY
1698     NodeImpl *body = nullptr;
1699     for (NodeImpl *i = de->firstChild(); i; i = i->nextSibling()) {
1700         if (i->id() == ID_FRAMESET) {
1701             return static_cast<HTMLElementImpl *>(i);
1702         }
1703 
1704         if (i->id() == ID_BODY) {
1705             body = i;
1706         }
1707     }
1708     return static_cast<HTMLElementImpl *>(body);
1709 }
1710 
1711 void DocumentImpl::close()
1712 {
1713     if (parsing() && hasVariableLength() && m_tokenizer) {
1714         m_tokenizer->finish();
1715     } else if (parsing() || !m_tokenizer) {
1716         return;
1717     }
1718 
1719     if (m_render) {
1720         m_render->close();
1721     }
1722 
1723     // on an explicit document.close(), the tokenizer might still be waiting on scripts,
1724     // and in that case we don't want to destroy it because that will prevent the
1725     // scripts from getting processed.
1726     if (m_tokenizer && !m_tokenizer->isWaitingForScripts() && !m_tokenizer->isExecutingScript()) {
1727         delete m_tokenizer;
1728         m_tokenizer = nullptr;
1729     }
1730 
1731     if (m_view) {
1732         m_view->part()->checkEmitLoadEvent();
1733     }
1734 }
1735 
1736 void DocumentImpl::write(const DOMString &text)
1737 {
1738     write(text.string());
1739 }
1740 
1741 void DocumentImpl::write(const QString &text)
1742 {
1743     if (!m_tokenizer) {
1744         open();
1745         if (m_view) {
1746             m_view->part()->resetFromScript();
1747         }
1748         setHasVariableLength();
1749     }
1750     m_tokenizer->write(text, false);
1751 }
1752 
1753 void DocumentImpl::writeln(const DOMString &text)
1754 {
1755     write(text);
1756     write(DOMString("\n"));
1757 }
1758 
1759 void DocumentImpl::finishParsing()
1760 {
1761     if (m_tokenizer) {
1762         m_tokenizer->finish();
1763     }
1764 }
1765 
1766 QString DocumentImpl::completeURL(const QString &url) const
1767 {
1768     if (url.startsWith(QLatin1Char('#'))) {
1769         const QString ref = QUrl::fromPercentEncoding(url.mid(1).toUtf8());
1770         QUrl u = baseURL();
1771         if (ref.isEmpty()) {
1772             u.setFragment("");
1773         } else {
1774             u.setFragment(ref, QUrl::DecodedMode);
1775         }
1776     }
1777 
1778     return baseURL().resolved(QUrl(url)).toString();
1779 }
1780 
1781 void DocumentImpl::setUserStyleSheet(const QString &sheet)
1782 {
1783     if (m_usersheet != sheet) {
1784         m_usersheet = sheet;
1785         updateStyleSelector();
1786     }
1787 }
1788 
1789 CSSStyleSheetImpl *DocumentImpl::elementSheet()
1790 {
1791     if (!m_elemSheet) {
1792         m_elemSheet = new CSSStyleSheetImpl(this, baseURL().url());
1793         m_elemSheet->ref();
1794     }
1795     return m_elemSheet;
1796 }
1797 
1798 void DocumentImpl::determineParseMode()
1799 {
1800     // For XML documents, use strict parse mode
1801     pMode = Strict;
1802     hMode = XHtml;
1803     m_htmlCompat = false;
1804     // qCDebug(KHTML_LOG) << " using strict parseMode";
1805 }
1806 
1807 NodeImpl *DocumentImpl::nextFocusNode(NodeImpl *fromNode)
1808 {
1809     short fromTabIndex;
1810 
1811     if (!fromNode) {
1812         // No starting node supplied; begin with the top of the document
1813         NodeImpl *n;
1814 
1815         int lowestTabIndex = SHRT_MAX + 1;
1816         for (n = this; n != nullptr; n = n->traverseNextNode()) {
1817             if (n->isTabFocusable()) {
1818                 if ((n->tabIndex() > 0) && (n->tabIndex() < lowestTabIndex)) {
1819                     lowestTabIndex = n->tabIndex();
1820                 }
1821             }
1822         }
1823 
1824         if (lowestTabIndex == SHRT_MAX + 1) {
1825             lowestTabIndex = 0;
1826         }
1827 
1828         // Go to the first node in the document that has the desired tab index
1829         for (n = this; n != nullptr; n = n->traverseNextNode()) {
1830             if (n->isTabFocusable() && (n->tabIndex() == lowestTabIndex)) {
1831                 return n;
1832             }
1833         }
1834 
1835         return nullptr;
1836     } else {
1837         fromTabIndex = fromNode->tabIndex();
1838     }
1839 
1840     if (fromTabIndex == 0) {
1841         // Just need to find the next selectable node after fromNode (in document order) that doesn't have a tab index
1842         NodeImpl *n = fromNode->traverseNextNode();
1843         while (n && !(n->isTabFocusable() && n->tabIndex() == 0)) {
1844             n = n->traverseNextNode();
1845         }
1846         return n;
1847     } else {
1848         // Find the lowest tab index out of all the nodes except fromNode, that is greater than or equal to fromNode's
1849         // tab index. For nodes with the same tab index as fromNode, we are only interested in those that come after
1850         // fromNode in document order.
1851         // If we don't find a suitable tab index, the next focus node will be one with a tab index of 0.
1852         int lowestSuitableTabIndex = SHRT_MAX + 1;
1853         NodeImpl *n;
1854 
1855         bool reachedFromNode = false;
1856         for (n = this; n != nullptr; n = n->traverseNextNode()) {
1857             if (n->isTabFocusable() &&
1858                     ((reachedFromNode && (n->tabIndex() >= fromTabIndex)) ||
1859                      (!reachedFromNode && (n->tabIndex() > fromTabIndex))) &&
1860                     (n->tabIndex() < lowestSuitableTabIndex) &&
1861                     (n != fromNode)) {
1862 
1863                 // We found a selectable node with a tab index at least as high as fromNode's. Keep searching though,
1864                 // as there may be another node which has a lower tab index but is still suitable for use.
1865                 lowestSuitableTabIndex = n->tabIndex();
1866             }
1867 
1868             if (n == fromNode) {
1869                 reachedFromNode = true;
1870             }
1871         }
1872 
1873         if (lowestSuitableTabIndex == SHRT_MAX + 1) {
1874             // No next node with a tab index -> just take first node with tab index of 0
1875             NodeImpl *n = this;
1876             while (n && !(n->isTabFocusable() && n->tabIndex() == 0)) {
1877                 n = n->traverseNextNode();
1878             }
1879             return n;
1880         }
1881 
1882         // Search forwards from fromNode
1883         for (n = fromNode->traverseNextNode(); n != nullptr; n = n->traverseNextNode()) {
1884             if (n->isTabFocusable() && (n->tabIndex() == lowestSuitableTabIndex)) {
1885                 return n;
1886             }
1887         }
1888 
1889         // The next node isn't after fromNode, start from the beginning of the document
1890         for (n = this; n != fromNode; n = n->traverseNextNode()) {
1891             if (n->isTabFocusable() && (n->tabIndex() == lowestSuitableTabIndex)) {
1892                 return n;
1893             }
1894         }
1895 
1896         assert(false); // should never get here
1897         return nullptr;
1898     }
1899 }
1900 
1901 NodeImpl *DocumentImpl::previousFocusNode(NodeImpl *fromNode)
1902 {
1903     NodeImpl *lastNode = this;
1904     while (lastNode->lastChild()) {
1905         lastNode = lastNode->lastChild();
1906     }
1907 
1908     if (!fromNode) {
1909         // No starting node supplied; begin with the very last node in the document
1910         NodeImpl *n;
1911 
1912         int highestTabIndex = 0;
1913         for (n = lastNode; n != nullptr; n = n->traversePreviousNode()) {
1914             if (n->isTabFocusable()) {
1915                 if (n->tabIndex() == 0) {
1916                     return n;
1917                 } else if (n->tabIndex() > highestTabIndex) {
1918                     highestTabIndex = n->tabIndex();
1919                 }
1920             }
1921         }
1922 
1923         // No node with a tab index of 0; just go to the last node with the highest tab index
1924         for (n = lastNode; n != nullptr; n = n->traversePreviousNode()) {
1925             if (n->isTabFocusable() && (n->tabIndex() == highestTabIndex)) {
1926                 return n;
1927             }
1928         }
1929 
1930         return nullptr;
1931     } else {
1932         short fromTabIndex = fromNode->tabIndex();
1933 
1934         if (fromTabIndex == 0) {
1935             // Find the previous selectable node before fromNode (in document order) that doesn't have a tab index
1936             NodeImpl *n = fromNode->traversePreviousNode();
1937             while (n && !(n->isTabFocusable() && n->tabIndex() == 0)) {
1938                 n = n->traversePreviousNode();
1939             }
1940             if (n) {
1941                 return n;
1942             }
1943 
1944             // No previous nodes with a 0 tab index, go to the last node in the document that has the highest tab index
1945             int highestTabIndex = 0;
1946             for (n = this; n != nullptr; n = n->traverseNextNode()) {
1947                 if (n->isTabFocusable() && (n->tabIndex() > highestTabIndex)) {
1948                     highestTabIndex = n->tabIndex();
1949                 }
1950             }
1951 
1952             if (highestTabIndex == 0) {
1953                 return nullptr;
1954             }
1955 
1956             for (n = lastNode; n != nullptr; n = n->traversePreviousNode()) {
1957                 if (n->isTabFocusable() && (n->tabIndex() == highestTabIndex)) {
1958                     return n;
1959                 }
1960             }
1961 
1962             assert(false); // should never get here
1963             return nullptr;
1964         } else {
1965             // Find the lowest tab index out of all the nodes except fromNode, that is less than or equal to fromNode's
1966             // tab index. For nodes with the same tab index as fromNode, we are only interested in those before
1967             // fromNode.
1968             // If we don't find a suitable tab index, then there will be no previous focus node.
1969             short highestSuitableTabIndex = 0;
1970             NodeImpl *n;
1971 
1972             bool reachedFromNode = false;
1973             for (n = this; n != nullptr; n = n->traverseNextNode()) {
1974                 if (n->isTabFocusable() &&
1975                         ((!reachedFromNode && (n->tabIndex() <= fromTabIndex)) ||
1976                          (reachedFromNode && (n->tabIndex() < fromTabIndex)))  &&
1977                         (n->tabIndex() > highestSuitableTabIndex) &&
1978                         (n != fromNode)) {
1979 
1980                     // We found a selectable node with a tab index no higher than fromNode's. Keep searching though, as
1981                     // there may be another node which has a higher tab index but is still suitable for use.
1982                     highestSuitableTabIndex = n->tabIndex();
1983                 }
1984 
1985                 if (n == fromNode) {
1986                     reachedFromNode = true;
1987                 }
1988             }
1989 
1990             if (highestSuitableTabIndex == 0) {
1991                 // No previous node with a tab index. Since the order specified by HTML is nodes with tab index > 0
1992                 // first, this means that there is no previous node.
1993                 return nullptr;
1994             }
1995 
1996             // Search backwards from fromNode
1997             for (n = fromNode->traversePreviousNode(); n != nullptr; n = n->traversePreviousNode()) {
1998                 if (n->isTabFocusable() && (n->tabIndex() == highestSuitableTabIndex)) {
1999                     return n;
2000                 }
2001             }
2002             // The previous node isn't before fromNode, start from the end of the document
2003             for (n = lastNode; n != fromNode; n = n->traversePreviousNode()) {
2004                 if (n->isTabFocusable() && (n->tabIndex() == highestSuitableTabIndex)) {
2005                     return n;
2006                 }
2007             }
2008 
2009             assert(false); // should never get here
2010             return nullptr;
2011         }
2012     }
2013 }
2014 
2015 ElementImpl *DocumentImpl::findAccessKeyElement(QChar c)
2016 {
2017     c = c.toUpper();
2018     for (NodeImpl *n = this;
2019             n != nullptr;
2020             n = n->traverseNextNode()) {
2021         if (n->isElementNode()) {
2022             ElementImpl *en = static_cast< ElementImpl * >(n);
2023             DOMString s = en->getAttribute(ATTR_ACCESSKEY);
2024             if (s.length() == 1
2025                     && s[ 0 ].toUpper() == c) {
2026                 return en;
2027             }
2028         }
2029     }
2030     return nullptr;
2031 }
2032 
2033 int DocumentImpl::nodeAbsIndex(NodeImpl *node)
2034 {
2035     assert(node->document() == this);
2036 
2037     int absIndex = 0;
2038     for (NodeImpl *n = node; n && n != this; n = n->traversePreviousNode()) {
2039         absIndex++;
2040     }
2041     return absIndex;
2042 }
2043 
2044 NodeImpl *DocumentImpl::nodeWithAbsIndex(int absIndex)
2045 {
2046     NodeImpl *n = this;
2047     for (int i = 0; n && (i < absIndex); i++) {
2048         n = n->traverseNextNode();
2049     }
2050     return n;
2051 }
2052 
2053 void DocumentImpl::processHttpEquiv(const DOMString &equiv, const DOMString &content)
2054 {
2055     assert(!equiv.isNull() && !content.isNull());
2056 
2057     KHTMLView *v = document()->view();
2058 
2059     if (strcasecmp(equiv, "refresh") == 0 && v && v->part()->metaRefreshEnabled()) {
2060         // get delay and url
2061         QString str = content.string().trimmed();
2062         int pos = str.indexOf(QRegExp("[;,]"));
2063         if (pos == -1) {
2064             pos = str.indexOf(QRegExp("[ \t]"));
2065         }
2066 
2067         bool ok = false;
2068         int delay = qMax(0, content.implementation()->toInt(&ok));
2069         if (!ok && str.length() && str[0] == '.') {
2070             ok = true;
2071         }
2072 
2073         if (pos == -1) { // There can be no url (David)
2074             if (ok) {
2075                 v->part()->scheduleRedirection(delay, v->part()->url().toString());
2076             }
2077         } else {
2078             pos++;
2079             while (pos < str.length() && str[pos].isSpace()) {
2080                 pos++;
2081             }
2082             str = str.mid(pos);
2083             if (str.indexOf("url", 0, Qt::CaseInsensitive) == 0) {
2084                 str = str.mid(3);
2085             }
2086             str = str.trimmed();
2087             if (str.length() && str[0] == '=') {
2088                 str = str.mid(1).trimmed();
2089             }
2090             while (str.length() &&
2091                     (str[str.length() - 1] == ';' || str[str.length() - 1] == ',')) {
2092                 str.resize(str.length() - 1);
2093             }
2094             str = DOMString(str).trimSpaces().string();
2095             const QString newURL = document()->completeURL(str);
2096             if (ok) {
2097                 v->part()->scheduleRedirection(delay, newURL,  delay < 2 || newURL == URL().url());
2098             }
2099         }
2100     } else if (strcasecmp(equiv, "expires") == 0) {
2101         if (m_docLoader) {
2102             QString str = content.string().trimmed();
2103             //QDateTime can't convert from a RFCDate format string
2104             QDateTime expire_date = QDateTime::fromString(str, Qt::RFC2822Date);
2105 
2106             if (!expire_date.isValid()) {
2107                 qint64 seconds = str.toLongLong();
2108                 if (seconds != 0) {
2109                     m_docLoader->setRelativeExpireDate(seconds);
2110                 } else {
2111                     expire_date = QDateTime::currentDateTime(); // expire now
2112                     m_docLoader->setExpireDate(expire_date);
2113                 }
2114             }
2115         }
2116     } else if (v && (strcasecmp(equiv, "pragma") == 0 || strcasecmp(equiv, "cache-control") == 0)) {
2117         QString str = content.string().toLower().trimmed();
2118         QUrl url = v->part()->url();
2119         if ((str == "no-cache") && url.scheme().startsWith(QLatin1String("http"))) {
2120             KIO::http_update_cache(url, true, QDateTime::fromTime_t(0));
2121         }
2122     } else if ((strcasecmp(equiv, "set-cookie") == 0)) {
2123         // ### make setCookie work on XML documents too; e.g. in case of <html:meta .....>
2124         HTMLDocumentImpl *d = static_cast<HTMLDocumentImpl *>(this);
2125         d->setCookie(content);
2126     } else if (strcasecmp(equiv, "default-style") == 0) {
2127         // HTML 4.0 14.3.2
2128         // https://www.hixie.ch/tests/evil/css/import/main/preferred.html
2129         m_preferredStylesheetSet = content;
2130         updateStyleSelector();
2131     } else if (strcasecmp(equiv, "content-language") == 0) {
2132         m_contentLanguage = content.string();
2133     }
2134 }
2135 
2136 bool DocumentImpl::prepareMouseEvent(bool readonly, int _x, int _y, MouseEvent *ev)
2137 {
2138     if (m_render) {
2139         assert(m_render->isCanvas());
2140         RenderObject::NodeInfo renderInfo(readonly, ev->type == MousePress);
2141         bool isInside = m_render->layer()->nodeAtPoint(renderInfo, _x, _y);
2142         ev->innerNode = renderInfo.innerNode();
2143         ev->innerNonSharedNode = renderInfo.innerNonSharedNode();
2144 
2145         if (renderInfo.URLElement()) {
2146             assert(renderInfo.URLElement()->isElementNode());
2147             //qDebug("urlnode: %s  (%d)", getTagName(renderInfo.URLElement()->id()).string().toLatin1().constData(), renderInfo.URLElement()->id());
2148 
2149             ElementImpl *e =  static_cast<ElementImpl *>(renderInfo.URLElement());
2150             DOMString href = e->getAttribute(ATTR_HREF).trimSpaces();
2151             DOMString target = e->getAttribute(ATTR_TARGET);
2152 
2153             if (!target.isNull() && !href.isNull()) {
2154                 ev->target = target;
2155                 ev->url = href;
2156             } else {
2157                 ev->url = href;
2158             }
2159         }
2160 
2161         if (!readonly) {
2162             updateRendering();
2163         }
2164 
2165         return isInside;
2166     }
2167 
2168     return false;
2169 }
2170 
2171 // DOM Section 1.1.1
2172 bool DocumentImpl::childTypeAllowed(unsigned short type)
2173 {
2174     switch (type) {
2175     case Node::ATTRIBUTE_NODE:
2176     case Node::CDATA_SECTION_NODE:
2177     case Node::DOCUMENT_FRAGMENT_NODE:
2178     case Node::DOCUMENT_NODE:
2179     case Node::ENTITY_NODE:
2180     case Node::ENTITY_REFERENCE_NODE:
2181     case Node::NOTATION_NODE:
2182     case Node::TEXT_NODE:
2183 //        case Node::XPATH_NAMESPACE_NODE:
2184         return false;
2185     case Node::COMMENT_NODE:
2186     case Node::PROCESSING_INSTRUCTION_NODE:
2187         return true;
2188     case Node::DOCUMENT_TYPE_NODE:
2189     case Node::ELEMENT_NODE:
2190         // Documents may contain no more than one of each of these.
2191         // (One Element and one DocumentType.)
2192         for (NodeImpl *c = firstChild(); c; c = c->nextSibling())
2193             if (c->nodeType() == type) {
2194                 return false;
2195             }
2196         return true;
2197     }
2198     return false;
2199 }
2200 
2201 WTF::PassRefPtr<NodeImpl> DocumentImpl::cloneNode(bool deep)
2202 {
2203 #if 0
2204     NodeImpl *dtn = m_doctype->cloneNode(deep);
2205     DocumentTypeImpl *dt = static_cast<DocumentTypeImpl *>(dtn);
2206 #endif
2207 
2208     int exceptioncode;
2209     WTF::RefPtr<NodeImpl> clone = DOMImplementationImpl::createDocument("",
2210                                   "",
2211                                   nullptr, nullptr,
2212                                   exceptioncode);
2213     assert(exceptioncode == 0);
2214 
2215     // ### attributes, styles, ...
2216 
2217     if (deep) {
2218         cloneChildNodes(clone.get());
2219     }
2220 
2221     return clone;
2222 }
2223 
2224 // This method is called whenever a top-level stylesheet has finished loading.
2225 void DocumentImpl::styleSheetLoaded()
2226 {
2227     // Make sure we knew this sheet was pending, and that our count isn't out of sync.
2228     assert(m_pendingStylesheets > 0);
2229 
2230     m_pendingStylesheets--;
2231     updateStyleSelector();
2232     if (!m_pendingStylesheets && m_tokenizer) {
2233         m_tokenizer->executeScriptsWaitingForStylesheets();
2234     }
2235 }
2236 
2237 void DocumentImpl::addPendingSheet()
2238 {
2239     m_pendingStylesheets++;
2240 }
2241 
2242 DOMString DocumentImpl::selectedStylesheetSet() const
2243 {
2244     if (!view()) {
2245         return DOMString();
2246     }
2247 
2248     return view()->part()->d->m_sheetUsed;
2249 }
2250 
2251 void DocumentImpl::setSelectedStylesheetSet(const DOMString &s)
2252 {
2253     // this code is evil
2254     if (view() && view()->part()->d->m_sheetUsed != s.string()) {
2255         view()->part()->d->m_sheetUsed = s.string();
2256         updateStyleSelector();
2257     }
2258 }
2259 
2260 void DocumentImpl::addStyleSheet(StyleSheetImpl *sheet, int *exceptioncode)
2261 {
2262     int excode = 0;
2263 
2264     if (!m_addedStyleSheets) {
2265         m_addedStyleSheets = new StyleSheetListImpl;
2266         m_addedStyleSheets->ref();
2267     }
2268 
2269     m_addedStyleSheets->add(sheet);
2270     if (sheet->isCSSStyleSheet()) {
2271         updateStyleSelector();
2272     }
2273 
2274     if (exceptioncode) {
2275         *exceptioncode = excode;
2276     }
2277 }
2278 
2279 void DocumentImpl::removeStyleSheet(StyleSheetImpl *sheet, int *exceptioncode)
2280 {
2281     int excode = 0;
2282     bool removed = false;
2283     bool is_css = sheet->isCSSStyleSheet();
2284 
2285     if (m_addedStyleSheets) {
2286         bool in_main_list = !sheet->hasOneRef();
2287         removed = m_addedStyleSheets->styleSheets.removeAll(sheet);
2288         sheet->deref();
2289 
2290         if (m_addedStyleSheets->styleSheets.count() == 0) {
2291             bool reset = m_addedStyleSheets->hasOneRef();
2292             m_addedStyleSheets->deref();
2293             if (reset) {
2294                 m_addedStyleSheets = nullptr;
2295             }
2296         }
2297 
2298         // remove from main list, too
2299         if (in_main_list) {
2300             m_styleSheets->remove(sheet);
2301         }
2302     }
2303 
2304     if (removed) {
2305         if (is_css) {
2306             updateStyleSelector();
2307         }
2308     } else {
2309         excode = DOMException::NOT_FOUND_ERR;
2310     }
2311 
2312     if (exceptioncode) {
2313         *exceptioncode = excode;
2314     }
2315 }
2316 
2317 void DocumentImpl::updateStyleSelector(bool shallow)
2318 {
2319 //    qCDebug(KHTML_LOG) << "PENDING " << m_pendingStylesheets;
2320 
2321     // Don't bother updating, since we haven't loaded all our style info yet.
2322     if (m_pendingStylesheets > 0) {
2323         // ... however, if the list of stylesheets changed, mark it as dirty
2324         // so DOM ops can get an up-to-date version.
2325         if (!shallow) {
2326             m_styleSheetListDirty = true;
2327         }
2328         return;
2329     }
2330 
2331     if (!shallow) {
2332         rebuildStyleSheetList();
2333     }
2334 
2335     rebuildStyleSelector();
2336 
2337     recalcStyle(Force);
2338 #if 0
2339 
2340     m_styleSelectorDirty = true;
2341 #endif
2342     if (renderer()) {
2343         renderer()->setNeedsLayoutAndMinMaxRecalc();
2344     }
2345 }
2346 
2347 bool DocumentImpl::readyForLayout() const
2348 {
2349     return renderer() && haveStylesheetsLoaded() && (!isHTMLDocument() || (body() && body()->renderer()));
2350 }
2351 
2352 void DocumentImpl::rebuildStyleSheetList(bool force)
2353 {
2354     if (!m_render || !attached()) {
2355         // Unless we're forced due to CSS DOM ops, we don't have to compute info
2356         // when there is nothing to display
2357         if (!force) {
2358             m_styleSheetListDirty = true;
2359             return;
2360         }
2361     }
2362 
2363     // Mark us as clean, as we can call add on the list below, forcing us to re-enter
2364     m_styleSheetListDirty = false;
2365 
2366     QList<StyleSheetImpl *> oldStyleSheets = m_styleSheets->styleSheets;
2367     m_styleSheets->styleSheets.clear();
2368     QString sheetUsed = view() ? view()->part()->d->m_sheetUsed.replace("&&", "&") : QString();
2369     bool autoselect = sheetUsed.isEmpty();
2370     if (autoselect && !m_preferredStylesheetSet.isEmpty()) {
2371         sheetUsed = m_preferredStylesheetSet.string();
2372     }
2373     NodeImpl *n;
2374     for (int i = 0; i < 2; i++) {
2375         m_availableSheets.clear();
2376         m_availableSheets << i18n("Basic Page Style");
2377         bool canResetSheet = false;
2378 
2379         QString title;
2380         for (n = this; n; n = n->traverseNextNode()) {
2381             StyleSheetImpl *sheet = nullptr;
2382 
2383             if (n->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) {
2384                 // Processing instruction (XML documents only)
2385                 ProcessingInstructionImpl *pi = static_cast<ProcessingInstructionImpl *>(n);
2386                 sheet = pi->sheet();
2387                 if (!sheet && !pi->localHref().isEmpty()) {
2388                     // Processing instruction with reference to an element in this document - e.g.
2389                     // <?xml-stylesheet href="#mystyle">, with the element
2390                     // <foo id="mystyle">heading { color: red; }</foo> at some location in
2391                     // the document
2392                     ElementImpl *elem = getElementById(pi->localHref());
2393                     if (elem) {
2394                         DOMString sheetText("");
2395                         NodeImpl *c;
2396                         for (c = elem->firstChild(); c; c = c->nextSibling()) {
2397                             if (c->nodeType() == Node::TEXT_NODE || c->nodeType() == Node::CDATA_SECTION_NODE) {
2398                                 sheetText += c->nodeValue();
2399                             }
2400                         }
2401 
2402                         CSSStyleSheetImpl *cssSheet = new CSSStyleSheetImpl(this);
2403                         cssSheet->parseString(sheetText);
2404                         pi->setStyleSheet(cssSheet);
2405                         sheet = cssSheet;
2406                     }
2407                 }
2408                 if (sheet) {
2409                     title = sheet->title().string();
2410                     if ((autoselect || title != sheetUsed) && sheet->disabled()) {
2411                         sheet = nullptr;
2412                     } else if (!title.isEmpty() && !pi->isAlternate() && sheetUsed.isEmpty()) {
2413                         sheetUsed = title;
2414                         sheet->setDisabled(false);
2415                     }
2416                 }
2417             } else if (n->isHTMLElement() && (n->id() == ID_LINK || n->id() == ID_STYLE)) {
2418                 if (n->id() == ID_LINK) {
2419                     HTMLLinkElementImpl *l = static_cast<HTMLLinkElementImpl *>(n);
2420                     if (l->isCSSStyleSheet()) {
2421                         sheet = l->sheet();
2422 
2423                         if (sheet || l->isLoading() || l->isAlternate()) {
2424                             title = l->getAttribute(ATTR_TITLE).string();
2425                         }
2426 
2427                         if ((autoselect || title != sheetUsed) && l->isDisabled()) {
2428                             sheet = nullptr;
2429                         } else if (!title.isEmpty() && !l->isAlternate() && sheetUsed.isEmpty()) {
2430                             sheetUsed = title;
2431                             l->setDisabled(false);
2432                         }
2433                     }
2434                 } else {
2435                     // <STYLE> element
2436                     HTMLStyleElementImpl *s = static_cast<HTMLStyleElementImpl *>(n);
2437                     if (!s->isLoading()) {
2438                         sheet = s->sheet();
2439                         if (sheet) {
2440                             title = s->getAttribute(ATTR_TITLE).string();
2441                         }
2442                     }
2443                     if (!title.isEmpty() && sheetUsed.isEmpty()) {
2444                         sheetUsed = title;
2445                     }
2446                 }
2447             } else if (n->isHTMLElement() && n->id() == ID_BODY) {
2448                 // <BODY> element (doesn't contain styles as such but vlink="..." and friends
2449                 // are treated as style declarations)
2450                 sheet = static_cast<HTMLBodyElementImpl *>(n)->sheet();
2451             }
2452 
2453             if (!title.isEmpty()) {
2454                 if (title != sheetUsed) {
2455                     sheet = nullptr;    // don't use it
2456                 }
2457                 title = title.replace('&',  "&&");
2458                 if (!m_availableSheets.contains(title)) {
2459                     m_availableSheets.append(title);
2460                 }
2461                 title.clear();
2462             }
2463 
2464             if (sheet) {
2465                 sheet->ref();
2466                 m_styleSheets->styleSheets.append(sheet);
2467             }
2468 
2469             // For HTML documents, stylesheets are not allowed within/after the <BODY> tag. So we
2470             // can stop searching here.
2471             if (isHTMLDocument() && n->id() == ID_BODY) {
2472                 canResetSheet = !canResetSheet;
2473                 break;
2474             }
2475         }
2476 
2477         // we're done if we don't select an alternative sheet
2478         // or we found the sheet we selected
2479         if (sheetUsed.isEmpty() ||
2480                 (!canResetSheet && tokenizer()) ||
2481                 m_availableSheets.contains(sheetUsed)) {
2482             break;
2483         }
2484 
2485         // the alternative sheet we used doesn't exist anymore
2486         // so try from scratch again
2487         if (view()) {
2488             view()->part()->d->m_sheetUsed.clear();
2489         }
2490         if (!m_preferredStylesheetSet.isEmpty() && !(sheetUsed == m_preferredStylesheetSet)) {
2491             sheetUsed = m_preferredStylesheetSet.string();
2492         } else {
2493             sheetUsed.clear();
2494         }
2495         autoselect = true;
2496     }
2497 
2498     // Include programmatically added style sheets
2499     if (m_addedStyleSheets) {
2500         foreach (StyleSheetImpl *sh, m_addedStyleSheets->styleSheets) {
2501             if (sh->isCSSStyleSheet() && !sh->disabled()) {
2502                 m_styleSheets->add(sh);
2503             }
2504         }
2505     }
2506 
2507     // De-reference all the stylesheets in the old list
2508     foreach (StyleSheetImpl *sh, oldStyleSheets) {
2509         sh->deref();
2510     }
2511 }
2512 
2513 void DocumentImpl::rebuildStyleSelector()
2514 {
2515     if (!m_render || !attached()) {
2516         return;
2517     }
2518 
2519     // Create a new style selector
2520     delete m_styleSelector;
2521     QString usersheet = m_usersheet;
2522     if (m_view && m_view->mediaType() == "print") {
2523         usersheet += m_printSheet;
2524     }
2525     m_styleSelector = new CSSStyleSelector(this, usersheet, m_styleSheets, m_url,
2526                                            !inCompatMode());
2527 
2528     m_styleSelectorDirty = false;
2529 }
2530 
2531 void DocumentImpl::setBaseURL(const QUrl &_baseURL)
2532 {
2533     m_baseURL = _baseURL;
2534     if (m_elemSheet) {
2535         m_elemSheet->setHref(baseURL().toString());
2536     }
2537 }
2538 
2539 void DocumentImpl::setHoverNode(NodeImpl *newHoverNode)
2540 {
2541     NodeImpl *oldHoverNode = m_hoverNode;
2542     if (newHoverNode) {
2543         newHoverNode->ref();
2544     }
2545     m_hoverNode = newHoverNode;
2546     if (oldHoverNode) {
2547         oldHoverNode->deref();
2548     }
2549 }
2550 
2551 void DocumentImpl::setActiveNode(NodeImpl *newActiveNode)
2552 {
2553     NodeImpl *oldActiveNode = m_activeNode;
2554     if (newActiveNode) {
2555         newActiveNode->ref();
2556     }
2557     m_activeNode = newActiveNode;
2558     if (oldActiveNode) {
2559         oldActiveNode->deref();
2560     }
2561 }
2562 
2563 void DocumentImpl::quietResetFocus()
2564 {
2565     assert(m_focusNode != this);
2566     if (m_focusNode) {
2567         if (m_focusNode->active()) {
2568             setActiveNode(nullptr);
2569         }
2570 
2571         m_focusNode->setFocus(false);
2572         m_focusNode->deref();
2573     }
2574     m_focusNode = nullptr;
2575 
2576     //We're blurring. Better clear the Qt focus/give it to the view...
2577     if (view()) {
2578         view()->setFocus();
2579     }
2580 }
2581 
2582 void DocumentImpl::setFocusNode(NodeImpl *newFocusNode)
2583 {
2584     // don't process focus changes while detaching
2585     if (!m_render) {
2586         return;
2587     }
2588 
2589     // See if the new node is really focusable. It might not be
2590     // if focus() was called explicitly.
2591     if (newFocusNode && !newFocusNode->isFocusable()) {
2592         return;
2593     }
2594 
2595     // Make sure newFocusNode is actually in this document
2596     if (newFocusNode && (newFocusNode->document() != this)) {
2597         return;
2598     }
2599 
2600     if (m_focusNode != newFocusNode) {
2601         NodeImpl *oldFocusNode = m_focusNode;
2602 
2603         // We are blurring, so m_focusNode ATM is 0; this is observable to the
2604         // event handlers.
2605         m_focusNode = nullptr;
2606 
2607         // Remove focus from the existing focus node (if any)
2608         if (oldFocusNode) {
2609             if (oldFocusNode->active()) {
2610                 oldFocusNode->setActive(false);
2611             }
2612 
2613             oldFocusNode->setFocus(false);
2614             if (oldFocusNode->renderer() && oldFocusNode->renderer()->isWidget()) {
2615                 // Editable widgets may need to dispatch CHANGE_EVENT
2616                 RenderWidget *rw = static_cast<RenderWidget *>(oldFocusNode->renderer());
2617                 if (rw->isRedirectedWidget()) {
2618                     rw->handleFocusOut();
2619                 }
2620             }
2621 
2622             oldFocusNode->dispatchHTMLEvent(EventImpl::BLUR_EVENT, false, false);
2623             oldFocusNode->dispatchUIEvent(EventImpl::DOMFOCUSOUT_EVENT);
2624 
2625             if ((oldFocusNode == this) && oldFocusNode->hasOneRef()) {
2626                 oldFocusNode->deref(); // may delete this, if there are not kids keeping it alive...
2627                 // so we better not add any.
2628                 return;
2629             } else {
2630                 oldFocusNode->deref();
2631             }
2632         }
2633 
2634         // It's possible that one of the blur, etc. handlers has already set focus.
2635         // in that case, we don't want to override it.
2636         if (!m_focusNode && newFocusNode) {
2637             // Set focus on the new node
2638             m_focusNode = newFocusNode;
2639             m_focusNode->ref();
2640             m_focusNode->dispatchHTMLEvent(EventImpl::FOCUS_EVENT, false, false);
2641             if (m_focusNode != newFocusNode) {
2642                 return;
2643             }
2644             m_focusNode->dispatchUIEvent(EventImpl::DOMFOCUSIN_EVENT);
2645             if (m_focusNode != newFocusNode) {
2646                 return;
2647             }
2648             m_focusNode->setFocus();
2649             if (m_focusNode != newFocusNode) {
2650                 return;
2651             }
2652 
2653             // eww, I suck. set the qt focus correctly
2654             // ### find a better place in the code for this
2655             if (view()) {
2656                 if (!m_focusNode->renderer() || !m_focusNode->renderer()->isWidget()) {
2657                     view()->setFocus();
2658                 } else if (static_cast<RenderWidget *>(m_focusNode->renderer())->widget()) {
2659                     if (view()->isVisible()) {
2660                         static_cast<RenderWidget *>(m_focusNode->renderer())->widget()->setFocus();
2661                     }
2662                 }
2663             }
2664         } else {
2665             //We're blurring. Better clear the Qt focus/give it to the view...
2666             if (view()) {
2667                 view()->setFocus();
2668             }
2669         }
2670 
2671         updateRendering();
2672     }
2673 }
2674 
2675 void DocumentImpl::setCSSTarget(NodeImpl *n)
2676 {
2677     if (n == m_cssTarget) {
2678         return;
2679     }
2680 
2681     if (m_cssTarget) {
2682         m_cssTarget->setChanged();
2683         m_cssTarget->deref();
2684     }
2685     m_cssTarget = n;
2686     if (n) {
2687         n->setChanged();
2688         n->ref();
2689     }
2690 }
2691 
2692 void DocumentImpl::attachNodeIterator(NodeIteratorImpl *ni)
2693 {
2694     m_nodeIterators.append(ni);
2695 }
2696 
2697 void DocumentImpl::detachNodeIterator(NodeIteratorImpl *ni)
2698 {
2699     int i = m_nodeIterators.indexOf(ni);
2700     if (i != -1) {
2701         m_nodeIterators.removeAt(i);
2702     }
2703 }
2704 
2705 void DocumentImpl::notifyBeforeNodeRemoval(NodeImpl *n)
2706 {
2707     QListIterator<NodeIteratorImpl *> it(m_nodeIterators);
2708     while (it.hasNext()) {
2709         it.next()->notifyBeforeNodeRemoval(n);
2710     }
2711 }
2712 
2713 bool DocumentImpl::isURLAllowed(const QString &url) const
2714 {
2715     KHTMLPart *thisPart = part();
2716 
2717     QUrl newURL(completeURL(url));
2718     newURL.setFragment(QString());
2719 
2720     if (KHTMLGlobal::defaultHTMLSettings()->isAdFiltered(newURL.url())) {
2721         return false;
2722     }
2723 
2724     // Prohibit non-file URLs if we are asked to.
2725     if (!thisPart || (thisPart->onlyLocalReferences() && newURL.scheme() != "file" && newURL.scheme() != "data")) {
2726         return false;
2727     }
2728 
2729     // do we allow this suburl ?
2730     if (newURL.scheme() != "javascript" && !KUrlAuthorized::authorizeUrlAction("redirect", thisPart->url(), newURL)) {
2731         return false;
2732     }
2733 
2734     // We allow one level of self-reference because some sites depend on that.
2735     // But we don't allow more than one.
2736     bool foundSelfReference = false;
2737     for (KHTMLPart *part = thisPart; part; part = part->parentPart()) {
2738         QUrl partURL = part->url();
2739         partURL.setFragment(QString());
2740         if (partURL == newURL) {
2741             if (foundSelfReference) {
2742                 return false;
2743             }
2744             foundSelfReference = true;
2745         }
2746     }
2747 
2748     return true;
2749 }
2750 
2751 void DocumentImpl::setDesignMode(bool b)
2752 {
2753     if (part()) {
2754         part()->setEditable(b);
2755     }
2756 }
2757 
2758 bool DocumentImpl::designMode() const
2759 {
2760     return part() ? part()->isEditable() : false;
2761 }
2762 
2763 EventImpl *DocumentImpl::createEvent(const DOMString &eventType, int &exceptioncode)
2764 {
2765     if (eventType == "UIEvents" || eventType == "UIEvent") {
2766         return new UIEventImpl();
2767     } else if (eventType == "MouseEvents" || eventType == "MouseEvent") {
2768         return new MouseEventImpl();
2769     } else if (eventType == "TextEvent") {
2770         return new TextEventImpl();
2771     } else if (eventType == "KeyboardEvent") {
2772         return new KeyboardEventImpl();
2773     } else if (eventType == "MutationEvents" || eventType == "MutationEvent") {
2774         return new MutationEventImpl();
2775     } else if (eventType == "HTMLEvents" || eventType == "Events" ||
2776                eventType == "HTMLEvent"  || eventType == "Event") {
2777         return new EventImpl();
2778     } else {
2779         exceptioncode = DOMException::NOT_SUPPORTED_ERR;
2780         return nullptr;
2781     }
2782 }
2783 
2784 CSSStyleDeclarationImpl *DocumentImpl::getOverrideStyle(ElementImpl * /*elt*/, DOMStringImpl * /*pseudoElt*/)
2785 {
2786     return nullptr; // ###
2787 }
2788 
2789 void DocumentImpl::abort()
2790 {
2791     if (m_inSyncLoad) {
2792         assert(m_inSyncLoad->isRunning());
2793         m_inSyncLoad->exit();
2794     }
2795 
2796     if (m_loadingXMLDoc) {
2797         m_loadingXMLDoc->deref(this);
2798     }
2799     m_loadingXMLDoc = nullptr;
2800 }
2801 
2802 void DocumentImpl::load(const DOMString &uri)
2803 {
2804     if (m_inSyncLoad) {
2805         assert(m_inSyncLoad->isRunning());
2806         m_inSyncLoad->exit();
2807     }
2808 
2809     m_hadLoadError = false;
2810     if (m_loadingXMLDoc) {
2811         m_loadingXMLDoc->deref(this);
2812     }
2813 
2814     // Use the document loader to retrieve the XML file. We use CachedCSSStyleSheet because
2815     // this is an easy way to retrieve an arbitrary text file... it is not specific to
2816     // stylesheets.
2817 
2818     // ### Note: By loading the XML document this way we do not get the proper decoding
2819     // of the data retrieved from the server based on the character set, as happens with
2820     // HTML files. Need to look into a way of using the decoder in CachedCSSStyleSheet.
2821     m_docLoading = true;
2822     m_loadingXMLDoc = m_docLoader->requestStyleSheet(uri.string(), QString(), "text/xml");
2823 
2824     if (!m_loadingXMLDoc) {
2825         m_docLoading = false;
2826         return;
2827     }
2828 
2829     m_loadingXMLDoc->ref(this);
2830 
2831     if (!m_async && m_docLoading) {
2832         assert(!m_inSyncLoad);
2833         m_inSyncLoad = new QEventLoop();
2834         m_inSyncLoad->exec();
2835         // returning from event loop:
2836         assert(!m_inSyncLoad->isRunning());
2837         delete m_inSyncLoad;
2838         m_inSyncLoad = nullptr;
2839     }
2840 }
2841 
2842 void DocumentImpl::loadXML(const DOMString &source)
2843 {
2844     open(false);
2845     write(source);
2846     finishParsing();
2847     close();
2848     dispatchHTMLEvent(EventImpl::LOAD_EVENT, false, false);
2849 }
2850 
2851 void DocumentImpl::setStyleSheet(const DOM::DOMString &url, const DOM::DOMString &sheet, const DOM::DOMString &/*charset*/, const DOM::DOMString &mimetype)
2852 {
2853     if (!m_hadLoadError) {
2854         m_url = QUrl(url.string());
2855         loadXML(khtml::isAcceptableCSSMimetype(mimetype) ? sheet : "");
2856     }
2857 
2858     m_docLoading = false;
2859     if (m_inSyncLoad) {
2860         assert(m_inSyncLoad->isRunning());
2861         m_inSyncLoad->exit();
2862     }
2863 
2864     assert(m_loadingXMLDoc != nullptr);
2865     m_loadingXMLDoc->deref(this);
2866     m_loadingXMLDoc = nullptr;
2867 }
2868 
2869 void DocumentImpl::error(int err, const QString &text)
2870 {
2871     m_docLoading = false;
2872     if (m_inSyncLoad) {
2873         assert(m_inSyncLoad->isRunning());
2874         m_inSyncLoad->exit();
2875     }
2876 
2877     m_hadLoadError = true;
2878 
2879     int exceptioncode = 0;
2880     EventImpl *evt = new EventImpl(EventImpl::ERROR_EVENT, false, false);
2881     if (err != 0) {
2882         evt->setMessage(KIO::buildErrorString(err, text));
2883     } else {
2884         evt->setMessage(text);
2885     }
2886     evt->ref();
2887     dispatchEvent(evt, exceptioncode, true);
2888     evt->deref();
2889 
2890     assert(m_loadingXMLDoc != nullptr);
2891     m_loadingXMLDoc->deref(this);
2892     m_loadingXMLDoc = nullptr;
2893 }
2894 
2895 void DocumentImpl::defaultEventHandler(EventImpl *evt)
2896 {
2897     if (evt->id() == EventImpl::KHTML_CONTENTLOADED_EVENT && !evt->propagationStopped() && !evt->defaultPrevented()) {
2898         contentLoaded();
2899     }
2900 }
2901 
2902 void DocumentImpl::setHTMLWindowEventListener(EventName id, EventListener *listener)
2903 {
2904     windowEventTarget()->listenerList().setHTMLEventListener(id, listener);
2905 }
2906 
2907 void DocumentImpl::setHTMLWindowEventListener(unsigned id, EventListener *listener)
2908 {
2909     windowEventTarget()->listenerList().setHTMLEventListener(EventName::fromId(id), listener);
2910 }
2911 
2912 EventListener *DocumentImpl::getHTMLWindowEventListener(EventName id)
2913 {
2914     return windowEventTarget()->listenerList().getHTMLEventListener(id);
2915 }
2916 
2917 EventListener *DocumentImpl::getHTMLWindowEventListener(unsigned id)
2918 {
2919     return windowEventTarget()->listenerList().getHTMLEventListener(EventName::fromId(id));
2920 }
2921 
2922 void DocumentImpl::addWindowEventListener(EventName id, EventListener *listener, const bool useCapture)
2923 {
2924     windowEventTarget()->listenerList().addEventListener(id, listener, useCapture);
2925 }
2926 
2927 void DocumentImpl::removeWindowEventListener(EventName id, EventListener *listener, bool useCapture)
2928 {
2929     windowEventTarget()->listenerList().removeEventListener(id, listener, useCapture);
2930 }
2931 
2932 bool DocumentImpl::hasWindowEventListener(EventName id)
2933 {
2934     return windowEventTarget()->listenerList().hasEventListener(id);
2935 }
2936 
2937 EventListener *DocumentImpl::createHTMLEventListener(const QString &code, const QString &name, NodeImpl *node)
2938 {
2939     return part() ? part()->createHTMLEventListener(code, name, node) : nullptr;
2940 }
2941 
2942 void DocumentImpl::dispatchImageLoadEventSoon(HTMLImageElementImpl *image)
2943 {
2944     m_imageLoadEventDispatchSoonList.append(image);
2945     if (!m_imageLoadEventTimer) {
2946         m_imageLoadEventTimer = startTimer(0);
2947     }
2948 }
2949 
2950 void DocumentImpl::removeImage(HTMLImageElementImpl *image)
2951 {
2952     // Remove instances of this image from both lists.
2953     m_imageLoadEventDispatchSoonList.removeAll(image);
2954     m_imageLoadEventDispatchingList.removeAll(image);
2955     if (m_imageLoadEventDispatchSoonList.isEmpty() && m_imageLoadEventTimer) {
2956         killTimer(m_imageLoadEventTimer);
2957         m_imageLoadEventTimer = 0;
2958     }
2959 }
2960 
2961 void DocumentImpl::dispatchImageLoadEventsNow()
2962 {
2963     // need to avoid re-entering this function; if new dispatches are
2964     // scheduled before the parent finishes processing the list, they
2965     // will set a timer and eventually be processed
2966     if (!m_imageLoadEventDispatchingList.isEmpty()) {
2967         return;
2968     }
2969 
2970     if (m_imageLoadEventTimer) {
2971         killTimer(m_imageLoadEventTimer);
2972         m_imageLoadEventTimer = 0;
2973     }
2974 
2975     m_imageLoadEventDispatchingList = m_imageLoadEventDispatchSoonList;
2976     m_imageLoadEventDispatchSoonList.clear();
2977     while (!m_imageLoadEventDispatchingList.isEmpty()) {
2978         m_imageLoadEventDispatchingList.takeFirst()->dispatchLoadEvent();
2979     }
2980     m_imageLoadEventDispatchingList.clear();
2981 }
2982 
2983 void DocumentImpl::timerEvent(QTimerEvent *e)
2984 {
2985     assert(e->timerId() == m_imageLoadEventTimer);
2986     Q_UNUSED(e);
2987     dispatchImageLoadEventsNow();
2988 }
2989 
2990 /*void DocumentImpl::setDecoderCodec(const QTextCodec *codec)
2991 {
2992     m_decoderMibEnum = codec->mibEnum();
2993 }*/
2994 
2995 HTMLPartContainerElementImpl *DocumentImpl::ownerElement() const
2996 {
2997     KHTMLPart *childPart = part();
2998     if (!childPart) {
2999         return nullptr;
3000     }
3001     ChildFrame *childFrame = childPart->d->m_frame;
3002     if (!childFrame) {
3003         return nullptr;
3004     }
3005     return childFrame->m_partContainerElement.data();
3006 }
3007 
3008 khtml::SecurityOrigin *DocumentImpl::origin() const
3009 {
3010     if (!m_origin) {
3011         m_origin = SecurityOrigin::create(URL());
3012     }
3013     return m_origin.get();
3014 }
3015 
3016 void DocumentImpl::setOrigin(khtml::SecurityOrigin *newOrigin)
3017 {
3018     assert(origin()->isEmpty());
3019     m_origin = newOrigin;
3020 }
3021 
3022 DOMString DocumentImpl::domain() const
3023 {
3024     return origin()->domain();
3025 }
3026 
3027 void DocumentImpl::setDomain(const DOMString &newDomain)
3028 {
3029     // ### this test really should move to SecurityOrigin..
3030     DOMString oldDomain = origin()->domain();
3031 
3032     // Both NS and IE specify that changing the domain is only allowed when
3033     // the new domain is a suffix of the old domain.
3034     int oldLength = oldDomain.length();
3035     int newLength = newDomain.length();
3036     if (newLength < oldLength) {   // e.g. newDomain=kde.org (7) and m_domain=www.kde.org (11)
3037         DOMString test = oldDomain.copy();
3038         DOMString reference = newDomain.lower();
3039         if (test[oldLength - newLength - 1] == '.') { // Check that it's a subdomain, not e.g. "de.org"
3040             test.remove(0, oldLength - newLength);   // now test is "kde.org" from m_domain
3041             if (test == reference) {                 // and we check that it's the same thing as newDomain
3042                 m_origin->setDomainFromDOM(reference.string());
3043             }
3044         }
3045     } else if (oldLength == newLength) {
3046         // It's OK and not a no-op to set the domain to the present one:
3047         // we want to set the 'set from DOM' bit in that case
3048         DOMString reference = newDomain.lower();
3049         if (oldDomain.lower() == reference) {
3050             m_origin->setDomainFromDOM(reference.string());
3051         }
3052     }
3053 }
3054 
3055 DOMString DocumentImpl::toString() const
3056 {
3057     DOMString result;
3058 
3059     for (NodeImpl *child = firstChild(); child != nullptr; child = child->nextSibling()) {
3060         result += child->toString();
3061     }
3062 
3063     return result;
3064 }
3065 
3066 void DOM::DocumentImpl::setRestoreState(const QStringList &s)
3067 {
3068     m_state = s;
3069     m_stateRestorePos = 0;
3070 }
3071 
3072 KHTMLView *DOM::DocumentImpl::view() const
3073 {
3074     return m_view;
3075 }
3076 
3077 KHTMLPart *DOM::DocumentImpl::part() const
3078 {
3079     // ### TODO: make this independent from a KHTMLView one day.
3080     return view() ? view()->part() : nullptr;
3081 }
3082 
3083 DynamicNodeListImpl::Cache *DOM::DocumentImpl::acquireCachedNodeListInfo(
3084     DynamicNodeListImpl::CacheFactory *factory, NodeImpl *base, int type)
3085 {
3086     //### might want to flush the dict when the version number
3087     //changes
3088     DynamicNodeListImpl::CacheKey key(base, type);
3089 
3090     //Check to see if we have this sort of item cached.
3091     DynamicNodeListImpl::Cache *cached =
3092         (type == DynamicNodeListImpl::UNCACHEABLE) ? nullptr : m_nodeListCache.value(key.hash());
3093 
3094     if (cached) {
3095         if (cached->key == key) {
3096             cached->ref(); //Add the nodelist's reference
3097             return cached;
3098         } else {
3099             //Conflict. Drop our reference to the old item.
3100             cached->deref();
3101         }
3102     }
3103 
3104     //Nothing to reuse, make a new item.
3105     DynamicNodeListImpl::Cache *newInfo = factory();
3106     newInfo->key = key;
3107     newInfo->clear(this);
3108     newInfo->ref(); //Add the nodelist's reference
3109 
3110     if (type != DynamicNodeListImpl::UNCACHEABLE) {
3111         newInfo->ref(); //Add the cache's reference
3112         m_nodeListCache.insert(key.hash(), newInfo);
3113     }
3114 
3115     return newInfo;
3116 }
3117 
3118 void DOM::DocumentImpl::releaseCachedNodeListInfo(DynamicNodeListImpl::Cache *entry)
3119 {
3120     entry->deref();
3121 }
3122 
3123 bool DOM::DocumentImpl::isSVGDocument() const
3124 {
3125     return (documentElement()->id() == WebCore::SVGNames::svgTag.id());
3126 }
3127 
3128 const WebCore::SVGDocumentExtensions *DOM::DocumentImpl::svgExtensions()
3129 {
3130     return m_svgExtensions;
3131 }
3132 
3133 WebCore::SVGDocumentExtensions *DOM::DocumentImpl::accessSVGExtensions()
3134 {
3135     if (!m_svgExtensions) {
3136         m_svgExtensions = new WebCore::SVGDocumentExtensions(this);
3137     }
3138     return m_svgExtensions;
3139 }
3140 
3141 // ----------------------------------------------------------------------------
3142 // Support for Javascript execCommand, and related methods
3143 
3144 JSEditor *DocumentImpl::jsEditor()
3145 {
3146     if (!m_jsEditor) {
3147         m_jsEditor = new JSEditor(this);
3148     }
3149     return m_jsEditor;
3150 }
3151 
3152 bool DocumentImpl::execCommand(const DOMString &command, bool userInterface, const DOMString &value)
3153 {
3154     // qCDebug(KHTML_LOG) << "[execute command]" << command << userInterface << value;
3155     return jsEditor()->execCommand(jsEditor()->commandImp(command), userInterface, value);
3156 }
3157 
3158 bool DocumentImpl::queryCommandEnabled(const DOMString &command)
3159 {
3160     return jsEditor()->queryCommandEnabled(jsEditor()->commandImp(command));
3161 }
3162 
3163 bool DocumentImpl::queryCommandIndeterm(const DOMString &command)
3164 {
3165     return jsEditor()->queryCommandIndeterm(jsEditor()->commandImp(command));
3166 }
3167 
3168 bool DocumentImpl::queryCommandState(const DOMString &command)
3169 {
3170     return jsEditor()->queryCommandState(jsEditor()->commandImp(command));
3171 }
3172 
3173 bool DocumentImpl::queryCommandSupported(const DOMString &command)
3174 {
3175     // qCDebug(KHTML_LOG) << "[query command supported]" << command;
3176     return jsEditor()->queryCommandSupported(jsEditor()->commandImp(command));
3177 }
3178 
3179 DOMString DocumentImpl::queryCommandValue(const DOMString &command)
3180 {
3181     return jsEditor()->queryCommandValue(jsEditor()->commandImp(command));
3182 }
3183 
3184 // ----------------------------------------------------------------------------
3185 // DOM3 XPath, from XPathEvaluator interface
3186 
3187 khtml::XPathExpressionImpl *DocumentImpl::createExpression(DOMString &expression,
3188         khtml::XPathNSResolverImpl *resolver,
3189         int &exceptioncode)
3190 {
3191     XPathExpressionImpl *cand = new XPathExpressionImpl(expression, resolver);
3192     if ((exceptioncode = cand->parseExceptionCode())) {
3193         delete cand;
3194         return nullptr;
3195     }
3196 
3197     return cand;
3198 }
3199 
3200 khtml::XPathNSResolverImpl *DocumentImpl::createNSResolver(NodeImpl *nodeResolver)
3201 {
3202     return nodeResolver ? new DefaultXPathNSResolverImpl(nodeResolver) : nullptr;
3203 }
3204 
3205 khtml::XPathResultImpl *DocumentImpl::evaluate(DOMString &expression,
3206         NodeImpl *contextNode,
3207         khtml::XPathNSResolverImpl *resolver,
3208         unsigned short type,
3209         khtml::XPathResultImpl * /*result*/,
3210         int &exceptioncode)
3211 {
3212     XPathExpressionImpl *expr = createExpression(expression, resolver, exceptioncode);
3213     if (exceptioncode) {
3214         delete expr;
3215         return nullptr;
3216     }
3217 
3218     XPathResultImpl *res = expr->evaluate(contextNode, type, nullptr, exceptioncode);
3219     delete expr;  // don't need it anymore.
3220 
3221     if (exceptioncode) {
3222         delete res;
3223         return nullptr;
3224     }
3225 
3226     return res;
3227 }
3228 // ----------------------------------------------------------------------------
3229 
3230 WindowEventTargetImpl::WindowEventTargetImpl(DOM::DocumentImpl *owner):
3231     m_owner(owner)
3232 {}
3233 
3234 EventTargetImpl::Type WindowEventTargetImpl::eventTargetType() const
3235 {
3236     return WINDOW;
3237 }
3238 
3239 DocumentImpl *WindowEventTargetImpl::eventTargetDocument()
3240 {
3241     return m_owner;
3242 }
3243 
3244 KJS::Window *WindowEventTargetImpl::window()
3245 {
3246     if (m_owner->part()) {
3247         return KJS::Window::retrieveWindow(m_owner->part());
3248     } else {
3249         return nullptr;
3250     }
3251 }
3252 // ----------------------------------------------------------------------------
3253 
3254 DocumentFragmentImpl::DocumentFragmentImpl(DocumentImpl *doc) : NodeBaseImpl(doc)
3255 {
3256 }
3257 
3258 DOMString DocumentFragmentImpl::nodeName() const
3259 {
3260     return "#document-fragment";
3261 }
3262 
3263 unsigned short DocumentFragmentImpl::nodeType() const
3264 {
3265     return Node::DOCUMENT_FRAGMENT_NODE;
3266 }
3267 
3268 // DOM Section 1.1.1
3269 bool DocumentFragmentImpl::childTypeAllowed(unsigned short type)
3270 {
3271     switch (type) {
3272     case Node::ELEMENT_NODE:
3273     case Node::PROCESSING_INSTRUCTION_NODE:
3274     case Node::COMMENT_NODE:
3275     case Node::TEXT_NODE:
3276     case Node::CDATA_SECTION_NODE:
3277     case Node::ENTITY_REFERENCE_NODE:
3278         return true;
3279         break;
3280     default:
3281         return false;
3282     }
3283 }
3284 
3285 DOMString DocumentFragmentImpl::toString() const
3286 {
3287     DOMString result;
3288 
3289     for (NodeImpl *child = firstChild(); child != nullptr; child = child->nextSibling()) {
3290         if (child->nodeType() == Node::COMMENT_NODE || child->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) {
3291             continue;
3292         }
3293         result += child->toString();
3294     }
3295 
3296     return result;
3297 }
3298 
3299 WTF::PassRefPtr<NodeImpl> DocumentFragmentImpl::cloneNode(bool deep)
3300 {
3301     WTF::RefPtr<DocumentFragmentImpl> clone = new DocumentFragmentImpl(docPtr());
3302     if (deep) {
3303         cloneChildNodes(clone.get());
3304     }
3305     return clone;
3306 }
3307 
3308 // ----------------------------------------------------------------------------
3309 
3310 DocumentTypeImpl::DocumentTypeImpl(DOMImplementationImpl *implementation, DocumentImpl *doc,
3311                                    const DOMString &qualifiedName, const DOMString &publicId,
3312                                    const DOMString &systemId)
3313     : NodeImpl(doc), m_implementation(implementation),
3314       m_qualifiedName(qualifiedName), m_publicId(publicId), m_systemId(systemId)
3315 {
3316     m_implementation->ref();
3317 
3318     m_entities = nullptr;
3319     m_notations = nullptr;
3320 
3321     // if doc is 0, it is not attached to a document and / or
3322     // therefore does not provide entities or notations. (DOM Level 3)
3323 }
3324 
3325 DocumentTypeImpl::~DocumentTypeImpl()
3326 {
3327     m_implementation->deref();
3328     if (m_entities) {
3329         m_entities->deref();
3330     }
3331     if (m_notations) {
3332         m_notations->deref();
3333     }
3334 }
3335 
3336 DOMString DocumentTypeImpl::toString() const
3337 {
3338     DOMString result = "<!DOCTYPE ";
3339     result += m_qualifiedName;
3340     if (!m_publicId.isEmpty()) {
3341         result += " PUBLIC \"";
3342         result += m_publicId;
3343         result += "\" \"";
3344         result += m_systemId;
3345         result += "\"";
3346     } else if (!m_systemId.isEmpty()) {
3347         result += " SYSTEM \"";
3348         result += m_systemId;
3349         result += "\"";
3350     }
3351 
3352     if (!m_subset.isEmpty()) {
3353         result += " [";
3354         result += m_subset;
3355         result += "]";
3356     }
3357 
3358     result += ">";
3359 
3360     return result;
3361 }
3362 
3363 DOMString DocumentTypeImpl::nodeName() const
3364 {
3365     return name();
3366 }
3367 
3368 unsigned short DocumentTypeImpl::nodeType() const
3369 {
3370     return Node::DOCUMENT_TYPE_NODE;
3371 }
3372 
3373 // DOM Section 1.1.1
3374 bool DocumentTypeImpl::childTypeAllowed(unsigned short /*type*/)
3375 {
3376     return false;
3377 }
3378 
3379 WTF::PassRefPtr<NodeImpl> DocumentTypeImpl::cloneNode(bool /*deep*/)
3380 {
3381     DocumentTypeImpl *clone = new DocumentTypeImpl(implementation(),
3382             nullptr,
3383             name(), publicId(),
3384             systemId());
3385     // ### copy entities etc.
3386     return clone;
3387 }
3388 
3389 NamedNodeMapImpl *DocumentTypeImpl::entities() const
3390 {
3391     if (!m_entities) {
3392         m_entities = new GenericRONamedNodeMapImpl(docPtr());
3393         m_entities->ref();
3394     }
3395     return m_entities;
3396 }
3397 
3398 NamedNodeMapImpl *DocumentTypeImpl::notations() const
3399 {
3400     if (!m_notations) {
3401         m_notations = new GenericRONamedNodeMapImpl(docPtr());
3402         m_notations->ref();
3403     }
3404     return m_notations;
3405 }
3406 
3407 void XMLDocumentImpl::close()
3408 {
3409     bool doload = !parsing() && m_tokenizer;
3410 
3411     DocumentImpl::close();
3412 
3413     if (doload) {
3414         document()->dispatchWindowEvent(EventImpl::LOAD_EVENT, false, false);
3415     }
3416 }
3417 
3418 #include "moc_dom_docimpl.cpp"