File indexing completed on 2024-04-28 11:39:31
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"