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