Reviewed by John.
[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     ContainerNodeImpl::detach();
1245
1246     if ( render )
1247         render->detach();
1248
1249     if (m_paintDevice == m_view)
1250         setPaintDevice(0);
1251     m_view = 0;
1252     
1253     if (m_renderArena){
1254         delete m_renderArena;
1255         m_renderArena = 0;
1256     }
1257 }
1258
1259 void DocumentImpl::removeAllEventListenersFromAllNodes()
1260 {
1261     m_windowEventListeners.clear();
1262     removeAllDisconnectedNodeEventListeners();
1263     for (NodeImpl *n = this; n; n = n->traverseNextNode()) {
1264         n->removeAllEventListeners();
1265     }
1266 }
1267
1268 void DocumentImpl::registerDisconnectedNodeWithEventListeners(NodeImpl *node)
1269 {
1270     m_disconnectedNodesWithEventListeners.insert(node, node);
1271 }
1272
1273 void DocumentImpl::unregisterDisconnectedNodeWithEventListeners(NodeImpl *node)
1274 {
1275     m_disconnectedNodesWithEventListeners.remove(node);
1276 }
1277
1278 void DocumentImpl::removeAllDisconnectedNodeEventListeners()
1279 {
1280     for (QPtrDictIterator<NodeImpl> iter(m_disconnectedNodesWithEventListeners);
1281          iter.current();
1282          ++iter) {
1283         iter.current()->removeAllEventListeners();
1284     }
1285 }
1286
1287 #if APPLE_CHANGES
1288 KWQAccObjectCache* DocumentImpl::getAccObjectCache()
1289 {
1290     // The only document that actually has a KWQAccObjectCache is the top-level
1291     // document.  This is because we need to be able to get from any KWQAccObject
1292     // to any other KWQAccObject on the same page.  Using a single cache allows
1293     // lookups across nested webareas (i.e. multiple documents).
1294     
1295     if (m_accCache) {
1296         // return already known top-level cache
1297         if (!ownerElement())
1298             return m_accCache;
1299         
1300         // In some pages with frames, the cache is created before the sub-webarea is
1301         // inserted into the tree.  Here, we catch that case and just toss the old
1302         // cache and start over.
1303         delete m_accCache;
1304         m_accCache = 0;
1305     }
1306     
1307     // look for top-level document
1308     ElementImpl *element = ownerElement();
1309     if (element) {
1310         DocumentImpl *doc;
1311         while (element) {
1312             doc = element->getDocument();
1313             element = doc->ownerElement();
1314         }
1315         
1316         // ask the top-level document for its cache
1317         return doc->getAccObjectCache();
1318     }
1319     
1320     // this is the top-level document, so install a new cache
1321     m_accCache = new KWQAccObjectCache;
1322     return m_accCache;
1323 }
1324 #endif
1325
1326 void DocumentImpl::setVisuallyOrdered()
1327 {
1328     visuallyOrdered = true;
1329     if (m_render)
1330         m_render->style()->setVisuallyOrdered(true);
1331 }
1332
1333 void DocumentImpl::updateSelection()
1334 {
1335     if (!m_render)
1336         return;
1337     
1338     RenderCanvas *canvas = static_cast<RenderCanvas*>(m_render);
1339     Selection s = part()->selection();
1340     if (!s.isRange()) {
1341         canvas->clearSelection();
1342     }
1343     else {
1344         Position startPos = VisiblePosition(s.start(), s.startAffinity()).deepEquivalent();
1345         Position endPos = VisiblePosition(s.end(), s.endAffinity()).deepEquivalent();
1346         if (startPos.isNotNull() && endPos.isNotNull()) {
1347             RenderObject *startRenderer = startPos.node()->renderer();
1348             RenderObject *endRenderer = endPos.node()->renderer();
1349             static_cast<RenderCanvas*>(m_render)->setSelection(startRenderer, startPos.offset(), endRenderer, endPos.offset());
1350         }
1351     }
1352     
1353 #if APPLE_CHANGES
1354     // send the AXSelectedTextChanged notification only if the new selection is non-null,
1355     // because null selections are only transitory (e.g. when starting an EditCommand, currently)
1356     if (KWQAccObjectCache::accessibilityEnabled() && s.start().isNotNull() && s.end().isNotNull()) {
1357         getAccObjectCache()->postNotificationToTopWebArea(renderer(), "AXSelectedTextChanged");
1358     }
1359 #endif
1360
1361 }
1362
1363 Tokenizer *DocumentImpl::createTokenizer()
1364 {
1365     return newXMLTokenizer(docPtr(), m_view);
1366 }
1367
1368 void DocumentImpl::setPaintDevice( QPaintDevice *dev )
1369 {
1370     if (m_paintDevice == dev) {
1371         return;
1372     }
1373     m_paintDevice = dev;
1374     delete m_paintDeviceMetrics;
1375     m_paintDeviceMetrics = dev ? new QPaintDeviceMetrics( dev ) : 0;
1376 }
1377
1378 void DocumentImpl::open(  )
1379 {
1380     if (parsing()) return;
1381
1382     implicitOpen();
1383
1384     if (part()) {
1385         part()->didExplicitOpen();
1386     }
1387
1388     // This is work that we should probably do in clear(), but we can't have it
1389     // happen when implicitOpen() is called unless we reorganize KHTMLPart code.
1390     setURL(QString());
1391     DocumentImpl *parent = parentDocument();
1392     if (parent) {
1393         setBaseURL(parent->baseURL());
1394     }
1395 }
1396
1397 void DocumentImpl::implicitOpen()
1398 {
1399     if (m_tokenizer)
1400         close();
1401
1402     clear();
1403     m_tokenizer = createTokenizer();
1404     connect(m_tokenizer,SIGNAL(finishedParsing()),this,SIGNAL(finishedParsing()));
1405     setParsing(true);
1406
1407     if (m_view && m_view->part()->jScript()) {
1408         m_view->part()->jScript()->setSourceFile(m_url,""); //fixme
1409     }
1410 }
1411
1412 HTMLElementImpl* DocumentImpl::body()
1413 {
1414     NodeImpl *de = documentElement();
1415     if (!de)
1416         return 0;
1417     
1418     // try to prefer a FRAMESET element over BODY
1419     NodeImpl* body = 0;
1420     for (NodeImpl* i = de->firstChild(); i; i = i->nextSibling()) {
1421         if (i->id() == ID_FRAMESET)
1422             return static_cast<HTMLElementImpl*>(i);
1423         
1424         if (i->id() == ID_BODY)
1425             body = i;
1426     }
1427     return static_cast<HTMLElementImpl *>(body);
1428 }
1429
1430 void DocumentImpl::close()
1431 {
1432     if (part())
1433         part()->endIfNotLoading();
1434     implicitClose();
1435 }
1436
1437 void DocumentImpl::implicitClose()
1438 {
1439     // 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.
1440     if (m_inStyleRecalc) {
1441         m_closeAfterStyleRecalc = true;
1442         return;
1443     }
1444
1445     // First fire the onload.
1446     
1447     bool wasLocationChangePending = part() && part()->isScheduledLocationChangePending();
1448     bool doload = !parsing() && m_tokenizer && !m_processingLoadEvent && !wasLocationChangePending;
1449     
1450     if (doload) {
1451         m_processingLoadEvent = true;
1452
1453         // We have to clear the tokenizer, in case someone document.write()s from the
1454         // onLoad event handler, as in Radar 3206524
1455         delete m_tokenizer;
1456         m_tokenizer = 0;
1457
1458         // Create a body element if we don't already have one.
1459         // In the case of Radar 3758785, the window.onload was set in some javascript, but never fired because there was no body.  
1460         // This behavior now matches Firefox and IE.
1461         HTMLElementImpl *body = this->body();
1462         if (!body && isHTMLDocument()) {
1463             NodeImpl *de = documentElement();
1464             if (de) {
1465                 body = new HTMLBodyElementImpl(docPtr());
1466                 int exceptionCode = 0;
1467                 de->appendChild(body, exceptionCode);
1468                 if (exceptionCode != 0)
1469                     body = 0;
1470             }
1471         }
1472
1473         if (body) {
1474             dispatchImageLoadEventsNow();
1475             body->dispatchWindowEvent(EventImpl::LOAD_EVENT, false, false);
1476
1477 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1478             if (!ownerElement())
1479                 printf("onload fired at %d\n", elapsedTime());
1480 #endif
1481         }
1482
1483         m_processingLoadEvent = false;
1484     }
1485     
1486     // Make sure both the initial layout and reflow happen after the onload
1487     // fires. This will improve onload scores, and other browsers do it.
1488     // If they wanna cheat, we can too. -dwh
1489     
1490     bool isLocationChangePending = part() && part()->isScheduledLocationChangePending();
1491     
1492     if (doload && isLocationChangePending && m_startTime.elapsed() < cLayoutScheduleThreshold) {
1493         // Just bail out. Before or during the onload we were shifted to another page.
1494         // The old i-Bench suite does this. When this happens don't bother painting or laying out.        
1495         delete m_tokenizer;
1496         m_tokenizer = 0;
1497         view()->unscheduleRelayout();
1498         return;
1499     }
1500     
1501     if (doload) {
1502         // on an explicit document.close(), the tokenizer might still be waiting on scripts,
1503         // and in that case we don't want to destroy it because that will prevent the
1504         // scripts from getting processed.
1505         // FIXME: this check may no longer be necessary, since now it should be impossible
1506         // for parsing to be false while stil waiting for scripts
1507         if (m_tokenizer && !m_tokenizer->isWaitingForScripts()) {
1508             delete m_tokenizer;
1509             m_tokenizer = 0;
1510         }
1511
1512         if (m_view)
1513             m_view->part()->checkEmitLoadEvent();
1514     }
1515
1516     // Now do our painting/layout, but only if we aren't in a subframe or if we're in a subframe
1517     // that has been sized already.  Otherwise, our view size would be incorrect, so doing any 
1518     // layout/painting now would be pointless.
1519     if (doload) {
1520         if (!ownerElement() || (ownerElement()->renderer() && !ownerElement()->renderer()->needsLayout())) {
1521             updateRendering();
1522             
1523             // Always do a layout after loading if needed.
1524             if (view() && renderer() && (!renderer()->firstChild() || renderer()->needsLayout()))
1525                 view()->layout();
1526         }
1527 #if APPLE_CHANGES
1528         if (renderer() && KWQAccObjectCache::accessibilityEnabled())
1529             getAccObjectCache()->postNotification(renderer(), "AXLoadComplete");
1530 #endif
1531     }
1532 }
1533
1534 void DocumentImpl::setParsing(bool b)
1535 {
1536     m_bParsing = b;
1537     if (!m_bParsing && view())
1538         view()->scheduleRelayout();
1539
1540 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1541     if (!ownerElement() && !m_bParsing)
1542         printf("Parsing finished at %d\n", elapsedTime());
1543 #endif
1544 }
1545
1546 bool DocumentImpl::shouldScheduleLayout()
1547 {
1548     // We can update layout if:
1549     // (a) we actually need a layout
1550     // (b) our stylesheets are all loaded
1551     // (c) we have a <body>
1552     return (renderer() && renderer()->needsLayout() && haveStylesheetsLoaded() &&
1553             documentElement() && documentElement()->renderer() &&
1554             (documentElement()->id() != ID_HTML || body()));
1555 }
1556
1557 int DocumentImpl::minimumLayoutDelay()
1558 {
1559     if (m_overMinimumLayoutThreshold)
1560         return 0;
1561     
1562     int elapsed = m_startTime.elapsed();
1563     m_overMinimumLayoutThreshold = elapsed > cLayoutScheduleThreshold;
1564     
1565     // We'll want to schedule the timer to fire at the minimum layout threshold.
1566     return kMax(0, cLayoutScheduleThreshold - elapsed);
1567 }
1568
1569 int DocumentImpl::elapsedTime() const
1570 {
1571     return m_startTime.elapsed();
1572 }
1573
1574 void DocumentImpl::write( const DOMString &text )
1575 {
1576     write(text.string());
1577 }
1578
1579 void DocumentImpl::write( const QString &text )
1580 {
1581 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1582     if (!ownerElement())
1583         printf("Beginning a document.write at %d\n", elapsedTime());
1584 #endif
1585     
1586     if (!m_tokenizer) {
1587         open();
1588         write(QString::fromLatin1("<html>"));
1589     }
1590     m_tokenizer->write(text, false);
1591
1592     if (m_view && m_view->part()->jScript())
1593         m_view->part()->jScript()->appendSourceFile(m_url,text);
1594     
1595 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1596     if (!ownerElement())
1597         printf("Ending a document.write at %d\n", elapsedTime());
1598 #endif    
1599 }
1600
1601 void DocumentImpl::writeln( const DOMString &text )
1602 {
1603     write(text);
1604     write(DOMString("\n"));
1605 }
1606
1607 void DocumentImpl::finishParsing()
1608 {
1609 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1610     if (!ownerElement())
1611         printf("Received all data at %d\n", elapsedTime());
1612 #endif
1613     
1614     // Let the tokenizer go through as much data as it can.  There will be three possible outcomes after
1615     // finish() is called:
1616     // (1) All remaining data is parsed, document isn't loaded yet
1617     // (2) All remaining data is parsed, document is loaded, tokenizer gets deleted
1618     // (3) Data is still remaining to be parsed.
1619     if (m_tokenizer)
1620         m_tokenizer->finish();
1621 }
1622
1623 void DocumentImpl::clear()
1624 {
1625     delete m_tokenizer;
1626     m_tokenizer = 0;
1627
1628     removeChildren();
1629     QPtrListIterator<RegisteredEventListener> it(m_windowEventListeners);
1630     for (; it.current();)
1631         m_windowEventListeners.removeRef(it.current());
1632 }
1633
1634 void DocumentImpl::setURL(const QString& url)
1635 {
1636     m_url = url;
1637     if (m_styleSelector)
1638         m_styleSelector->setEncodedURL(m_url);
1639 }
1640
1641 void DocumentImpl::setStyleSheet(const DOMString &url, const DOMString &sheet)
1642 {
1643 //    kdDebug( 6030 ) << "HTMLDocument::setStyleSheet()" << endl;
1644     m_sheet = new CSSStyleSheetImpl(this, url);
1645     m_sheet->ref();
1646     m_sheet->parseString(sheet);
1647     m_loadingSheet = false;
1648
1649     updateStyleSelector();
1650 }
1651
1652 void DocumentImpl::setUserStyleSheet( const QString& sheet )
1653 {
1654     if ( m_usersheet != sheet ) {
1655         m_usersheet = sheet;
1656         updateStyleSelector();
1657     }
1658 }
1659
1660 CSSStyleSheetImpl* DocumentImpl::elementSheet()
1661 {
1662     if (!m_elemSheet) {
1663         m_elemSheet = new CSSStyleSheetImpl(this, baseURL() );
1664         m_elemSheet->ref();
1665     }
1666     return m_elemSheet;
1667 }
1668
1669 void DocumentImpl::determineParseMode( const QString &/*str*/ )
1670 {
1671     // For XML documents use strict parse mode.  HTML docs will override this method to
1672     // determine their parse mode.
1673     pMode = Strict;
1674     hMode = XHtml;
1675     kdDebug(6020) << " using strict parseMode" << endl;
1676 }
1677
1678 // Please see if there`s a possibility to merge that code
1679 // with the next function and getElementByID().
1680 NodeImpl *DocumentImpl::findElement( Id id )
1681 {
1682     QPtrStack<NodeImpl> nodeStack;
1683     NodeImpl *current = _first;
1684
1685     while(1)
1686     {
1687         if(!current)
1688         {
1689             if(nodeStack.isEmpty()) break;
1690             current = nodeStack.pop();
1691             current = current->nextSibling();
1692         }
1693         else
1694         {
1695             if(current->id() == id)
1696                 return current;
1697
1698             NodeImpl *child = current->firstChild();
1699             if(child)
1700             {
1701                 nodeStack.push(current);
1702                 current = child;
1703             }
1704             else
1705             {
1706                 current = current->nextSibling();
1707             }
1708         }
1709     }
1710
1711     return 0;
1712 }
1713
1714 NodeImpl *DocumentImpl::nextFocusNode(NodeImpl *fromNode)
1715 {
1716     unsigned short fromTabIndex;
1717
1718     if (!fromNode) {
1719         // No starting node supplied; begin with the top of the document
1720         NodeImpl *n;
1721
1722         int lowestTabIndex = 65535;
1723         for (n = this; n != 0; n = n->traverseNextNode()) {
1724             if (n->isKeyboardFocusable()) {
1725                 if ((n->tabIndex() > 0) && (n->tabIndex() < lowestTabIndex))
1726                     lowestTabIndex = n->tabIndex();
1727             }
1728         }
1729
1730         if (lowestTabIndex == 65535)
1731             lowestTabIndex = 0;
1732
1733         // Go to the first node in the document that has the desired tab index
1734         for (n = this; n != 0; n = n->traverseNextNode()) {
1735             if (n->isKeyboardFocusable() && (n->tabIndex() == lowestTabIndex))
1736                 return n;
1737         }
1738
1739         return 0;
1740     }
1741     else {
1742         fromTabIndex = fromNode->tabIndex();
1743     }
1744
1745     if (fromTabIndex == 0) {
1746         // Just need to find the next selectable node after fromNode (in document order) that doesn't have a tab index
1747         NodeImpl *n = fromNode->traverseNextNode();
1748         while (n && !(n->isKeyboardFocusable() && n->tabIndex() == 0))
1749             n = n->traverseNextNode();
1750         return n;
1751     }
1752     else {
1753         // Find the lowest tab index out of all the nodes except fromNode, that is greater than or equal to fromNode's
1754         // tab index. For nodes with the same tab index as fromNode, we are only interested in those that come after
1755         // fromNode in document order.
1756         // If we don't find a suitable tab index, the next focus node will be one with a tab index of 0.
1757         unsigned short lowestSuitableTabIndex = 65535;
1758         NodeImpl *n;
1759
1760         bool reachedFromNode = false;
1761         for (n = this; n != 0; n = n->traverseNextNode()) {
1762             if (n->isKeyboardFocusable() &&
1763                 ((reachedFromNode && (n->tabIndex() >= fromTabIndex)) ||
1764                  (!reachedFromNode && (n->tabIndex() > fromTabIndex))) &&
1765                 (n->tabIndex() < lowestSuitableTabIndex) &&
1766                 (n != fromNode)) {
1767
1768                 // We found a selectable node with a tab index at least as high as fromNode's. Keep searching though,
1769                 // as there may be another node which has a lower tab index but is still suitable for use.
1770                 lowestSuitableTabIndex = n->tabIndex();
1771             }
1772
1773             if (n == fromNode)
1774                 reachedFromNode = true;
1775         }
1776
1777         if (lowestSuitableTabIndex == 65535) {
1778             // No next node with a tab index -> just take first node with tab index of 0
1779             NodeImpl *n = this;
1780             while (n && !(n->isKeyboardFocusable() && n->tabIndex() == 0))
1781                 n = n->traverseNextNode();
1782             return n;
1783         }
1784
1785         // Search forwards from fromNode
1786         for (n = fromNode->traverseNextNode(); n != 0; n = n->traverseNextNode()) {
1787             if (n->isKeyboardFocusable() && (n->tabIndex() == lowestSuitableTabIndex))
1788                 return n;
1789         }
1790
1791         // The next node isn't after fromNode, start from the beginning of the document
1792         for (n = this; n != fromNode; n = n->traverseNextNode()) {
1793             if (n->isKeyboardFocusable() && (n->tabIndex() == lowestSuitableTabIndex))
1794                 return n;
1795         }
1796
1797         assert(false); // should never get here
1798         return 0;
1799     }
1800 }
1801
1802 NodeImpl *DocumentImpl::previousFocusNode(NodeImpl *fromNode)
1803 {
1804     NodeImpl *lastNode = this;
1805     while (lastNode->lastChild())
1806         lastNode = lastNode->lastChild();
1807
1808     if (!fromNode) {
1809         // No starting node supplied; begin with the very last node in the document
1810         NodeImpl *n;
1811
1812         int highestTabIndex = 0;
1813         for (n = lastNode; n != 0; n = n->traversePreviousNode()) {
1814             if (n->isKeyboardFocusable()) {
1815                 if (n->tabIndex() == 0)
1816                     return n;
1817                 else if (n->tabIndex() > highestTabIndex)
1818                     highestTabIndex = n->tabIndex();
1819             }
1820         }
1821
1822         // No node with a tab index of 0; just go to the last node with the highest tab index
1823         for (n = lastNode; n != 0; n = n->traversePreviousNode()) {
1824             if (n->isKeyboardFocusable() && (n->tabIndex() == highestTabIndex))
1825                 return n;
1826         }
1827
1828         return 0;
1829     }
1830     else {
1831         unsigned short fromTabIndex = fromNode->tabIndex();
1832
1833         if (fromTabIndex == 0) {
1834             // Find the previous selectable node before fromNode (in document order) that doesn't have a tab index
1835             NodeImpl *n = fromNode->traversePreviousNode();
1836             while (n && !(n->isKeyboardFocusable() && n->tabIndex() == 0))
1837                 n = n->traversePreviousNode();
1838             if (n)
1839                 return n;
1840
1841             // No previous nodes with a 0 tab index, go to the last node in the document that has the highest tab index
1842             int highestTabIndex = 0;
1843             for (n = this; n != 0; n = n->traverseNextNode()) {
1844                 if (n->isKeyboardFocusable() && (n->tabIndex() > highestTabIndex))
1845                     highestTabIndex = n->tabIndex();
1846             }
1847
1848             if (highestTabIndex == 0)
1849                 return 0;
1850
1851             for (n = lastNode; n != 0; n = n->traversePreviousNode()) {
1852                 if (n->isKeyboardFocusable() && (n->tabIndex() == highestTabIndex))
1853                     return n;
1854             }
1855
1856             assert(false); // should never get here
1857             return 0;
1858         }
1859         else {
1860             // Find the lowest tab index out of all the nodes except fromNode, that is less than or equal to fromNode's
1861             // tab index. For nodes with the same tab index as fromNode, we are only interested in those before
1862             // fromNode.
1863             // If we don't find a suitable tab index, then there will be no previous focus node.
1864             unsigned short highestSuitableTabIndex = 0;
1865             NodeImpl *n;
1866
1867             bool reachedFromNode = false;
1868             for (n = this; n != 0; n = n->traverseNextNode()) {
1869                 if (n->isKeyboardFocusable() &&
1870                     ((!reachedFromNode && (n->tabIndex() <= fromTabIndex)) ||
1871                      (reachedFromNode && (n->tabIndex() < fromTabIndex)))  &&
1872                     (n->tabIndex() > highestSuitableTabIndex) &&
1873                     (n != fromNode)) {
1874
1875                     // We found a selectable node with a tab index no higher than fromNode's. Keep searching though, as
1876                     // there may be another node which has a higher tab index but is still suitable for use.
1877                     highestSuitableTabIndex = n->tabIndex();
1878                 }
1879
1880                 if (n == fromNode)
1881                     reachedFromNode = true;
1882             }
1883
1884             if (highestSuitableTabIndex == 0) {
1885                 // No previous node with a tab index. Since the order specified by HTML is nodes with tab index > 0
1886                 // first, this means that there is no previous node.
1887                 return 0;
1888             }
1889
1890             // Search backwards from fromNode
1891             for (n = fromNode->traversePreviousNode(); n != 0; n = n->traversePreviousNode()) {
1892                 if (n->isKeyboardFocusable() && (n->tabIndex() == highestSuitableTabIndex))
1893                     return n;
1894             }
1895             // The previous node isn't before fromNode, start from the end of the document
1896             for (n = lastNode; n != fromNode; n = n->traversePreviousNode()) {
1897                 if (n->isKeyboardFocusable() && (n->tabIndex() == highestSuitableTabIndex))
1898                     return n;
1899             }
1900
1901             assert(false); // should never get here
1902             return 0;
1903         }
1904     }
1905 }
1906
1907 int DocumentImpl::nodeAbsIndex(NodeImpl *node)
1908 {
1909     assert(node->getDocument() == this);
1910
1911     int absIndex = 0;
1912     for (NodeImpl *n = node; n && n != this; n = n->traversePreviousNode())
1913         absIndex++;
1914     return absIndex;
1915 }
1916
1917 NodeImpl *DocumentImpl::nodeWithAbsIndex(int absIndex)
1918 {
1919     NodeImpl *n = this;
1920     for (int i = 0; n && (i < absIndex); i++) {
1921         n = n->traverseNextNode();
1922     }
1923     return n;
1924 }
1925
1926 void DocumentImpl::processHttpEquiv(const DOMString &equiv, const DOMString &content)
1927 {
1928     assert(!equiv.isNull() && !content.isNull());
1929
1930     KHTMLPart *part = this->part();
1931
1932     if (strcasecmp(equiv, "default-style") == 0) {
1933         // The preferred style set has been overridden as per section 
1934         // 14.3.2 of the HTML4.0 specification.  We need to update the
1935         // sheet used variable and then update our style selector. 
1936         // For more info, see the test at:
1937         // http://www.hixie.ch/tests/evil/css/import/main/preferred.html
1938         // -dwh
1939         part->d->m_sheetUsed = content.string();
1940         m_preferredStylesheetSet = content;
1941         updateStyleSelector();
1942     }
1943     else if(strcasecmp(equiv, "refresh") == 0 && part->metaRefreshEnabled())
1944     {
1945         // get delay and url
1946         QString str = content.string().stripWhiteSpace();
1947         int pos = str.find(QRegExp("[;,]"));
1948         if ( pos == -1 )
1949             pos = str.find(QRegExp("[ \t]"));
1950
1951         if (pos == -1) // There can be no url (David)
1952         {
1953             bool ok = false;
1954             int delay = 0;
1955             delay = str.toInt(&ok);
1956 #if APPLE_CHANGES
1957             // We want a new history item if the refresh timeout > 1 second
1958             if(ok && part) part->scheduleRedirection(delay, part->url().url(), delay <= 1);
1959 #else
1960             if(ok && part) part->scheduleRedirection(delay, part->url().url() );
1961 #endif
1962         } else {
1963             double delay = 0;
1964             bool ok = false;
1965             delay = str.left(pos).stripWhiteSpace().toDouble(&ok);
1966
1967             pos++;
1968             while(pos < (int)str.length() && str[pos].isSpace()) pos++;
1969             str = str.mid(pos);
1970             if(str.find("url", 0,  false ) == 0)  str = str.mid(3);
1971             str = str.stripWhiteSpace();
1972             if ( str.length() && str[0] == '=' ) str = str.mid( 1 ).stripWhiteSpace();
1973             str = parseURL( DOMString(str) ).string();
1974             if ( ok && part )
1975 #if APPLE_CHANGES
1976                 // We want a new history item if the refresh timeout > 1 second
1977                 part->scheduleRedirection(delay, completeURL( str ), delay <= 1);
1978 #else
1979                 part->scheduleRedirection(delay, completeURL( str ));
1980 #endif
1981         }
1982     }
1983     else if(strcasecmp(equiv, "expires") == 0)
1984     {
1985         QString str = content.string().stripWhiteSpace();
1986         time_t expire_date = str.toLong();
1987         if (m_docLoader)
1988             m_docLoader->setExpireDate(expire_date);
1989     }
1990     else if(strcasecmp(equiv, "pragma") == 0 || strcasecmp(equiv, "cache-control") == 0 && part)
1991     {
1992         QString str = content.string().lower().stripWhiteSpace();
1993         KURL url = part->url();
1994         if ((str == "no-cache") && url.protocol().startsWith("http"))
1995         {
1996            KIO::http_update_cache(url, true, 0);
1997         }
1998     }
1999     else if( (strcasecmp(equiv, "set-cookie") == 0))
2000     {
2001         // ### make setCookie work on XML documents too; e.g. in case of <html:meta .....>
2002         HTMLDocumentImpl *d = static_cast<HTMLDocumentImpl *>(this);
2003         d->setCookie(content);
2004     }
2005 }
2006
2007 bool DocumentImpl::prepareMouseEvent( bool readonly, int _x, int _y, MouseEvent *ev )
2008 {
2009     if ( m_render ) {
2010         assert(m_render->isCanvas());
2011         RenderObject::NodeInfo renderInfo(readonly, ev->type == MousePress);
2012         bool isInside = m_render->layer()->hitTest(renderInfo, _x, _y);
2013         ev->innerNode.reset(renderInfo.innerNode());
2014
2015         if (renderInfo.URLElement()) {
2016             assert(renderInfo.URLElement()->isElementNode());
2017             ElementImpl* e =  static_cast<ElementImpl*>(renderInfo.URLElement());
2018             DOMString href = khtml::parseURL(e->getAttribute(ATTR_HREF));
2019             DOMString target = e->getAttribute(ATTR_TARGET);
2020
2021             if (!target.isNull() && !href.isNull()) {
2022                 ev->target = target;
2023                 ev->url = href;
2024             }
2025             else
2026                 ev->url = href;
2027 //            qDebug("url: *%s*", ev->url.string().latin1());
2028         }
2029
2030         if (!readonly)
2031             updateRendering();
2032
2033         return isInside;
2034     }
2035
2036
2037     return false;
2038 }
2039
2040 // DOM Section 1.1.1
2041 bool DocumentImpl::childAllowed( NodeImpl *newChild )
2042 {
2043     // Documents may contain a maximum of one Element child
2044     if (newChild->nodeType() == Node::ELEMENT_NODE) {
2045         NodeImpl *c;
2046         for (c = firstChild(); c; c = c->nextSibling()) {
2047             if (c->nodeType() == Node::ELEMENT_NODE)
2048                 return false;
2049         }
2050     }
2051
2052     // Documents may contain a maximum of one DocumentType child
2053     if (newChild->nodeType() == Node::DOCUMENT_TYPE_NODE) {
2054         NodeImpl *c;
2055         for (c = firstChild(); c; c = c->nextSibling()) {
2056             if (c->nodeType() == Node::DOCUMENT_TYPE_NODE)
2057                 return false;
2058         }
2059     }
2060
2061     return childTypeAllowed(newChild->nodeType());
2062 }
2063
2064 bool DocumentImpl::childTypeAllowed( unsigned short type )
2065 {
2066     switch (type) {
2067         case Node::ELEMENT_NODE:
2068         case Node::PROCESSING_INSTRUCTION_NODE:
2069         case Node::COMMENT_NODE:
2070         case Node::DOCUMENT_TYPE_NODE:
2071             return true;
2072         default:
2073             return false;
2074     }
2075 }
2076
2077 NodeImpl *DocumentImpl::cloneNode ( bool /*deep*/ )
2078 {
2079     // Spec says cloning Document nodes is "implementation dependent"
2080     // so we do not support it...
2081     return 0;
2082 }
2083
2084 NodeImpl::Id DocumentImpl::attrId(DOMStringImpl* _namespaceURI, DOMStringImpl *_name, bool readonly)
2085 {
2086     // Each document maintains a mapping of attrname -> id for every attr name
2087     // encountered in the document.
2088     // For attrnames without a prefix (no qualified element name) and without matching
2089     // namespace, the value defined in misc/htmlattrs.h is used.
2090     NodeImpl::Id id = 0;
2091
2092     // First see if it's a HTML attribute name
2093     QConstString n(_name->s, _name->l);
2094     if (!_namespaceURI || !strcasecmp(_namespaceURI, XHTML_NAMESPACE)) {
2095         // we're in HTML namespace if we know the tag.
2096         // xhtml is lower case - case sensitive, easy to implement
2097         if ( htmlMode() == XHtml && (id = getAttrID(n.string().ascii(), _name->l)) )
2098             return id;
2099         // compatibility: upper case - case insensitive
2100         if ( htmlMode() != XHtml && (id = getAttrID(n.string().lower().ascii(), _name->l )) )
2101             return id;
2102
2103         // ok, the fast path didn't work out, we need the full check
2104     }
2105
2106     // now lets find out the namespace
2107     Q_UINT16 ns = noNamespace;
2108     if (_namespaceURI) {
2109         DOMString nsU(_namespaceURI);
2110         int nsID = XmlNamespaceTable::getNamespaceID(nsU, readonly);
2111         if (nsID != -1)
2112             ns = (Q_UINT16)nsID;
2113     }
2114     
2115     // Look in the m_attrNames array for the name
2116     // ### yeah, this is lame. use a dictionary / map instead
2117     DOMString nme(n.string());
2118     // compatibility mode has to store upper case
2119     if (htmlMode() != XHtml) nme = nme.upper();
2120     for (id = 0; id < m_attrNameCount; id++)
2121         if (DOMString(m_attrNames[id]) == nme)
2122             return makeId(ns, ATTR_LAST_ATTR+id);
2123
2124     // unknown
2125     if (readonly) return 0;
2126
2127     // Name not found in m_attrNames, so let's add it
2128     // ### yeah, this is lame. use a dictionary / map instead
2129     if (m_attrNameCount+1 > m_attrNameAlloc) {
2130         m_attrNameAlloc += 100;
2131         DOMStringImpl **newNames = new DOMStringImpl* [m_attrNameAlloc];
2132         if (m_attrNames) {
2133             unsigned short i;
2134             for (i = 0; i < m_attrNameCount; i++)
2135                 newNames[i] = m_attrNames[i];
2136             delete [] m_attrNames;
2137         }
2138         m_attrNames = newNames;
2139     }
2140
2141     id = m_attrNameCount++;
2142     m_attrNames[id] = nme.implementation();
2143     m_attrNames[id]->ref();
2144
2145     return makeId(ns, ATTR_LAST_ATTR+id);
2146 }
2147
2148 DOMString DocumentImpl::attrName(NodeImpl::Id _id) const
2149 {
2150     DOMString result;
2151     if (localNamePart(_id) >= ATTR_LAST_ATTR)
2152         result = m_attrNames[localNamePart(_id)-ATTR_LAST_ATTR];
2153     else
2154         result = getAttrName(_id);
2155
2156     // Attribute names are always lowercase in the DOM for both
2157     // HTML and XHTML.
2158     if (isHTMLDocument() || htmlMode() == XHtml)
2159         return result.lower();
2160
2161     return result;
2162 }
2163
2164 NodeImpl::Id DocumentImpl::tagId(DOMStringImpl* _namespaceURI, DOMStringImpl *_name, bool readonly)
2165 {
2166     if (!_name) return 0;
2167     // Each document maintains a mapping of tag name -> id for every tag name encountered
2168     // in the document.
2169     NodeImpl::Id id = 0;
2170
2171     // First see if it's a HTML element name
2172     QConstString n(_name->s, _name->l);
2173     if (!_namespaceURI || !strcasecmp(_namespaceURI, XHTML_NAMESPACE)) {
2174         // we're in HTML namespace if we know the tag.
2175         // xhtml is lower case - case sensitive, easy to implement
2176         if ( htmlMode() == XHtml && (id = getTagID(n.string().ascii(), _name->l)) )
2177             return id;
2178         // compatibility: upper case - case insensitive
2179         if ( htmlMode() != XHtml && (id = getTagID(n.string().lower().ascii(), _name->l )) )
2180             return id;
2181
2182         // ok, the fast path didn't work out, we need the full check
2183     }
2184
2185     // now lets find out the namespace
2186     Q_UINT16 ns = noNamespace;
2187     if (_namespaceURI) {
2188         DOMString nsU(_namespaceURI);
2189         int nsID = XmlNamespaceTable::getNamespaceID(nsU, readonly);
2190         if (nsID != -1)
2191             ns = (Q_UINT16)nsID;
2192     }
2193
2194     // Look in the m_elementNames array for the name
2195     // ### yeah, this is lame. use a dictionary / map instead
2196     DOMString nme(n.string());
2197     // compatibility mode has to store upper case
2198     if (htmlMode() != XHtml) nme = nme.upper();
2199     for (id = 0; id < m_elementNameCount; id++)
2200         if (DOMString(m_elementNames[id]) == nme)
2201             return makeId(ns, ID_LAST_TAG + 1 + id);
2202
2203     // unknown
2204     if (readonly) return 0;
2205
2206     // Name not found in m_elementNames, so let's add it
2207     if (m_elementNameCount+1 > m_elementNameAlloc) {
2208         m_elementNameAlloc += 100;
2209         DOMStringImpl **newNames = new DOMStringImpl* [m_elementNameAlloc];
2210         // ### yeah, this is lame. use a dictionary / map instead
2211         if (m_elementNames) {
2212             unsigned short i;
2213             for (i = 0; i < m_elementNameCount; i++)
2214                 newNames[i] = m_elementNames[i];
2215             delete [] m_elementNames;
2216         }
2217         m_elementNames = newNames;
2218     }
2219
2220     id = m_elementNameCount++;
2221     m_elementNames[id] = nme.implementation();
2222     m_elementNames[id]->ref();
2223
2224     return makeId(ns, ID_LAST_TAG + 1 + id);
2225 }
2226
2227 DOMString DocumentImpl::tagName(NodeImpl::Id _id) const
2228 {
2229     if (localNamePart(_id) > ID_LAST_TAG)
2230         return m_elementNames[localNamePart(_id) - (ID_LAST_TAG + 1)];
2231     else {
2232         // ### put them in a cache
2233         if (htmlMode() == XHtml)
2234             return getTagName(_id).lower();
2235         else
2236             return getTagName(_id);
2237     }
2238 }
2239
2240
2241 DOMStringImpl* DocumentImpl::namespaceURI(NodeImpl::Id _id) const
2242 {
2243     if (_id <= ID_LAST_TAG)
2244         return htmlMode() == XHtml ? XmlNamespaceTable::getNamespaceURI(xhtmlNamespace).implementation() : 0;
2245
2246     unsigned short ns = _id >> 16;
2247
2248     if (!ns) return 0;
2249
2250     return XmlNamespaceTable::getNamespaceURI(ns).implementation();
2251 }
2252
2253 StyleSheetListImpl* DocumentImpl::styleSheets()
2254 {
2255     return m_styleSheets;
2256 }
2257
2258 DOMString DocumentImpl::preferredStylesheetSet()
2259 {
2260   return m_preferredStylesheetSet;
2261 }
2262
2263 DOMString DocumentImpl::selectedStylesheetSet()
2264 {
2265   return view() ? view()->part()->d->m_sheetUsed : DOMString();
2266 }
2267
2268 void 
2269 DocumentImpl::setSelectedStylesheetSet(const DOMString& aString)
2270 {
2271   if (view()) {
2272     view()->part()->d->m_sheetUsed = aString.string();
2273     updateStyleSelector();
2274     if (renderer())
2275       renderer()->repaint();
2276   }
2277 }
2278
2279 // This method is called whenever a top-level stylesheet has finished loading.
2280 void DocumentImpl::stylesheetLoaded()
2281 {
2282   // Make sure we knew this sheet was pending, and that our count isn't out of sync.
2283   assert(m_pendingStylesheets > 0);
2284
2285   m_pendingStylesheets--;
2286   
2287 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2288   if (!ownerElement())
2289       printf("Stylesheet loaded at time %d. %d stylesheets still remain.\n", elapsedTime(), m_pendingStylesheets);
2290 #endif
2291
2292   updateStyleSelector();    
2293 }
2294
2295 void DocumentImpl::updateStyleSelector()
2296 {
2297     // Don't bother updating, since we haven't loaded all our style info yet.
2298     if (!haveStylesheetsLoaded())
2299         return;
2300
2301 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2302     if (!ownerElement())
2303         printf("Beginning update of style selector at time %d.\n", elapsedTime());
2304 #endif
2305
2306     recalcStyleSelector();
2307     recalcStyle(Force);
2308 #if 0
2309
2310     m_styleSelectorDirty = true;
2311 #endif
2312
2313 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2314     if (!ownerElement())
2315         printf("Finished update of style selector at time %d\n", elapsedTime());
2316 #endif
2317
2318     if (renderer()) {
2319         renderer()->setNeedsLayoutAndMinMaxRecalc();
2320         if (view())
2321             view()->scheduleRelayout();
2322     }
2323 }
2324
2325
2326 QStringList DocumentImpl::availableStyleSheets() const
2327 {
2328     return m_availableSheets;
2329 }
2330
2331 void DocumentImpl::recalcStyleSelector()
2332 {
2333     if ( !m_render || !attached() ) return;
2334
2335     QPtrList<StyleSheetImpl> oldStyleSheets = m_styleSheets->styleSheets;
2336     m_styleSheets->styleSheets.clear();
2337     m_availableSheets.clear();
2338     NodeImpl *n;
2339     for (n = this; n; n = n->traverseNextNode()) {
2340         StyleSheetImpl *sheet = 0;
2341
2342         if (n->nodeType() == Node::PROCESSING_INSTRUCTION_NODE)
2343         {
2344             // Processing instruction (XML documents only)
2345             ProcessingInstructionImpl* pi = static_cast<ProcessingInstructionImpl*>(n);
2346             sheet = pi->sheet();
2347 #ifdef KHTML_XSLT
2348             if (pi->isXSL()) {
2349                 applyXSLTransform(pi);
2350                 return;
2351             }
2352 #endif
2353             if (!sheet && !pi->localHref().isEmpty())
2354             {
2355                 // Processing instruction with reference to an element in this document - e.g.
2356                 // <?xml-stylesheet href="#mystyle">, with the element
2357                 // <foo id="mystyle">heading { color: red; }</foo> at some location in
2358                 // the document
2359                 ElementImpl* elem = getElementById(pi->localHref());
2360                 if (elem) {
2361                     DOMString sheetText("");
2362                     NodeImpl *c;
2363                     for (c = elem->firstChild(); c; c = c->nextSibling()) {
2364                         if (c->nodeType() == Node::TEXT_NODE || c->nodeType() == Node::CDATA_SECTION_NODE)
2365                             sheetText += c->nodeValue();
2366                     }
2367
2368                     CSSStyleSheetImpl *cssSheet = new CSSStyleSheetImpl(this);
2369                     cssSheet->parseString(sheetText);
2370                     pi->setStyleSheet(cssSheet);
2371                     sheet = cssSheet;
2372                 }
2373             }
2374
2375         }
2376         else if (n->isHTMLElement() && (n->id() == ID_LINK || n->id() == ID_STYLE)) {
2377             ElementImpl *e = static_cast<ElementImpl *>(n);
2378             QString title = e->getAttribute( ATTR_TITLE ).string();
2379             bool enabledViaScript = false;
2380             if (n->id() == ID_LINK) {
2381                 // <LINK> element
2382                 HTMLLinkElementImpl* l = static_cast<HTMLLinkElementImpl*>(n);
2383                 if (l->isLoading() || l->isDisabled())
2384                     continue;
2385                 if (!l->sheet())
2386                     title = QString::null;
2387                 enabledViaScript = l->isEnabledViaScript();
2388             }
2389
2390             // Get the current preferred styleset.  This is the
2391             // set of sheets that will be enabled.
2392             if ( n->id() == ID_LINK )
2393                 sheet = static_cast<HTMLLinkElementImpl*>(n)->sheet();
2394             else
2395                 // <STYLE> element
2396                 sheet = static_cast<HTMLStyleElementImpl*>(n)->sheet();
2397
2398             // Check to see if this sheet belongs to a styleset
2399             // (thus making it PREFERRED or ALTERNATE rather than
2400             // PERSISTENT).
2401             if (!enabledViaScript && !title.isEmpty()) {
2402                 // Yes, we have a title.
2403                 if (m_preferredStylesheetSet.isEmpty()) {
2404                     // No preferred set has been established.  If
2405                     // we are NOT an alternate sheet, then establish
2406                     // us as the preferred set.  Otherwise, just ignore
2407                     // this sheet.
2408                     QString rel = e->getAttribute( ATTR_REL ).string();
2409                     if (n->id() == ID_STYLE || !rel.contains("alternate"))
2410                         m_preferredStylesheetSet = view()->part()->d->m_sheetUsed = title;
2411                 }
2412                       
2413                 if (!m_availableSheets.contains( title ) )
2414                     m_availableSheets.append( title );
2415                 
2416                 if (title != m_preferredStylesheetSet)
2417                     sheet = 0;
2418             }
2419         }
2420
2421         if (sheet) {
2422             sheet->ref();
2423             m_styleSheets->styleSheets.append(sheet);
2424         }
2425     
2426         // For HTML documents, stylesheets are not allowed within/after the <BODY> tag. So we
2427         // can stop searching here.
2428         if (isHTMLDocument() && n->id() == ID_BODY)
2429             break;
2430     }
2431
2432     // De-reference all the stylesheets in the old list
2433     QPtrListIterator<StyleSheetImpl> it(oldStyleSheets);
2434     for (; it.current(); ++it)
2435         it.current()->deref();
2436
2437     // Create a new style selector
2438     delete m_styleSelector;
2439     QString usersheet = m_usersheet;
2440     if ( m_view && m_view->mediaType() == "print" )
2441         usersheet += m_printSheet;
2442     m_styleSelector = new CSSStyleSelector(this, usersheet, m_styleSheets, !inCompatMode());
2443     m_styleSelector->setEncodedURL(m_url);
2444     m_styleSelectorDirty = false;
2445 }
2446
2447 void DocumentImpl::setHoverNode(NodeImpl* newHoverNode)
2448 {
2449     if (m_hoverNode != newHoverNode) {
2450         if (m_hoverNode)
2451             m_hoverNode->deref();
2452         m_hoverNode = newHoverNode;
2453         if (m_hoverNode)
2454             m_hoverNode->ref();
2455     }    
2456 }
2457
2458 #if APPLE_CHANGES
2459
2460 bool DocumentImpl::relinquishesEditingFocus(NodeImpl *node)
2461 {
2462     assert(node);
2463     assert(node->isContentEditable());
2464
2465     NodeImpl *root = node->rootEditableElement();
2466     if (!part() || !root)
2467         return false;
2468
2469     return part()->shouldEndEditing(rangeOfContents(root).get());
2470 }
2471
2472 bool DocumentImpl::acceptsEditingFocus(NodeImpl *node)
2473 {
2474     assert(node);
2475     assert(node->isContentEditable());
2476
2477     NodeImpl *root = node->rootEditableElement();
2478     if (!part() || !root)
2479         return false;
2480
2481     return part()->shouldBeginEditing(rangeOfContents(root).get());
2482 }
2483
2484 const QValueList<DashboardRegionValue> & DocumentImpl::dashboardRegions() const
2485 {
2486     return m_dashboardRegions;
2487 }
2488
2489 void DocumentImpl::setDashboardRegions (const QValueList<DashboardRegionValue>& regions)
2490 {
2491     m_dashboardRegions = regions;
2492     setDashboardRegionsDirty (false);
2493 }
2494
2495 #endif
2496
2497 static QWidget *widgetForNode(NodeImpl *focusNode)
2498 {
2499     if (!focusNode)
2500         return 0;
2501     RenderObject *renderer = focusNode->renderer();
2502     if (!renderer || !renderer->isWidget())
2503         return 0;
2504     return static_cast<RenderWidget *>(renderer)->widget();
2505 }
2506
2507 bool DocumentImpl::setFocusNode(NodeImpl *newFocusNode)
2508 {    
2509     // Make sure newFocusNode is actually in this document
2510     if (newFocusNode && (newFocusNode->getDocument() != this))
2511         return true;
2512
2513     if (m_focusNode == newFocusNode)
2514         return true;
2515
2516 #if APPLE_CHANGES
2517     if (m_focusNode && m_focusNode->isContentEditable() && !relinquishesEditingFocus(m_focusNode))
2518         return false;
2519 #endif     
2520        
2521     bool focusChangeBlocked = false;
2522     NodeImpl *oldFocusNode = m_focusNode;
2523     m_focusNode = 0;
2524
2525     // Remove focus from the existing focus node (if any)
2526     if (oldFocusNode) {
2527         // This goes hand in hand with the Qt focus setting below.
2528         if (!newFocusNode && view()) {
2529             view()->setFocus();
2530         }
2531
2532         if (oldFocusNode->active())
2533             oldFocusNode->setActive(false);
2534
2535         oldFocusNode->setFocus(false);
2536         oldFocusNode->dispatchHTMLEvent(EventImpl::BLUR_EVENT, false, false);
2537         if (m_focusNode != 0) {
2538             // handler shifted focus
2539             focusChangeBlocked = true;
2540             newFocusNode = 0;
2541         }
2542         oldFocusNode->dispatchUIEvent(EventImpl::DOMFOCUSOUT_EVENT);
2543         if (m_focusNode != 0) {
2544             // handler shifted focus
2545             focusChangeBlocked = true;
2546             newFocusNode = 0;
2547         }
2548         if ((oldFocusNode == this) && oldFocusNode->hasOneRef()) {
2549             oldFocusNode->deref(); // deletes this
2550             return true;
2551         }
2552         else {
2553             oldFocusNode->deref();
2554         }
2555     }
2556
2557     // Clear the selection when changing the focus node to null or to a node that is not 
2558     // contained by the current selection.
2559     if (part()) {
2560         NodeImpl *startContainer = part()->selection().start().node();
2561         if (!newFocusNode || (startContainer && startContainer != newFocusNode && !startContainer->isAncestor(newFocusNode)))
2562             part()->clearSelection();
2563     }
2564
2565     if (newFocusNode) {
2566 #if APPLE_CHANGES            
2567         if (newFocusNode->isContentEditable() && !acceptsEditingFocus(newFocusNode)) {
2568             // delegate blocks focus change
2569             focusChangeBlocked = true;
2570             goto SetFocusNodeDone;
2571         }
2572 #endif
2573         // Set focus on the new node
2574         m_focusNode = newFocusNode;
2575         m_focusNode->ref();
2576         m_focusNode->dispatchHTMLEvent(EventImpl::FOCUS_EVENT, false, false);
2577         if (m_focusNode != newFocusNode) {
2578             // handler shifted focus
2579             focusChangeBlocked = true;
2580             goto SetFocusNodeDone;
2581         }
2582         m_focusNode->dispatchUIEvent(EventImpl::DOMFOCUSIN_EVENT);
2583         if (m_focusNode != newFocusNode) { 
2584             // handler shifted focus
2585             focusChangeBlocked = true;
2586             goto SetFocusNodeDone;
2587         }
2588         m_focusNode->setFocus();
2589         // eww, I suck. set the qt focus correctly
2590         // ### find a better place in the code for this
2591         if (view()) {
2592             QWidget *focusWidget = widgetForNode(m_focusNode);
2593             if (focusWidget) {
2594                 // Make sure a widget has the right size before giving it focus.
2595                 // Otherwise, we are testing edge cases of the QWidget code.
2596                 // Specifically, in WebCore this does not work well for text fields.
2597                 updateLayout();
2598                 // Re-get the widget in case updating the layout changed things.
2599                 focusWidget = widgetForNode(m_focusNode);
2600             }
2601             if (focusWidget)
2602                 focusWidget->setFocus();
2603             else
2604                 view()->setFocus();
2605         }
2606    }
2607
2608 #if APPLE_CHANGES
2609     if (!focusChangeBlocked && m_focusNode && KWQAccObjectCache::accessibilityEnabled())
2610         getAccObjectCache()->handleFocusedUIElementChanged();
2611 #endif
2612
2613 SetFocusNodeDone:
2614     updateRendering();
2615     return !focusChangeBlocked;
2616 }
2617
2618 void DocumentImpl::setCSSTarget(NodeImpl* n)
2619 {
2620     if (m_cssTarget)
2621         m_cssTarget->setChanged();
2622     m_cssTarget = n;
2623     if (n)
2624         n->setChanged();
2625 }
2626
2627 NodeImpl* DocumentImpl::getCSSTarget()
2628 {
2629     return m_cssTarget;
2630 }
2631
2632 void DocumentImpl::attachNodeIterator(NodeIteratorImpl *ni)
2633 {
2634     m_nodeIterators.append(ni);
2635 }
2636
2637 void DocumentImpl::detachNodeIterator(NodeIteratorImpl *ni)
2638 {
2639     m_nodeIterators.remove(ni);
2640 }
2641
2642 void DocumentImpl::notifyBeforeNodeRemoval(NodeImpl *n)
2643 {
2644     QPtrListIterator<NodeIteratorImpl> it(m_nodeIterators);
2645     for (; it.current(); ++it)
2646         it.current()->notifyBeforeNodeRemoval(n);
2647 }
2648
2649 AbstractViewImpl *DocumentImpl::defaultView() const
2650 {
2651     return m_defaultView;
2652 }
2653
2654 EventImpl *DocumentImpl::createEvent(const DOMString &eventType, int &exceptioncode)
2655 {
2656     if (eventType == "UIEvents")
2657         return new UIEventImpl();
2658     else if (eventType == "MouseEvents")
2659         return new MouseEventImpl();
2660     else if (eventType == "MutationEvents")
2661         return new MutationEventImpl();
2662     else if (eventType == "KeyboardEvents")
2663         return new KeyboardEventImpl();
2664     else if (eventType == "HTMLEvents")
2665         return new EventImpl();
2666     else {
2667         exceptioncode = DOMException::NOT_SUPPORTED_ERR;
2668         return 0;
2669     }
2670 }
2671
2672 CSSStyleDeclarationImpl *DocumentImpl::getOverrideStyle(ElementImpl */*elt*/, const DOMString &/*pseudoElt*/)
2673 {
2674     return 0; // ###
2675 }
2676
2677 void DocumentImpl::defaultEventHandler(EventImpl *evt)
2678 {
2679     // if any html event listeners are registered on the window, then dispatch them here
2680     QPtrList<RegisteredEventListener> listenersCopy = m_windowEventListeners;
2681     QPtrListIterator<RegisteredEventListener> it(listenersCopy);
2682     for (; it.current(); ++it) {
2683         if (it.current()->id == evt->id()) {
2684             it.current()->listener->handleEventImpl(evt, true);
2685         }
2686     }
2687
2688     // handle accesskey
2689     if (evt->id()==EventImpl::KEYDOWN_EVENT) {
2690         KeyboardEventImpl *kevt = static_cast<KeyboardEventImpl *>(evt);
2691         if (kevt->ctrlKey()) {
2692             QString key = kevt->qKeyEvent()->unmodifiedText().lower();
2693             ElementImpl *elem = getElementByAccessKey(key);
2694             if (elem) {
2695                 elem->accessKeyAction(false);
2696                 evt->setDefaultHandled();
2697             }
2698         }
2699     }
2700 }
2701
2702 void DocumentImpl::setHTMLWindowEventListener(int id, EventListener *listener)
2703 {
2704     // If we already have it we don't want removeWindowEventListener to delete it
2705     if (listener)
2706         listener->ref();
2707     removeHTMLWindowEventListener(id);
2708     if (listener) {
2709         addWindowEventListener(id, listener, false);
2710         listener->deref();
2711     }
2712 }
2713
2714 EventListener *DocumentImpl::getHTMLWindowEventListener(int id)
2715 {
2716     QPtrListIterator<RegisteredEventListener> it(m_windowEventListeners);
2717     for (; it.current(); ++it) {
2718         if (it.current()->id == id &&
2719             it.current()->listener->eventListenerType() == "_khtml_HTMLEventListener") {
2720             return it.current()->listener;
2721         }
2722     }
2723
2724     return 0;
2725 }
2726
2727 void DocumentImpl::removeHTMLWindowEventListener(int id)
2728 {
2729     QPtrListIterator<RegisteredEventListener> it(m_windowEventListeners);
2730     for (; it.current(); ++it) {
2731         if (it.current()->id == id &&
2732             it.current()->listener->eventListenerType() == "_khtml_HTMLEventListener") {
2733             m_windowEventListeners.removeRef(it.current());
2734             return;
2735         }
2736     }
2737 }
2738
2739 void DocumentImpl::addWindowEventListener(int id, EventListener *listener, const bool useCapture)
2740 {
2741     listener->ref();
2742
2743     // remove existing identical listener set with identical arguments - the DOM2
2744     // spec says that "duplicate instances are discarded" in this case.
2745     removeWindowEventListener(id,listener,useCapture);
2746
2747     RegisteredEventListener *rl = new RegisteredEventListener(static_cast<EventImpl::EventId>(id), listener, useCapture);
2748     m_windowEventListeners.append(rl);
2749
2750     listener->deref();
2751 }
2752
2753 void DocumentImpl::removeWindowEventListener(int id, EventListener *listener, bool useCapture)
2754 {
2755     RegisteredEventListener rl(static_cast<EventImpl::EventId>(id),listener,useCapture);
2756
2757     QPtrListIterator<RegisteredEventListener> it(m_windowEventListeners);
2758     for (; it.current(); ++it)
2759         if (*(it.current()) == rl) {
2760             m_windowEventListeners.removeRef(it.current());
2761             return;
2762         }
2763 }
2764
2765 bool DocumentImpl::hasWindowEventListener(int id)
2766 {
2767     QPtrListIterator<RegisteredEventListener> it(m_windowEventListeners);
2768     for (; it.current(); ++it) {
2769         if (it.current()->id == id) {
2770             return true;
2771         }
2772     }
2773
2774     return false;
2775 }
2776
2777 EventListener *DocumentImpl::createHTMLEventListener(QString code, NodeImpl *node)
2778 {
2779     if (part()) {
2780         return part()->createHTMLEventListener(code, node);
2781     } else {
2782         return NULL;
2783     }
2784 }
2785
2786 void DocumentImpl::dispatchImageLoadEventSoon(HTMLImageLoader *image)
2787 {
2788     m_imageLoadEventDispatchSoonList.append(image);
2789     if (!m_imageLoadEventTimer) {
2790         m_imageLoadEventTimer = startTimer(0);
2791     }
2792 }
2793
2794 void DocumentImpl::removeImage(HTMLImageLoader* image)
2795 {
2796     // Remove instances of this image from both lists.
2797     // Use loops because we allow multiple instances to get into the lists.
2798     while (m_imageLoadEventDispatchSoonList.removeRef(image)) { }
2799     while (m_imageLoadEventDispatchingList.removeRef(image)) { }
2800     if (m_imageLoadEventDispatchSoonList.isEmpty() && m_imageLoadEventTimer) {
2801         killTimer(m_imageLoadEventTimer);
2802         m_imageLoadEventTimer = 0;
2803     }
2804 }
2805
2806 void DocumentImpl::dispatchImageLoadEventsNow()
2807 {
2808     // need to avoid re-entering this function; if new dispatches are
2809     // scheduled before the parent finishes processing the list, they
2810     // will set a timer and eventually be processed
2811     if (!m_imageLoadEventDispatchingList.isEmpty()) {
2812         return;
2813     }
2814
2815     if (m_imageLoadEventTimer) {
2816         killTimer(m_imageLoadEventTimer);
2817         m_imageLoadEventTimer = 0;
2818     }
2819     
2820     m_imageLoadEventDispatchingList = m_imageLoadEventDispatchSoonList;
2821     m_imageLoadEventDispatchSoonList.clear();
2822     for (QPtrListIterator<HTMLImageLoader> it(m_imageLoadEventDispatchingList); it.current(); ) {
2823         HTMLImageLoader* image = it.current();
2824         // Must advance iterator *before* dispatching call.
2825         // Otherwise, it might be advanced automatically if dispatching the call had a side effect
2826         // of destroying the current HTMLImageLoader, and then we would advance past the *next* item,
2827         // missing one altogether.
2828         ++it;
2829         image->dispatchLoadEvent();
2830     }
2831     m_imageLoadEventDispatchingList.clear();
2832 }
2833
2834 void DocumentImpl::timerEvent(QTimerEvent *)
2835 {
2836     dispatchImageLoadEventsNow();
2837 }
2838
2839 ElementImpl *DocumentImpl::ownerElement()
2840 {
2841     KHTMLView *childView = view();
2842     if (!childView)
2843         return 0;
2844     KHTMLPart *childPart = childView->part();
2845     if (!childPart)
2846         return 0;
2847     KHTMLPart *parent = childPart->parentPart();
2848     if (!parent)
2849         return 0;
2850     ChildFrame *childFrame = parent->childFrame(childPart);
2851     if (!childFrame)
2852         return 0;
2853     RenderPart *renderPart = childFrame->m_frame;
2854     if (!renderPart)
2855         return 0;
2856     return static_cast<ElementImpl *>(renderPart->element());
2857 }
2858
2859 DOMString DocumentImpl::domain() const
2860 {
2861     if ( m_domain.isEmpty() ) // not set yet (we set it on demand to save time and space)
2862         m_domain = KURL(URL()).host(); // Initially set to the host
2863     return m_domain;
2864 }
2865
2866 void DocumentImpl::setDomain(const DOMString &newDomain, bool force /*=false*/)
2867 {
2868     if ( force ) {
2869         m_domain = newDomain;
2870         return;
2871     }
2872     if ( m_domain.isEmpty() ) // not set yet (we set it on demand to save time and space)
2873         m_domain = KURL(URL()).host(); // Initially set to the host
2874
2875     // Both NS and IE specify that changing the domain is only allowed when
2876     // the new domain is a suffix of the old domain.
2877     int oldLength = m_domain.length();
2878     int newLength = newDomain.length();
2879     if ( newLength < oldLength ) // e.g. newDomain=kde.org (7) and m_domain=www.kde.org (11)
2880     {
2881         DOMString test = m_domain.copy();
2882         if ( test[oldLength - newLength - 1] == '.' ) // Check that it's a subdomain, not e.g. "de.org"
2883         {
2884             test.remove( 0, oldLength - newLength ); // now test is "kde.org" from m_domain
2885             if ( test == newDomain )                 // and we check that it's the same thing as newDomain
2886                 m_domain = newDomain;
2887         }
2888     }
2889 }
2890
2891 bool DocumentImpl::isValidName(const DOMString &name)
2892 {
2893     static const char validFirstCharacter[] = "ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz";
2894     static const char validSubsequentCharacter[] = "ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz0123456789-_:.";
2895     const unsigned length = name.length();
2896     if (length == 0)
2897         return false;
2898     const QChar * const characters = name.unicode();
2899     const char fc = characters[0];
2900     if (!fc)
2901         return false;
2902     if (strchr(validFirstCharacter, fc) == 0)
2903         return false;
2904     for (unsigned i = 1; i < length; ++i) {
2905         const char sc = characters[i];
2906         if (!sc)
2907             return false;
2908         if (strchr(validSubsequentCharacter, sc) == 0)
2909             return false;
2910     }
2911     return true;
2912 }
2913
2914 void DocumentImpl::addImageMap(HTMLMapElementImpl *imageMap)
2915 {
2916     // Add the image map, unless there's already another with that name.
2917     // "First map wins" is the rule other browsers seem to implement.
2918     QString name = imageMap->getName().string();
2919     if (!m_imageMapsByName.contains(name))
2920         m_imageMapsByName.insert(name, imageMap);
2921 }
2922
2923 void DocumentImpl::removeImageMap(HTMLMapElementImpl *imageMap)
2924 {
2925     // Remove the image map by name.
2926     // But don't remove some other image map that just happens to have the same name.
2927     QString name = imageMap->getName().string();
2928     QMapIterator<QString, HTMLMapElementImpl *> it = m_imageMapsByName.find(name);
2929     if (it != m_imageMapsByName.end() && *it == imageMap)
2930         m_imageMapsByName.remove(it);
2931 }
2932
2933 HTMLMapElementImpl *DocumentImpl::getImageMap(const DOMString &URL) const
2934 {
2935     if (URL.isNull()) {
2936         return 0;
2937     }
2938
2939     QString s = URL.string();
2940     int hashPos = s.find('#');
2941     if (hashPos >= 0)
2942         s = s.mid(hashPos + 1);
2943
2944     QMapConstIterator<QString, HTMLMapElementImpl *> it = m_imageMapsByName.find(s);
2945     if (it == m_imageMapsByName.end())
2946         return 0;
2947     return *it;
2948 }
2949
2950 #if APPLE_CHANGES
2951
2952 void DocumentImpl::setDecoder(Decoder *decoder)
2953 {
2954     decoder->ref();
2955     if (m_decoder) {
2956         m_decoder->deref();
2957     }
2958     m_decoder = decoder;
2959 }
2960
2961 QString DocumentImpl::completeURL(const QString &URL)
2962 {
2963     return KURL(baseURL(), URL, m_decoder ? m_decoder->codec() : 0).url();
2964 }
2965
2966 DOMString DocumentImpl::completeURL(const DOMString &URL)
2967 {
2968     if (URL.isNull())
2969         return URL;
2970     return completeURL(URL.string());
2971 }
2972
2973 bool DocumentImpl::inPageCache()
2974 {
2975     return m_inPageCache;
2976 }
2977
2978 void DocumentImpl::setInPageCache(bool flag)
2979 {
2980     if (m_inPageCache == flag)
2981         return;
2982
2983     m_inPageCache = flag;
2984     if (flag) {
2985         assert(m_savedRenderer == 0);
2986         m_savedRenderer = m_render;
2987         if (m_view) {
2988             m_view->resetScrollBars();
2989         }
2990     } else {
2991         assert(m_render == 0 || m_render == m_savedRenderer);
2992         m_render = m_savedRenderer;
2993         m_savedRenderer = 0;
2994     }
2995 }
2996
2997 void DocumentImpl::passwordFieldAdded()
2998 {
2999     m_passwordFields++;
3000 }
3001
3002 void DocumentImpl::passwordFieldRemoved()
3003 {
3004     assert(m_passwordFields > 0);
3005     m_passwordFields--;
3006 }
3007
3008 bool DocumentImpl::hasPasswordField() const
3009 {
3010     return m_passwordFields > 0;
3011 }
3012
3013 void DocumentImpl::secureFormAdded()
3014 {
3015     m_secureForms++;
3016 }
3017
3018 void DocumentImpl::secureFormRemoved()
3019 {
3020     assert(m_secureForms > 0);
3021     m_secureForms--;
3022 }
3023
3024 bool DocumentImpl::hasSecureForm() const
3025 {
3026     return m_secureForms > 0;
3027 }
3028
3029 void DocumentImpl::setShouldCreateRenderers(bool f)
3030 {
3031     m_createRenderers = f;
3032 }
3033
3034 bool DocumentImpl::shouldCreateRenderers()
3035 {
3036     return m_createRenderers;
3037 }
3038
3039 DOMString DocumentImpl::toString() const
3040 {
3041     DOMString result;
3042
3043     for (NodeImpl *child = firstChild(); child != NULL; child = child->nextSibling()) {
3044         result += child->toString();
3045     }
3046
3047     return result;
3048 }
3049
3050 #endif // APPLE_CHANGES
3051
3052 // ----------------------------------------------------------------------------
3053 // Support for Javascript execCommand, and related methods
3054
3055 JSEditor *DocumentImpl::jsEditor()
3056 {
3057     if (!m_jsEditor)
3058         m_jsEditor = new JSEditor(this);
3059     return m_jsEditor;
3060 }
3061
3062 bool DocumentImpl::execCommand(const DOMString &command, bool userInterface, const DOMString &value)
3063 {
3064     return jsEditor()->execCommand(command, userInterface, value);
3065 }
3066
3067 bool DocumentImpl::queryCommandEnabled(const DOMString &command)
3068 {
3069     return jsEditor()->queryCommandEnabled(command);
3070 }
3071
3072 bool DocumentImpl::queryCommandIndeterm(const DOMString &command)
3073 {
3074     return jsEditor()->queryCommandIndeterm(command);
3075 }
3076
3077 bool DocumentImpl::queryCommandState(const DOMString &command)
3078 {
3079     return jsEditor()->queryCommandState(command);
3080 }
3081
3082 bool DocumentImpl::queryCommandSupported(const DOMString &command)
3083 {
3084     return jsEditor()->queryCommandSupported(command);
3085 }
3086
3087 DOMString DocumentImpl::queryCommandValue(const DOMString &command)
3088 {
3089     return jsEditor()->queryCommandValue(command);
3090 }
3091
3092 // ----------------------------------------------------------------------------
3093
3094 void DocumentImpl::addMarker(RangeImpl *range, DocumentMarker::MarkerType type)
3095 {
3096     // Use a TextIterator to visit the potentially multiple nodes the range covers.
3097     for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
3098         SharedPtr<RangeImpl> textPiece = markedText.range();
3099         int exception = 0;
3100         DocumentMarker marker = {type, textPiece->startOffset(exception), textPiece->endOffset(exception)};
3101         addMarker(textPiece->startContainer(exception), marker);
3102     }
3103 }
3104
3105 void DocumentImpl::removeMarker(RangeImpl *range, DocumentMarker::MarkerType type)
3106 {
3107     // Use a TextIterator to visit the potentially multiple nodes the range covers.
3108     for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
3109         SharedPtr<RangeImpl> textPiece = markedText.range();
3110         int exception = 0;
3111         DocumentMarker marker = {type, textPiece->startOffset(exception), textPiece->endOffset(exception)};
3112         removeMarker(textPiece->startContainer(exception), marker);
3113     }
3114 }
3115
3116 // FIXME:  We don't deal with markers of more than one type yet
3117
3118 // Markers are stored in order sorted by their location.  They do not overlap each other, as currently
3119 // required by the drawing code in render_text.cpp.
3120
3121 void DocumentImpl::addMarker(NodeImpl *node, DocumentMarker newMarker) 
3122 {
3123     assert(newMarker.endOffset >= newMarker.startOffset);
3124     if (newMarker.endOffset == newMarker.startOffset) {
3125         return;     // zero length markers are a NOP
3126     }
3127     
3128     QValueList <DocumentMarker> *markers = m_markers.find(node);
3129     if (!markers) {
3130         markers = new QValueList <DocumentMarker>;
3131         markers->append(newMarker);
3132         m_markers.insert(node, markers);
3133     } else {
3134         QValueListIterator<DocumentMarker> it;
3135         for (it = markers->begin(); it != markers->end(); ) {
3136             DocumentMarker marker = *it;
3137             
3138             if (newMarker.endOffset < marker.startOffset+1) {
3139                 // This is the first marker that is completely after newMarker, and disjoint from it.
3140                 // We found our insertion point.\10
3141                 break;
3142             } else if (newMarker.startOffset > marker.endOffset) {
3143                 // maker is before newMarker, and disjoint from it.  Keep scanning.
3144                 it++;
3145             } else if (newMarker == marker) {
3146                 // already have this one, NOP
3147                 return;
3148             } else {
3149                 // marker and newMarker intersect or touch - merge them into newMarker
3150                 newMarker.startOffset = kMin(newMarker.startOffset, marker.startOffset);
3151                 newMarker.endOffset = kMax(newMarker.endOffset, marker.endOffset);
3152                 // remove old one, we'll add newMarker later
3153                 it = markers->remove(it);
3154                 // it points to the next marker to consider
3155             }
3156         }
3157         // at this point it points to the node before which we want to insert
3158         markers->insert(it, newMarker);
3159     }
3160     
3161     // repaint the affected node
3162     if (node->renderer())
3163         node->renderer()->repaint();
3164 }
3165
3166 void DocumentImpl::removeMarker(NodeImpl *node, DocumentMarker target)
3167 {
3168     assert(target.endOffset >= target.startOffset);
3169     if (target.endOffset == target.startOffset) {
3170         return;     // zero length markers are a NOP
3171     }
3172
3173     QValueList <DocumentMarker> *markers = m_markers.find(node);
3174     if (!markers) {
3175         return;
3176     }
3177     
3178     bool docDirty = false;
3179     QValueListIterator<DocumentMarker> it;
3180     for (it = markers->begin(); it != markers->end(); ) {
3181         DocumentMarker marker = *it;
3182
3183         if (target.endOffset <= marker.startOffset) {
3184             // This is the first marker that is completely after target.  All done.
3185             break;
3186         } else if (target.startOffset >= marker.endOffset) {
3187             // marker is before target.  Keep scanning.
3188             it++;
3189         } else {
3190             // at this point we know that marker and target intersect in some way
3191             docDirty = true;
3192
3193             // pitch the old marker
3194             it = markers->remove(it);
3195             // it now points to the next node
3196             
3197             // add either of the resulting slices that are left after removing target
3198             if (target.startOffset > marker.startOffset) {
3199                 DocumentMarker newLeft = marker;
3200                 newLeft.endOffset = target.startOffset;
3201                 markers->insert(it, newLeft);
3202             }
3203             if (marker.endOffset > target.endOffset) {
3204                 DocumentMarker newRight = marker;
3205                 newRight.startOffset = target.endOffset;
3206                 markers->insert(it, newRight);
3207             }
3208         }
3209     }
3210
3211     if (markers->isEmpty())
3212         m_markers.remove(node);
3213
3214     // repaint the affected node
3215     if (docDirty && node->renderer())
3216         node->renderer()->repaint();
3217 }
3218
3219 QValueList<DocumentMarker> DocumentImpl::markersForNode(NodeImpl *node)
3220 {
3221     QValueList <DocumentMarker> *markers = m_markers.find(node);
3222     if (markers) {
3223         return *markers;
3224     } else {
3225         return QValueList <DocumentMarker> ();
3226     }
3227 }
3228
3229 void DocumentImpl::removeAllMarkers(NodeImpl *node, ulong startOffset, long length)
3230 {
3231     // FIXME - yet another cheat that relies on us only having one marker type
3232     DocumentMarker marker = {DocumentMarker::Spelling, startOffset, startOffset+length};
3233     removeMarker(node, marker);
3234 }
3235
3236 void DocumentImpl::removeAllMarkers(NodeImpl *node)
3237 {
3238     QValueList<DocumentMarker> *markers = m_markers.take(node);
3239     if (markers) {
3240         RenderObject *renderer = node->renderer();
3241         if (renderer)
3242             renderer->repaint();
3243         delete markers;
3244     }
3245 }
3246
3247 void DocumentImpl::removeAllMarkers()
3248 {
3249     QPtrDictIterator< QValueList<DocumentMarker> > it(m_markers);
3250     for (; NodeImpl *node = static_cast<NodeImpl *>(it.currentKey()); ++it) {
3251         RenderObject *renderer = node->renderer();
3252         if (renderer)
3253             renderer->repaint();
3254     }
3255     m_markers.clear();
3256 }
3257
3258 void DocumentImpl::shiftMarkers(NodeImpl *node, ulong startOffset, long delta)
3259 {
3260     QValueList <DocumentMarker> *markers = m_markers.find(node);
3261     if (!markers)
3262         return;
3263
3264     bool docDirty = false;
3265     QValueListIterator<DocumentMarker> it;
3266     for (it = markers->begin(); it != markers->end(); ++it) {
3267         DocumentMarker &marker = *it;
3268         if (marker.startOffset >= startOffset) {
3269             assert((int)marker.startOffset + delta >= 0);
3270             marker.startOffset += delta;
3271             marker.endOffset += delta;
3272             docDirty = true;
3273         }
3274     }
3275     
3276     // repaint the affected node
3277     if (docDirty && node->renderer())
3278         node->renderer()->repaint();
3279 }
3280
3281 #ifdef KHTML_XSLT
3282 void DocumentImpl::applyXSLTransform(ProcessingInstructionImpl* pi)
3283 {
3284     // Ref ourselves to keep from being destroyed.
3285     XSLTProcessorImpl processor(static_cast<XSLStyleSheetImpl*>(pi->sheet()), this);
3286     processor.transformDocument(this);
3287
3288     // FIXME: If the transform failed we should probably report an error (like Mozilla does) in this
3289     // case.
3290 }
3291
3292 void DocumentImpl::setTransformSourceDocument(DocumentImpl* doc)
3293
3294     if (m_transformSourceDocument)
3295         m_transformSourceDocument->deref(); 
3296     m_transformSourceDocument = doc;
3297     if (doc)
3298         doc->ref();
3299 }
3300
3301 #endif
3302
3303 void DocumentImpl::setDesignMode(InheritedBool value)
3304 {
3305     m_designMode = value;
3306 }
3307
3308 DocumentImpl::InheritedBool DocumentImpl::getDesignMode() const
3309 {
3310     return m_designMode;
3311 }
3312
3313 bool DocumentImpl::inDesignMode() const
3314 {
3315     for (const DocumentImpl* d = this; d; d = d->parentDocument()) {
3316         if (d->m_designMode != inherit)
3317             return d->m_designMode;      
3318     }
3319     return false;
3320 }
3321
3322 DocumentImpl *DocumentImpl::parentDocument() const
3323 {
3324     KHTMLPart *childPart = part();
3325     if (!childPart)
3326         return 0;
3327     KHTMLPart *parent = childPart->parentPart();
3328     if (!parent)
3329         return 0;
3330     return parent->xmlDocImpl();
3331 }
3332
3333 DocumentImpl *DocumentImpl::topDocument() const
3334 {
3335     DocumentImpl *doc = const_cast<DocumentImpl *>(this);
3336     ElementImpl *element;
3337     while ((element = doc->ownerElement()) != 0) {
3338         doc = element->getDocument();
3339         element = doc ? doc->ownerElement() : 0;
3340     }
3341     
3342     return doc;
3343 }
3344
3345 AttrImpl *DocumentImpl::createAttributeNS(const DOMString &namespaceURI, const DOMString &qualifiedName, int &exception)
3346 {
3347     if (qualifiedName.isNull()) {
3348         exception = DOMException::NAMESPACE_ERR;
3349         return 0;
3350     }
3351
3352     DOMString localName(qualifiedName.copy());
3353     DOMString prefix;
3354     int colonpos;
3355     if ((colonpos = qualifiedName.find(':')) >= 0) {
3356         prefix = qualifiedName.copy();
3357         prefix.truncate(colonpos);
3358         localName.remove(0, colonpos+1);
3359     }
3360
3361     if (!isValidName(localName)) {
3362         exception = DOMException::INVALID_CHARACTER_ERR;
3363         return 0;
3364     }
3365     // ### check correctness of namespace, prefix?
3366
3367     Id id = attrId(namespaceURI.implementation(), localName.implementation(), false /* allocate */);
3368     AttrImpl *attr = createAttribute(id);
3369     if (!prefix.isNull())
3370         attr->setPrefix(prefix.implementation(), exception);
3371     return attr;
3372 }
3373
3374 SharedPtr<HTMLCollectionImpl> DocumentImpl::images()
3375 {
3376     return SharedPtr<HTMLCollectionImpl>(new HTMLCollectionImpl(this, HTMLCollectionImpl::DOC_IMAGES));
3377 }
3378
3379 SharedPtr<HTMLCollectionImpl> DocumentImpl::applets()
3380 {
3381     return SharedPtr<HTMLCollectionImpl>(new HTMLCollectionImpl(this, HTMLCollectionImpl::DOC_APPLETS));
3382 }
3383
3384 SharedPtr<HTMLCollectionImpl> DocumentImpl::embeds()
3385 {
3386     return SharedPtr<HTMLCollectionImpl>(new HTMLCollectionImpl(this, HTMLCollectionImpl::DOC_EMBEDS));
3387 }
3388
3389 SharedPtr<HTMLCollectionImpl> DocumentImpl::objects()
3390 {
3391     return SharedPtr<HTMLCollectionImpl>(new HTMLCollectionImpl(this, HTMLCollectionImpl::DOC_OBJECTS));
3392 }
3393
3394 SharedPtr<HTMLCollectionImpl> DocumentImpl::links()
3395 {
3396     return SharedPtr<HTMLCollectionImpl>(new HTMLCollectionImpl(this, HTMLCollectionImpl::DOC_LINKS));
3397 }
3398
3399 SharedPtr<HTMLCollectionImpl> DocumentImpl::forms()
3400 {
3401     return SharedPtr<HTMLCollectionImpl>(new HTMLCollectionImpl(this, HTMLCollectionImpl::DOC_FORMS));
3402 }
3403
3404 SharedPtr<HTMLCollectionImpl> DocumentImpl::anchors()
3405 {
3406     return SharedPtr<HTMLCollectionImpl>(new HTMLCollectionImpl(this, HTMLCollectionImpl::DOC_ANCHORS));
3407 }
3408
3409 SharedPtr<HTMLCollectionImpl> DocumentImpl::all()
3410 {
3411     return SharedPtr<HTMLCollectionImpl>(new HTMLCollectionImpl(this, HTMLCollectionImpl::DOC_ALL));
3412 }
3413
3414 SharedPtr<HTMLCollectionImpl> DocumentImpl::nameableItems()
3415 {
3416     return SharedPtr<HTMLCollectionImpl>(new HTMLCollectionImpl(this, HTMLCollectionImpl::DOC_NAMEABLE_ITEMS));
3417 }
3418
3419 SharedPtr<NameNodeListImpl> DocumentImpl::getElementsByName(const DOMString &elementName)
3420 {
3421     return SharedPtr<NameNodeListImpl>(new NameNodeListImpl(this, elementName));
3422 }
3423
3424 // ----------------------------------------------------------------------------
3425
3426 DocumentFragmentImpl::DocumentFragmentImpl(DocumentPtr *doc) : ContainerNodeImpl(doc)
3427 {
3428 }
3429
3430 DOMString DocumentFragmentImpl::nodeName() const
3431 {
3432   return "#document-fragment";
3433 }
3434
3435 unsigned short DocumentFragmentImpl::nodeType() const
3436 {
3437     return Node::DOCUMENT_FRAGMENT_NODE;
3438 }
3439
3440 // DOM Section 1.1.1
3441 bool DocumentFragmentImpl::childTypeAllowed( unsigned short type )
3442 {
3443     switch (type) {
3444         case Node::ELEMENT_NODE:
3445         case Node::PROCESSING_INSTRUCTION_NODE:
3446         case Node::COMMENT_NODE:
3447         case Node::TEXT_NODE:
3448         case Node::CDATA_SECTION_NODE:
3449         case Node::ENTITY_REFERENCE_NODE:
3450             return true;
3451         default:
3452             return false;
3453     }
3454 }
3455
3456 DOMString DocumentFragmentImpl::toString() const
3457 {
3458     DOMString result;
3459
3460     for (NodeImpl *child = firstChild(); child != NULL; child = child->nextSibling()) {
3461         result += child->toString();
3462     }
3463
3464     return result;
3465 }
3466
3467
3468 NodeImpl *DocumentFragmentImpl::cloneNode ( bool deep )
3469 {
3470     DocumentFragmentImpl *clone = new DocumentFragmentImpl( docPtr() );
3471     if (deep)
3472         cloneChildNodes(clone);
3473     return clone;
3474 }
3475
3476
3477 // ----------------------------------------------------------------------------
3478
3479 DocumentTypeImpl::DocumentTypeImpl(DOMImplementationImpl *implementation, DocumentPtr *doc,
3480                                    const DOMString &qualifiedName, const DOMString &publicId,
3481                                    const DOMString &systemId)
3482     : NodeImpl(doc), m_implementation(implementation),
3483       m_qualifiedName(qualifiedName), m_publicId(publicId), m_systemId(systemId)
3484 {
3485     if (m_implementation)
3486         m_implementation->ref();
3487
3488     m_entities = 0;
3489     m_notations = 0;
3490
3491     // if doc is 0, it is not attached to a document and / or
3492     // therefore does not provide entities or notations. (DOM Level 3)
3493 }
3494
3495 DocumentTypeImpl::~DocumentTypeImpl()
3496 {
3497     if (m_implementation)
3498         m_implementation->deref();
3499     if (m_entities)
3500         m_entities->deref();
3501     if (m_notations)
3502         m_notations->deref();
3503 }
3504
3505 void DocumentTypeImpl::copyFrom(const DocumentTypeImpl& other)
3506 {
3507     m_qualifiedName = other.m_qualifiedName;
3508     m_publicId = other.m_publicId;
3509     m_systemId = other.m_systemId;
3510     m_subset = other.m_subset;
3511 }
3512
3513 DOMString DocumentTypeImpl::toString() const
3514 {
3515     DOMString result;
3516     if (m_qualifiedName.isEmpty()) {
3517         return "";
3518     } else {
3519         result = "<!DOCTYPE ";
3520         result += m_qualifiedName;
3521     }
3522     if (!m_publicId.isEmpty()) {
3523         result += " PUBLIC \"";
3524         result += m_publicId;
3525         result += "\" \"";
3526         result += m_systemId;
3527         result += "\"";
3528     } else if (!m_systemId.isEmpty()) {
3529         result += " SYSTEM \"";
3530         result += m_systemId;
3531         result += "\"";
3532     }
3533     if (!m_subset.isEmpty()) {
3534         result += " [";
3535         result += m_subset;
3536         result += "]";
3537     }
3538     result += ">";
3539     return result;
3540 }
3541
3542 DOMString DocumentTypeImpl::nodeName() const
3543 {
3544     return name();
3545 }
3546
3547 unsigned short DocumentTypeImpl::nodeType() const
3548 {
3549     return Node::DOCUMENT_TYPE_NODE;
3550 }
3551
3552 // DOM Section 1.1.1
3553 bool DocumentTypeImpl::childTypeAllowed( unsigned short /*type*/ )
3554 {
3555     return false;
3556 }
3557
3558 NodeImpl *DocumentTypeImpl::cloneNode ( bool /*deep*/ )
3559 {
3560     // Spec says cloning Document nodes is "implementation dependent"
3561     // so we do not support it...
3562     return 0;
3563 }
3564
3565 #include "dom_docimpl.moc"