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