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