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