653c2b1b828a429c0ffd9d357c861b88f4ec780f
[WebKit-https.git] / WebCore / khtml / xml / dom_docimpl.cpp
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  * Copyright (C) 2004 Apple Computer, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #include "dom/dom_exception.h"
26
27 #include "xml/dom_textimpl.h"
28 #include "xml/dom_xmlimpl.h"
29 #include "xml/dom2_rangeimpl.h"
30 #include "xml/dom2_eventsimpl.h"
31 #include "xml/xml_tokenizer.h"
32
33 #include "xml_namespace_table.h"
34
35 #include "css/csshelper.h"
36 #include "css/cssstyleselector.h"
37 #include "css/css_stylesheetimpl.h"
38 #include "css/css_valueimpl.h"
39 #include "misc/htmlhashes.h"
40 #include "misc/helper.h"
41 #include "ecma/kjs_proxy.h"
42 #include "ecma/kjs_binding.h"
43
44 #include <qptrstack.h>
45 #include <qpaintdevicemetrics.h>
46 #include <qregexp.h>
47 #include <kdebug.h>
48 #include <kstaticdeleter.h>
49
50 #include "rendering/render_canvas.h"
51 #include "rendering/render_frames.h"
52 #include "rendering/render_image.h"
53 #include "rendering/render_object.h"
54 #include "render_arena.h"
55
56 #include "khtmlview.h"
57 #include "khtml_part.h"
58
59 #include <kglobalsettings.h>
60 #include <kstringhandler.h>
61 #include "khtml_settings.h"
62 #include "khtmlpart_p.h"
63
64 #include "html/html_baseimpl.h"
65 #include "html/html_blockimpl.h"
66 #include "html/html_canvasimpl.h"
67 #include "html/html_documentimpl.h"
68 #include "html/html_formimpl.h"
69 #include "html/html_headimpl.h"
70 #include "html/html_imageimpl.h"
71 #include "html/html_listimpl.h"
72 #include "html/html_miscimpl.h"
73 #include "html/html_tableimpl.h"
74 #include "html/html_objectimpl.h"
75
76 #include "cssvalues.h"
77
78 #include "editing/jsediting.h"
79 #include "editing/visible_position.h"
80 #include "editing/visible_text.h"
81
82 #include <kio/job.h>
83
84 #ifdef KHTML_XSLT
85 #include "xsl_stylesheetimpl.h"
86 #include "xslt_processorimpl.h"
87 #endif
88
89 #ifndef KHTML_NO_XBL
90 #include "xbl/xbl_binding_manager.h"
91 using XBL::XBLBindingManager;
92 #endif
93
94 #if APPLE_CHANGES
95 #include "KWQAccObjectCache.h"
96 #include "KWQLogging.h"
97 #endif
98
99 using namespace DOM;
100 using namespace khtml;
101
102 // #define INSTRUMENT_LAYOUT_SCHEDULING 1
103
104 // This amount of time must have elapsed before we will even consider scheduling a layout without a delay.
105 // FIXME: For faster machines this value can really be lowered to 200.  250 is adequate, but a little high
106 // for dual G5s. :)
107 const int cLayoutScheduleThreshold = 250;
108
109 DOMImplementationImpl *DOMImplementationImpl::m_instance = 0;
110
111 DOMImplementationImpl::DOMImplementationImpl()
112 {
113 }
114
115 DOMImplementationImpl::~DOMImplementationImpl()
116 {
117 }
118
119 bool DOMImplementationImpl::hasFeature ( const DOMString &feature, const DOMString &version )
120 {
121     QString lower = feature.string().lower();
122     if (lower == "core" || lower == "html" || lower == "xml")
123         return version.isEmpty() || version == "1.0" || version == "2.0";
124     if (lower == "css"
125             || lower == "css2"
126             || lower == "events"
127             || lower == "htmlevents"
128             || lower == "mouseevents"
129             || lower == "mutationevents"
130             || lower == "range"
131             || lower == "stylesheets"
132             || lower == "traversal"
133             || lower == "uievents"
134             || lower == "views")
135         return version.isEmpty() || version == "2.0";
136     return false;
137 }
138
139 DocumentTypeImpl *DOMImplementationImpl::createDocumentType( const DOMString &qualifiedName, const DOMString &publicId,
140                                                              const DOMString &systemId, int &exceptioncode )
141 {
142     // Not mentioned in spec: throw NAMESPACE_ERR if no qualifiedName supplied
143     if (qualifiedName.isNull()) {
144         exceptioncode = DOMException::NAMESPACE_ERR;
145         return 0;
146     }
147
148     // INVALID_CHARACTER_ERR: Raised if the specified qualified name contains an illegal character.
149     if (!Element::khtmlValidQualifiedName(qualifiedName)) {
150         exceptioncode = DOMException::INVALID_CHARACTER_ERR;
151         return 0;
152     }
153
154     // NAMESPACE_ERR: Raised if the qualifiedName is malformed.
155     if (Element::khtmlMalformedQualifiedName(qualifiedName)) {
156         exceptioncode = DOMException::NAMESPACE_ERR;
157         return 0;
158     }
159
160     return new DocumentTypeImpl(this,0,qualifiedName,publicId,systemId);
161 }
162
163 DOMImplementationImpl* DOMImplementationImpl::getInterface(const DOMString& /*feature*/) const
164 {
165     // ###
166     return 0;
167 }
168
169 DocumentImpl *DOMImplementationImpl::createDocument( const DOMString &namespaceURI, const DOMString &qualifiedName,
170                                                      const DocumentType &doctype, int &exceptioncode )
171 {
172     exceptioncode = 0;
173
174     // Not mentioned in spec: throw NAMESPACE_ERR if no qualifiedName supplied
175     if (qualifiedName.isNull()) {
176         exceptioncode = DOMException::NAMESPACE_ERR;
177         return 0;
178     }
179
180     // INVALID_CHARACTER_ERR: Raised if the specified qualified name contains an illegal character.
181     if (!Element::khtmlValidQualifiedName(qualifiedName)) {
182         exceptioncode = DOMException::INVALID_CHARACTER_ERR;
183         return 0;
184     }
185
186     // NAMESPACE_ERR:
187     // - Raised if the qualifiedName is malformed,
188     // - if the qualifiedName has a prefix and the namespaceURI is null, or
189     // - if the qualifiedName has a prefix that is "xml" and the namespaceURI is different
190     //   from "http://www.w3.org/XML/1998/namespace" [Namespaces].
191     int colonpos = -1;
192     uint i;
193     DOMStringImpl *qname = qualifiedName.implementation();
194     for (i = 0; i < qname->l && colonpos < 0; i++) {
195         if ((*qname)[i] == ':')
196             colonpos = i;
197     }
198
199     if (Element::khtmlMalformedQualifiedName(qualifiedName) ||
200         (colonpos >= 0 && namespaceURI.isNull()) ||
201         (colonpos == 3 && qualifiedName[0] == 'x' && qualifiedName[1] == 'm' && qualifiedName[2] == 'l' &&
202          namespaceURI != "http://www.w3.org/XML/1998/namespace")) {
203
204         exceptioncode = DOMException::NAMESPACE_ERR;
205         return 0;
206     }
207
208     DocumentTypeImpl *dtype = static_cast<DocumentTypeImpl*>(doctype.handle());
209     // WRONG_DOCUMENT_ERR: Raised if doctype has already been used with a different document or was
210     // created from a different implementation.
211     if (dtype && (dtype->getDocument() || dtype->implementation() != this)) {
212         exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
213         return 0;
214     }
215
216     // ### this is completely broken.. without a view it will not work (Dirk)
217     DocumentImpl *doc = new DocumentImpl(this, 0);
218
219     // now get the interesting parts of the doctype
220     // ### create new one if not there (currently always there)
221     if (doc->doctype() && dtype)
222         doc->doctype()->copyFrom(*dtype);
223
224     return doc;
225 }
226
227 CSSStyleSheetImpl *DOMImplementationImpl::createCSSStyleSheet(DOMStringImpl */*title*/, DOMStringImpl *media,
228                                                               int &/*exceptioncode*/)
229 {
230     // ### TODO : title should be set, and media could have wrong syntax, in which case we should
231         // generate an exception.
232         CSSStyleSheetImpl *parent = 0L;
233         CSSStyleSheetImpl *sheet = new CSSStyleSheetImpl(parent, DOMString());
234         sheet->setMedia(new MediaListImpl(sheet, media));
235         return sheet;
236 }
237
238 DocumentImpl *DOMImplementationImpl::createDocument( KHTMLView *v )
239 {
240     return new DocumentImpl(this, v);
241 }
242
243 HTMLDocumentImpl *DOMImplementationImpl::createHTMLDocument( KHTMLView *v )
244 {
245     return new HTMLDocumentImpl(this, v);
246 }
247
248 DOMImplementationImpl *DOMImplementationImpl::instance()
249 {
250     if (!m_instance) {
251         m_instance = new DOMImplementationImpl();
252         m_instance->ref();
253     }
254
255     return m_instance;
256 }
257
258 // ------------------------------------------------------------------------
259
260 KStaticDeleter< QPtrList<DocumentImpl> > s_changedDocumentsDeleter;
261 QPtrList<DocumentImpl> * DocumentImpl::changedDocuments = 0;
262
263 // KHTMLView might be 0
264 DocumentImpl::DocumentImpl(DOMImplementationImpl *_implementation, KHTMLView *v)
265     : NodeBaseImpl( new DocumentPtr() )
266       , m_domtree_version(0)
267       , m_imageLoadEventTimer(0)
268 #ifndef KHTML_NO_XBL
269       , m_bindingManager(new XBLBindingManager(this))
270 #endif
271 #ifdef KHTML_XSLT
272     , m_transformSource(NULL)
273     , m_transformSourceDocument(0)
274 #endif
275 #if APPLE_CHANGES
276     , m_finishedParsing(this, SIGNAL(finishedParsing()))
277     , m_inPageCache(false)
278     , m_savedRenderer(0)
279     , m_passwordFields(0)
280     , m_secureForms(0)
281     , m_decoder(0)
282     , m_createRenderers(true)
283     , m_designMode(inherit)
284     , m_hasDashboardRegions(false)
285     , m_dashboardRegionsDirty(false)
286 #endif
287 {
288     document->doc = this;
289
290     m_paintDevice = 0;
291     m_paintDeviceMetrics = 0;
292
293     m_view = v;
294     m_renderArena = 0;
295
296 #if APPLE_CHANGES
297     m_accCache = 0;
298 #endif
299     
300     if ( v ) {
301         m_docLoader = new DocLoader(v->part(), this );
302         setPaintDevice( m_view );
303     }
304     else
305         m_docLoader = new DocLoader( 0, this );
306
307     visuallyOrdered = false;
308     m_loadingSheet = false;
309     m_bParsing = false;
310     m_docChanged = false;
311     m_sheet = 0;
312     m_elemSheet = 0;
313     m_tokenizer = 0;
314
315     // ### this should be created during parsing a <!DOCTYPE>
316     // not during construction. Not sure who added that and why (Dirk)
317     m_doctype = new DocumentTypeImpl(_implementation, document,
318                                      DOMString() /* qualifiedName */,
319                                      DOMString() /* publicId */,
320                                      DOMString() /* systemId */);
321     m_doctype->ref();
322
323     m_implementation = _implementation;
324     if (m_implementation)
325         m_implementation->ref();
326     pMode = Strict;
327     hMode = XHtml;
328     m_textColor = Qt::black;
329     m_elementNames = 0;
330     m_elementNameAlloc = 0;
331     m_elementNameCount = 0;
332     m_attrNames = 0;
333     m_attrNameAlloc = 0;
334     m_attrNameCount = 0;
335     m_focusNode = 0;
336     m_hoverNode = 0;
337     m_defaultView = new AbstractViewImpl(this);
338     m_defaultView->ref();
339     m_listenerTypes = 0;
340     m_styleSheets = new StyleSheetListImpl;
341     m_styleSheets->ref();
342     m_inDocument = true;
343     m_styleSelectorDirty = false;
344     m_inStyleRecalc = false;
345     m_usesDescendantRules = false;
346     m_usesSiblingRules = false;
347
348     m_styleSelector = new CSSStyleSelector(this, m_usersheet, m_styleSheets, !inCompatMode());
349     m_windowEventListeners.setAutoDelete(true);
350     m_pendingStylesheets = 0;
351     m_ignorePendingStylesheets = false;
352
353     m_cssTarget = 0;
354     m_accessKeyDictValid = false;
355
356     resetLinkColor();
357     resetVisitedLinkColor();
358     resetActiveLinkColor();
359
360     m_processingLoadEvent = false;
361     m_startTime.restart();
362     m_overMinimumLayoutThreshold = false;
363     
364     m_jsEditor = 0;
365
366     m_markers.setAutoDelete(true);
367     
368     static int docID = 0;
369     m_docID = docID++;
370 }
371
372 DocumentImpl::~DocumentImpl()
373 {
374     assert(!m_render);
375 #if APPLE_CHANGES
376     assert(!m_inPageCache);
377     assert(m_savedRenderer == 0);
378 #endif
379     
380     KJS::ScriptInterpreter::forgetDOMObjectsForDocument(this);
381
382     if (changedDocuments && m_docChanged)
383         changedDocuments->remove(this);
384     delete m_tokenizer;
385     document->doc = 0;
386     delete m_sheet;
387     delete m_styleSelector;
388     delete m_docLoader;
389     if (m_elemSheet )  m_elemSheet->deref();
390     if (m_doctype)
391         m_doctype->deref();
392     if (m_implementation)
393         m_implementation->deref();
394     delete m_paintDeviceMetrics;
395
396     if (m_elementNames) {
397         for (unsigned short id = 0; id < m_elementNameCount; id++)
398             m_elementNames[id]->deref();
399         delete [] m_elementNames;
400     }
401     if (m_attrNames) {
402         for (unsigned short id = 0; id < m_attrNameCount; id++)
403             m_attrNames[id]->deref();
404         delete [] m_attrNames;
405     }
406     m_defaultView->deref();
407     m_styleSheets->deref();
408
409     if (m_focusNode)
410         m_focusNode->deref();
411     if (m_hoverNode)
412         m_hoverNode->deref();
413     
414     if (m_renderArena){
415         delete m_renderArena;
416         m_renderArena = 0;
417     }
418
419 #ifdef KHTML_XSLT
420     xmlFreeDoc((xmlDocPtr)m_transformSource);
421     if (m_transformSourceDocument)
422         m_transformSourceDocument->deref();
423 #endif
424
425 #ifndef KHTML_NO_XBL
426     delete m_bindingManager;
427 #endif
428
429 #if APPLE_CHANGES
430     if (m_accCache){
431         delete m_accCache;
432         m_accCache = 0;
433     }
434 #endif
435     
436     if (m_decoder){
437         m_decoder->deref();
438         m_decoder = 0;
439     }
440     
441     if (m_jsEditor) {
442         delete m_jsEditor;
443         m_jsEditor = 0;
444     }
445 }
446
447 void DocumentImpl::resetLinkColor()
448 {
449     m_linkColor = QColor(0, 0, 238);
450 }
451
452 void DocumentImpl::resetVisitedLinkColor()
453 {
454     m_visitedLinkColor = QColor(85, 26, 139);    
455 }
456
457 void DocumentImpl::resetActiveLinkColor()
458 {
459     m_activeLinkColor.setNamedColor(QString("red"));
460 }
461
462 DocumentTypeImpl *DocumentImpl::doctype() const
463 {
464     return m_doctype;
465 }
466
467 DOMImplementationImpl *DocumentImpl::implementation() const
468 {
469     return m_implementation;
470 }
471
472 ElementImpl *DocumentImpl::documentElement() const
473 {
474     NodeImpl *n = firstChild();
475     while (n && n->nodeType() != Node::ELEMENT_NODE)
476       n = n->nextSibling();
477     return static_cast<ElementImpl*>(n);
478 }
479
480 ElementImpl *DocumentImpl::createElement( const DOMString &name, int &exceptioncode )
481 {
482     return new XMLElementImpl( document, name.implementation() );
483 }
484
485 DocumentFragmentImpl *DocumentImpl::createDocumentFragment(  )
486 {
487     return new DocumentFragmentImpl( docPtr() );
488 }
489
490 TextImpl *DocumentImpl::createTextNode( const DOMString &data )
491 {
492     return new TextImpl( docPtr(), data);
493 }
494
495 CommentImpl *DocumentImpl::createComment ( const DOMString &data )
496 {
497     return new CommentImpl( docPtr(), data );
498 }
499
500 CDATASectionImpl *DocumentImpl::createCDATASection ( const DOMString &data )
501 {
502     return new CDATASectionImpl( docPtr(), data );
503 }
504
505 ProcessingInstructionImpl *DocumentImpl::createProcessingInstruction ( const DOMString &target, const DOMString &data )
506 {
507     return new ProcessingInstructionImpl( docPtr(),target,data);
508 }
509
510 Attr DocumentImpl::createAttribute( NodeImpl::Id id )
511 {
512     // Assume this is an HTML attribute, since createAttribute isn't namespace-aware.  There's no harm to XML
513     // documents if we're wrong.
514     return new AttrImpl(0, docPtr(), new HTMLAttributeImpl(id, DOMString("").implementation()));
515 }
516
517 EntityReferenceImpl *DocumentImpl::createEntityReference ( const DOMString &name )
518 {
519     return new EntityReferenceImpl(docPtr(), name.implementation());
520 }
521
522 EditingTextImpl *DocumentImpl::createEditingTextNode(const DOMString &text)
523 {
524     return new EditingTextImpl(docPtr(), text);
525 }
526
527 CSSStyleDeclarationImpl *DocumentImpl::createCSSStyleDeclaration()
528 {
529     return new CSSMutableStyleDeclarationImpl;
530 }
531
532 NodeImpl *DocumentImpl::importNode(NodeImpl *importedNode, bool deep, int &exceptioncode)
533 {
534     exceptioncode = 0;
535
536     switch (importedNode->nodeType()) {
537         case Node::TEXT_NODE:
538             return createTextNode(importedNode->nodeValue());
539         case Node::CDATA_SECTION_NODE:
540             return createCDATASection(importedNode->nodeValue());
541         case Node::ENTITY_REFERENCE_NODE:
542             return createEntityReference(importedNode->nodeName());
543         case Node::PROCESSING_INSTRUCTION_NODE:
544             return createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue());
545         case Node::COMMENT_NODE:
546             return createComment(importedNode->nodeValue());
547         case Node::ELEMENT_NODE: {
548             ElementImpl *oldElement = static_cast<ElementImpl *>(importedNode);
549             DocumentImpl *oldDoc = oldElement->getDocument();
550             static DOMString HTMLNamespace(XHTML_NAMESPACE);
551             DOMString elementNamespace = oldElement->isHTMLElement() ? HTMLNamespace : oldElement->namespaceURI();
552             ElementImpl *newElement = createElementNS(elementNamespace.implementation(), oldElement->tagName(), exceptioncode);
553             if (exceptioncode != 0)
554                 return 0;
555
556             newElement->ref();
557
558             NamedAttrMapImpl *attrs = oldElement->attributes(true);
559             if (attrs) {
560                 unsigned length = attrs->length();
561                 for (unsigned i = 0; i < length; i++) {
562                     AttrImpl *attr = attrs->item(i);
563                     DOMString qualifiedName = attr->nodeName();
564                     DOMString value = attr->nodeValue();
565
566                     int colonpos = qualifiedName.find(':');
567                     DOMString localName = qualifiedName;
568                     if (colonpos >= 0) {
569                         localName.remove(0, colonpos + 1);
570                         // ### extract and set new prefix
571                     }
572
573                     NodeImpl::Id nodeId = attrId(oldDoc->namespaceURI(attr->attrImpl()->id()), localName.implementation(), false /* allocate */);
574                     newElement->setAttribute(nodeId, value.implementation(), exceptioncode);
575                     if (exceptioncode != 0) {
576                         newElement->deref();
577                         return 0;
578                     }
579                 }
580             }
581
582             if (deep) {
583                 for (NodeImpl *oldChild = oldElement->firstChild(); oldChild; oldChild = oldChild->nextSibling()) {
584                     NodeImpl *newChild = importNode(oldChild, true, exceptioncode);
585                     if (exceptioncode != 0) {
586                         newElement->deref();
587                         return 0;
588                     }
589                     newElement->appendChild(newChild, exceptioncode);
590                     if (exceptioncode != 0) {
591                         newElement->deref();
592                         return 0;
593                     }
594                 }
595             }
596
597             // Trick to get the result back to the floating state, with 0 refs but not destroyed.
598             newElement->setParent(this);
599             newElement->deref();
600             newElement->setParent(0);
601
602             return newElement;
603         }
604     }
605
606     exceptioncode = DOMException::NOT_SUPPORTED_ERR;
607     return 0;
608 }
609
610 ElementImpl *DocumentImpl::createElementNS( const DOMString &_namespaceURI, const DOMString &_qualifiedName, int &exceptioncode)
611 {
612     ElementImpl *e = 0;
613     QString qName = _qualifiedName.string();
614     int colonPos = qName.find(':',0);
615
616     if (_namespaceURI == XHTML_NAMESPACE) {
617         // User requested an element in the XHTML namespace - this means we create a HTML element
618         // (elements not in this namespace are treated as normal XML elements)
619         e = createHTMLElement(qName.mid(colonPos+1), exceptioncode);
620         if (exceptioncode)
621             return 0;
622         if (e && colonPos >= 0) {
623             e->setPrefix(qName.left(colonPos), exceptioncode);
624             if (exceptioncode) {
625                 delete e;
626                 return 0;
627             }
628         }
629     }
630     if (!e)
631         e = new XMLElementImpl( document, _qualifiedName.implementation(), _namespaceURI.implementation() );
632
633     return e;
634 }
635
636 ElementImpl *DocumentImpl::getElementById( const DOMString &elementId ) const
637 {
638     if (elementId.length() == 0) {
639         return 0;
640     }
641
642     return m_elementsById.find(elementId.string());
643 }
644
645 ElementImpl *DocumentImpl::elementFromPoint( const int _x, const int _y ) const
646 {
647     if (!m_render) return 0;
648     
649     RenderObject::NodeInfo nodeInfo(true, true);
650     m_render->layer()->hitTest(nodeInfo, _x, _y); 
651     NodeImpl* n = nodeInfo.innerNode();
652
653     while ( n && !n->isElementNode() ) {
654         n = n->parentNode();
655     }
656     
657     return static_cast<ElementImpl*>(n);
658 }
659
660 void DocumentImpl::addElementById(const DOMString &elementId, ElementImpl *element)
661 {
662     QString qId = elementId.string();
663
664     if (m_elementsById.find(qId) == NULL) {
665         m_elementsById.insert(qId, element);
666         m_accessKeyDictValid = false;
667     }
668 }
669
670 void DocumentImpl::removeElementById(const DOMString &elementId, ElementImpl *element)
671 {
672     QString qId = elementId.string();
673
674     if (m_elementsById.find(qId) == element) {
675         m_elementsById.remove(qId);
676         m_accessKeyDictValid = false;
677     }
678 }
679
680 ElementImpl *DocumentImpl::getElementByAccessKey( const DOMString &key )
681 {
682     if (key.length() == 0)
683         return 0;
684
685     QString k(key.string());
686     if (!m_accessKeyDictValid) {
687         m_elementsByAccessKey.clear();
688     
689         const NodeImpl *n;
690         for (n = this; n != 0; n = n->traverseNextNode()) {
691             if (!n->isElementNode())
692                 continue;
693             const ElementImpl *elementImpl = static_cast<const ElementImpl *>(n);
694             DOMString accessKey(elementImpl->getAttribute(ATTR_ACCESSKEY));
695             if (!accessKey.isEmpty()) {
696                 QString ak = accessKey.string().lower();
697                 if (m_elementsByAccessKey.find(ak) == NULL)
698                     m_elementsByAccessKey.insert(ak, elementImpl);
699             }
700         }
701         m_accessKeyDictValid = true;
702     }
703     return m_elementsByAccessKey.find(k);
704 }
705
706 void DocumentImpl::setTitle(DOMString _title)
707 {
708     m_title = _title;
709
710     if (!part())
711         return;
712
713 #if APPLE_CHANGES
714     KWQ(part())->setTitle(_title);
715 #else
716     QString titleStr = m_title.string();
717     for (int i = 0; i < titleStr.length(); ++i)
718         if (titleStr[i] < ' ')
719             titleStr[i] = ' ';
720     titleStr = titleStr.stripWhiteSpace();
721     titleStr.compose();
722     if ( !part()->parentPart() ) {
723         if (titleStr.isNull() || titleStr.isEmpty()) {
724             // empty title... set window caption as the URL
725             KURL url = m_url;
726             url.setRef(QString::null);
727             url.setQuery(QString::null);
728             titleStr = url.url();
729         }
730
731         emit part()->setWindowCaption( KStringHandler::csqueeze( titleStr, 128 ) );
732     }
733 #endif
734 }
735
736 DOMString DocumentImpl::nodeName() const
737 {
738     return "#document";
739 }
740
741 unsigned short DocumentImpl::nodeType() const
742 {
743     return Node::DOCUMENT_NODE;
744 }
745
746 ElementImpl *DocumentImpl::createHTMLElement( const DOMString &name, int &exceptioncode )
747 {
748     if (!isValidName(name)) {
749         exceptioncode = DOMException::INVALID_CHARACTER_ERR;
750         return 0;
751     }
752     return createHTMLElement(tagId(0, name.implementation(), false));
753 }
754
755 ElementImpl *DocumentImpl::createHTMLElement(unsigned short tagID)
756 {
757     switch (tagID)
758     {
759     case ID_HTML:
760         return new HTMLHtmlElementImpl(docPtr());
761     case ID_HEAD:
762         return new HTMLHeadElementImpl(docPtr());
763     case ID_BODY:
764         return new HTMLBodyElementImpl(docPtr());
765
766 // head elements
767     case ID_BASE:
768         return new HTMLBaseElementImpl(docPtr());
769     case ID_LINK:
770         return new HTMLLinkElementImpl(docPtr());
771     case ID_META:
772         return new HTMLMetaElementImpl(docPtr());
773     case ID_STYLE:
774         return new HTMLStyleElementImpl(docPtr());
775     case ID_TITLE:
776         return new HTMLTitleElementImpl(docPtr());
777
778 // frames
779     case ID_FRAME:
780         return new HTMLFrameElementImpl(docPtr());
781     case ID_FRAMESET:
782         return new HTMLFrameSetElementImpl(docPtr());
783     case ID_IFRAME:
784         return new HTMLIFrameElementImpl(docPtr());
785
786 // form elements
787 // ### FIXME: we need a way to set form dependency after we have made the form elements
788     case ID_FORM:
789         return new HTMLFormElementImpl(docPtr());
790     case ID_BUTTON:
791         return new HTMLButtonElementImpl(docPtr());
792     case ID_FIELDSET:
793         return new HTMLFieldSetElementImpl(docPtr());
794     case ID_INPUT:
795         return new HTMLInputElementImpl(docPtr());
796     case ID_ISINDEX:
797         return new HTMLIsIndexElementImpl(docPtr());
798     case ID_LABEL:
799         return new HTMLLabelElementImpl(docPtr());
800     case ID_LEGEND:
801         return new HTMLLegendElementImpl(docPtr());
802     case ID_OPTGROUP:
803         return new HTMLOptGroupElementImpl(docPtr());
804     case ID_OPTION:
805         return new HTMLOptionElementImpl(docPtr());
806     case ID_SELECT:
807         return new HTMLSelectElementImpl(docPtr());
808     case ID_TEXTAREA:
809         return new HTMLTextAreaElementImpl(docPtr());
810
811 // lists
812     case ID_DL:
813         return new HTMLDListElementImpl(docPtr());
814     case ID_DD:
815         return new HTMLGenericElementImpl(docPtr(), tagID);
816     case ID_DT:
817         return new HTMLGenericElementImpl(docPtr(), tagID);
818     case ID_UL:
819         return new HTMLUListElementImpl(docPtr());
820     case ID_OL:
821         return new HTMLOListElementImpl(docPtr());
822     case ID_DIR:
823         return new HTMLDirectoryElementImpl(docPtr());
824     case ID_MENU:
825         return new HTMLMenuElementImpl(docPtr());
826     case ID_LI:
827         return new HTMLLIElementImpl(docPtr());
828
829 // formatting elements (block)
830     case ID_BLOCKQUOTE:
831         return new HTMLBlockquoteElementImpl(docPtr());
832     case ID_DIV:
833         return new HTMLDivElementImpl(docPtr());
834     case ID_H1:
835     case ID_H2:
836     case ID_H3:
837     case ID_H4:
838     case ID_H5:
839     case ID_H6:
840         return new HTMLHeadingElementImpl(docPtr(), tagID);
841     case ID_HR:
842         return new HTMLHRElementImpl(docPtr());
843     case ID_P:
844         return new HTMLParagraphElementImpl(docPtr());
845     case ID_PRE:
846     case ID_XMP:
847     case ID_PLAINTEXT:
848         return new HTMLPreElementImpl(docPtr(), tagID);
849     case ID_LAYER:
850         return new HTMLLayerElementImpl(docPtr());
851
852 // font stuff
853     case ID_BASEFONT:
854         return new HTMLBaseFontElementImpl(docPtr());
855     case ID_FONT:
856         return new HTMLFontElementImpl(docPtr());
857
858 // ins/del
859     case ID_DEL:
860     case ID_INS:
861         return new HTMLGenericElementImpl(docPtr(), tagID);
862
863 // anchor
864     case ID_A:
865         return new HTMLAnchorElementImpl(docPtr());
866
867 // images
868     case ID_IMG:
869         return new HTMLImageElementImpl(docPtr());
870     case ID_MAP:
871         return new HTMLMapElementImpl(docPtr());
872     case ID_AREA:
873         return new HTMLAreaElementImpl(docPtr());
874     case ID_CANVAS:
875         return new HTMLCanvasElementImpl(docPtr());
876
877 // objects, applets and scripts
878     case ID_APPLET:
879         return new HTMLAppletElementImpl(docPtr());
880     case ID_EMBED:
881         return new HTMLEmbedElementImpl(docPtr());
882     case ID_OBJECT:
883         return new HTMLObjectElementImpl(docPtr());
884     case ID_PARAM:
885         return new HTMLParamElementImpl(docPtr());
886     case ID_SCRIPT:
887         return new HTMLScriptElementImpl(docPtr());
888
889 // tables
890     case ID_TABLE:
891         return new HTMLTableElementImpl(docPtr());
892     case ID_CAPTION:
893         return new HTMLTableCaptionElementImpl(docPtr());
894     case ID_COLGROUP:
895     case ID_COL:
896         return new HTMLTableColElementImpl(docPtr(), tagID);
897     case ID_TR:
898         return new HTMLTableRowElementImpl(docPtr());
899     case ID_TD:
900     case ID_TH:
901         return new HTMLTableCellElementImpl(docPtr(), tagID);
902     case ID_THEAD:
903     case ID_TBODY:
904     case ID_TFOOT:
905         return new HTMLTableSectionElementImpl(docPtr(), tagID, false);
906
907 // inline elements
908     case ID_BR:
909         return new HTMLBRElementImpl(docPtr());
910     case ID_Q:
911         return new HTMLGenericElementImpl(docPtr(), tagID);
912
913 // elements with no special representation in the DOM
914
915 // block:
916     case ID_ADDRESS:
917     case ID_CENTER:
918
919 // inline
920         // %fontstyle
921     case ID_TT:
922     case ID_U:
923     case ID_B:
924     case ID_I:
925     case ID_S:
926     case ID_STRIKE:
927     case ID_BIG:
928     case ID_SMALL:
929
930         // %phrase
931     case ID_EM:
932     case ID_STRONG:
933     case ID_DFN:
934     case ID_CODE:
935     case ID_SAMP:
936     case ID_KBD:
937     case ID_VAR:
938     case ID_CITE:
939     case ID_ABBR:
940     case ID_ACRONYM:
941
942         // %special
943     case ID_SUB:
944     case ID_SUP:
945     case ID_SPAN:
946     case ID_NOBR:
947     case ID_WBR:
948
949     case ID_BDO:
950     default:
951         return new HTMLGenericElementImpl(docPtr(), tagID);
952
953     case ID_MARQUEE:
954         return new HTMLMarqueeElementImpl(docPtr());
955         
956 // text
957     case ID_TEXT:
958         kdDebug( 6020 ) << "Use document->createTextNode()" << endl;
959         return 0;
960     }
961
962     return 0;
963 }
964
965 QString DocumentImpl::nextState()
966 {
967    QString state;
968    if (!m_state.isEmpty())
969    {
970       state = m_state.first();
971       m_state.remove(m_state.begin());
972    }
973    return state;
974 }
975
976 QStringList DocumentImpl::docState()
977 {
978     QStringList s;
979     for (QPtrListIterator<NodeImpl> it(m_maintainsState); it.current(); ++it)
980         s.append(it.current()->state());
981
982     return s;
983 }
984
985 KHTMLPart *DocumentImpl::part() const 
986 {
987     return m_view ? m_view->part() : 0; 
988 }
989
990 RangeImpl *DocumentImpl::createRange()
991 {
992     return new RangeImpl( docPtr() );
993 }
994
995 NodeIteratorImpl *DocumentImpl::createNodeIterator(NodeImpl *root, unsigned long whatToShow, 
996     NodeFilterImpl *filter, bool expandEntityReferences, int &exceptioncode)
997 {
998     if (!root) {
999         exceptioncode = DOMException::NOT_SUPPORTED_ERR;
1000         return 0;
1001     }
1002     return new NodeIteratorImpl(root, whatToShow, filter, expandEntityReferences);
1003 }
1004
1005 TreeWalkerImpl *DocumentImpl::createTreeWalker(NodeImpl *root, unsigned long whatToShow, 
1006     NodeFilterImpl *filter, bool expandEntityReferences, int &exceptioncode)
1007 {
1008     if (!root) {
1009         exceptioncode = DOMException::NOT_SUPPORTED_ERR;
1010         return 0;
1011     }
1012     return new TreeWalkerImpl(root, whatToShow, filter, expandEntityReferences);
1013 }
1014
1015 void DocumentImpl::setDocumentChanged(bool b)
1016 {
1017     if (!changedDocuments)
1018         changedDocuments = s_changedDocumentsDeleter.setObject( new QPtrList<DocumentImpl>() );
1019
1020     if (b && !m_docChanged)
1021         changedDocuments->append(this);
1022     else if (!b && m_docChanged)
1023         changedDocuments->remove(this);
1024     m_docChanged = b;
1025     
1026     if (m_docChanged)
1027         m_accessKeyDictValid = false;
1028 }
1029
1030 void DocumentImpl::recalcStyle( StyleChange change )
1031 {
1032 //     qDebug("recalcStyle(%p)", this);
1033 //     QTime qt;
1034 //     qt.start();
1035     if (m_inStyleRecalc)
1036         return; // Guard against re-entrancy. -dwh
1037         
1038     m_inStyleRecalc = true;
1039     
1040     if( !m_render ) goto bail_out;
1041
1042     if ( change == Force ) {
1043         RenderStyle* oldStyle = m_render->style();
1044         if ( oldStyle ) oldStyle->ref();
1045         RenderStyle* _style = new (m_renderArena) RenderStyle();
1046         _style->ref();
1047         _style->setDisplay(BLOCK);
1048         _style->setVisuallyOrdered( visuallyOrdered );
1049         // ### make the font stuff _really_ work!!!!
1050
1051         khtml::FontDef fontDef;
1052         QFont f = KGlobalSettings::generalFont();
1053         fontDef.family = *(f.firstFamily());
1054         fontDef.italic = f.italic();
1055         fontDef.weight = f.weight();
1056 #if APPLE_CHANGES
1057         bool printing = m_paintDevice && (m_paintDevice->devType() == QInternal::Printer);
1058         fontDef.usePrinterFont = printing;
1059 #endif
1060         if (m_view) {
1061             const KHTMLSettings *settings = m_view->part()->settings();
1062 #if APPLE_CHANGES
1063             if (printing && !settings->shouldPrintBackgrounds()) {
1064                 _style->setForceBackgroundsToWhite(true);
1065             }
1066 #endif
1067             QString stdfont = settings->stdFontName();
1068             if ( !stdfont.isEmpty() ) {
1069                 fontDef.family.setFamily(stdfont);
1070                 fontDef.family.appendFamily(0);
1071             }
1072             m_styleSelector->setFontSize(fontDef, m_styleSelector->fontSizeForKeyword(CSS_VAL_MEDIUM, inCompatMode()));
1073         }
1074
1075         //kdDebug() << "DocumentImpl::attach: setting to charset " << settings->charset() << endl;
1076         _style->setFontDef(fontDef);
1077         _style->htmlFont().update( paintDeviceMetrics() );
1078         if ( inCompatMode() )
1079             _style->setHtmlHacks(true); // enable html specific rendering tricks
1080
1081         StyleChange ch = diff( _style, oldStyle );
1082         if(m_render && ch != NoChange)
1083             m_render->setStyle(_style);
1084         if ( change != Force )
1085             change = ch;
1086
1087         _style->deref(m_renderArena);
1088         if (oldStyle)
1089             oldStyle->deref(m_renderArena);
1090     }
1091
1092     NodeImpl *n;
1093     for (n = _first; n; n = n->nextSibling())
1094         if ( change>= Inherit || n->hasChangedChild() || n->changed() )
1095             n->recalcStyle( change );
1096     //kdDebug( 6020 ) << "TIME: recalcStyle() dt=" << qt.elapsed() << endl;
1097
1098     if (changed() && m_view)
1099         m_view->layout();
1100
1101 bail_out:
1102     setChanged( false );
1103     setHasChangedChild( false );
1104     setDocumentChanged( false );
1105     
1106     m_inStyleRecalc = false;
1107 }
1108
1109 void DocumentImpl::updateRendering()
1110 {
1111     if (!hasChangedChild()) return;
1112
1113 //     QTime time;
1114 //     time.start();
1115 //     kdDebug() << "UPDATERENDERING: "<<endl;
1116
1117     StyleChange change = NoChange;
1118 #if 0
1119     if ( m_styleSelectorDirty ) {
1120         recalcStyleSelector();
1121         change = Force;
1122     }
1123 #endif
1124     recalcStyle( change );
1125
1126 //    kdDebug() << "UPDATERENDERING time used="<<time.elapsed()<<endl;
1127 }
1128
1129 void DocumentImpl::updateDocumentsRendering()
1130 {
1131     if (!changedDocuments)
1132         return;
1133
1134     while (DocumentImpl* doc = changedDocuments->take()) {
1135         doc->m_docChanged = false;
1136         doc->updateRendering();
1137     }
1138 }
1139
1140 void DocumentImpl::updateLayout()
1141 {
1142     // FIXME: Dave's pretty sure we can remove this because
1143     // layout calls recalcStyle as needed.
1144     updateRendering();
1145
1146     // Only do a layout if changes have occurred that make it necessary.      
1147     if (m_view && renderer() && renderer()->needsLayout())
1148         m_view->layout();
1149 }
1150
1151 // FIXME: This is a bad idea and needs to be removed eventually.
1152 // Other browsers load stylesheets before they continue parsing the web page.
1153 // Since we don't, we can run JavaScript code that needs answers before the
1154 // stylesheets are loaded. Doing a layout ignoring the pending stylesheets
1155 // lets us get reasonable answers. The long term solution to this problem is
1156 // to instead suspend JavaScript execution.
1157 void DocumentImpl::updateLayoutIgnorePendingStylesheets()
1158 {
1159     bool oldIgnore = m_ignorePendingStylesheets;
1160     
1161     if (!haveStylesheetsLoaded()) {
1162         m_ignorePendingStylesheets = true;
1163         updateStyleSelector();    
1164     }
1165
1166     updateLayout();
1167
1168     m_ignorePendingStylesheets = oldIgnore;
1169 }
1170
1171 void DocumentImpl::attach()
1172 {
1173     assert(!attached());
1174 #if APPLE_CHANGES
1175     assert(!m_inPageCache);
1176 #endif
1177
1178     if ( m_view )
1179         setPaintDevice( m_view );
1180
1181     if (!m_renderArena)
1182         m_renderArena = new RenderArena();
1183     
1184     // Create the rendering tree
1185     m_render = new (m_renderArena) RenderCanvas(this, m_view);
1186     recalcStyle( Force );
1187
1188     RenderObject* render = m_render;
1189     m_render = 0;
1190
1191     NodeBaseImpl::attach();
1192     m_render = render;
1193 }
1194
1195 void DocumentImpl::restoreRenderer(RenderObject* render)
1196 {
1197     m_render = render;
1198 }
1199
1200 void DocumentImpl::detach()
1201 {
1202     RenderObject* render = m_render;
1203
1204     // indicate destruction mode,  i.e. attached() but m_render == 0
1205     m_render = 0;
1206     
1207 #if APPLE_CHANGES
1208     if (m_inPageCache) {
1209         if ( render )
1210             getAccObjectCache()->detach(render);
1211         return;
1212     }
1213 #endif
1214
1215     // Empty out these lists as a performance optimization, since detaching
1216     // all the individual render objects will cause all the RenderImage
1217     // objects to remove themselves from the lists.
1218     m_imageLoadEventDispatchSoonList.clear();
1219     m_imageLoadEventDispatchingList.clear();
1220     
1221     
1222     // FIXME: UNLOAD_EVENT will not dispatch due to deleting event listeners prior to closeURL(). 
1223     removeAllEventListenersFromAllNodes();
1224
1225     NodeBaseImpl::detach();
1226
1227     if ( render )
1228         render->detach();
1229
1230     if (m_paintDevice == m_view)
1231         setPaintDevice(0);
1232     m_view = 0;
1233     
1234     if (m_renderArena){
1235         delete m_renderArena;
1236         m_renderArena = 0;
1237     }
1238 }
1239
1240 void DocumentImpl::removeAllEventListenersFromAllNodes()
1241 {
1242     m_windowEventListeners.clear();
1243     removeAllDisconnectedNodeEventListeners();
1244     for (NodeImpl *n = this; n; n = n->traverseNextNode()) {
1245         n->removeAllEventListeners();
1246     }
1247 }
1248
1249 void DocumentImpl::registerDisconnectedNodeWithEventListeners(NodeImpl *node)
1250 {
1251     m_disconnectedNodesWithEventListeners.insert(node, node);
1252 }
1253
1254 void DocumentImpl::unregisterDisconnectedNodeWithEventListeners(NodeImpl *node)
1255 {
1256     m_disconnectedNodesWithEventListeners.remove(node);
1257 }
1258
1259 void DocumentImpl::removeAllDisconnectedNodeEventListeners()
1260 {
1261     for (QPtrDictIterator<NodeImpl> iter(m_disconnectedNodesWithEventListeners);
1262          iter.current();
1263          ++iter) {
1264         iter.current()->removeAllEventListeners();
1265     }
1266 }
1267
1268 #if APPLE_CHANGES
1269 KWQAccObjectCache* DocumentImpl::getAccObjectCache()
1270 {
1271     // The only document that actually has a KWQAccObjectCache is the top-level
1272     // document.  This is because we need to be able to get from any KWQAccObject
1273     // to any other KWQAccObject on the same page.  Using a single cache allows
1274     // lookups across nested webareas (i.e. multiple documents).
1275     
1276     if (m_accCache) {
1277         // return already known top-level cache
1278         if (!ownerElement())
1279             return m_accCache;
1280         
1281         // In some pages with frames, the cache is created before the sub-webarea is
1282         // inserted into the tree.  Here, we catch that case and just toss the old
1283         // cache and start over.
1284         delete m_accCache;
1285         m_accCache = 0;
1286     }
1287     
1288     // look for top-level document
1289     ElementImpl *element = ownerElement();
1290     if (element) {
1291         DocumentImpl *doc;
1292         while (element) {
1293             doc = element->getDocument();
1294             element = doc->ownerElement();
1295         }
1296         
1297         // ask the top-level document for its cache
1298         return doc->getAccObjectCache();
1299     }
1300     
1301     // this is the top-level document, so install a new cache
1302     m_accCache = new KWQAccObjectCache;
1303     return m_accCache;
1304 }
1305 #endif
1306
1307 void DocumentImpl::setVisuallyOrdered()
1308 {
1309     visuallyOrdered = true;
1310     if (m_render)
1311         m_render->style()->setVisuallyOrdered(true);
1312 }
1313
1314 void DocumentImpl::updateSelection()
1315 {
1316     if (!m_render)
1317         return;
1318     
1319     RenderCanvas *canvas = static_cast<RenderCanvas*>(m_render);
1320     Selection s = part()->selection();
1321     if (!s.isRange()) {
1322         canvas->clearSelection();
1323     }
1324     else {
1325         Position startPos = VisiblePosition(s.start(), s.startAffinity(), khtml::VisiblePosition::INIT_UP).deepEquivalent();
1326         Position endPos = VisiblePosition(s.end(), s.endAffinity(), khtml::VisiblePosition::INIT_DOWN).deepEquivalent();
1327         if (startPos.isNotNull() && endPos.isNotNull()) {
1328             RenderObject *startRenderer = startPos.node()->renderer();
1329             RenderObject *endRenderer = endPos.node()->renderer();
1330             static_cast<RenderCanvas*>(m_render)->setSelection(startRenderer, startPos.offset(), endRenderer, endPos.offset());
1331         }
1332     }
1333     
1334 #if APPLE_CHANGES
1335     // send the AXSelectedTextChanged notification only if the new selection is non-null,
1336     // because null selections are only transitory (e.g. when starting an EditCommand, currently)
1337     if (KWQAccObjectCache::accessibilityEnabled() && s.start().isNotNull() && s.end().isNotNull()) {
1338         getAccObjectCache()->postNotificationToTopWebArea(renderer(), "AXSelectedTextChanged");
1339     }
1340 #endif
1341
1342 }
1343
1344 Tokenizer *DocumentImpl::createTokenizer()
1345 {
1346     return newXMLTokenizer(docPtr(), m_view);
1347 }
1348
1349 void DocumentImpl::setPaintDevice( QPaintDevice *dev )
1350 {
1351     if (m_paintDevice == dev) {
1352         return;
1353     }
1354     m_paintDevice = dev;
1355     delete m_paintDeviceMetrics;
1356     m_paintDeviceMetrics = dev ? new QPaintDeviceMetrics( dev ) : 0;
1357 }
1358
1359 void DocumentImpl::open(  )
1360 {
1361     if (parsing()) return;
1362
1363     implicitOpen();
1364
1365     if (part()) {
1366         part()->didExplicitOpen();
1367     }
1368
1369     // This is work that we should probably do in clear(), but we can't have it
1370     // happen when implicitOpen() is called unless we reorganize KHTMLPart code.
1371     setURL(QString());
1372     DocumentImpl *parent = parentDocument();
1373     if (parent) {
1374         setBaseURL(parent->baseURL());
1375     }
1376 }
1377
1378 void DocumentImpl::implicitOpen()
1379 {
1380     if (m_tokenizer)
1381         close();
1382
1383     clear();
1384     m_tokenizer = createTokenizer();
1385     connect(m_tokenizer,SIGNAL(finishedParsing()),this,SIGNAL(finishedParsing()));
1386     setParsing(true);
1387
1388     if (m_view && m_view->part()->jScript()) {
1389         m_view->part()->jScript()->setSourceFile(m_url,""); //fixme
1390     }
1391 }
1392
1393 HTMLElementImpl* DocumentImpl::body()
1394 {
1395     NodeImpl *de = documentElement();
1396     if (!de)
1397         return 0;
1398     
1399     // try to prefer a FRAMESET element over BODY
1400     NodeImpl* body = 0;
1401     for (NodeImpl* i = de->firstChild(); i; i = i->nextSibling()) {
1402         if (i->id() == ID_FRAMESET)
1403             return static_cast<HTMLElementImpl*>(i);
1404         
1405         if (i->id() == ID_BODY)
1406             body = i;
1407     }
1408     return static_cast<HTMLElementImpl *>(body);
1409 }
1410
1411 void DocumentImpl::close()
1412 {
1413     if (part())
1414         part()->endIfNotLoading();
1415     implicitClose();
1416 }
1417
1418 void DocumentImpl::implicitClose()
1419 {
1420     // First fire the onload.
1421     
1422     bool wasLocationChangePending = part() && part()->isScheduledLocationChangePending();
1423     bool doload = !parsing() && m_tokenizer && !m_processingLoadEvent && !wasLocationChangePending;
1424     
1425     if (doload) {
1426         m_processingLoadEvent = true;
1427
1428         // We have to clear the tokenizer, in case someone document.write()s from the
1429         // onLoad event handler, as in Radar 3206524
1430         delete m_tokenizer;
1431         m_tokenizer = 0;
1432
1433         // Create a body element if we don't already have one.
1434         // In the case of Radar 3758785, the window.onload was set in some javascript, but never fired because there was no body.  
1435         // This behavior now matches Firefox and IE.
1436         HTMLElementImpl *body = this->body();
1437         if (!body && isHTMLDocument()) {
1438             NodeImpl *de = documentElement();
1439             if (de) {
1440                 body = new HTMLBodyElementImpl(docPtr());
1441                 int exceptionCode = 0;
1442                 de->appendChild(body, exceptionCode);
1443                 if (exceptionCode != 0)
1444                     body = 0;
1445             }
1446         }
1447
1448         if (body) {
1449             dispatchImageLoadEventsNow();
1450             body->dispatchWindowEvent(EventImpl::LOAD_EVENT, false, false);
1451
1452 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1453             if (!ownerElement())
1454                 printf("onload fired at %d\n", elapsedTime());
1455 #endif
1456         }
1457
1458         m_processingLoadEvent = false;
1459     }
1460     
1461     // Make sure both the initial layout and reflow happen after the onload
1462     // fires. This will improve onload scores, and other browsers do it.
1463     // If they wanna cheat, we can too. -dwh
1464     
1465     bool isLocationChangePending = part() && part()->isScheduledLocationChangePending();
1466     
1467     if (doload && isLocationChangePending && m_startTime.elapsed() < cLayoutScheduleThreshold) {
1468         // Just bail out. Before or during the onload we were shifted to another page.
1469         // The old i-Bench suite does this. When this happens don't bother painting or laying out.        
1470         delete m_tokenizer;
1471         m_tokenizer = 0;
1472         view()->unscheduleRelayout();
1473         return;
1474     }
1475     
1476     if (doload) {
1477         // on an explicit document.close(), the tokenizer might still be waiting on scripts,
1478         // and in that case we don't want to destroy it because that will prevent the
1479         // scripts from getting processed.
1480         // FIXME: this check may no longer be necessary, since now it should be impossible
1481         // for parsing to be false while stil waiting for scripts
1482         if (m_tokenizer && !m_tokenizer->isWaitingForScripts()) {
1483             delete m_tokenizer;
1484             m_tokenizer = 0;
1485         }
1486
1487         if (m_view)
1488             m_view->part()->checkEmitLoadEvent();
1489     }
1490
1491     // Now do our painting/layout, but only if we aren't in a subframe or if we're in a subframe
1492     // that has been sized already.  Otherwise, our view size would be incorrect, so doing any 
1493     // layout/painting now would be pointless.
1494     if (doload) {
1495         if (!ownerElement() || (ownerElement()->renderer() && !ownerElement()->renderer()->needsLayout())) {
1496             updateRendering();
1497             
1498             // Always do a layout after loading if needed.
1499             if (view() && renderer() && (!renderer()->firstChild() || renderer()->needsLayout()))
1500                 view()->layout();
1501         }
1502 #if APPLE_CHANGES
1503         if (renderer() && KWQAccObjectCache::accessibilityEnabled())
1504             getAccObjectCache()->postNotification(renderer(), "AXLoadComplete");
1505 #endif
1506     }
1507 }
1508
1509 void DocumentImpl::setParsing(bool b)
1510 {
1511     m_bParsing = b;
1512     if (!m_bParsing && view())
1513         view()->scheduleRelayout();
1514
1515 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1516     if (!ownerElement() && !m_bParsing)
1517         printf("Parsing finished at %d\n", elapsedTime());
1518 #endif
1519 }
1520
1521 bool DocumentImpl::shouldScheduleLayout()
1522 {
1523     // We can update layout if:
1524     // (a) we actually need a layout
1525     // (b) our stylesheets are all loaded
1526     // (c) we have a <body>
1527     return (renderer() && renderer()->needsLayout() && haveStylesheetsLoaded() &&
1528             documentElement() && documentElement()->renderer() &&
1529             (documentElement()->id() != ID_HTML || body()));
1530 }
1531
1532 int DocumentImpl::minimumLayoutDelay()
1533 {
1534     if (m_overMinimumLayoutThreshold)
1535         return 0;
1536     
1537     int elapsed = m_startTime.elapsed();
1538     m_overMinimumLayoutThreshold = elapsed > cLayoutScheduleThreshold;
1539     
1540     // We'll want to schedule the timer to fire at the minimum layout threshold.
1541     return kMax(0, cLayoutScheduleThreshold - elapsed);
1542 }
1543
1544 int DocumentImpl::elapsedTime() const
1545 {
1546     return m_startTime.elapsed();
1547 }
1548
1549 void DocumentImpl::write( const DOMString &text )
1550 {
1551     write(text.string());
1552 }
1553
1554 void DocumentImpl::write( const QString &text )
1555 {
1556 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1557     if (!ownerElement())
1558         printf("Beginning a document.write at %d\n", elapsedTime());
1559 #endif
1560     
1561     if (!m_tokenizer) {
1562         open();
1563         write(QString::fromLatin1("<html>"));
1564     }
1565     m_tokenizer->write(text, false);
1566
1567     if (m_view && m_view->part()->jScript())
1568         m_view->part()->jScript()->appendSourceFile(m_url,text);
1569     
1570 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1571     if (!ownerElement())
1572         printf("Ending a document.write at %d\n", elapsedTime());
1573 #endif    
1574 }
1575
1576 void DocumentImpl::writeln( const DOMString &text )
1577 {
1578     write(text);
1579     write(DOMString("\n"));
1580 }
1581
1582 void DocumentImpl::finishParsing()
1583 {
1584 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1585     if (!ownerElement())
1586         printf("Received all data at %d\n", elapsedTime());
1587 #endif
1588     
1589     // Let the tokenizer go through as much data as it can.  There will be three possible outcomes after
1590     // finish() is called:
1591     // (1) All remaining data is parsed, document isn't loaded yet
1592     // (2) All remaining data is parsed, document is loaded, tokenizer gets deleted
1593     // (3) Data is still remaining to be parsed.
1594     if (m_tokenizer)
1595         m_tokenizer->finish();
1596 }
1597
1598 void DocumentImpl::clear()
1599 {
1600     delete m_tokenizer;
1601     m_tokenizer = 0;
1602
1603     removeChildren();
1604     QPtrListIterator<RegisteredEventListener> it(m_windowEventListeners);
1605     for (; it.current();)
1606         m_windowEventListeners.removeRef(it.current());
1607 }
1608
1609 void DocumentImpl::setURL(const QString& url)
1610 {
1611     m_url = url;
1612     if (m_styleSelector)
1613         m_styleSelector->setEncodedURL(m_url);
1614 }
1615
1616 void DocumentImpl::setStyleSheet(const DOMString &url, const DOMString &sheet)
1617 {
1618 //    kdDebug( 6030 ) << "HTMLDocument::setStyleSheet()" << endl;
1619     m_sheet = new CSSStyleSheetImpl(this, url);
1620     m_sheet->ref();
1621     m_sheet->parseString(sheet);
1622     m_loadingSheet = false;
1623
1624     updateStyleSelector();
1625 }
1626
1627 void DocumentImpl::setUserStyleSheet( const QString& sheet )
1628 {
1629     if ( m_usersheet != sheet ) {
1630         m_usersheet = sheet;
1631         updateStyleSelector();
1632     }
1633 }
1634
1635 CSSStyleSheetImpl* DocumentImpl::elementSheet()
1636 {
1637     if (!m_elemSheet) {
1638         m_elemSheet = new CSSStyleSheetImpl(this, baseURL() );
1639         m_elemSheet->ref();
1640     }
1641     return m_elemSheet;
1642 }
1643
1644 void DocumentImpl::determineParseMode( const QString &/*str*/ )
1645 {
1646     // For XML documents use strict parse mode.  HTML docs will override this method to
1647     // determine their parse mode.
1648     pMode = Strict;
1649     hMode = XHtml;
1650     kdDebug(6020) << " using strict parseMode" << endl;
1651 }
1652
1653 // Please see if there`s a possibility to merge that code
1654 // with the next function and getElementByID().
1655 NodeImpl *DocumentImpl::findElement( Id id )
1656 {
1657     QPtrStack<NodeImpl> nodeStack;
1658     NodeImpl *current = _first;
1659
1660     while(1)
1661     {
1662         if(!current)
1663         {
1664             if(nodeStack.isEmpty()) break;
1665             current = nodeStack.pop();
1666             current = current->nextSibling();
1667         }
1668         else
1669         {
1670             if(current->id() == id)
1671                 return current;
1672
1673             NodeImpl *child = current->firstChild();
1674             if(child)
1675             {
1676                 nodeStack.push(current);
1677                 current = child;
1678             }
1679             else
1680             {
1681                 current = current->nextSibling();
1682             }
1683         }
1684     }
1685
1686     return 0;
1687 }
1688
1689 NodeImpl *DocumentImpl::nextFocusNode(NodeImpl *fromNode)
1690 {
1691     unsigned short fromTabIndex;
1692
1693     if (!fromNode) {
1694         // No starting node supplied; begin with the top of the document
1695         NodeImpl *n;
1696
1697         int lowestTabIndex = 65535;
1698         for (n = this; n != 0; n = n->traverseNextNode()) {
1699             if (n->isKeyboardFocusable()) {
1700                 if ((n->tabIndex() > 0) && (n->tabIndex() < lowestTabIndex))
1701                     lowestTabIndex = n->tabIndex();
1702             }
1703         }
1704
1705         if (lowestTabIndex == 65535)
1706             lowestTabIndex = 0;
1707
1708         // Go to the first node in the document that has the desired tab index
1709         for (n = this; n != 0; n = n->traverseNextNode()) {
1710             if (n->isKeyboardFocusable() && (n->tabIndex() == lowestTabIndex))
1711                 return n;
1712         }
1713
1714         return 0;
1715     }
1716     else {
1717         fromTabIndex = fromNode->tabIndex();
1718     }
1719
1720     if (fromTabIndex == 0) {
1721         // Just need to find the next selectable node after fromNode (in document order) that doesn't have a tab index
1722         NodeImpl *n = fromNode->traverseNextNode();
1723         while (n && !(n->isKeyboardFocusable() && n->tabIndex() == 0))
1724             n = n->traverseNextNode();
1725         return n;
1726     }
1727     else {
1728         // Find the lowest tab index out of all the nodes except fromNode, that is greater than or equal to fromNode's
1729         // tab index. For nodes with the same tab index as fromNode, we are only interested in those that come after
1730         // fromNode in document order.
1731         // If we don't find a suitable tab index, the next focus node will be one with a tab index of 0.
1732         unsigned short lowestSuitableTabIndex = 65535;
1733         NodeImpl *n;
1734
1735         bool reachedFromNode = false;
1736         for (n = this; n != 0; n = n->traverseNextNode()) {
1737             if (n->isKeyboardFocusable() &&
1738                 ((reachedFromNode && (n->tabIndex() >= fromTabIndex)) ||
1739                  (!reachedFromNode && (n->tabIndex() > fromTabIndex))) &&
1740                 (n->tabIndex() < lowestSuitableTabIndex) &&
1741                 (n != fromNode)) {
1742
1743                 // We found a selectable node with a tab index at least as high as fromNode's. Keep searching though,
1744                 // as there may be another node which has a lower tab index but is still suitable for use.
1745                 lowestSuitableTabIndex = n->tabIndex();
1746             }
1747
1748             if (n == fromNode)
1749                 reachedFromNode = true;
1750         }
1751
1752         if (lowestSuitableTabIndex == 65535) {
1753             // No next node with a tab index -> just take first node with tab index of 0
1754             NodeImpl *n = this;
1755             while (n && !(n->isKeyboardFocusable() && n->tabIndex() == 0))
1756                 n = n->traverseNextNode();
1757             return n;
1758         }
1759
1760         // Search forwards from fromNode
1761         for (n = fromNode->traverseNextNode(); n != 0; n = n->traverseNextNode()) {
1762             if (n->isKeyboardFocusable() && (n->tabIndex() == lowestSuitableTabIndex))
1763                 return n;
1764         }
1765
1766         // The next node isn't after fromNode, start from the beginning of the document
1767         for (n = this; n != fromNode; n = n->traverseNextNode()) {
1768             if (n->isKeyboardFocusable() && (n->tabIndex() == lowestSuitableTabIndex))
1769                 return n;
1770         }
1771
1772         assert(false); // should never get here
1773         return 0;
1774     }
1775 }
1776
1777 NodeImpl *DocumentImpl::previousFocusNode(NodeImpl *fromNode)
1778 {
1779     NodeImpl *lastNode = this;
1780     while (lastNode->lastChild())
1781         lastNode = lastNode->lastChild();
1782
1783     if (!fromNode) {
1784         // No starting node supplied; begin with the very last node in the document
1785         NodeImpl *n;
1786
1787         int highestTabIndex = 0;
1788         for (n = lastNode; n != 0; n = n->traversePreviousNode()) {
1789             if (n->isKeyboardFocusable()) {
1790                 if (n->tabIndex() == 0)
1791                     return n;
1792                 else if (n->tabIndex() > highestTabIndex)
1793                     highestTabIndex = n->tabIndex();
1794             }
1795         }
1796
1797         // No node with a tab index of 0; just go to the last node with the highest tab index
1798         for (n = lastNode; n != 0; n = n->traversePreviousNode()) {
1799             if (n->isKeyboardFocusable() && (n->tabIndex() == highestTabIndex))
1800                 return n;
1801         }
1802
1803         return 0;
1804     }
1805     else {
1806         unsigned short fromTabIndex = fromNode->tabIndex();
1807
1808         if (fromTabIndex == 0) {
1809             // Find the previous selectable node before fromNode (in document order) that doesn't have a tab index
1810             NodeImpl *n = fromNode->traversePreviousNode();
1811             while (n && !(n->isKeyboardFocusable() && n->tabIndex() == 0))
1812                 n = n->traversePreviousNode();
1813             if (n)
1814                 return n;
1815
1816             // No previous nodes with a 0 tab index, go to the last node in the document that has the highest tab index
1817             int highestTabIndex = 0;
1818             for (n = this; n != 0; n = n->traverseNextNode()) {
1819                 if (n->isKeyboardFocusable() && (n->tabIndex() > highestTabIndex))
1820                     highestTabIndex = n->tabIndex();
1821             }
1822
1823             if (highestTabIndex == 0)
1824                 return 0;
1825
1826             for (n = lastNode; n != 0; n = n->traversePreviousNode()) {
1827                 if (n->isKeyboardFocusable() && (n->tabIndex() == highestTabIndex))
1828                     return n;
1829             }
1830
1831             assert(false); // should never get here
1832             return 0;
1833         }
1834         else {
1835             // Find the lowest tab index out of all the nodes except fromNode, that is less than or equal to fromNode's
1836             // tab index. For nodes with the same tab index as fromNode, we are only interested in those before
1837             // fromNode.
1838             // If we don't find a suitable tab index, then there will be no previous focus node.
1839             unsigned short highestSuitableTabIndex = 0;
1840             NodeImpl *n;
1841
1842             bool reachedFromNode = false;
1843             for (n = this; n != 0; n = n->traverseNextNode()) {
1844                 if (n->isKeyboardFocusable() &&
1845                     ((!reachedFromNode && (n->tabIndex() <= fromTabIndex)) ||
1846                      (reachedFromNode && (n->tabIndex() < fromTabIndex)))  &&
1847                     (n->tabIndex() > highestSuitableTabIndex) &&
1848                     (n != fromNode)) {
1849
1850                     // We found a selectable node with a tab index no higher than fromNode's. Keep searching though, as
1851                     // there may be another node which has a higher tab index but is still suitable for use.
1852                     highestSuitableTabIndex = n->tabIndex();
1853                 }
1854
1855                 if (n == fromNode)
1856                     reachedFromNode = true;
1857             }
1858
1859             if (highestSuitableTabIndex == 0) {
1860                 // No previous node with a tab index. Since the order specified by HTML is nodes with tab index > 0
1861                 // first, this means that there is no previous node.
1862                 return 0;
1863             }
1864
1865             // Search backwards from fromNode
1866             for (n = fromNode->traversePreviousNode(); n != 0; n = n->traversePreviousNode()) {
1867                 if (n->isKeyboardFocusable() && (n->tabIndex() == highestSuitableTabIndex))
1868                     return n;
1869             }
1870             // The previous node isn't before fromNode, start from the end of the document
1871             for (n = lastNode; n != fromNode; n = n->traversePreviousNode()) {
1872                 if (n->isKeyboardFocusable() && (n->tabIndex() == highestSuitableTabIndex))
1873                     return n;
1874             }
1875
1876             assert(false); // should never get here
1877             return 0;
1878         }
1879     }
1880 }
1881
1882 int DocumentImpl::nodeAbsIndex(NodeImpl *node)
1883 {
1884     assert(node->getDocument() == this);
1885
1886     int absIndex = 0;
1887     for (NodeImpl *n = node; n && n != this; n = n->traversePreviousNode())
1888         absIndex++;
1889     return absIndex;
1890 }
1891
1892 NodeImpl *DocumentImpl::nodeWithAbsIndex(int absIndex)
1893 {
1894     NodeImpl *n = this;
1895     for (int i = 0; n && (i < absIndex); i++) {
1896         n = n->traverseNextNode();
1897     }
1898     return n;
1899 }
1900
1901 void DocumentImpl::processHttpEquiv(const DOMString &equiv, const DOMString &content)
1902 {
1903     assert(!equiv.isNull() && !content.isNull());
1904
1905     KHTMLPart *part = this->part();
1906
1907     if (strcasecmp(equiv, "default-style") == 0) {
1908         // The preferred style set has been overridden as per section 
1909         // 14.3.2 of the HTML4.0 specification.  We need to update the
1910         // sheet used variable and then update our style selector. 
1911         // For more info, see the test at:
1912         // http://www.hixie.ch/tests/evil/css/import/main/preferred.html
1913         // -dwh
1914         part->d->m_sheetUsed = content.string();
1915         m_preferredStylesheetSet = content;
1916         updateStyleSelector();
1917     }
1918     else if(strcasecmp(equiv, "refresh") == 0 && part->metaRefreshEnabled())
1919     {
1920         // get delay and url
1921         QString str = content.string().stripWhiteSpace();
1922         int pos = str.find(QRegExp("[;,]"));
1923         if ( pos == -1 )
1924             pos = str.find(QRegExp("[ \t]"));
1925
1926         if (pos == -1) // There can be no url (David)
1927         {
1928             bool ok = false;
1929             int delay = 0;
1930             delay = str.toInt(&ok);
1931 #if APPLE_CHANGES
1932             // We want a new history item if the refresh timeout > 1 second
1933             if(ok && part) part->scheduleRedirection(delay, part->url().url(), delay <= 1);
1934 #else
1935             if(ok && part) part->scheduleRedirection(delay, part->url().url() );
1936 #endif
1937         } else {
1938             double delay = 0;
1939             bool ok = false;
1940             delay = str.left(pos).stripWhiteSpace().toDouble(&ok);
1941
1942             pos++;
1943             while(pos < (int)str.length() && str[pos].isSpace()) pos++;
1944             str = str.mid(pos);
1945             if(str.find("url", 0,  false ) == 0)  str = str.mid(3);
1946             str = str.stripWhiteSpace();
1947             if ( str.length() && str[0] == '=' ) str = str.mid( 1 ).stripWhiteSpace();
1948             str = parseURL( DOMString(str) ).string();
1949             if ( ok && part )
1950 #if APPLE_CHANGES
1951                 // We want a new history item if the refresh timeout > 1 second
1952                 part->scheduleRedirection(delay, completeURL( str ), delay <= 1);
1953 #else
1954                 part->scheduleRedirection(delay, completeURL( str ));
1955 #endif
1956         }
1957     }
1958     else if(strcasecmp(equiv, "expires") == 0)
1959     {
1960         QString str = content.string().stripWhiteSpace();
1961         time_t expire_date = str.toLong();
1962         if (m_docLoader)
1963             m_docLoader->setExpireDate(expire_date);
1964     }
1965     else if(strcasecmp(equiv, "pragma") == 0 || strcasecmp(equiv, "cache-control") == 0 && part)
1966     {
1967         QString str = content.string().lower().stripWhiteSpace();
1968         KURL url = part->url();
1969         if ((str == "no-cache") && url.protocol().startsWith("http"))
1970         {
1971            KIO::http_update_cache(url, true, 0);
1972         }
1973     }
1974     else if( (strcasecmp(equiv, "set-cookie") == 0))
1975     {
1976         // ### make setCookie work on XML documents too; e.g. in case of <html:meta .....>
1977         HTMLDocumentImpl *d = static_cast<HTMLDocumentImpl *>(this);
1978         d->setCookie(content);
1979     }
1980 }
1981
1982 bool DocumentImpl::prepareMouseEvent( bool readonly, int _x, int _y, MouseEvent *ev )
1983 {
1984     if ( m_render ) {
1985         assert(m_render->isCanvas());
1986         RenderObject::NodeInfo renderInfo(readonly, ev->type == MousePress);
1987         bool isInside = m_render->layer()->hitTest(renderInfo, _x, _y);
1988         ev->innerNode = renderInfo.innerNode();
1989
1990         if (renderInfo.URLElement()) {
1991             assert(renderInfo.URLElement()->isElementNode());
1992             ElementImpl* e =  static_cast<ElementImpl*>(renderInfo.URLElement());
1993             DOMString href = khtml::parseURL(e->getAttribute(ATTR_HREF));
1994             DOMString target = e->getAttribute(ATTR_TARGET);
1995
1996             if (!target.isNull() && !href.isNull()) {
1997                 ev->target = target;
1998                 ev->url = href;
1999             }
2000             else
2001                 ev->url = href;
2002 //            qDebug("url: *%s*", ev->url.string().latin1());
2003         }
2004
2005         if (!readonly)
2006             updateRendering();
2007
2008         return isInside;
2009     }
2010
2011
2012     return false;
2013 }
2014
2015 // DOM Section 1.1.1
2016 bool DocumentImpl::childAllowed( NodeImpl *newChild )
2017 {
2018     // Documents may contain a maximum of one Element child
2019     if (newChild->nodeType() == Node::ELEMENT_NODE) {
2020         NodeImpl *c;
2021         for (c = firstChild(); c; c = c->nextSibling()) {
2022             if (c->nodeType() == Node::ELEMENT_NODE)
2023                 return false;
2024         }
2025     }
2026
2027     // Documents may contain a maximum of one DocumentType child
2028     if (newChild->nodeType() == Node::DOCUMENT_TYPE_NODE) {
2029         NodeImpl *c;
2030         for (c = firstChild(); c; c = c->nextSibling()) {
2031             if (c->nodeType() == Node::DOCUMENT_TYPE_NODE)
2032                 return false;
2033         }
2034     }
2035
2036     return childTypeAllowed(newChild->nodeType());
2037 }
2038
2039 bool DocumentImpl::childTypeAllowed( unsigned short type )
2040 {
2041     switch (type) {
2042         case Node::ELEMENT_NODE:
2043         case Node::PROCESSING_INSTRUCTION_NODE:
2044         case Node::COMMENT_NODE:
2045         case Node::DOCUMENT_TYPE_NODE:
2046             return true;
2047         default:
2048             return false;
2049     }
2050 }
2051
2052 NodeImpl *DocumentImpl::cloneNode ( bool /*deep*/ )
2053 {
2054     // Spec says cloning Document nodes is "implementation dependent"
2055     // so we do not support it...
2056     return 0;
2057 }
2058
2059 NodeImpl::Id DocumentImpl::attrId(DOMStringImpl* _namespaceURI, DOMStringImpl *_name, bool readonly)
2060 {
2061     // Each document maintains a mapping of attrname -> id for every attr name
2062     // encountered in the document.
2063     // For attrnames without a prefix (no qualified element name) and without matching
2064     // namespace, the value defined in misc/htmlattrs.h is used.
2065     NodeImpl::Id id = 0;
2066
2067     // First see if it's a HTML attribute name
2068     QConstString n(_name->s, _name->l);
2069     if (!_namespaceURI || !strcasecmp(_namespaceURI, XHTML_NAMESPACE)) {
2070         // we're in HTML namespace if we know the tag.
2071         // xhtml is lower case - case sensitive, easy to implement
2072         if ( htmlMode() == XHtml && (id = getAttrID(n.string().ascii(), _name->l)) )
2073             return id;
2074         // compatibility: upper case - case insensitive
2075         if ( htmlMode() != XHtml && (id = getAttrID(n.string().lower().ascii(), _name->l )) )
2076             return id;
2077
2078         // ok, the fast path didn't work out, we need the full check
2079     }
2080
2081     // now lets find out the namespace
2082     Q_UINT16 ns = noNamespace;
2083     if (_namespaceURI) {
2084         DOMString nsU(_namespaceURI);
2085         int nsID = XmlNamespaceTable::getNamespaceID(nsU, readonly);
2086         if (nsID != -1)
2087             ns = (Q_UINT16)nsID;
2088     }
2089     
2090     // Look in the m_attrNames array for the name
2091     // ### yeah, this is lame. use a dictionary / map instead
2092     DOMString nme(n.string());
2093     // compatibility mode has to store upper case
2094     if (htmlMode() != XHtml) nme = nme.upper();
2095     for (id = 0; id < m_attrNameCount; id++)
2096         if (DOMString(m_attrNames[id]) == nme)
2097             return makeId(ns, ATTR_LAST_ATTR+id);
2098
2099     // unknown
2100     if (readonly) return 0;
2101
2102     // Name not found in m_attrNames, so let's add it
2103     // ### yeah, this is lame. use a dictionary / map instead
2104     if (m_attrNameCount+1 > m_attrNameAlloc) {
2105         m_attrNameAlloc += 100;
2106         DOMStringImpl **newNames = new DOMStringImpl* [m_attrNameAlloc];
2107         if (m_attrNames) {
2108             unsigned short i;
2109             for (i = 0; i < m_attrNameCount; i++)
2110                 newNames[i] = m_attrNames[i];
2111             delete [] m_attrNames;
2112         }
2113         m_attrNames = newNames;
2114     }
2115
2116     id = m_attrNameCount++;
2117     m_attrNames[id] = nme.implementation();
2118     m_attrNames[id]->ref();
2119
2120     return makeId(ns, ATTR_LAST_ATTR+id);
2121 }
2122
2123 DOMString DocumentImpl::attrName(NodeImpl::Id _id) const
2124 {
2125     DOMString result;
2126     if (localNamePart(_id) >= ATTR_LAST_ATTR)
2127         result = m_attrNames[localNamePart(_id)-ATTR_LAST_ATTR];
2128     else
2129         result = getAttrName(_id);
2130
2131     // Attribute names are always lowercase in the DOM for both
2132     // HTML and XHTML.
2133     if (isHTMLDocument() || htmlMode() == XHtml)
2134         return result.lower();
2135
2136     return result;
2137 }
2138
2139 NodeImpl::Id DocumentImpl::tagId(DOMStringImpl* _namespaceURI, DOMStringImpl *_name, bool readonly)
2140 {
2141     if (!_name) return 0;
2142     // Each document maintains a mapping of tag name -> id for every tag name encountered
2143     // in the document.
2144     NodeImpl::Id id = 0;
2145
2146     // First see if it's a HTML element name
2147     QConstString n(_name->s, _name->l);
2148     if (!_namespaceURI || !strcasecmp(_namespaceURI, XHTML_NAMESPACE)) {
2149         // we're in HTML namespace if we know the tag.
2150         // xhtml is lower case - case sensitive, easy to implement
2151         if ( htmlMode() == XHtml && (id = getTagID(n.string().ascii(), _name->l)) )
2152             return id;
2153         // compatibility: upper case - case insensitive
2154         if ( htmlMode() != XHtml && (id = getTagID(n.string().lower().ascii(), _name->l )) )
2155             return id;
2156
2157         // ok, the fast path didn't work out, we need the full check
2158     }
2159
2160     // now lets find out the namespace
2161     Q_UINT16 ns = noNamespace;
2162     if (_namespaceURI) {
2163         DOMString nsU(_namespaceURI);
2164         int nsID = XmlNamespaceTable::getNamespaceID(nsU, readonly);
2165         if (nsID != -1)
2166             ns = (Q_UINT16)nsID;
2167     }
2168
2169     // Look in the m_elementNames array for the name
2170     // ### yeah, this is lame. use a dictionary / map instead
2171     DOMString nme(n.string());
2172     // compatibility mode has to store upper case
2173     if (htmlMode() != XHtml) nme = nme.upper();
2174     for (id = 0; id < m_elementNameCount; id++)
2175         if (DOMString(m_elementNames[id]) == nme)
2176             return makeId(ns, ID_LAST_TAG + 1 + id);
2177
2178     // unknown
2179     if (readonly) return 0;
2180
2181     // Name not found in m_elementNames, so let's add it
2182     if (m_elementNameCount+1 > m_elementNameAlloc) {
2183         m_elementNameAlloc += 100;
2184         DOMStringImpl **newNames = new DOMStringImpl* [m_elementNameAlloc];
2185         // ### yeah, this is lame. use a dictionary / map instead
2186         if (m_elementNames) {
2187             unsigned short i;
2188             for (i = 0; i < m_elementNameCount; i++)
2189                 newNames[i] = m_elementNames[i];
2190             delete [] m_elementNames;
2191         }
2192         m_elementNames = newNames;
2193     }
2194
2195     id = m_elementNameCount++;
2196     m_elementNames[id] = nme.implementation();
2197     m_elementNames[id]->ref();
2198
2199     return makeId(ns, ID_LAST_TAG + 1 + id);
2200 }
2201
2202 DOMString DocumentImpl::tagName(NodeImpl::Id _id) const
2203 {
2204     if (localNamePart(_id) > ID_LAST_TAG)
2205         return m_elementNames[localNamePart(_id) - (ID_LAST_TAG + 1)];
2206     else {
2207         // ### put them in a cache
2208         if (htmlMode() == XHtml)
2209             return getTagName(_id).lower();
2210         else
2211             return getTagName(_id);
2212     }
2213 }
2214
2215
2216 DOMStringImpl* DocumentImpl::namespaceURI(NodeImpl::Id _id) const
2217 {
2218     if (_id <= ID_LAST_TAG)
2219         return htmlMode() == XHtml ? XmlNamespaceTable::getNamespaceURI(xhtmlNamespace).implementation() : 0;
2220
2221     unsigned short ns = _id >> 16;
2222
2223     if (!ns) return 0;
2224
2225     return XmlNamespaceTable::getNamespaceURI(ns).implementation();
2226 }
2227
2228 StyleSheetListImpl* DocumentImpl::styleSheets()
2229 {
2230     return m_styleSheets;
2231 }
2232
2233 DOMString DocumentImpl::preferredStylesheetSet()
2234 {
2235   return m_preferredStylesheetSet;
2236 }
2237
2238 DOMString DocumentImpl::selectedStylesheetSet()
2239 {
2240   return view() ? view()->part()->d->m_sheetUsed : DOMString();
2241 }
2242
2243 void 
2244 DocumentImpl::setSelectedStylesheetSet(const DOMString& aString)
2245 {
2246   if (view()) {
2247     view()->part()->d->m_sheetUsed = aString.string();
2248     updateStyleSelector();
2249     if (renderer())
2250       renderer()->repaint();
2251   }
2252 }
2253
2254 // This method is called whenever a top-level stylesheet has finished loading.
2255 void DocumentImpl::stylesheetLoaded()
2256 {
2257   // Make sure we knew this sheet was pending, and that our count isn't out of sync.
2258   assert(m_pendingStylesheets > 0);
2259
2260   m_pendingStylesheets--;
2261   
2262 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2263   if (!ownerElement())
2264       printf("Stylesheet loaded at time %d. %d stylesheets still remain.\n", elapsedTime(), m_pendingStylesheets);
2265 #endif
2266
2267   updateStyleSelector();    
2268 }
2269
2270 void DocumentImpl::updateStyleSelector()
2271 {
2272     // Don't bother updating, since we haven't loaded all our style info yet.
2273     if (!haveStylesheetsLoaded())
2274         return;
2275
2276 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2277     if (!ownerElement())
2278         printf("Beginning update of style selector at time %d.\n", elapsedTime());
2279 #endif
2280
2281     recalcStyleSelector();
2282     recalcStyle(Force);
2283 #if 0
2284
2285     m_styleSelectorDirty = true;
2286 #endif
2287
2288 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2289     if (!ownerElement())
2290         printf("Finished update of style selector at time %d\n", elapsedTime());
2291 #endif
2292
2293     if (renderer()) {
2294         renderer()->setNeedsLayoutAndMinMaxRecalc();
2295         if (view())
2296             view()->scheduleRelayout();
2297     }
2298 }
2299
2300
2301 QStringList DocumentImpl::availableStyleSheets() const
2302 {
2303     return m_availableSheets;
2304 }
2305
2306 void DocumentImpl::recalcStyleSelector()
2307 {
2308     if ( !m_render || !attached() ) return;
2309
2310     QPtrList<StyleSheetImpl> oldStyleSheets = m_styleSheets->styleSheets;
2311     m_styleSheets->styleSheets.clear();
2312     m_availableSheets.clear();
2313     NodeImpl *n;
2314     for (n = this; n; n = n->traverseNextNode()) {
2315         StyleSheetImpl *sheet = 0;
2316
2317         if (n->nodeType() == Node::PROCESSING_INSTRUCTION_NODE)
2318         {
2319             // Processing instruction (XML documents only)
2320             ProcessingInstructionImpl* pi = static_cast<ProcessingInstructionImpl*>(n);
2321             sheet = pi->sheet();
2322 #ifdef KHTML_XSLT
2323             if (pi->isXSL()) {
2324                 applyXSLTransform(pi);
2325                 return;
2326             }
2327 #endif
2328             if (!sheet && !pi->localHref().isEmpty())
2329             {
2330                 // Processing instruction with reference to an element in this document - e.g.
2331                 // <?xml-stylesheet href="#mystyle">, with the element
2332                 // <foo id="mystyle">heading { color: red; }</foo> at some location in
2333                 // the document
2334                 ElementImpl* elem = getElementById(pi->localHref());
2335                 if (elem) {
2336                     DOMString sheetText("");
2337                     NodeImpl *c;
2338                     for (c = elem->firstChild(); c; c = c->nextSibling()) {
2339                         if (c->nodeType() == Node::TEXT_NODE || c->nodeType() == Node::CDATA_SECTION_NODE)
2340                             sheetText += c->nodeValue();
2341                     }
2342
2343                     CSSStyleSheetImpl *cssSheet = new CSSStyleSheetImpl(this);
2344                     cssSheet->parseString(sheetText);
2345                     pi->setStyleSheet(cssSheet);
2346                     sheet = cssSheet;
2347                 }
2348             }
2349
2350         }
2351         else if (n->isHTMLElement() && (n->id() == ID_LINK || n->id() == ID_STYLE)) {
2352             ElementImpl *e = static_cast<ElementImpl *>(n);
2353             QString title = e->getAttribute( ATTR_TITLE ).string();
2354             bool enabledViaScript = false;
2355             if (n->id() == ID_LINK) {
2356                 // <LINK> element
2357                 HTMLLinkElementImpl* l = static_cast<HTMLLinkElementImpl*>(n);
2358                 if (l->isLoading() || l->isDisabled())
2359                     continue;
2360                 if (!l->sheet())
2361                     title = QString::null;
2362                 enabledViaScript = l->isEnabledViaScript();
2363             }
2364
2365             // Get the current preferred styleset.  This is the
2366             // set of sheets that will be enabled.
2367             if ( n->id() == ID_LINK )
2368                 sheet = static_cast<HTMLLinkElementImpl*>(n)->sheet();
2369             else
2370                 // <STYLE> element
2371                 sheet = static_cast<HTMLStyleElementImpl*>(n)->sheet();
2372
2373             // Check to see if this sheet belongs to a styleset
2374             // (thus making it PREFERRED or ALTERNATE rather than
2375             // PERSISTENT).
2376             if (!enabledViaScript && !title.isEmpty()) {
2377                 // Yes, we have a title.
2378                 if (m_preferredStylesheetSet.isEmpty()) {
2379                     // No preferred set has been established.  If
2380                     // we are NOT an alternate sheet, then establish
2381                     // us as the preferred set.  Otherwise, just ignore
2382                     // this sheet.
2383                     QString rel = e->getAttribute( ATTR_REL ).string();
2384                     if (n->id() == ID_STYLE || !rel.contains("alternate"))
2385                         m_preferredStylesheetSet = view()->part()->d->m_sheetUsed = title;
2386                 }
2387                       
2388                 if (!m_availableSheets.contains( title ) )
2389                     m_availableSheets.append( title );
2390                 
2391                 if (title != m_preferredStylesheetSet)
2392                     sheet = 0;
2393             }
2394         }
2395
2396         if (sheet) {
2397             sheet->ref();
2398             m_styleSheets->styleSheets.append(sheet);
2399         }
2400     
2401         // For HTML documents, stylesheets are not allowed within/after the <BODY> tag. So we
2402         // can stop searching here.
2403         if (isHTMLDocument() && n->id() == ID_BODY)
2404             break;
2405     }
2406
2407     // De-reference all the stylesheets in the old list
2408     QPtrListIterator<StyleSheetImpl> it(oldStyleSheets);
2409     for (; it.current(); ++it)
2410         it.current()->deref();
2411
2412     // Create a new style selector
2413     delete m_styleSelector;
2414     QString usersheet = m_usersheet;
2415     if ( m_view && m_view->mediaType() == "print" )
2416         usersheet += m_printSheet;
2417     m_styleSelector = new CSSStyleSelector(this, usersheet, m_styleSheets, !inCompatMode());
2418     m_styleSelector->setEncodedURL(m_url);
2419     m_styleSelectorDirty = false;
2420 }
2421
2422 void DocumentImpl::setHoverNode(NodeImpl* newHoverNode)
2423 {
2424     if (m_hoverNode != newHoverNode) {
2425         if (m_hoverNode)
2426             m_hoverNode->deref();
2427         m_hoverNode = newHoverNode;
2428         if (m_hoverNode)
2429             m_hoverNode->ref();
2430     }    
2431 }
2432
2433 #if APPLE_CHANGES
2434
2435 bool DocumentImpl::relinquishesEditingFocus(NodeImpl *node)
2436 {
2437     assert(node);
2438     assert(node->isContentEditable());
2439
2440     NodeImpl *rootImpl = node->rootEditableElement();
2441     if (!part() || !rootImpl)
2442         return false;
2443
2444     Node root(rootImpl);
2445     Range range(root, 0, root, rootImpl->childNodeCount());
2446     return part()->shouldEndEditing(range);
2447 }
2448
2449 bool DocumentImpl::acceptsEditingFocus(NodeImpl *node)
2450 {
2451     assert(node);
2452     assert(node->isContentEditable());
2453
2454     NodeImpl *rootImpl = node->rootEditableElement();
2455     if (!part() || !rootImpl)
2456         return false;
2457
2458     Node root(rootImpl);
2459     Range range(root, 0, root, rootImpl->childNodeCount());
2460     return part()->shouldBeginEditing(range);
2461 }
2462
2463 const QValueList<DashboardRegionValue> & DocumentImpl::dashboardRegions() const
2464 {
2465     return m_dashboardRegions;
2466 }
2467
2468 void DocumentImpl::setDashboardRegions (const QValueList<DashboardRegionValue>& regions)
2469 {
2470     m_dashboardRegions = regions;
2471     setDashboardRegionsDirty (false);
2472 }
2473
2474 #endif
2475
2476 static QWidget *widgetForNode(NodeImpl *focusNode)
2477 {
2478     if (!focusNode)
2479         return 0;
2480     RenderObject *renderer = focusNode->renderer();
2481     if (!renderer || !renderer->isWidget())
2482         return 0;
2483     return static_cast<RenderWidget *>(renderer)->widget();
2484 }
2485
2486 bool DocumentImpl::setFocusNode(NodeImpl *newFocusNode)
2487 {    
2488     // Make sure newFocusNode is actually in this document
2489     if (newFocusNode && (newFocusNode->getDocument() != this))
2490         return true;
2491
2492     if (m_focusNode == newFocusNode)
2493         return true;
2494
2495 #if APPLE_CHANGES
2496     if (m_focusNode && m_focusNode->isContentEditable() && !relinquishesEditingFocus(m_focusNode))
2497         return false;
2498 #endif     
2499        
2500     bool focusChangeBlocked = false;
2501     NodeImpl *oldFocusNode = m_focusNode;
2502     m_focusNode = 0;
2503
2504     // Remove focus from the existing focus node (if any)
2505     if (oldFocusNode) {
2506         // This goes hand in hand with the Qt focus setting below.
2507         if (!newFocusNode && view()) {
2508             view()->setFocus();
2509         }
2510
2511         if (oldFocusNode->active())
2512             oldFocusNode->setActive(false);
2513
2514         oldFocusNode->setFocus(false);
2515         oldFocusNode->dispatchHTMLEvent(EventImpl::BLUR_EVENT, false, false);
2516         if (m_focusNode != 0) {
2517             // handler shifted focus
2518             focusChangeBlocked = true;
2519             newFocusNode = 0;
2520         }
2521         oldFocusNode->dispatchUIEvent(EventImpl::DOMFOCUSOUT_EVENT);
2522         if (m_focusNode != 0) {
2523             // handler shifted focus
2524             focusChangeBlocked = true;
2525             newFocusNode = 0;
2526         }
2527         if ((oldFocusNode == this) && oldFocusNode->hasOneRef()) {
2528             oldFocusNode->deref(); // deletes this
2529             return true;
2530         }
2531         else {
2532             oldFocusNode->deref();
2533         }
2534     }
2535
2536     // Clear the selection when changing the focus node to null or to a node that is not 
2537     // contained by the current selection.
2538     if (part()) {
2539         NodeImpl *startContainer = part()->selection().start().node();
2540         if (!newFocusNode || (startContainer && startContainer != newFocusNode && !startContainer->isAncestor(newFocusNode)))
2541             part()->clearSelection();
2542     }
2543
2544     if (newFocusNode) {
2545 #if APPLE_CHANGES            
2546         if (newFocusNode->isContentEditable() && !acceptsEditingFocus(newFocusNode)) {
2547             // delegate blocks focus change
2548             focusChangeBlocked = true;
2549             goto SetFocusNodeDone;
2550         }
2551 #endif
2552         // Set focus on the new node
2553         m_focusNode = newFocusNode;
2554         m_focusNode->ref();
2555         m_focusNode->dispatchHTMLEvent(EventImpl::FOCUS_EVENT, false, false);
2556         if (m_focusNode != newFocusNode) {
2557             // handler shifted focus
2558             focusChangeBlocked = true;
2559             goto SetFocusNodeDone;
2560         }
2561         m_focusNode->dispatchUIEvent(EventImpl::DOMFOCUSIN_EVENT);
2562         if (m_focusNode != newFocusNode) { 
2563             // handler shifted focus
2564             focusChangeBlocked = true;
2565             goto SetFocusNodeDone;
2566         }
2567         m_focusNode->setFocus();
2568         // eww, I suck. set the qt focus correctly
2569         // ### find a better place in the code for this
2570         if (view()) {
2571             QWidget *focusWidget = widgetForNode(m_focusNode);
2572             if (focusWidget) {
2573                 // Make sure a widget has the right size before giving it focus.
2574                 // Otherwise, we are testing edge cases of the QWidget code.
2575                 // Specifically, in WebCore this does not work well for text fields.
2576                 updateLayout();
2577                 // Re-get the widget in case updating the layout changed things.
2578                 focusWidget = widgetForNode(m_focusNode);
2579             }
2580             if (focusWidget)
2581                 focusWidget->setFocus();
2582             else
2583                 view()->setFocus();
2584         }
2585    }
2586
2587 #if APPLE_CHANGES
2588     if (!focusChangeBlocked && m_focusNode && KWQAccObjectCache::accessibilityEnabled())
2589         getAccObjectCache()->handleFocusedUIElementChanged();
2590 #endif
2591
2592 SetFocusNodeDone:
2593     updateRendering();
2594     return !focusChangeBlocked;
2595 }
2596
2597 void DocumentImpl::setCSSTarget(NodeImpl* n)
2598 {
2599     if (m_cssTarget)
2600         m_cssTarget->setChanged();
2601     m_cssTarget = n;
2602     if (n)
2603         n->setChanged();
2604 }
2605
2606 NodeImpl* DocumentImpl::getCSSTarget()
2607 {
2608     return m_cssTarget;
2609 }
2610
2611 void DocumentImpl::attachNodeIterator(NodeIteratorImpl *ni)
2612 {
2613     m_nodeIterators.append(ni);
2614 }
2615
2616 void DocumentImpl::detachNodeIterator(NodeIteratorImpl *ni)
2617 {
2618     m_nodeIterators.remove(ni);
2619 }
2620
2621 void DocumentImpl::notifyBeforeNodeRemoval(NodeImpl *n)
2622 {
2623     QPtrListIterator<NodeIteratorImpl> it(m_nodeIterators);
2624     for (; it.current(); ++it)
2625         it.current()->notifyBeforeNodeRemoval(n);
2626 }
2627
2628 AbstractViewImpl *DocumentImpl::defaultView() const
2629 {
2630     return m_defaultView;
2631 }
2632
2633 EventImpl *DocumentImpl::createEvent(const DOMString &eventType, int &exceptioncode)
2634 {
2635     if (eventType == "UIEvents")
2636         return new UIEventImpl();
2637     else if (eventType == "MouseEvents")
2638         return new MouseEventImpl();
2639     else if (eventType == "MutationEvents")
2640         return new MutationEventImpl();
2641     else if (eventType == "KeyboardEvents")
2642         return new KeyboardEventImpl();
2643     else if (eventType == "HTMLEvents")
2644         return new EventImpl();
2645     else {
2646         exceptioncode = DOMException::NOT_SUPPORTED_ERR;
2647         return 0;
2648     }
2649 }
2650
2651 CSSStyleDeclarationImpl *DocumentImpl::getOverrideStyle(ElementImpl */*elt*/, DOMStringImpl */*pseudoElt*/)
2652 {
2653     return 0; // ###
2654 }
2655
2656 void DocumentImpl::defaultEventHandler(EventImpl *evt)
2657 {
2658     // if any html event listeners are registered on the window, then dispatch them here
2659     QPtrList<RegisteredEventListener> listenersCopy = m_windowEventListeners;
2660     QPtrListIterator<RegisteredEventListener> it(listenersCopy);
2661     Event ev(evt);
2662     for (; it.current(); ++it) {
2663         if (it.current()->id == evt->id()) {
2664             it.current()->listener->handleEvent(ev, true);
2665         }
2666     }
2667
2668     // handle accesskey
2669     if (evt->id()==EventImpl::KEYDOWN_EVENT) {
2670         KeyboardEventImpl *kevt = static_cast<KeyboardEventImpl *>(evt);
2671         if (kevt->ctrlKey()) {
2672             QString key = kevt->qKeyEvent()->unmodifiedText().lower();
2673             ElementImpl *elem = getElementByAccessKey(key);
2674             if (elem) {
2675                 elem->accessKeyAction(false);
2676                 evt->setDefaultHandled();
2677             }
2678         }
2679     }
2680 }
2681
2682 void DocumentImpl::setHTMLWindowEventListener(int id, EventListener *listener)
2683 {
2684     // If we already have it we don't want removeWindowEventListener to delete it
2685     if (listener)
2686         listener->ref();
2687     removeHTMLWindowEventListener(id);
2688     if (listener) {
2689         addWindowEventListener(id, listener, false);
2690         listener->deref();
2691     }
2692 }
2693
2694 EventListener *DocumentImpl::getHTMLWindowEventListener(int id)
2695 {
2696     QPtrListIterator<RegisteredEventListener> it(m_windowEventListeners);
2697     for (; it.current(); ++it) {
2698         if (it.current()->id == id &&
2699             it.current()->listener->eventListenerType() == "_khtml_HTMLEventListener") {
2700             return it.current()->listener;
2701         }
2702     }
2703
2704     return 0;
2705 }
2706
2707 void DocumentImpl::removeHTMLWindowEventListener(int id)
2708 {
2709     QPtrListIterator<RegisteredEventListener> it(m_windowEventListeners);
2710     for (; it.current(); ++it) {
2711         if (it.current()->id == id &&
2712             it.current()->listener->eventListenerType() == "_khtml_HTMLEventListener") {
2713             m_windowEventListeners.removeRef(it.current());
2714             return;
2715         }
2716     }
2717 }
2718
2719 void DocumentImpl::addWindowEventListener(int id, EventListener *listener, const bool useCapture)
2720 {
2721     listener->ref();
2722
2723     // remove existing identical listener set with identical arguments - the DOM2
2724     // spec says that "duplicate instances are discarded" in this case.
2725     removeWindowEventListener(id,listener,useCapture);
2726
2727     RegisteredEventListener *rl = new RegisteredEventListener(static_cast<EventImpl::EventId>(id), listener, useCapture);
2728     m_windowEventListeners.append(rl);
2729
2730     listener->deref();
2731 }
2732
2733 void DocumentImpl::removeWindowEventListener(int id, EventListener *listener, bool useCapture)
2734 {
2735     RegisteredEventListener rl(static_cast<EventImpl::EventId>(id),listener,useCapture);
2736
2737     QPtrListIterator<RegisteredEventListener> it(m_windowEventListeners);
2738     for (; it.current(); ++it)
2739         if (*(it.current()) == rl) {
2740             m_windowEventListeners.removeRef(it.current());
2741             return;
2742         }
2743 }
2744
2745 bool DocumentImpl::hasWindowEventListener(int id)
2746 {
2747     QPtrListIterator<RegisteredEventListener> it(m_windowEventListeners);
2748     for (; it.current(); ++it) {
2749         if (it.current()->id == id) {
2750             return true;
2751         }
2752     }
2753
2754     return false;
2755 }
2756
2757 EventListener *DocumentImpl::createHTMLEventListener(QString code, NodeImpl *node)
2758 {
2759     if (part()) {
2760         return part()->createHTMLEventListener(code, node);
2761     } else {
2762         return NULL;
2763     }
2764 }
2765
2766 void DocumentImpl::dispatchImageLoadEventSoon(HTMLImageLoader *image)
2767 {
2768     m_imageLoadEventDispatchSoonList.append(image);
2769     if (!m_imageLoadEventTimer) {
2770         m_imageLoadEventTimer = startTimer(0);
2771     }
2772 }
2773
2774 void DocumentImpl::removeImage(HTMLImageLoader* image)
2775 {
2776     // Remove instances of this image from both lists.
2777     // Use loops because we allow multiple instances to get into the lists.
2778     while (m_imageLoadEventDispatchSoonList.removeRef(image)) { }
2779     while (m_imageLoadEventDispatchingList.removeRef(image)) { }
2780     if (m_imageLoadEventDispatchSoonList.isEmpty() && m_imageLoadEventTimer) {
2781         killTimer(m_imageLoadEventTimer);
2782         m_imageLoadEventTimer = 0;
2783     }
2784 }
2785
2786 void DocumentImpl::dispatchImageLoadEventsNow()
2787 {
2788     // need to avoid re-entering this function; if new dispatches are
2789     // scheduled before the parent finishes processing the list, they
2790     // will set a timer and eventually be processed
2791     if (!m_imageLoadEventDispatchingList.isEmpty()) {
2792         return;
2793     }
2794
2795     if (m_imageLoadEventTimer) {
2796         killTimer(m_imageLoadEventTimer);
2797         m_imageLoadEventTimer = 0;
2798     }
2799     
2800     m_imageLoadEventDispatchingList = m_imageLoadEventDispatchSoonList;
2801     m_imageLoadEventDispatchSoonList.clear();
2802     for (QPtrListIterator<HTMLImageLoader> it(m_imageLoadEventDispatchingList); it.current(); ) {
2803         HTMLImageLoader* image = it.current();
2804         // Must advance iterator *before* dispatching call.
2805         // Otherwise, it might be advanced automatically if dispatching the call had a side effect
2806         // of destroying the current HTMLImageLoader, and then we would advance past the *next* item,
2807         // missing one altogether.
2808         ++it;
2809         image->dispatchLoadEvent();
2810     }
2811     m_imageLoadEventDispatchingList.clear();
2812 }
2813
2814 void DocumentImpl::timerEvent(QTimerEvent *)
2815 {
2816     dispatchImageLoadEventsNow();
2817 }
2818
2819 ElementImpl *DocumentImpl::ownerElement()
2820 {
2821     KHTMLView *childView = view();
2822     if (!childView)
2823         return 0;
2824     KHTMLPart *childPart = childView->part();
2825     if (!childPart)
2826         return 0;
2827     KHTMLPart *parent = childPart->parentPart();
2828     if (!parent)
2829         return 0;
2830     ChildFrame *childFrame = parent->childFrame(childPart);
2831     if (!childFrame)
2832         return 0;
2833     RenderPart *renderPart = childFrame->m_frame;
2834     if (!renderPart)
2835         return 0;
2836     return static_cast<ElementImpl *>(renderPart->element());
2837 }
2838
2839 DOMString DocumentImpl::domain() const
2840 {
2841     if ( m_domain.isEmpty() ) // not set yet (we set it on demand to save time and space)
2842         m_domain = KURL(URL()).host(); // Initially set to the host
2843     return m_domain;
2844 }
2845
2846 void DocumentImpl::setDomain(const DOMString &newDomain, bool force /*=false*/)
2847 {
2848     if ( force ) {
2849         m_domain = newDomain;
2850         return;
2851     }
2852     if ( m_domain.isEmpty() ) // not set yet (we set it on demand to save time and space)
2853         m_domain = KURL(URL()).host(); // Initially set to the host
2854
2855     // Both NS and IE specify that changing the domain is only allowed when
2856     // the new domain is a suffix of the old domain.
2857     int oldLength = m_domain.length();
2858     int newLength = newDomain.length();
2859     if ( newLength < oldLength ) // e.g. newDomain=kde.org (7) and m_domain=www.kde.org (11)
2860     {
2861         DOMString test = m_domain.copy();
2862         if ( test[oldLength - newLength - 1] == '.' ) // Check that it's a subdomain, not e.g. "de.org"
2863         {
2864             test.remove( 0, oldLength - newLength ); // now test is "kde.org" from m_domain
2865             if ( test == newDomain )                 // and we check that it's the same thing as newDomain
2866                 m_domain = newDomain;
2867         }
2868     }
2869 }
2870
2871 bool DocumentImpl::isValidName(const DOMString &name)
2872 {
2873     static const char validFirstCharacter[] = "ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz";
2874     static const char validSubsequentCharacter[] = "ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz0123456789-_:.";
2875     const unsigned length = name.length();
2876     if (length == 0)
2877         return false;
2878     const QChar * const characters = name.unicode();
2879     const char fc = characters[0];
2880     if (!fc)
2881         return false;
2882     if (strchr(validFirstCharacter, fc) == 0)
2883         return false;
2884     for (unsigned i = 1; i < length; ++i) {
2885         const char sc = characters[i];
2886         if (!sc)
2887             return false;
2888         if (strchr(validSubsequentCharacter, sc) == 0)
2889             return false;
2890     }
2891     return true;
2892 }
2893
2894 void DocumentImpl::addImageMap(HTMLMapElementImpl *imageMap)
2895 {
2896     // Add the image map, unless there's already another with that name.
2897     // "First map wins" is the rule other browsers seem to implement.
2898     QString name = imageMap->getName().string();
2899     if (!m_imageMapsByName.contains(name))
2900         m_imageMapsByName.insert(name, imageMap);
2901 }
2902
2903 void DocumentImpl::removeImageMap(HTMLMapElementImpl *imageMap)
2904 {
2905     // Remove the image map by name.
2906     // But don't remove some other image map that just happens to have the same name.
2907     QString name = imageMap->getName().string();
2908     QMapIterator<QString, HTMLMapElementImpl *> it = m_imageMapsByName.find(name);
2909     if (it != m_imageMapsByName.end() && *it == imageMap)
2910         m_imageMapsByName.remove(it);
2911 }
2912
2913 HTMLMapElementImpl *DocumentImpl::getImageMap(const DOMString &URL) const
2914 {
2915     if (URL.isNull()) {
2916         return 0;
2917     }
2918
2919     QString s = URL.string();
2920     int hashPos = s.find('#');
2921     if (hashPos >= 0)
2922         s = s.mid(hashPos + 1);
2923
2924     QMapConstIterator<QString, HTMLMapElementImpl *> it = m_imageMapsByName.find(s);
2925     if (it == m_imageMapsByName.end())
2926         return 0;
2927     return *it;
2928 }
2929
2930 #if APPLE_CHANGES
2931
2932 void DocumentImpl::setDecoder(Decoder *decoder)
2933 {
2934     decoder->ref();
2935     if (m_decoder) {
2936         m_decoder->deref();
2937     }
2938     m_decoder = decoder;
2939 }
2940
2941 QString DocumentImpl::completeURL(const QString &URL)
2942 {
2943     return KURL(baseURL(), URL, m_decoder ? m_decoder->codec() : 0).url();
2944 }
2945
2946 bool DocumentImpl::inPageCache()
2947 {
2948     return m_inPageCache;
2949 }
2950
2951 void DocumentImpl::setInPageCache(bool flag)
2952 {
2953     if (m_inPageCache == flag)
2954         return;
2955
2956     m_inPageCache = flag;
2957     if (flag) {
2958         assert(m_savedRenderer == 0);
2959         m_savedRenderer = m_render;
2960         if (m_view) {
2961             m_view->resetScrollBars();
2962         }
2963     } else {
2964         assert(m_render == 0 || m_render == m_savedRenderer);
2965         m_render = m_savedRenderer;
2966         m_savedRenderer = 0;
2967     }
2968 }
2969
2970 void DocumentImpl::passwordFieldAdded()
2971 {
2972     m_passwordFields++;
2973 }
2974
2975 void DocumentImpl::passwordFieldRemoved()
2976 {
2977     assert(m_passwordFields > 0);
2978     m_passwordFields--;
2979 }
2980
2981 bool DocumentImpl::hasPasswordField() const
2982 {
2983     return m_passwordFields > 0;
2984 }
2985
2986 void DocumentImpl::secureFormAdded()
2987 {
2988     m_secureForms++;
2989 }
2990
2991 void DocumentImpl::secureFormRemoved()
2992 {
2993     assert(m_secureForms > 0);
2994     m_secureForms--;
2995 }
2996
2997 bool DocumentImpl::hasSecureForm() const
2998 {
2999     return m_secureForms > 0;
3000 }
3001
3002 void DocumentImpl::setShouldCreateRenderers(bool f)
3003 {
3004     m_createRenderers = f;
3005 }
3006
3007 bool DocumentImpl::shouldCreateRenderers()
3008 {
3009     return m_createRenderers;
3010 }
3011
3012 DOMString DocumentImpl::toString() const
3013 {
3014     DOMString result;
3015
3016     for (NodeImpl *child = firstChild(); child != NULL; child = child->nextSibling()) {
3017         result += child->toString();
3018     }
3019
3020     return result;
3021 }
3022
3023 #endif // APPLE_CHANGES
3024
3025 // ----------------------------------------------------------------------------
3026 // Support for Javascript execCommand, and related methods
3027
3028 JSEditor *DocumentImpl::jsEditor()
3029 {
3030     if (!m_jsEditor)
3031         m_jsEditor = new JSEditor(this);
3032     return m_jsEditor;
3033 }
3034
3035 bool DocumentImpl::execCommand(const DOMString &command, bool userInterface, const DOMString &value)
3036 {
3037     return jsEditor()->execCommand(command, userInterface, value);
3038 }
3039
3040 bool DocumentImpl::queryCommandEnabled(const DOMString &command)
3041 {
3042     return jsEditor()->queryCommandEnabled(command);
3043 }
3044
3045 bool DocumentImpl::queryCommandIndeterm(const DOMString &command)
3046 {
3047     return jsEditor()->queryCommandIndeterm(command);
3048 }
3049
3050 bool DocumentImpl::queryCommandState(const DOMString &command)
3051 {
3052     return jsEditor()->queryCommandState(command);
3053 }
3054
3055 bool DocumentImpl::queryCommandSupported(const DOMString &command)
3056 {
3057     return jsEditor()->queryCommandSupported(command);
3058 }
3059
3060 DOMString DocumentImpl::queryCommandValue(const DOMString &command)
3061 {
3062     return jsEditor()->queryCommandValue(command);
3063 }
3064
3065 // ----------------------------------------------------------------------------
3066
3067 void DocumentImpl::addMarker(Range range, DocumentMarker::MarkerType type)
3068 {
3069     // Use a TextIterator to visit the potentially multiple nodes the range covers.
3070     for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
3071         Range textPiece = markedText.range();
3072         DocumentMarker marker = {type, textPiece.startOffset(), textPiece.endOffset()};
3073         addMarker(textPiece.startContainer().handle(), marker);
3074     }
3075 }
3076
3077 void DocumentImpl::removeMarker(Range range, DocumentMarker::MarkerType type)
3078 {
3079     // Use a TextIterator to visit the potentially multiple nodes the range covers.
3080     for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
3081         Range textPiece = markedText.range();
3082         DocumentMarker marker = {type, textPiece.startOffset(), textPiece.endOffset()};
3083         removeMarker(textPiece.startContainer().handle(), marker);
3084     }
3085 }
3086
3087 // FIXME:  We don't deal with markers of more than one type yet
3088
3089 // Markers are stored in order sorted by their location.  They do not overlap each other, as currently
3090 // required by the drawing code in render_text.cpp.
3091
3092 void DocumentImpl::addMarker(NodeImpl *node, DocumentMarker newMarker) 
3093 {
3094     assert(newMarker.endOffset >= newMarker.startOffset);
3095     if (newMarker.endOffset == newMarker.startOffset) {
3096         return;     // zero length markers are a NOP
3097     }
3098     
3099     QValueList <DocumentMarker> *markers = m_markers.find(node);
3100     if (!markers) {
3101         markers = new QValueList <DocumentMarker>;
3102         markers->append(newMarker);
3103         m_markers.insert(node, markers);
3104     } else {
3105         QValueListIterator<DocumentMarker> it;
3106         for (it = markers->begin(); it != markers->end(); ) {
3107             DocumentMarker marker = *it;
3108             
3109             if (newMarker.endOffset < marker.startOffset+1) {
3110                 // This is the first marker that is completely after newMarker, and disjoint from it.
3111                 // We found our insertion point.\10
3112                 break;
3113             } else if (newMarker.startOffset > marker.endOffset) {
3114                 // maker is before newMarker, and disjoint from it.  Keep scanning.
3115                 it++;
3116             } else if (newMarker == marker) {
3117                 // already have this one, NOP
3118                 return;
3119             } else {
3120                 // marker and newMarker intersect or touch - merge them into newMarker
3121                 newMarker.startOffset = kMin(newMarker.startOffset, marker.startOffset);
3122                 newMarker.endOffset = kMax(newMarker.endOffset, marker.endOffset);
3123                 // remove old one, we'll add newMarker later
3124                 it = markers->remove(it);
3125                 // it points to the next marker to consider
3126             }
3127         }
3128         // at this point it points to the node before which we want to insert
3129         markers->insert(it, newMarker);
3130     }
3131     
3132     // repaint the affected node
3133     if (node->renderer())
3134         node->renderer()->repaint();
3135 }
3136
3137 void DocumentImpl::removeMarker(NodeImpl *node, DocumentMarker target)
3138 {
3139     assert(target.endOffset >= target.startOffset);
3140     if (target.endOffset == target.startOffset) {
3141         return;     // zero length markers are a NOP
3142     }
3143
3144     QValueList <DocumentMarker> *markers = m_markers.find(node);
3145     if (!markers) {
3146         return;
3147     }
3148     
3149     bool docDirty = false;
3150     QValueListIterator<DocumentMarker> it;
3151     for (it = markers->begin(); it != markers->end(); ) {
3152         DocumentMarker marker = *it;
3153
3154         if (target.endOffset <= marker.startOffset) {
3155             // This is the first marker that is completely after target.  All done.
3156             break;
3157         } else if (target.startOffset >= marker.endOffset) {
3158             // marker is before target.  Keep scanning.
3159             it++;
3160         } else {
3161             // at this point we know that marker and target intersect in some way
3162             docDirty = true;
3163
3164             // pitch the old marker
3165             it = markers->remove(it);
3166             // it now points to the next node
3167             
3168             // add either of the resulting slices that are left after removing target
3169             if (target.startOffset > marker.startOffset) {
3170                 DocumentMarker newLeft = marker;
3171                 newLeft.endOffset = target.startOffset;
3172                 markers->insert(it, newLeft);
3173             }
3174             if (marker.endOffset > target.endOffset) {
3175                 DocumentMarker newRight = marker;
3176                 newRight.startOffset = target.endOffset;
3177                 markers->insert(it, newRight);
3178             }
3179         }
3180     }
3181
3182     if (markers->isEmpty())
3183         m_markers.remove(node);
3184
3185     // repaint the affected node
3186     if (docDirty && node->renderer())
3187         node->renderer()->repaint();
3188 }
3189
3190 QValueList<DocumentMarker> DocumentImpl::markersForNode(NodeImpl *node)
3191 {
3192     QValueList <DocumentMarker> *markers = m_markers.find(node);
3193     if (markers) {
3194         return *markers;
3195     } else {
3196         return QValueList <DocumentMarker> ();
3197     }
3198 }
3199
3200 void DocumentImpl::removeAllMarkers(NodeImpl *node, ulong startOffset, long length)
3201 {
3202     // FIXME - yet another cheat that relies on us only having one marker type
3203     DocumentMarker marker = {DocumentMarker::Spelling, startOffset, startOffset+length};
3204     removeMarker(node, marker);
3205 }
3206
3207 void DocumentImpl::removeAllMarkers(NodeImpl *node)
3208 {
3209     QValueList<DocumentMarker> *markers = m_markers.take(node);
3210     if (markers) {
3211         RenderObject *renderer = node->renderer();
3212         if (renderer)
3213             renderer->repaint();
3214         delete markers;
3215     }
3216 }
3217
3218 void DocumentImpl::removeAllMarkers()
3219 {
3220     QPtrDictIterator< QValueList<DocumentMarker> > it(m_markers);
3221     for (; NodeImpl *node = static_cast<NodeImpl *>(it.currentKey()); ++it) {
3222         RenderObject *renderer = node->renderer();
3223         if (renderer)
3224             renderer->repaint();
3225     }
3226     m_markers.clear();
3227 }
3228
3229 void DocumentImpl::shiftMarkers(NodeImpl *node, ulong startOffset, long delta)
3230 {
3231     QValueList <DocumentMarker> *markers = m_markers.find(node);
3232     if (!markers)
3233         return;
3234
3235     bool docDirty = false;
3236     QValueListIterator<DocumentMarker> it;
3237     for (it = markers->begin(); it != markers->end(); ++it) {
3238         DocumentMarker &marker = *it;
3239         if (marker.startOffset >= startOffset) {
3240             assert((int)marker.startOffset + delta >= 0);
3241             marker.startOffset += delta;
3242             marker.endOffset += delta;
3243             docDirty = true;
3244         }
3245     }
3246     
3247     // repaint the affected node
3248     if (docDirty && node->renderer())
3249         node->renderer()->repaint();
3250 }
3251
3252 #ifdef KHTML_XSLT
3253 void DocumentImpl::applyXSLTransform(ProcessingInstructionImpl* pi)
3254 {
3255     // Ref ourselves to keep from being destroyed.
3256     XSLTProcessorImpl processor(static_cast<XSLStyleSheetImpl*>(pi->sheet()), this);
3257     processor.transformDocument(this);
3258
3259     // FIXME: If the transform failed we should probably report an error (like Mozilla does) in this
3260     // case.
3261 }
3262
3263 void DocumentImpl::setTransformSourceDocument(DocumentImpl* doc)
3264
3265     if (m_transformSourceDocument)
3266         m_transformSourceDocument->deref(); 
3267     m_transformSourceDocument = doc;
3268     if (doc)
3269         doc->ref();
3270 }
3271
3272 #endif
3273
3274 void DocumentImpl::setDesignMode(InheritedBool value)
3275 {
3276     m_designMode = value;
3277 }
3278
3279 DocumentImpl::InheritedBool DocumentImpl::getDesignMode() const
3280 {
3281     return m_designMode;
3282 }
3283
3284 bool DocumentImpl::inDesignMode() const
3285 {
3286     for (const DocumentImpl* d = this; d; d = d->parentDocument()) {
3287         if (d->m_designMode != inherit)
3288             return d->m_designMode;      
3289     }
3290     return false;
3291 }
3292
3293 DocumentImpl *DocumentImpl::parentDocument() const
3294 {
3295     KHTMLPart *childPart = part();
3296     if (!childPart)
3297         return 0;
3298     KHTMLPart *parent = childPart->parentPart();
3299     if (!parent)
3300         return 0;
3301     return parent->xmlDocImpl();
3302 }
3303
3304 DocumentImpl *DocumentImpl::topDocument() const
3305 {
3306     DocumentImpl *doc = const_cast<DocumentImpl *>(this);
3307     ElementImpl *element;
3308     while ((element = doc->ownerElement()) != 0) {
3309         doc = element->getDocument();
3310         element = doc ? doc->ownerElement() : 0;
3311     }
3312     
3313     return doc;
3314 }
3315
3316 // ----------------------------------------------------------------------------
3317
3318 DocumentFragmentImpl::DocumentFragmentImpl(DocumentPtr *doc) : NodeBaseImpl(doc)
3319 {
3320 }
3321
3322 DOMString DocumentFragmentImpl::nodeName() const
3323 {
3324   return "#document-fragment";
3325 }
3326
3327 unsigned short DocumentFragmentImpl::nodeType() const
3328 {
3329     return Node::DOCUMENT_FRAGMENT_NODE;
3330 }
3331
3332 // DOM Section 1.1.1
3333 bool DocumentFragmentImpl::childTypeAllowed( unsigned short type )
3334 {
3335     switch (type) {
3336         case Node::ELEMENT_NODE:
3337         case Node::PROCESSING_INSTRUCTION_NODE:
3338         case Node::COMMENT_NODE:
3339         case Node::TEXT_NODE:
3340         case Node::CDATA_SECTION_NODE:
3341         case Node::ENTITY_REFERENCE_NODE:
3342             return true;
3343         default:
3344             return false;
3345     }
3346 }
3347
3348 DOMString DocumentFragmentImpl::toString() const
3349 {
3350     DOMString result;
3351
3352     for (NodeImpl *child = firstChild(); child != NULL; child = child->nextSibling()) {
3353         result += child->toString();
3354     }
3355
3356     return result;
3357 }
3358
3359
3360 NodeImpl *DocumentFragmentImpl::cloneNode ( bool deep )
3361 {
3362     DocumentFragmentImpl *clone = new DocumentFragmentImpl( docPtr() );
3363     if (deep)
3364         cloneChildNodes(clone);
3365     return clone;
3366 }
3367
3368
3369 // ----------------------------------------------------------------------------
3370
3371 DocumentTypeImpl::DocumentTypeImpl(DOMImplementationImpl *implementation, DocumentPtr *doc,
3372                                    const DOMString &qualifiedName, const DOMString &publicId,
3373                                    const DOMString &systemId)
3374     : NodeImpl(doc), m_implementation(implementation),
3375       m_qualifiedName(qualifiedName), m_publicId(publicId), m_systemId(systemId)
3376 {
3377     if (m_implementation)
3378         m_implementation->ref();
3379
3380     m_entities = 0;
3381     m_notations = 0;
3382
3383     // if doc is 0, it is not attached to a document and / or
3384     // therefore does not provide entities or notations. (DOM Level 3)
3385 }
3386
3387 DocumentTypeImpl::~DocumentTypeImpl()
3388 {
3389     if (m_implementation)
3390         m_implementation->deref();
3391     if (m_entities)
3392         m_entities->deref();
3393     if (m_notations)
3394         m_notations->deref();
3395 }
3396
3397 void DocumentTypeImpl::copyFrom(const DocumentTypeImpl& other)
3398 {
3399     m_qualifiedName = other.m_qualifiedName;
3400     m_publicId = other.m_publicId;
3401     m_systemId = other.m_systemId;
3402     m_subset = other.m_subset;
3403 }
3404
3405 DOMString DocumentTypeImpl::toString() const
3406 {
3407     DOMString result;
3408     if (m_qualifiedName.isEmpty()) {
3409         return "";
3410     } else {
3411         result = "<!DOCTYPE ";
3412         result += m_qualifiedName;
3413     }
3414     if (!m_publicId.isEmpty()) {
3415         result += " PUBLIC \"";
3416         result += m_publicId;
3417         result += "\" \"";
3418         result += m_systemId;
3419         result += "\"";
3420     } else if (!m_systemId.isEmpty()) {
3421         result += " SYSTEM \"";
3422         result += m_systemId;
3423         result += "\"";
3424     }
3425     if (!m_subset.isEmpty()) {
3426         result += " [";
3427         result += m_subset;
3428         result += "]";
3429     }
3430     result += ">";
3431     return result;
3432 }
3433
3434 DOMString DocumentTypeImpl::nodeName() const
3435 {
3436     return name();
3437 }
3438
3439 unsigned short DocumentTypeImpl::nodeType() const
3440 {
3441     return Node::DOCUMENT_TYPE_NODE;
3442 }
3443
3444 // DOM Section 1.1.1
3445 bool DocumentTypeImpl::childTypeAllowed( unsigned short /*type*/ )
3446 {
3447     return false;
3448 }
3449
3450 NodeImpl *DocumentTypeImpl::cloneNode ( bool /*deep*/ )
3451 {
3452     // Spec says cloning Document nodes is "implementation dependent"
3453     // so we do not support it...
3454     return 0;
3455 }
3456
3457 #include "dom_docimpl.moc"