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