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