1 /**
2 * This file is part of the DOM implementation for KDE.
3 *
4 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5 * (C) 1999 Antti Koivisto (koivisto@kde.org)
6 * (C) 2001 Dirk Mueller (mueller@kde.org)
7 * (C) 2002-2006 Apple Computer, Inc.
8 * (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com)
9 * (C) 2005 Frerich Raabe <raabe@kde.org>
10 * (C) 2010 Maksim Orlovich <maksim@kde.org>
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
DOMImplementationImpl()132 DOMImplementationImpl::DOMImplementationImpl()
133 {
134 }
135
~DOMImplementationImpl()136 DOMImplementationImpl::~DOMImplementationImpl()
137 {
138 }
139
hasFeature(const DOMString & feature,const DOMString & version)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
createDocumentType(const DOMString & qualifiedName,const DOMString & publicId,const DOMString & systemId,int & exceptioncode)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
createDocument(const DOMString & namespaceURI,const DOMString & qualifiedName,DocumentTypeImpl * dtype,KHTMLView * v,int & exceptioncode)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
createCSSStyleSheet(DOMStringImpl * title,DOMStringImpl * media,int &)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
createDocument(KHTMLView * v)265 DocumentImpl *DOMImplementationImpl::createDocument(KHTMLView *v)
266 {
267 DocumentImpl *doc = new DocumentImpl(v);
268
269 return doc;
270 }
271
createXMLDocument(KHTMLView * v)272 XMLDocumentImpl *DOMImplementationImpl::createXMLDocument(KHTMLView *v)
273 {
274 XMLDocumentImpl *doc = new XMLDocumentImpl(v);
275
276 return doc;
277 }
278
createHTMLDocument(KHTMLView * v)279 HTMLDocumentImpl *DOMImplementationImpl::createHTMLDocument(KHTMLView *v)
280 {
281 HTMLDocumentImpl *doc = new HTMLDocumentImpl(v);
282
283 return doc;
284 }
285
286 // create SVG document
createSVGDocument(KHTMLView * v)287 WebCore::SVGDocument *DOMImplementationImpl::createSVGDocument(KHTMLView *v)
288 {
289 WebCore::SVGDocument *doc = new WebCore::SVGDocument(v);
290
291 return doc;
292 }
293
createHTMLDocument(const DOMString & title)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
ElementMappingCache()308 ElementMappingCache::ElementMappingCache(): m_dict()
309 {
310 }
311
~ElementMappingCache()312 ElementMappingCache::~ElementMappingCache()
313 {
314 qDeleteAll(m_dict);
315 }
316
add(const DOMString & id,ElementImpl * nd)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
set(const DOMString & id,ElementImpl * nd)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
remove(const DOMString & id,ElementImpl * nd)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
contains(const DOMString & id)365 bool ElementMappingCache::contains(const DOMString &id)
366 {
367 if (id.isEmpty()) {
368 return false;
369 }
370 return m_dict.contains(id);
371 }
372
get(const DOMString & id)373 ElementMappingCache::ItemInfo *ElementMappingCache::get(const DOMString &id)
374 {
375 if (id.isEmpty()) {
376 return nullptr;
377 }
378 return m_dict.value(id);
379 }
380
381 typedef QList<DocumentImpl *> ChangedDocuments;
Q_GLOBAL_STATIC(ChangedDocuments,s_changedDocuments)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
removedLastRef()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
~DocumentImpl()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
517 QHashIterator<long, DynamicNodeListImpl::Cache *> it(m_nodeListCache);
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
implementation() const571 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
childrenChanged()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
documentElement() const595 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
doctype() const610 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
createElement(const DOMString & name,int * pExceptioncode)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
createAttribute(const DOMString & tagName,int * pExceptioncode)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
createDocumentFragment()659 DocumentFragmentImpl *DocumentImpl::createDocumentFragment()
660 {
661 return new DocumentFragmentImpl(docPtr());
662 }
663
createComment(DOMStringImpl * data)664 CommentImpl *DocumentImpl::createComment(DOMStringImpl *data)
665 {
666 return new CommentImpl(docPtr(), data);
667 }
668
createCDATASection(DOMStringImpl * data,int & exceptioncode)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
createProcessingInstruction(const DOMString & target,DOMStringImpl * data)678 ProcessingInstructionImpl *DocumentImpl::createProcessingInstruction(const DOMString &target, DOMStringImpl *data)
679 {
680 return new ProcessingInstructionImpl(docPtr(), target, data);
681 }
682
createEntityReference(const DOMString & name,int & exceptioncode)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
createEditingTextNode(const DOMString & text)692 EditingTextImpl *DocumentImpl::createEditingTextNode(const DOMString &text)
693 {
694 return new EditingTextImpl(docPtr(), text);
695 }
696
importNode(NodeImpl * importedNode,bool deep,int & exceptioncode)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
createElementNS(const DOMString & _namespaceURI,const DOMString & _qualifiedName,int * pExceptioncode)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
createAttributeNS(const DOMString & _namespaceURI,const DOMString & _qualifiedName,int * pExceptioncode)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
getElementById(const DOMString & elementId) const831 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
setTitle(const DOMString & _title)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
nodeName() const908 DOMString DocumentImpl::nodeName() const
909 {
910 return "#document";
911 }
912
nodeType() const913 unsigned short DocumentImpl::nodeType() const
914 {
915 return Node::DOCUMENT_NODE;
916 }
917
createHTMLElement(const DOMString & name,bool caseInsensitive)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
createSVGElement(const QualifiedName & name)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
attemptRestoreState(NodeImpl * n)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
docState()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
unsubmittedFormChanges()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
createRange()1387 RangeImpl *DocumentImpl::createRange()
1388 {
1389 return new RangeImpl(docPtr());
1390 }
1391
createNodeIterator(NodeImpl * root,unsigned long whatToShow,NodeFilterImpl * filter,bool entityReferenceExpansion,int & exceptioncode)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
createTreeWalker(NodeImpl * root,unsigned long whatToShow,NodeFilterImpl * filter,bool entityReferenceExpansion,int & exceptioncode)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
setDocumentChanged(bool b)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
recalcStyle(StyleChange change)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
updateRendering()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
updateDocumentsRendering()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
updateLayout()1527 void DocumentImpl::updateLayout()
1528 {
1529 if (ElementImpl *oe = ownerElement()) {
1530 oe->document()->updateLayout();
1531 }
1532
1533 bool oldIgnore = m_ignorePendingStylesheets;
1534
1535 if (!haveStylesheetsLoaded()) {
1536 m_ignorePendingStylesheets = true;
1537 updateStyleSelector();
1538 }
1539
1540 updateRendering();
1541
1542 // Only do a layout if changes have occurred that make it necessary.
1543 if (m_view && renderer() && renderer()->needsLayout()) {
1544 m_view->layout();
1545 }
1546
1547 m_ignorePendingStylesheets = oldIgnore;
1548 }
1549
attach()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
detach()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
setVisuallyOrdered()1601 void DocumentImpl::setVisuallyOrdered()
1602 {
1603 visuallyOrdered = true;
1604 if (m_render) {
1605 m_render->style()->setVisuallyOrdered(true);
1606 }
1607 }
1608
setSelection(NodeImpl * s,int sp,NodeImpl * e,int ep)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
clearSelection()1616 void DocumentImpl::clearSelection()
1617 {
1618 if (m_render) {
1619 static_cast<RenderCanvas *>(m_render)->clearSelection();
1620 }
1621 }
1622
updateSelection()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
createTokenizer()1642 khtml::Tokenizer *DocumentImpl::createTokenizer()
1643 {
1644 return new khtml::XMLTokenizer(docPtr(), m_view);
1645 }
1646
logicalDpiY()1647 int DocumentImpl::logicalDpiY()
1648 {
1649 return m_paintDevice->logicalDpiY();
1650 }
1651
open(bool clearEventListeners)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
body() const1690 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
close()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
write(const DOMString & text)1736 void DocumentImpl::write(const DOMString &text)
1737 {
1738 write(text.string());
1739 }
1740
write(const QString & text)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
writeln(const DOMString & text)1753 void DocumentImpl::writeln(const DOMString &text)
1754 {
1755 write(text);
1756 write(DOMString("\n"));
1757 }
1758
finishParsing()1759 void DocumentImpl::finishParsing()
1760 {
1761 if (m_tokenizer) {
1762 m_tokenizer->finish();
1763 }
1764 }
1765
completeURL(const QString & url) const1766 QString DocumentImpl::completeURL(const QString &url) const
1767 {
1768 if (url.startsWith(QLatin1Char('#'))) {
1769 const QString ref = QUrl::fromPercentEncoding(url.mid(1).toUtf8());
1770 QUrl u = baseURL();
1771 if (ref.isEmpty()) {
1772 u.setFragment("");
1773 } else {
1774 u.setFragment(ref, QUrl::DecodedMode);
1775 }
1776 }
1777
1778 return baseURL().resolved(QUrl(url)).toString();
1779 }
1780
setUserStyleSheet(const QString & sheet)1781 void DocumentImpl::setUserStyleSheet(const QString &sheet)
1782 {
1783 if (m_usersheet != sheet) {
1784 m_usersheet = sheet;
1785 updateStyleSelector();
1786 }
1787 }
1788
elementSheet()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
determineParseMode()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
nextFocusNode(NodeImpl * fromNode)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
previousFocusNode(NodeImpl * fromNode)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
findAccessKeyElement(QChar c)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
nodeAbsIndex(NodeImpl * node)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
nodeWithAbsIndex(int absIndex)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
processHttpEquiv(const DOMString & equiv,const DOMString & content)2053 void DocumentImpl::processHttpEquiv(const DOMString &equiv, const DOMString &content)
2054 {
2055 assert(!equiv.isNull() && !content.isNull());
2056
2057 KHTMLView *v = document()->view();
2058
2059 if (strcasecmp(equiv, "refresh") == 0 && v && v->part()->metaRefreshEnabled()) {
2060 // get delay and url
2061 QString str = content.string().trimmed();
2062 int pos = str.indexOf(QRegExp("[;,]"));
2063 if (pos == -1) {
2064 pos = str.indexOf(QRegExp("[ \t]"));
2065 }
2066
2067 bool ok = false;
2068 int delay = qMax(0, content.implementation()->toInt(&ok));
2069 if (!ok && str.length() && str[0] == '.') {
2070 ok = true;
2071 }
2072
2073 if (pos == -1) { // There can be no url (David)
2074 if (ok) {
2075 v->part()->scheduleRedirection(delay, v->part()->url().toString());
2076 }
2077 } else {
2078 pos++;
2079 while (pos < str.length() && str[pos].isSpace()) {
2080 pos++;
2081 }
2082 str = str.mid(pos);
2083 if (str.indexOf("url", 0, Qt::CaseInsensitive) == 0) {
2084 str = str.mid(3);
2085 }
2086 str = str.trimmed();
2087 if (str.length() && str[0] == '=') {
2088 str = str.mid(1).trimmed();
2089 }
2090 while (str.length() &&
2091 (str[str.length() - 1] == ';' || str[str.length() - 1] == ',')) {
2092 str.resize(str.length() - 1);
2093 }
2094 str = DOMString(str).trimSpaces().string();
2095 const QString newURL = document()->completeURL(str);
2096 if (ok) {
2097 v->part()->scheduleRedirection(delay, newURL, delay < 2 || newURL == URL().url());
2098 }
2099 }
2100 } else if (strcasecmp(equiv, "expires") == 0) {
2101 if (m_docLoader) {
2102 QString str = content.string().trimmed();
2103 //QDateTime can't convert from a RFCDate format string
2104 QDateTime expire_date = QDateTime::fromString(str, Qt::RFC2822Date);
2105
2106 if (!expire_date.isValid()) {
2107 qint64 seconds = str.toLongLong();
2108 if (seconds != 0) {
2109 m_docLoader->setRelativeExpireDate(seconds);
2110 } else {
2111 expire_date = QDateTime::currentDateTime(); // expire now
2112 m_docLoader->setExpireDate(expire_date);
2113 }
2114 }
2115 }
2116 } else if (v && (strcasecmp(equiv, "pragma") == 0 || strcasecmp(equiv, "cache-control") == 0)) {
2117 QString str = content.string().toLower().trimmed();
2118 QUrl url = v->part()->url();
2119 if ((str == "no-cache") && url.scheme().startsWith(QLatin1String("http"))) {
2120 KIO::http_update_cache(url, true, QDateTime::fromTime_t(0));
2121 }
2122 } else if ((strcasecmp(equiv, "set-cookie") == 0)) {
2123 // ### make setCookie work on XML documents too; e.g. in case of <html:meta .....>
2124 HTMLDocumentImpl *d = static_cast<HTMLDocumentImpl *>(this);
2125 d->setCookie(content);
2126 } else if (strcasecmp(equiv, "default-style") == 0) {
2127 // HTML 4.0 14.3.2
2128 // https://www.hixie.ch/tests/evil/css/import/main/preferred.html
2129 m_preferredStylesheetSet = content;
2130 updateStyleSelector();
2131 } else if (strcasecmp(equiv, "content-language") == 0) {
2132 m_contentLanguage = content.string();
2133 }
2134 }
2135
prepareMouseEvent(bool readonly,int _x,int _y,MouseEvent * ev)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
childTypeAllowed(unsigned short type)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
cloneNode(bool deep)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.
styleSheetLoaded()2225 void DocumentImpl::styleSheetLoaded()
2226 {
2227 // Make sure we knew this sheet was pending, and that our count isn't out of sync.
2228 assert(m_pendingStylesheets > 0);
2229
2230 m_pendingStylesheets--;
2231 updateStyleSelector();
2232 if (!m_pendingStylesheets && m_tokenizer) {
2233 m_tokenizer->executeScriptsWaitingForStylesheets();
2234 }
2235 }
2236
addPendingSheet()2237 void DocumentImpl::addPendingSheet()
2238 {
2239 m_pendingStylesheets++;
2240 }
2241
selectedStylesheetSet() const2242 DOMString DocumentImpl::selectedStylesheetSet() const
2243 {
2244 if (!view()) {
2245 return DOMString();
2246 }
2247
2248 return view()->part()->d->m_sheetUsed;
2249 }
2250
setSelectedStylesheetSet(const DOMString & s)2251 void DocumentImpl::setSelectedStylesheetSet(const DOMString &s)
2252 {
2253 // this code is evil
2254 if (view() && view()->part()->d->m_sheetUsed != s.string()) {
2255 view()->part()->d->m_sheetUsed = s.string();
2256 updateStyleSelector();
2257 }
2258 }
2259
addStyleSheet(StyleSheetImpl * sheet,int * exceptioncode)2260 void DocumentImpl::addStyleSheet(StyleSheetImpl *sheet, int *exceptioncode)
2261 {
2262 int excode = 0;
2263
2264 if (!m_addedStyleSheets) {
2265 m_addedStyleSheets = new StyleSheetListImpl;
2266 m_addedStyleSheets->ref();
2267 }
2268
2269 m_addedStyleSheets->add(sheet);
2270 if (sheet->isCSSStyleSheet()) {
2271 updateStyleSelector();
2272 }
2273
2274 if (exceptioncode) {
2275 *exceptioncode = excode;
2276 }
2277 }
2278
removeStyleSheet(StyleSheetImpl * sheet,int * exceptioncode)2279 void DocumentImpl::removeStyleSheet(StyleSheetImpl *sheet, int *exceptioncode)
2280 {
2281 int excode = 0;
2282 bool removed = false;
2283 bool is_css = sheet->isCSSStyleSheet();
2284
2285 if (m_addedStyleSheets) {
2286 bool in_main_list = !sheet->hasOneRef();
2287 removed = m_addedStyleSheets->styleSheets.removeAll(sheet);
2288 sheet->deref();
2289
2290 if (m_addedStyleSheets->styleSheets.count() == 0) {
2291 bool reset = m_addedStyleSheets->hasOneRef();
2292 m_addedStyleSheets->deref();
2293 if (reset) {
2294 m_addedStyleSheets = nullptr;
2295 }
2296 }
2297
2298 // remove from main list, too
2299 if (in_main_list) {
2300 m_styleSheets->remove(sheet);
2301 }
2302 }
2303
2304 if (removed) {
2305 if (is_css) {
2306 updateStyleSelector();
2307 }
2308 } else {
2309 excode = DOMException::NOT_FOUND_ERR;
2310 }
2311
2312 if (exceptioncode) {
2313 *exceptioncode = excode;
2314 }
2315 }
2316
updateStyleSelector(bool shallow)2317 void DocumentImpl::updateStyleSelector(bool shallow)
2318 {
2319 // qCDebug(KHTML_LOG) << "PENDING " << m_pendingStylesheets;
2320
2321 // Don't bother updating, since we haven't loaded all our style info yet.
2322 if (m_pendingStylesheets > 0) {
2323 // ... however, if the list of stylesheets changed, mark it as dirty
2324 // so DOM ops can get an up-to-date version.
2325 if (!shallow) {
2326 m_styleSheetListDirty = true;
2327 }
2328 return;
2329 }
2330
2331 if (!shallow) {
2332 rebuildStyleSheetList();
2333 }
2334
2335 rebuildStyleSelector();
2336
2337 recalcStyle(Force);
2338 #if 0
2339
2340 m_styleSelectorDirty = true;
2341 #endif
2342 if (renderer()) {
2343 renderer()->setNeedsLayoutAndMinMaxRecalc();
2344 }
2345 }
2346
readyForLayout() const2347 bool DocumentImpl::readyForLayout() const
2348 {
2349 return renderer() && haveStylesheetsLoaded() && (!isHTMLDocument() || (body() && body()->renderer()));
2350 }
2351
rebuildStyleSheetList(bool force)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
rebuildStyleSelector()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
setBaseURL(const QUrl & _baseURL)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
setHoverNode(NodeImpl * newHoverNode)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
setActiveNode(NodeImpl * newActiveNode)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
quietResetFocus()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
setFocusNode(NodeImpl * newFocusNode)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
setCSSTarget(NodeImpl * n)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
attachNodeIterator(NodeIteratorImpl * ni)2692 void DocumentImpl::attachNodeIterator(NodeIteratorImpl *ni)
2693 {
2694 m_nodeIterators.append(ni);
2695 }
2696
detachNodeIterator(NodeIteratorImpl * ni)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
notifyBeforeNodeRemoval(NodeImpl * n)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
isURLAllowed(const QString & url) const2713 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
setDesignMode(bool b)2751 void DocumentImpl::setDesignMode(bool b)
2752 {
2753 if (part()) {
2754 part()->setEditable(b);
2755 }
2756 }
2757
designMode() const2758 bool DocumentImpl::designMode() const
2759 {
2760 return part() ? part()->isEditable() : false;
2761 }
2762
createEvent(const DOMString & eventType,int & exceptioncode)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
getOverrideStyle(ElementImpl *,DOMStringImpl *)2784 CSSStyleDeclarationImpl *DocumentImpl::getOverrideStyle(ElementImpl * /*elt*/, DOMStringImpl * /*pseudoElt*/)
2785 {
2786 return nullptr; // ###
2787 }
2788
abort()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
load(const DOMString & uri)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
loadXML(const DOMString & source)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
setStyleSheet(const DOM::DOMString & url,const DOM::DOMString & sheet,const DOM::DOMString &,const DOM::DOMString & mimetype)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
error(int err,const QString & text)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
defaultEventHandler(EventImpl * evt)2895 void DocumentImpl::defaultEventHandler(EventImpl *evt)
2896 {
2897 if (evt->id() == EventImpl::KHTML_CONTENTLOADED_EVENT && !evt->propagationStopped() && !evt->defaultPrevented()) {
2898 contentLoaded();
2899 }
2900 }
2901
setHTMLWindowEventListener(EventName id,EventListener * listener)2902 void DocumentImpl::setHTMLWindowEventListener(EventName id, EventListener *listener)
2903 {
2904 windowEventTarget()->listenerList().setHTMLEventListener(id, listener);
2905 }
2906
setHTMLWindowEventListener(unsigned id,EventListener * listener)2907 void DocumentImpl::setHTMLWindowEventListener(unsigned id, EventListener *listener)
2908 {
2909 windowEventTarget()->listenerList().setHTMLEventListener(EventName::fromId(id), listener);
2910 }
2911
getHTMLWindowEventListener(EventName id)2912 EventListener *DocumentImpl::getHTMLWindowEventListener(EventName id)
2913 {
2914 return windowEventTarget()->listenerList().getHTMLEventListener(id);
2915 }
2916
getHTMLWindowEventListener(unsigned id)2917 EventListener *DocumentImpl::getHTMLWindowEventListener(unsigned id)
2918 {
2919 return windowEventTarget()->listenerList().getHTMLEventListener(EventName::fromId(id));
2920 }
2921
addWindowEventListener(EventName id,EventListener * listener,const bool useCapture)2922 void DocumentImpl::addWindowEventListener(EventName id, EventListener *listener, const bool useCapture)
2923 {
2924 windowEventTarget()->listenerList().addEventListener(id, listener, useCapture);
2925 }
2926
removeWindowEventListener(EventName id,EventListener * listener,bool useCapture)2927 void DocumentImpl::removeWindowEventListener(EventName id, EventListener *listener, bool useCapture)
2928 {
2929 windowEventTarget()->listenerList().removeEventListener(id, listener, useCapture);
2930 }
2931
hasWindowEventListener(EventName id)2932 bool DocumentImpl::hasWindowEventListener(EventName id)
2933 {
2934 return windowEventTarget()->listenerList().hasEventListener(id);
2935 }
2936
createHTMLEventListener(const QString & code,const QString & name,NodeImpl * node)2937 EventListener *DocumentImpl::createHTMLEventListener(const QString &code, const QString &name, NodeImpl *node)
2938 {
2939 return part() ? part()->createHTMLEventListener(code, name, node) : nullptr;
2940 }
2941
dispatchImageLoadEventSoon(HTMLImageElementImpl * image)2942 void DocumentImpl::dispatchImageLoadEventSoon(HTMLImageElementImpl *image)
2943 {
2944 m_imageLoadEventDispatchSoonList.append(image);
2945 if (!m_imageLoadEventTimer) {
2946 m_imageLoadEventTimer = startTimer(0);
2947 }
2948 }
2949
removeImage(HTMLImageElementImpl * image)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
dispatchImageLoadEventsNow()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
timerEvent(QTimerEvent * e)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
ownerElement() const2995 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
origin() const3008 khtml::SecurityOrigin *DocumentImpl::origin() const
3009 {
3010 if (!m_origin) {
3011 m_origin = SecurityOrigin::create(URL());
3012 }
3013 return m_origin.get();
3014 }
3015
setOrigin(khtml::SecurityOrigin * newOrigin)3016 void DocumentImpl::setOrigin(khtml::SecurityOrigin *newOrigin)
3017 {
3018 assert(origin()->isEmpty());
3019 m_origin = newOrigin;
3020 }
3021
domain() const3022 DOMString DocumentImpl::domain() const
3023 {
3024 return origin()->domain();
3025 }
3026
setDomain(const DOMString & newDomain)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
toString() const3055 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
setRestoreState(const QStringList & s)3066 void DOM::DocumentImpl::setRestoreState(const QStringList &s)
3067 {
3068 m_state = s;
3069 m_stateRestorePos = 0;
3070 }
3071
view() const3072 KHTMLView *DOM::DocumentImpl::view() const
3073 {
3074 return m_view;
3075 }
3076
part() const3077 KHTMLPart *DOM::DocumentImpl::part() const
3078 {
3079 // ### TODO: make this independent from a KHTMLView one day.
3080 return view() ? view()->part() : nullptr;
3081 }
3082
acquireCachedNodeListInfo(DynamicNodeListImpl::CacheFactory * factory,NodeImpl * base,int type)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
releaseCachedNodeListInfo(DynamicNodeListImpl::Cache * entry)3118 void DOM::DocumentImpl::releaseCachedNodeListInfo(DynamicNodeListImpl::Cache *entry)
3119 {
3120 entry->deref();
3121 }
3122
isSVGDocument() const3123 bool DOM::DocumentImpl::isSVGDocument() const
3124 {
3125 return (documentElement()->id() == WebCore::SVGNames::svgTag.id());
3126 }
3127
svgExtensions()3128 const WebCore::SVGDocumentExtensions *DOM::DocumentImpl::svgExtensions()
3129 {
3130 return m_svgExtensions;
3131 }
3132
accessSVGExtensions()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
jsEditor()3144 JSEditor *DocumentImpl::jsEditor()
3145 {
3146 if (!m_jsEditor) {
3147 m_jsEditor = new JSEditor(this);
3148 }
3149 return m_jsEditor;
3150 }
3151
execCommand(const DOMString & command,bool userInterface,const DOMString & value)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
queryCommandEnabled(const DOMString & command)3158 bool DocumentImpl::queryCommandEnabled(const DOMString &command)
3159 {
3160 return jsEditor()->queryCommandEnabled(jsEditor()->commandImp(command));
3161 }
3162
queryCommandIndeterm(const DOMString & command)3163 bool DocumentImpl::queryCommandIndeterm(const DOMString &command)
3164 {
3165 return jsEditor()->queryCommandIndeterm(jsEditor()->commandImp(command));
3166 }
3167
queryCommandState(const DOMString & command)3168 bool DocumentImpl::queryCommandState(const DOMString &command)
3169 {
3170 return jsEditor()->queryCommandState(jsEditor()->commandImp(command));
3171 }
3172
queryCommandSupported(const DOMString & command)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
queryCommandValue(const DOMString & command)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
createExpression(DOMString & expression,khtml::XPathNSResolverImpl * resolver,int & exceptioncode)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
createNSResolver(NodeImpl * nodeResolver)3200 khtml::XPathNSResolverImpl *DocumentImpl::createNSResolver(NodeImpl *nodeResolver)
3201 {
3202 return nodeResolver ? new DefaultXPathNSResolverImpl(nodeResolver) : nullptr;
3203 }
3204
evaluate(DOMString & expression,NodeImpl * contextNode,khtml::XPathNSResolverImpl * resolver,unsigned short type,khtml::XPathResultImpl *,int & exceptioncode)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
WindowEventTargetImpl(DOM::DocumentImpl * owner)3230 WindowEventTargetImpl::WindowEventTargetImpl(DOM::DocumentImpl *owner):
3231 m_owner(owner)
3232 {}
3233
eventTargetType() const3234 EventTargetImpl::Type WindowEventTargetImpl::eventTargetType() const
3235 {
3236 return WINDOW;
3237 }
3238
eventTargetDocument()3239 DocumentImpl *WindowEventTargetImpl::eventTargetDocument()
3240 {
3241 return m_owner;
3242 }
3243
window()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
DocumentFragmentImpl(DocumentImpl * doc)3254 DocumentFragmentImpl::DocumentFragmentImpl(DocumentImpl *doc) : NodeBaseImpl(doc)
3255 {
3256 }
3257
nodeName() const3258 DOMString DocumentFragmentImpl::nodeName() const
3259 {
3260 return "#document-fragment";
3261 }
3262
nodeType() const3263 unsigned short DocumentFragmentImpl::nodeType() const
3264 {
3265 return Node::DOCUMENT_FRAGMENT_NODE;
3266 }
3267
3268 // DOM Section 1.1.1
childTypeAllowed(unsigned short type)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
toString() const3285 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
cloneNode(bool deep)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
DocumentTypeImpl(DOMImplementationImpl * implementation,DocumentImpl * doc,const DOMString & qualifiedName,const DOMString & publicId,const DOMString & systemId)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
~DocumentTypeImpl()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
toString() const3336 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
nodeName() const3363 DOMString DocumentTypeImpl::nodeName() const
3364 {
3365 return name();
3366 }
3367
nodeType() const3368 unsigned short DocumentTypeImpl::nodeType() const
3369 {
3370 return Node::DOCUMENT_TYPE_NODE;
3371 }
3372
3373 // DOM Section 1.1.1
childTypeAllowed(unsigned short)3374 bool DocumentTypeImpl::childTypeAllowed(unsigned short /*type*/)
3375 {
3376 return false;
3377 }
3378
cloneNode(bool)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
entities() const3389 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
notations() const3398 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
close()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