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