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