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