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