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