KHtml

dom_docimpl.cpp
1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll ([email protected])
5  * (C) 1999 Antti Koivisto ([email protected])
6  * (C) 2001 Dirk Mueller ([email protected])
7  * (C) 2002-2006 Apple Computer, Inc.
8  * (C) 2006 Allan Sandfeld Jensen ([email protected])
9  * (C) 2005 Frerich Raabe <[email protected]>
10  * (C) 2010 Maksim Orlovich <[email protected]>
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public License
23  * along with this library; see the file COPYING.LIB. If not, write to
24  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27 
28 #include "dom_docimpl.h"
29 
30 #include <dom/dom_exception.h>
31 
32 #include "dom_textimpl.h"
33 #include "dom_xmlimpl.h"
34 #include "dom2_rangeimpl.h"
35 #include "dom2_eventsimpl.h"
36 #include "xml_tokenizer.h"
37 #include <html/htmltokenizer.h>
38 #include "dom_restyler.h"
39 
40 #include <css/cssstyleselector.h>
41 #include <css/css_stylesheetimpl.h>
42 #include <misc/seed.h>
43 #include <misc/loader.h>
44 #include <ecma/kjs_proxy.h>
45 #include <ecma/kjs_binding.h>
46 
47 #include <QStack>
48 //Added by qt3to4:
49 #include "khtml_debug.h"
50 #include <klocalizedstring.h>
51 
52 #include <rendering/counter_tree.h>
53 #include <rendering/render_canvas.h>
54 #include <rendering/render_replaced.h>
55 #include <rendering/render_arena.h>
56 #include <rendering/render_layer.h>
57 #include <rendering/render_frames.h>
58 #include <rendering/render_image.h>
59 
60 #include <khtmlview.h>
61 #include <khtml_part.h>
62 #include <kurlauthorized.h>
63 #include <khtml_settings.h>
64 #include <khtmlpart_p.h>
65 
66 #include <xml/dom3_xpathimpl.h>
67 #include <html/html_baseimpl.h>
68 #include <html/html_blockimpl.h>
69 #include <html/html_canvasimpl.h>
70 #include <html/html_documentimpl.h>
71 #include <html/html_formimpl.h>
72 #include <html/html_headimpl.h>
73 #include <html/html_imageimpl.h>
74 #include <html/html_listimpl.h>
75 #include <html/html_miscimpl.h>
76 #include <html/html_tableimpl.h>
77 #include <html/html_objectimpl.h>
78 #include <html/HTMLAudioElement.h>
79 #include <html/HTMLVideoElement.h>
80 #include <html/HTMLSourceElement.h>
81 #include <editing/jsediting.h>
82 
83 #include <ecma/kjs_window.h>
84 
85 // SVG (WebCore)
86 #include <svg/SVGElement.h>
87 #include <svg/SVGSVGElement.h>
88 #include <svg/SVGNames.h>
89 #include <svg/SVGDocumentExtensions.h>
90 #include <svg/SVGRectElement.h>
91 #include <svg/SVGDocument.h>
92 #include <svg/SVGCircleElement.h>
93 #include <svg/SVGStyleElement.h>
94 #include <svg/SVGEllipseElement.h>
95 #include <svg/SVGPolygonElement.h>
96 #include <svg/SVGPolylineElement.h>
97 #include <svg/SVGPathElement.h>
98 #include <svg/SVGDefsElement.h>
99 #include <svg/SVGLinearGradientElement.h>
100 #include <svg/SVGRadialGradientElement.h>
101 #include <svg/SVGStopElement.h>
102 #include <svg/SVGClipPathElement.h>
103 #include <svg/SVGGElement.h>
104 #include <svg/SVGUseElement.h>
105 #include <svg/SVGLineElement.h>
106 #include <svg/SVGTextElement.h>
107 #include <svg/SVGAElement.h>
108 #include <svg/SVGScriptElement.h>
109 #include <svg/SVGDescElement.h>
110 #include <svg/SVGTitleElement.h>
111 #include <svg/SVGTextPathElement.h>
112 #include <svg/SVGTSpanElement.h>
113 #include <svg/SVGHKernElement.h>
114 #include <svg/SVGAltGlyphElement.h>
115 #include <svg/SVGFontElement.h>
116 
117 #include <kio/job.h>
118 #include <QFontDatabase>
119 
120 #include <stdlib.h>
121 #include <limits.h>
122 
123 #undef FOCUS_EVENT // for win32, MinGW
124 
125 template class QStack<DOM::NodeImpl *>;
126 
127 using namespace DOM;
128 using namespace khtml;
129 
130 // ------------------------------------------------------------------------
131 
132 DOMImplementationImpl::DOMImplementationImpl()
133 {
134 }
135 
136 DOMImplementationImpl::~DOMImplementationImpl()
137 {
138 }
139 
140 bool DOMImplementationImpl::hasFeature(const DOMString &feature, const DOMString &version)
141 {
142  // ### update when we (fully) support the relevant features
143  QString lower = feature.string().toLower();
144  if ((lower == "html" || lower == "xml") &&
145  (version.isEmpty() || version == "1.0" || version == "2.0")) {
146  return true;
147  }
148 
149  // ## Do we support Core Level 3 ?
150  if ((lower == "core") &&
151  (version.isEmpty() || version == "2.0")) {
152  return true;
153  }
154 
155  if ((lower == "traversal") &&
156  (version.isEmpty() || version == "2.0")) {
157  return true;
158  }
159 
160  if ((lower == "css") &&
161  (version.isEmpty() || version == "2.0")) {
162  return true;
163  }
164 
165  if ((lower == "events" || lower == "uievents" ||
166  lower == "mouseevents" || lower == "mutationevents" ||
167  lower == "htmlevents" || lower == "textevents") &&
168  (version.isEmpty() || version == "2.0" || version == "3.0")) {
169  return true;
170  }
171 
172  if (lower == "selectors-api" && version == "1.0") {
173  return true;
174  }
175 
176  return false;
177 }
178 
179 DocumentTypeImpl *DOMImplementationImpl::createDocumentType(const DOMString &qualifiedName, const DOMString &publicId,
180  const DOMString &systemId, int &exceptioncode)
181 {
182  // Not mentioned in spec: throw NAMESPACE_ERR if no qualifiedName supplied
183  if (qualifiedName.isNull()) {
184  exceptioncode = DOMException::NAMESPACE_ERR;
185  return nullptr;
186  }
187 
188  // INVALID_CHARACTER_ERR: Raised if the specified qualified name contains an illegal character.
189  if (!Element::khtmlValidQualifiedName(qualifiedName)) {
190  exceptioncode = DOMException::INVALID_CHARACTER_ERR;
191  return nullptr;
192  }
193 
194  // NAMESPACE_ERR: Raised if the qualifiedName is malformed.
195  // Added special case for the empty string, which seems to be a common pre-DOM2 misuse
196  if (!qualifiedName.isEmpty() && Element::khtmlMalformedQualifiedName(qualifiedName)) {
197  exceptioncode = DOMException::NAMESPACE_ERR;
198  return nullptr;
199  }
200 
201  return new DocumentTypeImpl(this, nullptr, qualifiedName, publicId, systemId);
202 }
203 
204 DocumentImpl *DOMImplementationImpl::createDocument(const DOMString &namespaceURI, const DOMString &qualifiedName,
205  DocumentTypeImpl *dtype,
206  KHTMLView *v,
207  int &exceptioncode)
208 {
209  exceptioncode = 0;
210 
211  if (!checkQualifiedName(qualifiedName, namespaceURI, nullptr, true/*nameCanBeNull*/,
212  true /*nameCanBeEmpty, see #61650*/, &exceptioncode)) {
213  return nullptr;
214  }
215 
216  // WRONG_DOCUMENT_ERR: Raised if doctype has already been used with a different document or was
217  // created from a different implementation.
218  // We elide the "different implementation" case here, since we're not doing interop
219  // of different implementations, and different impl objects exist only for
220  // isolation reasons
221  if (dtype && dtype->document()) {
222  exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
223  return nullptr;
224  }
225 
226  // ### view can be 0 which can cause problems
227  DocumentImpl *doc;
228  if (namespaceURI == XHTML_NAMESPACE) {
229  doc = new HTMLDocumentImpl(v);
230  } else {
231  doc = new DocumentImpl(v);
232  }
233 
234  if (dtype) {
235  dtype->setDocument(doc);
236  doc->appendChild(dtype, exceptioncode);
237  }
238 
239  // the document must be created empty if all parameters are null
240  // (or empty for qName/nsURI as a tolerance) - see DOM 3 Core.
241  if (dtype || !qualifiedName.isEmpty() || !namespaceURI.isEmpty()) {
242  ElementImpl *element = doc->createElementNS(namespaceURI, qualifiedName);
243  doc->appendChild(element, exceptioncode);
244  if (exceptioncode) {
245  delete element;
246  delete doc;
247  return nullptr;
248  }
249  }
250  return doc;
251 }
252 
253 CSSStyleSheetImpl *DOMImplementationImpl::createCSSStyleSheet(DOMStringImpl *title, DOMStringImpl *media,
254  int &/*exceptioncode*/)
255 {
256  // ### TODO : media could have wrong syntax, in which case we should
257  // generate an exception.
258  CSSStyleSheetImpl *parent = nullptr;
259  CSSStyleSheetImpl *sheet = new CSSStyleSheetImpl(parent, DOMString());
260  sheet->setMedia(new MediaListImpl(sheet, media, true /*fallbackToDescriptor*/));
261  sheet->setTitle(DOMString(title));
262  return sheet;
263 }
264 
265 DocumentImpl *DOMImplementationImpl::createDocument(KHTMLView *v)
266 {
267  DocumentImpl *doc = new DocumentImpl(v);
268 
269  return doc;
270 }
271 
272 XMLDocumentImpl *DOMImplementationImpl::createXMLDocument(KHTMLView *v)
273 {
274  XMLDocumentImpl *doc = new XMLDocumentImpl(v);
275 
276  return doc;
277 }
278 
279 HTMLDocumentImpl *DOMImplementationImpl::createHTMLDocument(KHTMLView *v)
280 {
281  HTMLDocumentImpl *doc = new HTMLDocumentImpl(v);
282 
283  return doc;
284 }
285 
286 // create SVG document
287 WebCore::SVGDocument *DOMImplementationImpl::createSVGDocument(KHTMLView *v)
288 {
289  WebCore::SVGDocument *doc = new WebCore::SVGDocument(v);
290 
291  return doc;
292 }
293 
294 HTMLDocumentImpl *DOMImplementationImpl::createHTMLDocument(const DOMString &title)
295 {
296  HTMLDocumentImpl *r = createHTMLDocument(nullptr /* ### create a view otherwise it doesn't work */);
297 
298  r->open();
299 
300  r->write(QLatin1String("<HTML><HEAD><TITLE>") + title.string() +
301  QLatin1String("</TITLE></HEAD>"));
302 
303  return r;
304 }
305 
306 // ------------------------------------------------------------------------
307 
308 ElementMappingCache::ElementMappingCache(): m_dict()
309 {
310 }
311 
312 ElementMappingCache::~ElementMappingCache()
313 {
314  qDeleteAll(m_dict);
315 }
316 
317 void ElementMappingCache::add(const DOMString &id, ElementImpl *nd)
318 {
319  if (id.isEmpty()) {
320  return;
321  }
322 
323  ItemInfo *info = m_dict.value(id);
324  if (info) {
325  info->ref++;
326  info->nd = nullptr; //Now ambigous
327  } else {
328  ItemInfo *info = new ItemInfo();
329  info->ref = 1;
330  info->nd = nd;
331  m_dict.insert(id, info);
332  }
333 }
334 
335 void ElementMappingCache::set(const DOMString &id, ElementImpl *nd)
336 {
337  if (id.isEmpty()) {
338  return;
339  }
340 
341  assert(m_dict.contains(id));
342  ItemInfo *info = m_dict.value(id);
343  info->nd = nd;
344 }
345 
346 void ElementMappingCache::remove(const DOMString &id, ElementImpl *nd)
347 {
348  if (id.isEmpty()) {
349  return;
350  }
351 
352  assert(m_dict.contains(id));
353  ItemInfo *info = m_dict.value(id);
354  info->ref--;
355  if (info->ref == 0) {
356  m_dict.take(id);
357  delete info;
358  } else {
359  if (info->nd == nd) {
360  info->nd = nullptr;
361  }
362  }
363 }
364 
366 {
367  if (id.isEmpty()) {
368  return false;
369  }
370  return m_dict.contains(id);
371 }
372 
374 {
375  if (id.isEmpty()) {
376  return nullptr;
377  }
378  return m_dict.value(id);
379 }
380 
382 Q_GLOBAL_STATIC(ChangedDocuments, s_changedDocuments)
383 
384 // KHTMLView might be 0
385 DocumentImpl::DocumentImpl(KHTMLView *v)
386  : NodeBaseImpl(nullptr), m_svgExtensions(nullptr), m_counterDict(),
387  m_imageLoadEventTimer(0)
388 {
389  m_document.resetSkippingRef(this); //Make document return us..
390  m_selfOnlyRefCount = 0;
391 
392  m_paintDevice = nullptr;
393  //m_decoderMibEnum = 0;
394  m_textColor = Qt::black;
395 
396  m_view = v;
397  m_renderArena.reset();
398 
399  KHTMLGlobal::registerDocumentImpl(this);
400 
401  if (v) {
402  m_docLoader = new DocLoader(v->part(), this);
403  setPaintDevice(m_view);
404  } else {
405  m_docLoader = new DocLoader(nullptr, this);
406  }
407 
408  visuallyOrdered = false;
409  m_bParsing = false;
410  m_docChanged = false;
411  m_elemSheet = nullptr;
412  m_tokenizer = nullptr;
413  m_decoder = nullptr;
414  m_doctype = nullptr;
415  m_implementation = nullptr;
416  pMode = Strict;
417  hMode = XHtml;
418  m_htmlCompat = false;
419  m_textColor = "#000000";
420  m_focusNode = nullptr;
421  m_hoverNode = nullptr;
422  m_activeNode = nullptr;
423  m_defaultView = new AbstractViewImpl(this);
424  m_defaultView->ref();
425  m_listenerTypes = 0;
426  m_styleSheets = new StyleSheetListImpl(this);
427  m_styleSheets->ref();
428  m_addedStyleSheets = nullptr;
429  m_inDocument = true;
430  m_styleSelectorDirty = false;
431  m_styleSelector = nullptr;
432  m_styleSheetListDirty = true;
433 
434  m_inStyleRecalc = false;
435  m_pendingStylesheets = 0;
436  m_ignorePendingStylesheets = false;
437  m_async = true;
438  m_hadLoadError = false;
439  m_docLoading = false;
440  m_bVariableLength = false;
441  m_inSyncLoad = nullptr;
442  m_loadingXMLDoc = nullptr;
443  m_documentElement = nullptr;
444  m_cssTarget = nullptr;
445  m_jsEditor = nullptr;
446  m_dynamicDomRestyler = new khtml::DynamicDomRestyler();
447  m_stateRestorePos = 0;
448  m_windowEventTarget = new WindowEventTargetImpl(this);
449  m_windowEventTarget->ref();
450 
451  for (int c = 0; c < NumTreeVersions; ++c) {
452  m_domTreeVersions[c] = 0;
453  }
454 }
455 
456 void DocumentImpl::removedLastRef()
457 {
458  if (m_selfOnlyRefCount) {
459  /* In this case, the only references to us are from children,
460  so we have a cycle. We'll try to break it by disconnecting the
461  children from us; this sucks/is wrong, but it's pretty much
462  the best we can do without tracing.
463 
464  Of course, if dumping the children causes the refcount from them to
465  drop to 0 we can get killed right here, so better hold
466  a temporary reference, too
467  */
468  DocPtr<DocumentImpl> guard(this);
469 
470  // we must make sure not to be retaining any of our children through
471  // these extra pointers or we will create a reference cycle
472  if (m_doctype) {
473  m_doctype->deref();
474  m_doctype = nullptr;
475  }
476 
477  if (m_cssTarget) {
478  m_cssTarget->deref();
479  m_cssTarget = nullptr;
480  }
481 
482  if (m_focusNode) {
483  m_focusNode->deref();
484  m_focusNode = nullptr;
485  }
486 
487  if (m_hoverNode) {
488  m_hoverNode->deref();
489  m_hoverNode = nullptr;
490  }
491 
492  if (m_activeNode) {
493  m_activeNode->deref();
494  m_activeNode = nullptr;
495  }
496 
497  if (m_documentElement) {
498  m_documentElement->deref();
499  m_documentElement = nullptr;
500  }
501 
502  removeChildren();
503 
504  delete m_tokenizer;
505  m_tokenizer = nullptr;
506  } else {
507  delete this;
508  }
509 }
510 
511 DocumentImpl::~DocumentImpl()
512 {
513  //Important: if you need to remove stuff here,
514  //you may also have to fix removedLastRef() above - M.O.
515  assert(!m_render);
516 
518  while (it.hasNext()) {
519  it.next().value()->deref();
520  }
521 
522  if (m_loadingXMLDoc) {
523  m_loadingXMLDoc->deref(this);
524  }
525  if (s_changedDocuments() && m_docChanged) {
526  s_changedDocuments()->removeAll(this);
527  }
528  delete m_tokenizer;
529  m_document.resetSkippingRef(nullptr);
530  delete m_styleSelector;
531  delete m_docLoader;
532  if (m_elemSheet) {
533  m_elemSheet->deref();
534  }
535  if (m_doctype) {
536  m_doctype->deref();
537  }
538  if (m_implementation) {
539  m_implementation->deref();
540  }
541  delete m_dynamicDomRestyler;
542  delete m_jsEditor;
543  m_defaultView->deref();
544  m_styleSheets->deref();
545  if (m_addedStyleSheets) {
546  m_addedStyleSheets->deref();
547  }
548  if (m_cssTarget) {
549  m_cssTarget->deref();
550  }
551  if (m_focusNode) {
552  m_focusNode->deref();
553  }
554  if (m_hoverNode) {
555  m_hoverNode->deref();
556  }
557  if (m_activeNode) {
558  m_activeNode->deref();
559  }
560  if (m_documentElement) {
561  m_documentElement->deref();
562  }
563  m_windowEventTarget->deref();
564  qDeleteAll(m_counterDict);
565 
566  m_renderArena.reset();
567 
568  KHTMLGlobal::deregisterDocumentImpl(this);
569 }
570 
571 DOMImplementationImpl *DocumentImpl::implementation() const
572 {
573  if (!m_implementation) {
574  m_implementation = new DOMImplementationImpl();
575  m_implementation->ref();
576  }
577  return m_implementation;
578 }
579 
580 void DocumentImpl::childrenChanged()
581 {
582  // invalidate the document element we have cached in case it was replaced
583  if (m_documentElement) {
584  m_documentElement->deref();
585  }
586  m_documentElement = nullptr;
587 
588  // same for m_docType
589  if (m_doctype) {
590  m_doctype->deref();
591  }
592  m_doctype = nullptr;
593 }
594 
595 ElementImpl *DocumentImpl::documentElement() const
596 {
597  if (!m_documentElement) {
598  NodeImpl *n = firstChild();
599  while (n && n->nodeType() != Node::ELEMENT_NODE) {
600  n = n->nextSibling();
601  }
602  m_documentElement = static_cast<ElementImpl *>(n);
603  if (m_documentElement) {
604  m_documentElement->ref();
605  }
606  }
607  return m_documentElement;
608 }
609 
610 DocumentTypeImpl *DocumentImpl::doctype() const
611 {
612  if (!m_doctype) {
613  NodeImpl *n = firstChild();
614  while (n && n->nodeType() != Node::DOCUMENT_TYPE_NODE) {
615  n = n->nextSibling();
616  }
617  m_doctype = static_cast<DocumentTypeImpl *>(n);
618  if (m_doctype) {
619  m_doctype->ref();
620  }
621  }
622  return m_doctype;
623 }
624 
625 ElementImpl *DocumentImpl::createElement(const DOMString &name, int *pExceptioncode)
626 {
627  if (pExceptioncode && !Element::khtmlValidQualifiedName(name)) {
628  *pExceptioncode = DOMException::INVALID_CHARACTER_ERR;
629  return nullptr;
630  }
631 
632  PrefixName prefix;
633  LocalName localName;
634  bool htmlCompat = htmlMode() != XHtml;
635  splitPrefixLocalName(name, prefix, localName, htmlCompat);
636  XMLElementImpl *e = new XMLElementImpl(document(), emptyNamespaceName, localName, prefix);
637  e->setHTMLCompat(htmlCompat); // Not a real HTML element, but inside an html-compat doc all tags are uppercase.
638  return e;
639 }
640 
641 AttrImpl *DocumentImpl::createAttribute(const DOMString &tagName, int *pExceptioncode)
642 {
643  if (pExceptioncode && !Element::khtmlValidAttrName(tagName)) {
644  *pExceptioncode = DOMException::INVALID_CHARACTER_ERR;
645  return nullptr;
646  }
647 
648  PrefixName prefix;
649  LocalName localName;
650  bool htmlCompat = (htmlMode() != XHtml);
651  splitPrefixLocalName(tagName, prefix, localName, htmlCompat);
652 
653  AttrImpl *attr = new AttrImpl(nullptr, document(), NamespaceName::fromId(emptyNamespace),
654  localName, prefix, DOMString("").implementation());
655  attr->setHTMLCompat(htmlCompat);
656  return attr;
657 }
658 
659 DocumentFragmentImpl *DocumentImpl::createDocumentFragment()
660 {
661  return new DocumentFragmentImpl(docPtr());
662 }
663 
664 CommentImpl *DocumentImpl::createComment(DOMStringImpl *data)
665 {
666  return new CommentImpl(docPtr(), data);
667 }
668 
669 CDATASectionImpl *DocumentImpl::createCDATASection(DOMStringImpl *data, int &exceptioncode)
670 {
671  if (isHTMLDocument()) {
672  exceptioncode = DOMException::NOT_SUPPORTED_ERR;
673  return nullptr;
674  }
675  return new CDATASectionImpl(docPtr(), data);
676 }
677 
678 ProcessingInstructionImpl *DocumentImpl::createProcessingInstruction(const DOMString &target, DOMStringImpl *data)
679 {
680  return new ProcessingInstructionImpl(docPtr(), target, data);
681 }
682 
683 EntityReferenceImpl *DocumentImpl::createEntityReference(const DOMString &name, int &exceptioncode)
684 {
685  if (isHTMLDocument()) {
686  exceptioncode = DOMException::NOT_SUPPORTED_ERR;
687  return nullptr;
688  }
689  return new EntityReferenceImpl(docPtr(), name.implementation());
690 }
691 
692 EditingTextImpl *DocumentImpl::createEditingTextNode(const DOMString &text)
693 {
694  return new EditingTextImpl(docPtr(), text);
695 }
696 
697 NodeImpl *DocumentImpl::importNode(NodeImpl *importedNode, bool deep, int &exceptioncode)
698 {
699  NodeImpl *result = nullptr;
700 
701  // Not mentioned in spec: throw NOT_FOUND_ERR if evt is null
702  if (!importedNode) {
703  exceptioncode = DOMException::NOT_FOUND_ERR;
704  return nullptr;
705  }
706 
707  if (importedNode->nodeType() == Node::ELEMENT_NODE) {
708  // Why not use cloneNode?
709  ElementImpl *otherElem = static_cast<ElementImpl *>(importedNode);
710  NamedAttrMapImpl *otherMap = static_cast<ElementImpl *>(importedNode)->attributes(true);
711 
712  ElementImpl *tempElementImpl;
713  tempElementImpl = createElementNS(otherElem->namespaceURI(), otherElem->nonCaseFoldedTagName());
714  tempElementImpl->setHTMLCompat(htmlMode() != XHtml && otherElem->htmlCompat());
715  result = tempElementImpl;
716 
717  if (otherMap) {
718  for (unsigned i = 0; i < otherMap->length(); i++) {
719  AttrImpl *otherAttr = otherMap->attributeAt(i).createAttr(otherElem, otherElem->docPtr());
720 
721  tempElementImpl->setAttributeNS(otherAttr->namespaceURI(),
722  otherAttr->name(),
723  otherAttr->nodeValue(),
724  exceptioncode);
725 
726  if (exceptioncode != 0) {
727  break; // ### properly cleanup here
728  }
729  }
730  }
731  } else if (importedNode->nodeType() == Node::TEXT_NODE) {
732  result = createTextNode(static_cast<TextImpl *>(importedNode)->string());
733  deep = false;
734  } else if (importedNode->nodeType() == Node::CDATA_SECTION_NODE) {
735  result = createCDATASection(static_cast<CDATASectionImpl *>(importedNode)->string(), exceptioncode);
736  deep = false;
737  } else if (importedNode->nodeType() == Node::ENTITY_REFERENCE_NODE) {
738  result = createEntityReference(importedNode->nodeName(), exceptioncode);
739  } else if (importedNode->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) {
740  result = createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue().implementation());
741  deep = false;
742  } else if (importedNode->nodeType() == Node::COMMENT_NODE) {
743  result = createComment(static_cast<CommentImpl *>(importedNode)->string());
744  deep = false;
745  } else if (importedNode->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) {
746  result = createDocumentFragment();
747  } else {
748  exceptioncode = DOMException::NOT_SUPPORTED_ERR;
749  }
750 
751  //### FIXME: This should handle Attributes, and a few other things
752 
753  if (deep && result) {
754  for (Node n = importedNode->firstChild(); !n.isNull(); n = n.nextSibling()) {
755  result->appendChild(importNode(n.handle(), true, exceptioncode), exceptioncode);
756  }
757  }
758 
759  return result;
760 }
761 
762 ElementImpl *DocumentImpl::createElementNS(const DOMString &_namespaceURI, const DOMString &_qualifiedName, int *pExceptioncode)
763 {
764  ElementImpl *e = nullptr;
765  int colonPos = -2;
766  // check NAMESPACE_ERR/INVALID_CHARACTER_ERR
767  if (pExceptioncode && !checkQualifiedName(_qualifiedName, _namespaceURI, &colonPos,
768  false/*nameCanBeNull*/, false/*nameCanBeEmpty*/,
769  pExceptioncode)) {
770  return nullptr;
771  }
772  DOMString prefix, localName;
773  splitPrefixLocalName(_qualifiedName.implementation(), prefix, localName, colonPos);
774 
775  if (_namespaceURI == SVG_NAMESPACE) {
776  e = createSVGElement(QualifiedName(prefix, localName, _namespaceURI));
777  if (e) {
778  return e;
779  }
780  if (!e) {
781  qCWarning(KHTML_LOG) << "svg element" << localName << "either is not supported by khtml or it's not a proper svg element";
782  }
783  }
784 
785  // Regardless of document type (even for HTML), this method will only create HTML
786  // elements if given the namespace explicitly. Further, this method is always
787  // case sensitive, again, even in HTML; however .tagName will case-normalize
788  // in HTML regardless
789  if (_namespaceURI == XHTML_NAMESPACE) {
790  e = createHTMLElement(localName, false /* case sensitive */);
791  int _exceptioncode = 0;
792  if (!prefix.isNull()) {
793  e->setPrefix(prefix, _exceptioncode);
794  }
795  if (_exceptioncode) {
796  if (pExceptioncode) {
797  *pExceptioncode = _exceptioncode;
798  }
799  delete e;
800  return nullptr;
801  }
802  }
803  if (!e) {
804  e = new XMLElementImpl(document(), NamespaceName::fromString(_namespaceURI),
805  LocalName::fromString(localName), PrefixName::fromString(prefix));
806  }
807 
808  return e;
809 }
810 
811 AttrImpl *DocumentImpl::createAttributeNS(const DOMString &_namespaceURI,
812  const DOMString &_qualifiedName, int *pExceptioncode)
813 {
814  int colonPos = -2;
815  // check NAMESPACE_ERR/INVALID_CHARACTER_ERR
816  if (pExceptioncode && !checkQualifiedName(_qualifiedName, _namespaceURI, &colonPos,
817  false/*nameCanBeNull*/, false/*nameCanBeEmpty*/,
818  pExceptioncode)) {
819  return nullptr;
820  }
821  PrefixName prefix;
822  LocalName localName;
823  bool htmlCompat = _namespaceURI.isNull() && htmlMode() != XHtml;
824  splitPrefixLocalName(_qualifiedName, prefix, localName, false, colonPos);
825  AttrImpl *attr = new AttrImpl(nullptr, document(), NamespaceName::fromString(_namespaceURI),
826  localName, prefix, DOMString("").implementation());
827  attr->setHTMLCompat(htmlCompat);
828  return attr;
829 }
830 
831 ElementImpl *DocumentImpl::getElementById(const DOMString &elementId) const
832 {
833  ElementMappingCache::ItemInfo *info = m_getElementByIdCache.get(elementId);
834 
835  if (!info) {
836  return nullptr;
837  }
838 
839  //See if cache has an unambiguous answer.
840  if (info->nd) {
841  return info->nd;
842  }
843 
844  //Now we actually have to walk.
845  QStack<NodeImpl *> nodeStack;
846  NodeImpl *current = _first;
847 
848  while (1) {
849  if (!current) {
850  if (nodeStack.isEmpty()) {
851  break;
852  }
853  current = nodeStack.pop();
854  current = current->nextSibling();
855  } else {
856  if (current->isElementNode()) {
857  ElementImpl *e = static_cast<ElementImpl *>(current);
858  if (e->getAttribute(ATTR_ID) == elementId) {
859  info->nd = e;
860  return e;
861  }
862  }
863 
864  NodeImpl *child = current->firstChild();
865  if (child) {
866  nodeStack.push(current);
867  current = child;
868  } else {
869  current = current->nextSibling();
870  }
871  }
872  }
873 
874  assert(0); //If there is no item with such an ID, we should never get here
875 
876  //qCDebug(KHTML_LOG) << "WARNING: *DocumentImpl::getElementById not found " << elementId.string();
877 
878  return nullptr;
879 }
880 
881 void DocumentImpl::setTitle(const DOMString &_title)
882 {
883  if (_title == m_title && !m_title.isNull()) {
884  return;
885  }
886 
887  m_title = _title;
888 
889  QString titleStr = m_title.string();
890  for (int i = 0; i < titleStr.length(); ++i)
891  if (titleStr[i] < ' ') {
892  titleStr[i] = ' ';
893  }
894  titleStr = titleStr.simplified();
895  if (view() && !view()->part()->parentPart()) {
896  if (titleStr.isEmpty()) {
897  // empty title... set window caption as the URL
898  QUrl url = m_url;
899  url.setFragment(QString());
900  url.setQuery(QString());
901  titleStr = url.toDisplayString();
902  }
903 
904  emit view()->part()->setWindowCaption(titleStr);
905  }
906 }
907 
908 DOMString DocumentImpl::nodeName() const
909 {
910  return "#document";
911 }
912 
913 unsigned short DocumentImpl::nodeType() const
914 {
915  return Node::DOCUMENT_NODE;
916 }
917 
918 ElementImpl *DocumentImpl::createHTMLElement(const DOMString &name, bool caseInsensitive)
919 {
920  LocalName localname = LocalName::fromString(name,
921  caseInsensitive ? IDS_NormalizeLower : IDS_CaseSensitive);
922  uint id = localname.id();
923 
924  ElementImpl *n = nullptr;
925  switch (id) {
926  case ID_HTML:
927  n = new HTMLHtmlElementImpl(docPtr());
928  break;
929  case ID_HEAD:
930  n = new HTMLHeadElementImpl(docPtr());
931  break;
932  case ID_BODY:
933  n = new HTMLBodyElementImpl(docPtr());
934  break;
935 
936 // head elements
937  case ID_BASE:
938  n = new HTMLBaseElementImpl(docPtr());
939  break;
940  case ID_LINK:
941  n = new HTMLLinkElementImpl(docPtr());
942  break;
943  case ID_META:
944  n = new HTMLMetaElementImpl(docPtr());
945  break;
946  case ID_STYLE:
947  n = new HTMLStyleElementImpl(docPtr());
948  break;
949  case ID_TITLE:
950  n = new HTMLTitleElementImpl(docPtr());
951  break;
952 
953 // frames
954  case ID_FRAME:
955  n = new HTMLFrameElementImpl(docPtr());
956  break;
957  case ID_FRAMESET:
958  n = new HTMLFrameSetElementImpl(docPtr());
959  break;
960  case ID_IFRAME:
961  n = new HTMLIFrameElementImpl(docPtr());
962  break;
963 
964 // form elements
965 // ### FIXME: we need a way to set form dependency after we have made the form elements
966  case ID_FORM:
967  n = new HTMLFormElementImpl(docPtr(), false);
968  break;
969  case ID_BUTTON:
970  n = new HTMLButtonElementImpl(docPtr());
971  break;
972  case ID_FIELDSET:
973  n = new HTMLFieldSetElementImpl(docPtr());
974  break;
975  case ID_INPUT:
976  n = new HTMLInputElementImpl(docPtr());
977  break;
978  case ID_ISINDEX:
979  n = new HTMLIsIndexElementImpl(docPtr());
980  break;
981  case ID_LABEL:
982  n = new HTMLLabelElementImpl(docPtr());
983  break;
984  case ID_LEGEND:
985  n = new HTMLLegendElementImpl(docPtr());
986  break;
987  case ID_OPTGROUP:
988  n = new HTMLOptGroupElementImpl(docPtr());
989  break;
990  case ID_OPTION:
991  n = new HTMLOptionElementImpl(docPtr());
992  break;
993  case ID_SELECT:
994  n = new HTMLSelectElementImpl(docPtr());
995  break;
996  case ID_TEXTAREA:
997  n = new HTMLTextAreaElementImpl(docPtr());
998  break;
999 
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;
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 {
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;
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;
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.
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--;
2232  if (!m_pendingStylesheets && m_tokenizer) {
2233  m_tokenizer->executeScriptsWaitingForStylesheets();
2234  }
2235 }
2236 
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();
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()) {
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) {
2307  }
2308  } else {
2309  excode = DOMException::NOT_FOUND_ERR;
2310  }
2311 
2312  if (exceptioncode) {
2313  *exceptioncode = excode;
2314  }
2315 }
2316 
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"
This file is part of the HTML rendering engine for KDE.
void append(const T &value)
int timerId() const const
void remove(const DOMString &id, ElementImpl *nd)
Remove the item; it must have already been added.
int startTimer(int interval, Qt::TimerType timerType)
bool isNull() const const
bool isEmpty() const const
DOMString trimSpaces() const
Returns a string with Space Characters removed from the start and the end.
Definition: dom_string.cpp:345
void styleSheetLoaded()
Updates the pending sheet count and then calls updateStyleSelector.
void append(const T &value)
QString number(int n, int base)
CaseInsensitive
void setEditable(bool enable)
Makes the document editable.
bool isEditable() const
Returns true if the document is editable, false otherwise.
Introduced in DOM Level 2.
Definition: dom2_events.h:69
NodeImpl * nextFocusNode(NodeImpl *fromNode)
Searches through the document, starting from fromNode, for the next selectable element that comes aft...
Type type(const QSqlDatabase &db)
QString scheme() const const
bool isRunning() const const
QDateTime currentDateTime()
void ref()
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
QString trimmed() const const
void clear()
QChar toUpper() const const
qlonglong toLongLong(bool *ok, int base) const const
bool hasNext() const const
void add(const DOMString &id, ElementImpl *nd)
Add a pointer as just one of candidates, not neccesserily the proper one.
void addPendingSheet()
Increments the number of pending sheets.
QString fromPercentEncoding(const QByteArray &input)
This library provides a full-featured HTML parser and widget.
This class is khtml's main class.
Definition: khtml_part.h:208
Base Class for all rendering tree objects.
int exec(QEventLoop::ProcessEventsFlags flags)
int logicalDpiY() const const
Node target() const
Used to indicate the EventTarget to which the event was originally dispatched.
bool authorizeUrlAction(const QString &action, const QUrl &baseUrl, const QUrl &destUrl)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
DOMString type() const
The name of the event (case-insensitive).
Definition: dom2_events.cpp:91
QString simplified() const const
void exit(int returnCode)
KHTMLPart * part() const
Returns a pointer to the KHTMLPart that is rendering the page.
Definition: khtmlview.h:139
void resize(int size)
void removeAt(int i)
For each name, we hold a reference count, and a pointer.
Definition: dom_docimpl.h:160
KGuiItem test()
int size() const const
Renders and displays HTML in a QScrollArea.
Definition: khtmlview.h:97
int fontScaleFactor() const
Returns the current font scale factor.
QString toString(QUrl::FormattingOptions options) const const
QString i18n(const char *text, const TYPE &arg...)
void updateStyleSelector(bool shallow=false)
Called when one or more stylesheets in the document may have been added, removed or changed.
the StyleSelector implementation for CSS.
bool haveStylesheetsLoaded() const
This method returns true if all top-level stylesheets have loaded (including any @imports that they m...
Definition: dom_docimpl.h:296
int indexOf(const T &value, int from) const const
void killTimer(int id)
bool isEmpty() const const
bool onlyLocalReferences() const
Returns whether only file:/ or data:/ references are allowed to be loaded ( default false ).
QByteArray toUtf8() const const
int length() const const
QString toDisplayString(QUrl::FormattingOptions options) const const
NodeImpl * previousFocusNode(NodeImpl *fromNode)
Searches through the document, starting from fromNode, for the previous selectable element (that come...
int removeAll(const T &value)
QDateTime fromString(const QString &string, Qt::DateFormat format)
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
QUrl resolved(const QUrl &relative) const const
uint toUInt(bool *ok, int base) const const
Introduced in DOM Level 2.
Definition: dom2_events.h:413
QString & replace(int position, int n, QChar after)
void setQuery(const QString &query, QUrl::ParsingMode mode)
void clear()
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
void set(const DOMString &id, ElementImpl *nd)
Set the pointer as the definite mapping; it must have already been added.
QString toLower() const const
QDateTime fromTime_t(uint seconds)
void scheduleRedirection(int delay, const QString &url, bool lockHistory=true)
Schedules a redirection after delay seconds.
void push(const T &t)
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
unsigned int version()
QString name(StandardShortcut id)
DOMString lower() const
Returns a lowercase version of the string.
Definition: dom_string.cpp:232
bool isEmpty() const const
KCOREADDONS_EXPORT bool isInside()
bool isValid() const const
void setFragment(const QString &fragment, QUrl::ParsingMode mode)
void clear()
Q_SCRIPTABLE Q_NOREPLY void abort()
KGuiItem reset()
void processHttpEquiv(const DOMString &equiv, const DOMString &content)
Handles a HTTP header equivalent set by a meta tag using <meta http-equiv="..." content="....
bool contains(const DOMString &id)
Returns true if the item exists.
KHTMLPart * parentPart()
Returns a pointer to the parent KHTMLPart if the part is a frame in an HTML frameset.
The Node interface is the primary datatype for the entire Document Object Model.
Definition: dom_node.h:278
bool isNull() const
tests if this Node is 0.
Definition: dom_node.h:928
void layout()
ensure the display is up to date
Definition: khtmlview.cpp:982
QString mid(int position, int n) const const
void setFocus()
ItemInfo * get(const DOMString &id)
Returns the information for the given ID.
Node firstChild() const
The first child of this node.
Definition: dom_node.cpp:266
void setWindowCaption(const QString &caption)
RFC2822Date
DOMStringImpl * implementation() const
Definition: dom_string.h:145
MESSAGECORE_EXPORT KMime::Content * firstChild(const KMime::Content *node)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Dec 5 2023 03:56:12 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.