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