2 * This file is part of the DOM implementation for KDE.
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 * (C) 2002-2006 Apple Computer, Inc.
8 * (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com)
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
26 #include "dom_docimpl.h"
28 #include <dom/dom_exception.h>
30 #include "dom_textimpl.h"
31 #include "dom_xmlimpl.h"
32 #include "dom2_rangeimpl.h"
33 #include "dom2_eventsimpl.h"
34 #include "xml_tokenizer.h"
35 #include <html/htmltokenizer.h>
36 #include "dom_restyler.h"
38 #include <css/csshelper.h>
39 #include <css/cssstyleselector.h>
40 #include <css/css_stylesheetimpl.h>
41 #include <misc/htmlhashes.h>
42 #include <misc/helper.h>
43 #include <misc/seed.h>
44 #include <misc/loader.h>
45 #include <ecma/kjs_proxy.h>
46 #include <ecma/kjs_binding.h>
48 #include <QtCore/QStack>
50 #include <QTimerEvent>
51 #include <QtCore/QList>
55 #include <rendering/counter_tree.h>
56 #include <rendering/render_canvas.h>
57 #include <rendering/render_replaced.h>
58 #include <rendering/render_arena.h>
59 #include <rendering/render_layer.h>
60 #include <rendering/render_frames.h>
61 #include <rendering/render_image.h>
63 #include <khtmlview.h>
64 #include <khtml_part.h>
65 #include <kauthorized.h>
66 #include <kglobalsettings.h>
67 #include <kstringhandler.h>
68 #include <kdatetime.h>
69 #include <khtml_settings.h>
70 #include <khtmlpart_p.h>
72 #include <html/html_baseimpl.h>
73 #include <html/html_blockimpl.h>
74 #include <html/html_canvasimpl.h>
75 #include <html/html_documentimpl.h>
76 #include <html/html_formimpl.h>
77 #include <html/html_headimpl.h>
78 #include <html/html_imageimpl.h>
79 #include <html/html_listimpl.h>
80 #include <html/html_miscimpl.h>
81 #include <html/html_tableimpl.h>
82 #include <html/html_objectimpl.h>
83 #include <html/HTMLAudioElement.h>
84 #include <html/HTMLVideoElement.h>
85 #include <html/HTMLSourceElement.h>
86 #include <editing/htmlediting.h>
87 #include <editing/jsediting.h>
89 #include <kapplication.h>
96 using namespace khtml
;
98 // ------------------------------------------------------------------------
100 DOMImplementationImpl
*DOMImplementationImpl::m_instance
= 0;
102 DOMImplementationImpl::DOMImplementationImpl()
106 DOMImplementationImpl::~DOMImplementationImpl()
110 bool DOMImplementationImpl::hasFeature ( const DOMString
&feature
, const DOMString
&version
)
112 // ### update when we (fully) support the relevant features
113 QString lower
= feature
.string().toLower();
114 if ((lower
== "html" || lower
== "xml") &&
115 (version
.isEmpty() || version
== "1.0" || version
== "2.0"))
118 // ## Do we support Core Level 3 ?
119 if ((lower
== "core" ) &&
120 (version
.isEmpty() || version
== "2.0"))
123 if ((lower
== "traversal") &&
124 (version
.isEmpty() || version
== "2.0"))
127 if ((lower
== "events" || lower
== "uievents" ||
128 lower
== "mouseevents" || lower
== "mutationevents" ||
129 lower
== "htmlevents" || lower
== "textevents" ) &&
130 (version
.isEmpty() || version
== "2.0" || version
== "3.0"))
135 DocumentTypeImpl
*DOMImplementationImpl::createDocumentType( const DOMString
&qualifiedName
, const DOMString
&publicId
,
136 const DOMString
&systemId
, int &exceptioncode
)
138 // Not mentioned in spec: throw NAMESPACE_ERR if no qualifiedName supplied
139 if (qualifiedName
.isNull()) {
140 exceptioncode
= DOMException::NAMESPACE_ERR
;
144 // INVALID_CHARACTER_ERR: Raised if the specified qualified name contains an illegal character.
145 if (!Element::khtmlValidQualifiedName(qualifiedName
)) {
146 exceptioncode
= DOMException::INVALID_CHARACTER_ERR
;
150 // NAMESPACE_ERR: Raised if the qualifiedName is malformed.
151 // Added special case for the empty string, which seems to be a common pre-DOM2 misuse
152 if (!qualifiedName
.isEmpty() && Element::khtmlMalformedQualifiedName(qualifiedName
)) {
153 exceptioncode
= DOMException::NAMESPACE_ERR
;
157 return new DocumentTypeImpl(this,0,qualifiedName
,publicId
,systemId
);
160 DOMImplementationImpl
* DOMImplementationImpl::getInterface(const DOMString
& /*feature*/) const
166 DocumentImpl
*DOMImplementationImpl::createDocument( const DOMString
&namespaceURI
, const DOMString
&qualifiedName
,
167 DocumentTypeImpl
* dtype
, int &exceptioncode
)
171 if (!checkQualifiedName(qualifiedName
, namespaceURI
, 0, true/*nameCanBeNull*/,
172 true /*nameCanBeEmpty, see #61650*/, &exceptioncode
) )
175 // WRONG_DOCUMENT_ERR: Raised if doctype has already been used with a different document or was
176 // created from a different implementation.
177 if (dtype
&& (dtype
->getDocument() || dtype
->implementation() != this)) {
178 exceptioncode
= DOMException::WRONG_DOCUMENT_ERR
;
182 // ### this is completely broken.. without a view it will not work (Dirk)
183 DocumentImpl
*doc
= new DocumentImpl(this, 0);
186 doc
->setDocType(dtype
);
189 // the document must be created empty if all parameters are null
190 // (or empty for qName/nsURI as a tolerance) - see DOM 3 Core.
191 if (dtype
|| !qualifiedName
.isEmpty() || !namespaceURI
.isEmpty()) {
192 ElementImpl
*element
= doc
->createElementNS(namespaceURI
,qualifiedName
);
193 doc
->appendChild(element
,exceptioncode
);
203 CSSStyleSheetImpl
*DOMImplementationImpl::createCSSStyleSheet(DOMStringImpl
* /*title*/, DOMStringImpl
*media
,
204 int &/*exceptioncode*/)
206 // ### TODO : title should be set, and media could have wrong syntax, in which case we should
207 // generate an exception.
208 CSSStyleSheetImpl
*parent
= 0L;
209 CSSStyleSheetImpl
*sheet
= new CSSStyleSheetImpl(parent
, DOMString());
210 sheet
->setMedia(new MediaListImpl(sheet
, media
, true /*fallbackToDescriptor*/));
214 DocumentImpl
*DOMImplementationImpl::createDocument( KHTMLView
*v
)
216 DocumentImpl
* doc
= new DocumentImpl(this, v
);
221 HTMLDocumentImpl
*DOMImplementationImpl::createHTMLDocument( KHTMLView
*v
)
223 HTMLDocumentImpl
* doc
= new HTMLDocumentImpl(this, v
);
228 HTMLDocumentImpl
* DOMImplementationImpl::createHTMLDocument( const DOMString
& title
)
230 HTMLDocumentImpl
* r
= createHTMLDocument( 0 /* ### create a view otherwise it doesn't work */);
234 r
->write(QLatin1String("<HTML><HEAD><TITLE>") + title
.string() +
235 QLatin1String("</TITLE></HEAD>"));
240 DOMImplementationImpl
*DOMImplementationImpl::instance()
243 m_instance
= new DOMImplementationImpl();
250 // ------------------------------------------------------------------------
252 ElementMappingCache::ElementMappingCache():m_dict()
256 ElementMappingCache::~ElementMappingCache()
258 qDeleteAll( m_dict
);
261 void ElementMappingCache::add(const QString
& id
, ElementImpl
* nd
)
263 if (id
.isEmpty()) return;
265 ItemInfo
* info
= m_dict
.value(id
);
269 info
->nd
= 0; //Now ambigous
273 ItemInfo
* info
= new ItemInfo();
276 m_dict
.insert(id
, info
);
280 void ElementMappingCache::set(const QString
& id
, ElementImpl
* nd
)
282 if (id
.isEmpty()) return;
284 assert(m_dict
.contains(id
));
285 ItemInfo
* info
= m_dict
.value(id
);
289 void ElementMappingCache::remove(const QString
& id
, ElementImpl
* nd
)
291 if (id
.isEmpty()) return;
293 assert(m_dict
.contains(id
));
294 ItemInfo
* info
= m_dict
.value(id
);
308 bool ElementMappingCache::contains(const QString
& id
)
310 if (id
.isEmpty()) return false;
311 return m_dict
.contains(id
);
314 ElementMappingCache::ItemInfo
* ElementMappingCache::get(const QString
& id
)
316 if (id
.isEmpty()) return 0;
317 return m_dict
.value(id
);
320 typedef QList
<DocumentImpl
*> ChangedDocuments
;
321 K_GLOBAL_STATIC(ChangedDocuments
, s_changedDocuments
)
323 // KHTMLView might be 0
324 DocumentImpl::DocumentImpl(DOMImplementationImpl
*_implementation
, KHTMLView
*v
)
325 : NodeBaseImpl( 0 ), m_domtree_version(0), m_counterDict(),
326 m_imageLoadEventTimer(0)
328 m_document
.resetSkippingRef(this); //Make getDocument return us..
329 m_selfOnlyRefCount
= 0;
332 //m_decoderMibEnum = 0;
333 m_textColor
= Qt::black
;
336 m_renderArena
.reset();
338 KHTMLGlobal::registerDocumentImpl(this);
341 m_docLoader
= new DocLoader(v
->part(), this );
342 setPaintDevice( m_view
);
345 m_docLoader
= new DocLoader( 0, this );
347 visuallyOrdered
= false;
349 m_docChanged
= false;
353 m_implementation
= _implementation
;
354 m_implementation
->ref();
357 m_textColor
= "#000000";
358 m_attrMap
= new IdNameMapping(ATTR_LAST_ATTR
+1);
359 m_elementMap
= new IdNameMapping(ID_LAST_TAG
+1);
360 m_namespaceMap
= new IdNameMapping(1);
361 QString
xhtml(XHTML_NAMESPACE
);
362 m_namespaceMap
->names
.insert(emptyNamespace
, new DOMStringImpl(""));
363 m_namespaceMap
->names
.insert(xhtmlNamespace
, new DOMStringImpl(xhtml
.unicode(), xhtml
.length()));
364 m_namespaceMap
->names
[emptyNamespace
]->ref();
365 m_namespaceMap
->names
[xhtmlNamespace
]->ref();
366 m_namespaceMap
->count
+=2;
370 m_defaultView
= new AbstractViewImpl(this);
371 m_defaultView
->ref();
373 m_styleSheets
= new StyleSheetListImpl
;
374 m_styleSheets
->ref();
375 m_addedStyleSheets
= 0;
377 m_styleSelectorDirty
= false;
380 m_inStyleRecalc
= false;
381 m_pendingStylesheets
= 0;
382 m_ignorePendingStylesheets
= false;
384 m_hadLoadError
= false;
385 m_docLoading
= false;
388 m_documentElement
= 0;
391 m_dynamicDomRestyler
= new khtml::DynamicDomRestyler();
392 m_stateRestorePos
= 0;
395 void DocumentImpl::removedLastRef()
397 if (m_selfOnlyRefCount
) {
398 /* In this case, the only references to us are from children,
399 so we have a cycle. We'll try to break it by disconnecting the
400 children from us; this sucks/is wrong, but it's pretty much
401 the best we can do without tracing.
403 Of course, if dumping the children causes the refcount from them to
404 drop to 0 we can get killed right here, so better hold
405 a temporary reference, too
407 DocPtr
<DocumentImpl
> guard(this);
409 // we must make sure not to be retaining any of our children through
410 // these extra pointers or we will create a reference cycle
417 m_cssTarget
->deref();
422 m_focusNode
->deref();
427 m_hoverNode
->deref();
432 m_activeNode
->deref();
436 if (m_documentElement
) {
437 m_documentElement
->deref();
438 m_documentElement
= 0;
450 DocumentImpl::~DocumentImpl()
452 //Important: if you need to remove stuff here,
453 //you may also have to fix removedLastRef() above - M.O.
456 QHashIterator
<long,NodeListImpl::Cache
*> it(m_nodeListCache
);
458 it
.next().value()->deref();
461 m_loadingXMLDoc
->deref(this);
462 if (s_changedDocuments
&& m_docChanged
)
463 s_changedDocuments
->removeAll(this);
465 m_document
.resetSkippingRef(0);
466 delete m_styleSelector
;
468 if (m_elemSheet
) m_elemSheet
->deref();
471 m_implementation
->deref();
474 delete m_namespaceMap
;
475 delete m_dynamicDomRestyler
;
477 m_defaultView
->deref();
478 m_styleSheets
->deref();
479 if (m_addedStyleSheets
)
480 m_addedStyleSheets
->deref();
482 m_cssTarget
->deref();
484 m_focusNode
->deref();
486 m_hoverNode
->deref();
488 m_activeNode
->deref();
489 if (m_documentElement
)
490 m_documentElement
->deref();
491 qDeleteAll(m_counterDict
);
493 m_renderArena
.reset();
495 KHTMLGlobal::deregisterDocumentImpl(this);
499 DocumentTypeImpl
*DocumentImpl::doctype() const
504 void DocumentImpl::setDocType(DocumentTypeImpl
* dt
)
506 assert(m_doctype
== 0 && dt
!= 0);
509 m_doctype
->setDocument(this);
512 DOMImplementationImpl
*DocumentImpl::implementation() const
514 return m_implementation
;
517 void DocumentImpl::childrenChanged()
519 // invalidate the document element we have cached in case it was replaced
520 if (m_documentElement
)
521 m_documentElement
->deref();
522 m_documentElement
= 0;
525 ElementImpl
*DocumentImpl::documentElement() const
527 if (!m_documentElement
) {
528 NodeImpl
* n
= firstChild();
529 while (n
&& n
->nodeType() != Node::ELEMENT_NODE
)
530 n
= n
->nextSibling();
531 m_documentElement
= static_cast<ElementImpl
*>(n
);
532 if (m_documentElement
)
533 m_documentElement
->ref();
535 return m_documentElement
;
538 ElementImpl
*DocumentImpl::createElement( const DOMString
&name
, int* pExceptioncode
)
540 Id id
= getId( NodeImpl::ElementId
, name
.implementation(),
541 false /* allocate */, false /*HTMLDocumentImpl::createElement looked for HTML elements already*/,
543 if ( pExceptioncode
&& *pExceptioncode
)
546 XMLElementImpl
* e
= new XMLElementImpl( getDocument(), id
);
547 e
->setHTMLCompat( htmlMode() != XHtml
); // Not a real HTML element, but inside an html-compat doc all tags are uppercase.
551 AttrImpl
*DocumentImpl::createAttribute( const DOMString
&tagName
, int* pExceptioncode
)
553 Id id
= getId( NodeImpl::AttributeId
, tagName
.implementation(),
554 false /* allocate */, isHTMLDocument(), pExceptioncode
);
555 if ( pExceptioncode
&& *pExceptioncode
)
557 AttrImpl
* attr
= new AttrImpl( 0, getDocument(), id
, DOMString("").implementation());
558 attr
->setHTMLCompat( htmlMode() != XHtml
);
562 DocumentFragmentImpl
*DocumentImpl::createDocumentFragment( )
564 return new DocumentFragmentImpl( docPtr() );
567 CommentImpl
*DocumentImpl::createComment ( DOMStringImpl
* data
)
569 return new CommentImpl( docPtr(), data
);
572 CDATASectionImpl
*DocumentImpl::createCDATASection ( DOMStringImpl
* data
)
574 return new CDATASectionImpl( docPtr(), data
);
577 ProcessingInstructionImpl
*DocumentImpl::createProcessingInstruction ( const DOMString
&target
, DOMStringImpl
* data
)
579 return new ProcessingInstructionImpl( docPtr(),target
,data
);
582 EntityReferenceImpl
*DocumentImpl::createEntityReference ( const DOMString
&name
)
584 return new EntityReferenceImpl(docPtr(), name
.implementation());
587 EditingTextImpl
*DocumentImpl::createEditingTextNode(const DOMString
&text
)
589 return new EditingTextImpl(docPtr(), text
);
592 NodeImpl
*DocumentImpl::importNode(NodeImpl
*importedNode
, bool deep
, int &exceptioncode
)
594 NodeImpl
*result
= 0;
596 // Not mentioned in spec: throw NOT_FOUND_ERR if evt is null
598 exceptioncode
= DOMException::NOT_FOUND_ERR
;
602 if(importedNode
->nodeType() == Node::ELEMENT_NODE
)
604 // Why not use cloneNode?
605 ElementImpl
*otherElem
= static_cast<ElementImpl
*>(importedNode
);
606 NamedAttrMapImpl
*otherMap
= static_cast<ElementImpl
*>(importedNode
)->attributes(true);
608 ElementImpl
*tempElementImpl
;
609 if (!importedNode
->localName().isNull())
610 tempElementImpl
= createElementNS(otherElem
->namespaceURI(),otherElem
->nodeName());
612 tempElementImpl
= createElement(otherElem
->nodeName());
613 result
= tempElementImpl
;
617 for(unsigned long i
= 0; i
< otherMap
->length(); i
++)
619 AttrImpl
*otherAttr
= otherMap
->attrAt(i
)->createAttr(otherElem
,otherElem
->docPtr());
621 if (!otherAttr
->localName().isNull()) {
622 // attr was created via createElementNS()
623 tempElementImpl
->setAttributeNS(otherAttr
->namespaceURI(),
625 otherAttr
->nodeValue(),
629 // attr was created via createElement()
630 tempElementImpl
->setAttribute(otherAttr
->id(),
631 otherAttr
->nodeValue(),
636 if(exceptioncode
!= 0)
637 break; // ### properly cleanup here
641 else if(importedNode
->nodeType() == Node::TEXT_NODE
)
643 result
= createTextNode(static_cast<TextImpl
*>(importedNode
)->string());
646 else if(importedNode
->nodeType() == Node::CDATA_SECTION_NODE
)
648 result
= createCDATASection(static_cast<CDATASectionImpl
*>(importedNode
)->string());
651 else if(importedNode
->nodeType() == Node::ENTITY_REFERENCE_NODE
)
652 result
= createEntityReference(importedNode
->nodeName());
653 else if(importedNode
->nodeType() == Node::PROCESSING_INSTRUCTION_NODE
)
655 result
= createProcessingInstruction(importedNode
->nodeName(), importedNode
->nodeValue().implementation());
658 else if(importedNode
->nodeType() == Node::COMMENT_NODE
)
660 result
= createComment(static_cast<CommentImpl
*>(importedNode
)->string());
663 else if (importedNode
->nodeType() == Node::DOCUMENT_FRAGMENT_NODE
)
664 result
= createDocumentFragment();
666 exceptioncode
= DOMException::NOT_SUPPORTED_ERR
;
668 //### FIXME: This should handle Attributes, and a few other things
672 for(Node n
= importedNode
->firstChild(); !n
.isNull(); n
= n
.nextSibling())
673 result
->appendChild(importNode(n
.handle(), true, exceptioncode
), exceptioncode
);
679 ElementImpl
*DocumentImpl::createElementNS( const DOMString
&_namespaceURI
, const DOMString
&_qualifiedName
, int* pExceptioncode
)
683 // check NAMESPACE_ERR/INVALID_CHARACTER_ERR
684 if (pExceptioncode
&& !checkQualifiedName(_qualifiedName
, _namespaceURI
, &colonPos
,
685 false/*nameCanBeNull*/, false/*nameCanBeEmpty*/,
688 DOMString prefix
, localName
;
689 splitPrefixLocalName(_qualifiedName
.implementation(), prefix
, localName
, colonPos
);
691 if ((isHTMLDocument() && _namespaceURI
.isNull()) ||
692 (strcasecmp(_namespaceURI
, XHTML_NAMESPACE
) == 0 && localName
== localName
.lower())) {
693 e
= createHTMLElement(localName
);
695 int _exceptioncode
= 0;
696 if (!prefix
.isNull())
697 e
->setPrefix(prefix
, _exceptioncode
);
698 if ( _exceptioncode
) {
699 if ( pExceptioncode
) *pExceptioncode
= _exceptioncode
;
703 e
->setHTMLCompat( _namespaceURI
.isNull() && htmlMode() != XHtml
);
707 Id id
= getId(NodeImpl::ElementId
, _namespaceURI
.implementation(), prefix
.implementation(),
708 localName
.implementation(), false, false /*HTML already looked up*/);
709 e
= new XMLElementImpl( getDocument(), id
, prefix
.implementation() );
715 AttrImpl
*DocumentImpl::createAttributeNS( const DOMString
&_namespaceURI
,
716 const DOMString
&_qualifiedName
, int* pExceptioncode
)
719 // check NAMESPACE_ERR/INVALID_CHARACTER_ERR
720 if (pExceptioncode
&& !checkQualifiedName(_qualifiedName
, _namespaceURI
, &colonPos
,
721 false/*nameCanBeNull*/, false/*nameCanBeEmpty*/,
724 DOMString prefix
, localName
;
725 splitPrefixLocalName(_qualifiedName
.implementation(), prefix
, localName
, colonPos
);
726 Id id
= getId(NodeImpl::AttributeId
, _namespaceURI
.implementation(), prefix
.implementation(),
727 localName
.implementation(), false, true /*lookupHTML*/);
728 AttrImpl
* attr
= new AttrImpl(0, getDocument(), id
, DOMString("").implementation(),
729 prefix
.implementation());
730 attr
->setHTMLCompat( _namespaceURI
.isNull() && htmlMode() != XHtml
);
734 ElementImpl
*DocumentImpl::getElementById( const DOMString
&elementId
) const
736 QString stringKey
= elementId
.string();
738 ElementMappingCache::ItemInfo
* info
= m_getElementByIdCache
.get(stringKey
);
743 //See if cache has an unambiguous answer.
747 //Now we actually have to walk.
748 QStack
<NodeImpl
*> nodeStack
;
749 NodeImpl
*current
= _first
;
755 if(nodeStack
.isEmpty()) break;
756 current
= nodeStack
.pop();
757 current
= current
->nextSibling();
761 if(current
->isElementNode())
763 ElementImpl
*e
= static_cast<ElementImpl
*>(current
);
764 if(e
->getAttribute(ATTR_ID
) == elementId
) {
770 NodeImpl
*child
= current
->firstChild();
773 nodeStack
.push(current
);
778 current
= current
->nextSibling();
783 assert(0); //If there is no item with such an ID, we should never get here
785 //kDebug() << "WARNING: *DocumentImpl::getElementById not found " << elementId.string();
790 void DocumentImpl::setTitle(const DOMString
& _title
)
792 if (_title
== m_title
&& !m_title
.isNull()) return;
796 QString titleStr
= m_title
.string();
797 for (int i
= 0; i
< titleStr
.length(); ++i
)
798 if (titleStr
[i
] < ' ')
800 titleStr
= titleStr
.simplified();
801 if ( view() && !view()->part()->parentPart() ) {
802 if (titleStr
.isNull() || titleStr
.isEmpty()) {
803 // empty title... set window caption as the URL
805 url
.setRef(QString());
806 url
.setQuery(QString());
807 titleStr
= url
.prettyUrl();
810 emit
view()->part()->setWindowCaption( KStringHandler::csqueeze( titleStr
, 128 ) );
814 DOMString
DocumentImpl::nodeName() const
819 unsigned short DocumentImpl::nodeType() const
821 return Node::DOCUMENT_NODE
;
824 ElementImpl
*DocumentImpl::createHTMLElement( const DOMString
&name
)
826 uint id
= khtml::getTagID( name
.string().toLower().toLatin1().constData(), name
.string().length() );
832 n
= new HTMLHtmlElementImpl(docPtr());
835 n
= new HTMLHeadElementImpl(docPtr());
838 n
= new HTMLBodyElementImpl(docPtr());
843 n
= new HTMLBaseElementImpl(docPtr());
846 n
= new HTMLLinkElementImpl(docPtr());
849 n
= new HTMLMetaElementImpl(docPtr());
852 n
= new HTMLStyleElementImpl(docPtr());
855 n
= new HTMLTitleElementImpl(docPtr());
860 n
= new HTMLFrameElementImpl(docPtr());
863 n
= new HTMLFrameSetElementImpl(docPtr());
866 n
= new HTMLIFrameElementImpl(docPtr());
870 // ### FIXME: we need a way to set form dependency after we have made the form elements
872 n
= new HTMLFormElementImpl(docPtr(), false);
875 n
= new HTMLButtonElementImpl(docPtr());
878 n
= new HTMLFieldSetElementImpl(docPtr());
881 n
= new HTMLInputElementImpl(docPtr());
884 n
= new HTMLIsIndexElementImpl(docPtr());
887 n
= new HTMLLabelElementImpl(docPtr());
890 n
= new HTMLLegendElementImpl(docPtr());
893 n
= new HTMLOptGroupElementImpl(docPtr());
896 n
= new HTMLOptionElementImpl(docPtr());
899 n
= new HTMLSelectElementImpl(docPtr());
902 n
= new HTMLTextAreaElementImpl(docPtr());
907 n
= new HTMLDListElementImpl(docPtr());
910 n
= new HTMLGenericElementImpl(docPtr(), id
);
913 n
= new HTMLGenericElementImpl(docPtr(), id
);
916 n
= new HTMLUListElementImpl(docPtr());
919 n
= new HTMLOListElementImpl(docPtr());
922 n
= new HTMLDirectoryElementImpl(docPtr());
925 n
= new HTMLMenuElementImpl(docPtr());
928 n
= new HTMLLIElementImpl(docPtr());
931 // formatting elements (block)
934 n
= new HTMLDivElementImpl( docPtr(), id
);
943 n
= new HTMLGenericElementImpl(docPtr(), id
);
946 n
= new HTMLHRElementImpl(docPtr());
951 n
= new HTMLPreElementImpl(docPtr(), id
);
956 n
= new HTMLBaseFontElementImpl(docPtr());
959 n
= new HTMLFontElementImpl(docPtr());
965 n
= new HTMLGenericElementImpl(docPtr(), id
);
970 n
= new HTMLAnchorElementImpl(docPtr());
975 n
= new HTMLImageElementImpl(docPtr());
978 n
= new HTMLCanvasElementImpl(docPtr());
981 n
= new HTMLMapElementImpl(docPtr());
985 n
= new HTMLAreaElementImpl(docPtr());
988 // objects, applets and scripts
990 n
= new HTMLAppletElementImpl(docPtr());
993 n
= new HTMLObjectElementImpl(docPtr());
996 n
= new HTMLEmbedElementImpl(docPtr());
999 n
= new HTMLParamElementImpl(docPtr());
1002 n
= new HTMLScriptElementImpl(docPtr());
1007 n
= new HTMLAudioElement(docPtr());
1010 n
= new HTMLVideoElement(docPtr());
1013 n
= new HTMLSourceElement(docPtr());
1018 n
= new HTMLTableElementImpl(docPtr());
1021 n
= new HTMLTableCaptionElementImpl(docPtr());
1025 n
= new HTMLTableColElementImpl(docPtr(), id
);
1028 n
= new HTMLTableRowElementImpl(docPtr());
1032 n
= new HTMLTableCellElementImpl(docPtr(), id
);
1037 n
= new HTMLTableSectionElementImpl(docPtr(), id
, false);
1042 n
= new HTMLBRElementImpl(docPtr());
1045 n
= new HTMLWBRElementImpl(docPtr());
1048 n
= new HTMLGenericElementImpl(docPtr(), id
);
1051 // elements with no special representation in the DOM
1056 n
= new HTMLGenericElementImpl(docPtr(), id
);
1088 n
= new HTMLGenericElementImpl(docPtr(), id
);
1092 n
= new HTMLMarqueeElementImpl(docPtr());
1096 kDebug( 6020 ) << "Use document->createTextNode()";
1105 void DocumentImpl::attemptRestoreState(NodeImpl
* n
)
1107 if (!n
->isElementNode())
1110 ElementImpl
* el
= static_cast<ElementImpl
*>(n
);
1112 if (m_stateRestorePos
>= m_state
.size())
1115 // Grab the state and element info..
1116 QString idStr
= m_state
[m_stateRestorePos
];
1117 QString nmStr
= m_state
[m_stateRestorePos
+ 1];
1118 QString tpStr
= m_state
[m_stateRestorePos
+ 2];
1119 QString stStr
= m_state
[m_stateRestorePos
+ 3];
1121 // Make sure it matches!
1122 if (idStr
.toUInt() != el
->id())
1124 if (nmStr
!= el
->getAttribute(ATTR_NAME
).string())
1126 if (tpStr
!= el
->getAttribute(ATTR_TYPE
).string())
1129 m_stateRestorePos
+= 4;
1130 if (!stStr
.isNull())
1131 el
->restoreState(stStr
);
1134 QStringList
DocumentImpl::docState()
1137 for (QListIterator
<NodeImpl
*> it(m_maintainsState
); it
.hasNext();) {
1138 NodeImpl
* n
= it
.next();
1139 if (!n
->isElementNode())
1142 ElementImpl
* el
= static_cast<ElementImpl
*>(n
);
1143 // Encode the element ID, as well as the name and type attributes
1144 s
.append(QString::number(el
->id()));
1145 s
.append(el
->getAttribute(ATTR_NAME
).string());
1146 s
.append(el
->getAttribute(ATTR_TYPE
).string());
1147 s
.append(el
->state());
1153 bool DocumentImpl::unsubmittedFormChanges()
1155 for (QListIterator
<NodeImpl
*> it(m_maintainsState
); it
.hasNext();)
1156 if (it
.next()->state().endsWith('M'))
1162 RangeImpl
*DocumentImpl::createRange()
1164 return new RangeImpl( docPtr() );
1167 NodeIteratorImpl
*DocumentImpl::createNodeIterator(NodeImpl
*root
, unsigned long whatToShow
,
1168 NodeFilterImpl
* filter
, bool entityReferenceExpansion
,
1172 exceptioncode
= DOMException::NOT_SUPPORTED_ERR
;
1176 return new NodeIteratorImpl(root
,whatToShow
,filter
,entityReferenceExpansion
);
1179 TreeWalkerImpl
*DocumentImpl::createTreeWalker(NodeImpl
*root
, unsigned long whatToShow
, NodeFilterImpl
*filter
,
1180 bool entityReferenceExpansion
, int &exceptioncode
)
1183 exceptioncode
= DOMException::NOT_SUPPORTED_ERR
;
1187 return new TreeWalkerImpl( root
, whatToShow
, filter
, entityReferenceExpansion
);
1190 void DocumentImpl::setDocumentChanged(bool b
)
1192 if (b
&& !m_docChanged
)
1193 s_changedDocuments
->append(this);
1194 else if (!b
&& m_docChanged
)
1195 s_changedDocuments
->removeAll(this);
1199 void DocumentImpl::recalcStyle( StyleChange change
)
1201 // qDebug("recalcStyle(%p)", this);
1204 if (m_inStyleRecalc
)
1205 return; // Guard against re-entrancy. -dwh
1207 m_inStyleRecalc
= true;
1209 if( !m_render
) goto bail_out
;
1211 if ( change
== Force
) {
1212 RenderStyle
* oldStyle
= m_render
->style();
1213 if ( oldStyle
) oldStyle
->ref();
1214 RenderStyle
* _style
= new RenderStyle();
1215 _style
->setDisplay(BLOCK
);
1216 _style
->setVisuallyOrdered( visuallyOrdered
);
1217 // ### make the font stuff _really_ work!!!!
1219 khtml::FontDef fontDef
;
1220 QFont f
= KGlobalSettings::generalFont();
1221 fontDef
.family
= f
.family();
1222 fontDef
.italic
= f
.italic();
1223 fontDef
.weight
= f
.weight();
1225 const KHTMLSettings
*settings
= m_view
->part()->settings();
1226 QString stdfont
= settings
->stdFontName();
1227 if ( !stdfont
.isEmpty() )
1228 fontDef
.family
= stdfont
;
1230 fontDef
.size
= m_styleSelector
->fontSizes()[3];
1233 //kDebug() << "DocumentImpl::attach: setting to charset " << settings->charset();
1234 _style
->setFontDef(fontDef
);
1235 _style
->htmlFont().update( 0 );
1236 if ( inCompatMode() )
1237 _style
->setHtmlHacks(true); // enable html specific rendering tricks
1239 StyleChange ch
= diff( _style
, oldStyle
);
1240 if(m_render
&& ch
!= NoChange
)
1241 m_render
->setStyle(_style
);
1250 for (n
= _first
; n
; n
= n
->nextSibling())
1251 if ( change
>= Inherit
|| n
->hasChangedChild() || n
->changed() )
1252 n
->recalcStyle( change
);
1253 //kDebug( 6020 ) << "TIME: recalcStyle() dt=" << qt.elapsed();
1255 if (changed() && m_view
)
1259 setChanged( false );
1260 setHasChangedChild( false );
1261 setDocumentChanged( false );
1263 m_inStyleRecalc
= false;
1266 void DocumentImpl::updateRendering()
1268 if (!hasChangedChild()) return;
1272 // kDebug() << "UPDATERENDERING: ";
1274 StyleChange change
= NoChange
;
1276 if ( m_styleSelectorDirty
) {
1277 recalcStyleSelector();
1281 recalcStyle( change
);
1283 // kDebug() << "UPDATERENDERING time used="<<time.elapsed();
1286 void DocumentImpl::updateDocumentsRendering()
1288 if (!s_changedDocuments
)
1291 while ( !s_changedDocuments
->isEmpty() ) {
1292 DocumentImpl
* it
= s_changedDocuments
->takeFirst();
1293 if (it
->isDocumentChanged())
1294 it
->updateRendering();
1298 void DocumentImpl::updateLayout()
1300 if (ElementImpl
* oe
= ownerElement())
1301 oe
->getDocument()->updateLayout();
1303 bool oldIgnore
= m_ignorePendingStylesheets
;
1305 if (!haveStylesheetsLoaded()) {
1306 m_ignorePendingStylesheets
= true;
1307 updateStyleSelector();
1312 // Only do a layout if changes have occurred that make it necessary.
1313 if (m_view
&& renderer() && renderer()->needsLayout())
1316 m_ignorePendingStylesheets
= oldIgnore
;
1319 void DocumentImpl::attach()
1321 assert(!attached());
1324 setPaintDevice( m_view
);
1327 m_renderArena
.reset(new RenderArena());
1329 // Create the rendering tree
1330 assert(!m_styleSelector
);
1331 m_styleSelector
= new CSSStyleSelector( this, m_usersheet
, m_styleSheets
, m_url
,
1333 m_render
= new (m_renderArena
.get()) RenderCanvas(this, m_view
);
1334 m_styleSelector
->computeFontSizes(m_paintDevice
->logicalDpiY(), m_view
? m_view
->part()->fontScaleFactor() : 100);
1335 recalcStyle( Force
);
1337 RenderObject
* render
= m_render
;
1340 NodeBaseImpl::attach();
1344 void DocumentImpl::detach()
1346 RenderObject
* render
= m_render
;
1348 // indicate destruction mode, i.e. attached() but m_render == 0
1354 // Empty out these lists as a performance optimization
1355 m_imageLoadEventDispatchSoonList
.clear();
1356 m_imageLoadEventDispatchingList
.clear();
1357 NodeBaseImpl::detach();
1364 m_renderArena
.reset();
1367 void DocumentImpl::setVisuallyOrdered()
1369 visuallyOrdered
= true;
1371 m_render
->style()->setVisuallyOrdered(true);
1374 void DocumentImpl::setSelection(NodeImpl
* s
, int sp
, NodeImpl
* e
, int ep
)
1377 static_cast<RenderCanvas
*>(m_render
)->setSelection(s
->renderer(),sp
,e
->renderer(),ep
);
1380 void DocumentImpl::clearSelection()
1383 static_cast<RenderCanvas
*>(m_render
)->clearSelection();
1386 void DocumentImpl::updateSelection()
1391 RenderCanvas
*canvas
= static_cast<RenderCanvas
*>(m_render
);
1392 Selection s
= part()->caret();
1393 if (s
.isEmpty() || s
.state() == Selection::CARET
) {
1394 canvas
->clearSelection();
1397 RenderObject
*startRenderer
= s
.start().node() ? s
.start().node()->renderer() : 0;
1398 RenderObject
*endRenderer
= s
.end().node() ? s
.end().node()->renderer() : 0;
1399 static_cast<RenderCanvas
*>(m_render
)->setSelection(startRenderer
, s
.start().offset(), endRenderer
, s
.end().offset());
1403 khtml::Tokenizer
*DocumentImpl::createTokenizer()
1405 return new khtml::XMLTokenizer(docPtr(),m_view
);
1408 int DocumentImpl::logicalDpiY()
1410 return m_paintDevice
->logicalDpiY();
1413 void DocumentImpl::open( bool clearEventListeners
)
1415 if (parsing()) return;
1423 KHTMLView
* view
= m_view
;
1424 bool was_attached
= attached();
1429 delete m_styleSelector
;
1430 m_styleSelector
= 0;
1435 if (clearEventListeners
)
1436 m_windowEventListeners
.clear();
1438 m_tokenizer
= createTokenizer();
1439 //m_decoderMibEnum = 0;
1440 connect(m_tokenizer
,SIGNAL(finishedParsing()),this,SIGNAL(finishedParsing()));
1441 m_tokenizer
->begin();
1444 HTMLElementImpl
* DocumentImpl::body() const
1446 NodeImpl
*de
= documentElement();
1450 // try to prefer a FRAMESET element over BODY
1452 for (NodeImpl
* i
= de
->firstChild(); i
; i
= i
->nextSibling()) {
1453 if (i
->id() == ID_FRAMESET
)
1454 return static_cast<HTMLElementImpl
*>(i
);
1456 if (i
->id() == ID_BODY
)
1459 return static_cast<HTMLElementImpl
*>(body
);
1462 void DocumentImpl::close( )
1464 if (parsing() || !m_tokenizer
) return;
1469 // on an explicit document.close(), the tokenizer might still be waiting on scripts,
1470 // and in that case we don't want to destroy it because that will prevent the
1471 // scripts from getting processed.
1472 if (m_tokenizer
&& !m_tokenizer
->isWaitingForScripts() && !m_tokenizer
->isExecutingScript()) {
1478 m_view
->part()->checkEmitLoadEvent();
1481 void DocumentImpl::write( const DOMString
&text
)
1483 write(text
.string());
1486 void DocumentImpl::write( const QString
&text
)
1491 m_view
->part()->resetFromScript();
1492 m_tokenizer
->setAutoClose();
1493 write(QLatin1String("<html>"));
1495 m_tokenizer
->write(text
, false);
1498 void DocumentImpl::writeln( const DOMString
&text
)
1501 write(DOMString("\n"));
1504 void DocumentImpl::finishParsing ( )
1507 m_tokenizer
->finish();
1510 void DocumentImpl::setUserStyleSheet( const QString
& sheet
)
1512 if ( m_usersheet
!= sheet
) {
1513 m_usersheet
= sheet
;
1514 updateStyleSelector();
1518 CSSStyleSheetImpl
* DocumentImpl::elementSheet()
1521 m_elemSheet
= new CSSStyleSheetImpl(this, baseURL().url() );
1527 void DocumentImpl::determineParseMode()
1529 // For XML documents, use strict parse mode
1532 kDebug(6020) << " using strict parseMode";
1535 NodeImpl
*DocumentImpl::nextFocusNode(NodeImpl
*fromNode
)
1540 // No starting node supplied; begin with the top of the document
1543 int lowestTabIndex
= SHRT_MAX
+ 1;
1544 for (n
= this; n
!= 0; n
= n
->traverseNextNode()) {
1545 if (n
->isTabFocusable()) {
1546 if ((n
->tabIndex() > 0) && (n
->tabIndex() < lowestTabIndex
))
1547 lowestTabIndex
= n
->tabIndex();
1551 if (lowestTabIndex
== SHRT_MAX
+ 1)
1554 // Go to the first node in the document that has the desired tab index
1555 for (n
= this; n
!= 0; n
= n
->traverseNextNode()) {
1556 if (n
->isTabFocusable() && (n
->tabIndex() == lowestTabIndex
))
1563 fromTabIndex
= fromNode
->tabIndex();
1566 if (fromTabIndex
== 0) {
1567 // Just need to find the next selectable node after fromNode (in document order) that doesn't have a tab index
1568 NodeImpl
*n
= fromNode
->traverseNextNode();
1569 while (n
&& !(n
->isTabFocusable() && n
->tabIndex() == 0))
1570 n
= n
->traverseNextNode();
1574 // Find the lowest tab index out of all the nodes except fromNode, that is greater than or equal to fromNode's
1575 // tab index. For nodes with the same tab index as fromNode, we are only interested in those that come after
1576 // fromNode in document order.
1577 // If we don't find a suitable tab index, the next focus node will be one with a tab index of 0.
1578 int lowestSuitableTabIndex
= SHRT_MAX
+ 1;
1581 bool reachedFromNode
= false;
1582 for (n
= this; n
!= 0; n
= n
->traverseNextNode()) {
1583 if (n
->isTabFocusable() &&
1584 ((reachedFromNode
&& (n
->tabIndex() >= fromTabIndex
)) ||
1585 (!reachedFromNode
&& (n
->tabIndex() > fromTabIndex
))) &&
1586 (n
->tabIndex() < lowestSuitableTabIndex
) &&
1589 // We found a selectable node with a tab index at least as high as fromNode's. Keep searching though,
1590 // as there may be another node which has a lower tab index but is still suitable for use.
1591 lowestSuitableTabIndex
= n
->tabIndex();
1595 reachedFromNode
= true;
1598 if (lowestSuitableTabIndex
== SHRT_MAX
+ 1) {
1599 // No next node with a tab index -> just take first node with tab index of 0
1601 while (n
&& !(n
->isTabFocusable() && n
->tabIndex() == 0))
1602 n
= n
->traverseNextNode();
1606 // Search forwards from fromNode
1607 for (n
= fromNode
->traverseNextNode(); n
!= 0; n
= n
->traverseNextNode()) {
1608 if (n
->isTabFocusable() && (n
->tabIndex() == lowestSuitableTabIndex
))
1612 // The next node isn't after fromNode, start from the beginning of the document
1613 for (n
= this; n
!= fromNode
; n
= n
->traverseNextNode()) {
1614 if (n
->isTabFocusable() && (n
->tabIndex() == lowestSuitableTabIndex
))
1618 assert(false); // should never get here
1623 NodeImpl
*DocumentImpl::previousFocusNode(NodeImpl
*fromNode
)
1625 NodeImpl
*lastNode
= this;
1626 while (lastNode
->lastChild())
1627 lastNode
= lastNode
->lastChild();
1630 // No starting node supplied; begin with the very last node in the document
1633 int highestTabIndex
= 0;
1634 for (n
= lastNode
; n
!= 0; n
= n
->traversePreviousNode()) {
1635 if (n
->isTabFocusable()) {
1636 if (n
->tabIndex() == 0)
1638 else if (n
->tabIndex() > highestTabIndex
)
1639 highestTabIndex
= n
->tabIndex();
1643 // No node with a tab index of 0; just go to the last node with the highest tab index
1644 for (n
= lastNode
; n
!= 0; n
= n
->traversePreviousNode()) {
1645 if (n
->isTabFocusable() && (n
->tabIndex() == highestTabIndex
))
1652 short fromTabIndex
= fromNode
->tabIndex();
1654 if (fromTabIndex
== 0) {
1655 // Find the previous selectable node before fromNode (in document order) that doesn't have a tab index
1656 NodeImpl
*n
= fromNode
->traversePreviousNode();
1657 while (n
&& !(n
->isTabFocusable() && n
->tabIndex() == 0))
1658 n
= n
->traversePreviousNode();
1662 // No previous nodes with a 0 tab index, go to the last node in the document that has the highest tab index
1663 int highestTabIndex
= 0;
1664 for (n
= this; n
!= 0; n
= n
->traverseNextNode()) {
1665 if (n
->isTabFocusable() && (n
->tabIndex() > highestTabIndex
))
1666 highestTabIndex
= n
->tabIndex();
1669 if (highestTabIndex
== 0)
1672 for (n
= lastNode
; n
!= 0; n
= n
->traversePreviousNode()) {
1673 if (n
->isTabFocusable() && (n
->tabIndex() == highestTabIndex
))
1677 assert(false); // should never get here
1681 // Find the lowest tab index out of all the nodes except fromNode, that is less than or equal to fromNode's
1682 // tab index. For nodes with the same tab index as fromNode, we are only interested in those before
1684 // If we don't find a suitable tab index, then there will be no previous focus node.
1685 short highestSuitableTabIndex
= 0;
1688 bool reachedFromNode
= false;
1689 for (n
= this; n
!= 0; n
= n
->traverseNextNode()) {
1690 if (n
->isTabFocusable() &&
1691 ((!reachedFromNode
&& (n
->tabIndex() <= fromTabIndex
)) ||
1692 (reachedFromNode
&& (n
->tabIndex() < fromTabIndex
))) &&
1693 (n
->tabIndex() > highestSuitableTabIndex
) &&
1696 // We found a selectable node with a tab index no higher than fromNode's. Keep searching though, as
1697 // there may be another node which has a higher tab index but is still suitable for use.
1698 highestSuitableTabIndex
= n
->tabIndex();
1702 reachedFromNode
= true;
1705 if (highestSuitableTabIndex
== 0) {
1706 // No previous node with a tab index. Since the order specified by HTML is nodes with tab index > 0
1707 // first, this means that there is no previous node.
1711 // Search backwards from fromNode
1712 for (n
= fromNode
->traversePreviousNode(); n
!= 0; n
= n
->traversePreviousNode()) {
1713 if (n
->isTabFocusable() && (n
->tabIndex() == highestSuitableTabIndex
))
1716 // The previous node isn't before fromNode, start from the end of the document
1717 for (n
= lastNode
; n
!= fromNode
; n
= n
->traversePreviousNode()) {
1718 if (n
->isTabFocusable() && (n
->tabIndex() == highestSuitableTabIndex
))
1722 assert(false); // should never get here
1728 ElementImpl
* DocumentImpl::findAccessKeyElement(QChar c
)
1731 for( NodeImpl
* n
= this;
1733 n
= n
->traverseNextNode()) {
1734 if( n
->isElementNode()) {
1735 ElementImpl
* en
= static_cast< ElementImpl
* >( n
);
1736 DOMString s
= en
->getAttribute( ATTR_ACCESSKEY
);
1738 && s
[ 0 ].toUpper() == c
)
1745 int DocumentImpl::nodeAbsIndex(NodeImpl
*node
)
1747 assert(node
->getDocument() == this);
1750 for (NodeImpl
*n
= node
; n
&& n
!= this; n
= n
->traversePreviousNode())
1755 NodeImpl
*DocumentImpl::nodeWithAbsIndex(int absIndex
)
1758 for (int i
= 0; n
&& (i
< absIndex
); i
++) {
1759 n
= n
->traverseNextNode();
1764 void DocumentImpl::processHttpEquiv(const DOMString
&equiv
, const DOMString
&content
)
1766 assert(!equiv
.isNull() && !content
.isNull());
1768 KHTMLView
*v
= getDocument()->view();
1770 if(strcasecmp(equiv
, "refresh") == 0 && v
&& v
->part()->metaRefreshEnabled())
1772 // get delay and url
1773 QString str
= content
.string().trimmed();
1774 int pos
= str
.indexOf(QRegExp("[;,]"));
1776 pos
= str
.indexOf(QRegExp("[ \t]"));
1779 int delay
= qMax( 0, content
.implementation()->toInt(&ok
) );
1780 if ( !ok
&& str
.length() && str
[0] == '.' )
1783 if (pos
== -1) // There can be no url (David)
1786 v
->part()->scheduleRedirection(delay
, v
->part()->url().url() );
1789 while(pos
< (int)str
.length() && str
[pos
].isSpace()) pos
++;
1791 if(str
.indexOf("url", 0, Qt::CaseInsensitive
) == 0) str
= str
.mid(3);
1792 str
= str
.trimmed();
1793 if ( str
.length() && str
[0] == '=' ) str
= str
.mid( 1 ).trimmed();
1794 while(str
.length() &&
1795 (str
[str
.length()-1] == ';' || str
[str
.length()-1] == ','))
1796 str
.resize(str
.length()-1);
1797 str
= parseURL( DOMString(str
) ).string();
1798 QString newURL
= getDocument()->completeURL( str
);
1800 v
->part()->scheduleRedirection(delay
, getDocument()->completeURL( str
), delay
< 2 || newURL
== URL().url());
1803 else if(strcasecmp(equiv
, "expires") == 0)
1805 bool relative
= false;
1806 QString str
= content
.string().trimmed();
1807 time_t expire_date
= KDateTime::fromString(str
, KDateTime::RFCDate
).toTime_t();
1810 expire_date
= str
.toULong();
1814 expire_date
= 1; // expire now
1816 m_docLoader
->setExpireDate(expire_date
, relative
);
1818 else if(v
&& (strcasecmp(equiv
, "pragma") == 0 || strcasecmp(equiv
, "cache-control") == 0))
1820 QString str
= content
.string().toLower().trimmed();
1821 KUrl url
= v
->part()->url();
1822 if ((str
== "no-cache") && url
.protocol().startsWith("http"))
1824 KIO::http_update_cache(url
, true, 0);
1827 else if( (strcasecmp(equiv
, "set-cookie") == 0))
1829 // ### make setCookie work on XML documents too; e.g. in case of <html:meta .....>
1830 HTMLDocumentImpl
*d
= static_cast<HTMLDocumentImpl
*>(this);
1831 d
->setCookie(content
);
1833 else if (strcasecmp(equiv
, "default-style") == 0) {
1835 // http://www.hixie.ch/tests/evil/css/import/main/preferred.html
1836 m_preferredStylesheetSet
= content
;
1837 updateStyleSelector();
1839 else if (strcasecmp(equiv
, "content-language") == 0) {
1840 m_contentLanguage
= content
.string();
1844 bool DocumentImpl::prepareMouseEvent( bool readonly
, int _x
, int _y
, MouseEvent
*ev
)
1847 assert(m_render
->isCanvas());
1848 RenderObject::NodeInfo
renderInfo(readonly
, ev
->type
== MousePress
);
1849 bool isInside
= m_render
->layer()->nodeAtPoint(renderInfo
, _x
, _y
);
1850 ev
->innerNode
= renderInfo
.innerNode();
1851 ev
->innerNonSharedNode
= renderInfo
.innerNonSharedNode();
1853 if (renderInfo
.URLElement()) {
1854 assert(renderInfo
.URLElement()->isElementNode());
1855 //qDebug("urlnode: %s (%d)", getTagName(renderInfo.URLElement()->id()).string().toLatin1().constData(), renderInfo.URLElement()->id());
1857 ElementImpl
* e
= static_cast<ElementImpl
*>(renderInfo
.URLElement());
1858 DOMString href
= khtml::parseURL(e
->getAttribute(ATTR_HREF
));
1859 DOMString target
= e
->getAttribute(ATTR_TARGET
);
1861 if (!target
.isNull() && !href
.isNull()) {
1862 ev
->target
= target
;
1880 // DOM Section 1.1.1
1881 bool DocumentImpl::childTypeAllowed( unsigned short type
)
1884 case Node::ATTRIBUTE_NODE
:
1885 case Node::CDATA_SECTION_NODE
:
1886 case Node::DOCUMENT_FRAGMENT_NODE
:
1887 case Node::DOCUMENT_NODE
:
1888 case Node::ENTITY_NODE
:
1889 case Node::ENTITY_REFERENCE_NODE
:
1890 case Node::NOTATION_NODE
:
1891 case Node::TEXT_NODE
:
1892 // case Node::XPATH_NAMESPACE_NODE:
1894 case Node::COMMENT_NODE
:
1895 case Node::PROCESSING_INSTRUCTION_NODE
:
1897 case Node::DOCUMENT_TYPE_NODE
:
1898 case Node::ELEMENT_NODE
:
1899 // Documents may contain no more than one of each of these.
1900 // (One Element and one DocumentType.)
1901 for (NodeImpl
* c
= firstChild(); c
; c
= c
->nextSibling())
1902 if (c
->nodeType() == type
)
1909 NodeImpl
*DocumentImpl::cloneNode ( bool deep
)
1912 NodeImpl
*dtn
= m_doctype
->cloneNode(deep
);
1913 DocumentTypeImpl
*dt
= static_cast<DocumentTypeImpl
*>(dtn
);
1917 DocumentImpl
*clone
= m_implementation
->createDocument("",
1920 assert( exceptioncode
== 0 );
1922 // ### attributes, styles, ...
1925 cloneChildNodes(clone
);
1930 typedef const char* (*NameLookupFunction
)(unsigned short id
);
1931 typedef int (*IdLookupFunction
)(const char *tagStr
, int len
);
1933 NodeImpl::Id
DocumentImpl::getId( NodeImpl::IdType _type
, DOMStringImpl
* _nsURI
, DOMStringImpl
*_prefix
,
1934 DOMStringImpl
*_name
, bool readonly
, bool /*lookupHTML*/, int *pExceptioncode
)
1936 /*kDebug() << "DocumentImpl::getId( type: " << _type << ", uri: " << DOMString(_nsURI).string()
1937 << ", prefix: " << DOMString(_prefix).string() << ", name: " << DOMString(_name).string()
1938 << ", readonly: " << readonly
1939 << ", lookupHTML: " << lookupHTML
1940 << ", exceptions: " << (pExceptioncode ? "yes" : "no")
1943 if(!_name
) return 0;
1945 IdLookupFunction lookup
;
1948 case NodeImpl::ElementId
:
1952 case NodeImpl::AttributeId
:
1956 case NodeImpl::NamespaceId
:
1957 if( strcasecmp(_name
, XHTML_NAMESPACE
) == 0)
1958 return xhtmlNamespace
;
1960 return emptyNamespace
;
1961 // defaultNamespace handled by "if (!_name) return 0"
1962 map
= m_namespaceMap
;
1968 // Names and attributes with ""
1969 if (_name
->l
== 0) return 0;
1971 NodeImpl::Id id
, nsid
;
1973 const QString n
= QString::fromRawData(_name
->s
, _name
->l
);
1974 bool cs
= true; // case sensitive
1975 if (_type
!= NodeImpl::NamespaceId
) {
1977 nsid
= getId( NodeImpl::NamespaceId
, 0, 0, _nsURI
, false, false, 0 );
1979 // for attributes empty and default namespaces are the same
1980 if (_type
== NodeImpl::AttributeId
&& nsid
== emptyNamespace
)
1981 nsid
= defaultNamespace
;
1983 // Each document maintains a mapping of tag name -> id for every tag name encountered
1985 cs
= (htmlMode() == XHtml
) || (_nsURI
&& _type
!= NodeImpl::AttributeId
);
1987 // First see if it's a HTML element name
1988 // xhtml is lower case - case sensitive, easy to implement
1989 if ( cs
&& (id
= lookup(n
.toAscii().constData(), _name
->l
)) ) {
1990 map
->addAlias(_prefix
, _name
, cs
, id
);
1991 return makeId(nsid
, id
);
1993 // compatibility: upper case - case insensitive
1994 if ( !cs
&& (id
= lookup(n
.toLower().toAscii().constData(), _name
->l
)) ) {
1995 map
->addAlias(_prefix
, _name
, cs
, id
);
1996 return makeId(nsid
, id
);
2000 // Look in the names array for the name
2001 // compatibility mode has to lookup upper case
2002 QString name
= cs
? n
: n
.toUpper();
2005 id
= (NodeImpl::Id
)(long)map
->ids
.value( name
);
2006 if (!id
&& _type
!= NodeImpl::NamespaceId
) {
2007 id
= (NodeImpl::Id
)(long)map
->ids
.value( "aliases: " + name
);
2010 id
= (NodeImpl::Id
)(long)map
->ids
.value( name
);
2011 if (!readonly
&& id
&& _prefix
&& _prefix
->l
) {
2012 // we were called in registration mode... check if the alias exists
2013 const QString px
= QString::fromRawData( _prefix
->s
, _prefix
->l
);
2014 QString
qn("aliases: " + (cs
? px
: px
.toUpper()) + ":" + name
);
2015 if (!map
->ids
.contains( qn
)) {
2016 map
->ids
.insert( qn
, (void*)id
);
2021 if (id
) return makeId(nsid
, id
);
2024 if (readonly
) return 0;
2026 if ( pExceptioncode
&& _type
!= NodeImpl::NamespaceId
&& !Element::khtmlValidQualifiedName(_name
)) {
2027 *pExceptioncode
= DOMException::INVALID_CHARACTER_ERR
;
2031 // Name not found, so let's add it
2032 NodeImpl::Id cid
= map
->count
++ + map
->idStart
;
2033 map
->names
.insert( cid
, _name
);
2036 map
->ids
.insert( name
, (void*)cid
);
2038 // and register an alias if needed for DOM1 methods compatibility
2039 map
->addAlias(_prefix
, _name
, cs
, cid
);
2041 return makeId(nsid
, cid
);
2044 NodeImpl::Id
DocumentImpl::getId( NodeImpl::IdType _type
, DOMStringImpl
*_nodeName
, bool readonly
, bool lookupHTML
, int *pExceptioncode
)
2046 return getId(_type
, 0, 0, _nodeName
, readonly
, lookupHTML
, pExceptioncode
);
2049 DOMString
DocumentImpl::getName( NodeImpl::IdType _type
, NodeImpl::Id _id
) const
2052 NameLookupFunction lookup
;
2053 bool hasNS
= (namespacePart(_id
) != defaultNamespace
);
2055 case NodeImpl::ElementId
:
2057 lookup
= getTagName
;
2059 case NodeImpl::AttributeId
:
2061 lookup
= getAttrName
;
2063 case NodeImpl::NamespaceId
:
2064 if( _id
== xhtmlNamespace
)
2065 return XHTML_NAMESPACE
;
2067 if( _id
== emptyNamespace
)
2068 return DOMString("");
2070 if ( _id
== defaultNamespace
)
2072 map
= m_namespaceMap
;
2076 return DOMString();;
2078 _id
= localNamePart(_id
) ;
2079 if (_id
>= map
->idStart
) {
2080 return map
->names
[_id
];
2083 // ### put them in a cache
2085 return DOMString(lookup(_id
)).lower();
2092 // This method is called whenever a top-level stylesheet has finished loading.
2093 void DocumentImpl::styleSheetLoaded()
2095 // Make sure we knew this sheet was pending, and that our count isn't out of sync.
2096 assert(m_pendingStylesheets
> 0);
2098 m_pendingStylesheets
--;
2099 updateStyleSelector();
2102 void DocumentImpl::addPendingSheet()
2104 m_pendingStylesheets
++;
2107 DOMString
DocumentImpl::selectedStylesheetSet() const
2109 if (!view()) return DOMString();
2111 return view()->part()->d
->m_sheetUsed
;
2114 void DocumentImpl::setSelectedStylesheetSet(const DOMString
& s
)
2116 // this code is evil
2117 if (view() && view()->part()->d
->m_sheetUsed
!= s
.string()) {
2118 view()->part()->d
->m_sheetUsed
= s
.string();
2119 updateStyleSelector();
2123 void DocumentImpl::addStyleSheet(StyleSheetImpl
*sheet
, int *exceptioncode
)
2127 if (!m_addedStyleSheets
) {
2128 m_addedStyleSheets
= new StyleSheetListImpl
;
2129 m_addedStyleSheets
->ref();
2132 m_addedStyleSheets
->add(sheet
);
2133 if (sheet
->isCSSStyleSheet()) updateStyleSelector();
2135 if (exceptioncode
) *exceptioncode
= excode
;
2138 void DocumentImpl::removeStyleSheet(StyleSheetImpl
*sheet
, int *exceptioncode
)
2141 bool removed
= false;
2142 bool is_css
= sheet
->isCSSStyleSheet();
2144 if (m_addedStyleSheets
) {
2145 bool in_main_list
= !sheet
->hasOneRef();
2146 removed
= m_addedStyleSheets
->styleSheets
.removeAll(sheet
);
2149 if (m_addedStyleSheets
->styleSheets
.count() == 0) {
2150 bool reset
= m_addedStyleSheets
->hasOneRef();
2151 m_addedStyleSheets
->deref();
2152 if (reset
) m_addedStyleSheets
= 0;
2155 // remove from main list, too
2156 if (in_main_list
) m_styleSheets
->remove(sheet
);
2160 if (is_css
) updateStyleSelector();
2162 excode
= DOMException::NOT_FOUND_ERR
;
2164 if (exceptioncode
) *exceptioncode
= excode
;
2167 void DocumentImpl::updateStyleSelector(bool shallow
)
2169 // kDebug() << "PENDING " << m_pendingStylesheets;
2171 // Don't bother updating, since we haven't loaded all our style info yet.
2172 if (m_pendingStylesheets
> 0)
2176 rebuildStyleSelector();
2178 recalcStyleSelector();
2182 m_styleSelectorDirty
= true;
2185 renderer()->setNeedsLayoutAndMinMaxRecalc();
2188 bool DocumentImpl::readyForLayout() const
2190 return renderer() && haveStylesheetsLoaded() && (!isHTMLDocument() || (body() && body()->renderer()));
2193 void DocumentImpl::recalcStyleSelector()
2195 if ( !m_render
|| !attached() ) return;
2197 assert(m_pendingStylesheets
==0);
2199 QList
<StyleSheetImpl
*> oldStyleSheets
= m_styleSheets
->styleSheets
;
2200 m_styleSheets
->styleSheets
.clear();
2201 QString sheetUsed
= view() ? view()->part()->d
->m_sheetUsed
.replace("&&", "&") : QString();
2202 bool autoselect
= sheetUsed
.isEmpty();
2203 if (autoselect
&& !m_preferredStylesheetSet
.isEmpty())
2204 sheetUsed
= m_preferredStylesheetSet
.string();
2206 for (int i
=0 ; i
<2 ; i
++) {
2207 m_availableSheets
.clear();
2208 m_availableSheets
<< i18n("Basic Page Style");
2209 bool canResetSheet
= false;
2211 for (n
= this; n
; n
= n
->traverseNextNode()) {
2212 StyleSheetImpl
*sheet
= 0;
2214 if (n
->nodeType() == Node::PROCESSING_INSTRUCTION_NODE
)
2216 // Processing instruction (XML documents only)
2217 ProcessingInstructionImpl
* pi
= static_cast<ProcessingInstructionImpl
*>(n
);
2218 sheet
= pi
->sheet();
2219 if (!sheet
&& !pi
->localHref().isEmpty())
2221 // Processing instruction with reference to an element in this document - e.g.
2222 // <?xml-stylesheet href="#mystyle">, with the element
2223 // <foo id="mystyle">heading { color: red; }</foo> at some location in
2225 ElementImpl
* elem
= getElementById(pi
->localHref());
2227 DOMString
sheetText("");
2229 for (c
= elem
->firstChild(); c
; c
= c
->nextSibling()) {
2230 if (c
->nodeType() == Node::TEXT_NODE
|| c
->nodeType() == Node::CDATA_SECTION_NODE
)
2231 sheetText
+= c
->nodeValue();
2234 CSSStyleSheetImpl
*cssSheet
= new CSSStyleSheetImpl(this);
2235 cssSheet
->parseString(sheetText
);
2236 pi
->setStyleSheet(cssSheet
);
2242 else if (n
->isHTMLElement() && ( n
->id() == ID_LINK
|| n
->id() == ID_STYLE
) ) {
2244 if ( n
->id() == ID_LINK
) {
2245 HTMLLinkElementImpl
* l
= static_cast<HTMLLinkElementImpl
*>(n
);
2246 if (l
->isCSSStyleSheet()) {
2249 if (sheet
|| l
->isLoading() || l
->isAlternate() )
2250 title
= l
->getAttribute(ATTR_TITLE
).string();
2252 if ((autoselect
|| title
!= sheetUsed
) && l
->isDisabled()) {
2254 } else if (!title
.isEmpty() && !l
->isAlternate() && sheetUsed
.isEmpty()) {
2256 l
->setDisabled(false);
2262 HTMLStyleElementImpl
* s
= static_cast<HTMLStyleElementImpl
*>(n
);
2263 if (!s
->isLoading()) {
2265 if (sheet
) title
= s
->getAttribute(ATTR_TITLE
).string();
2267 if (!title
.isEmpty() && sheetUsed
.isEmpty())
2271 if ( !title
.isEmpty() ) {
2272 if ( title
!= sheetUsed
)
2273 sheet
= 0; // don't use it
2275 title
= title
.replace('&', "&&");
2277 if ( !m_availableSheets
.contains( title
) )
2278 m_availableSheets
.append( title
);
2281 else if (n
->isHTMLElement() && n
->id() == ID_BODY
) {
2282 // <BODY> element (doesn't contain styles as such but vlink="..." and friends
2283 // are treated as style declarations)
2284 sheet
= static_cast<HTMLBodyElementImpl
*>(n
)->sheet();
2289 m_styleSheets
->styleSheets
.append(sheet
);
2292 // For HTML documents, stylesheets are not allowed within/after the <BODY> tag. So we
2293 // can stop searching here.
2294 if (isHTMLDocument() && n
->id() == ID_BODY
) {
2295 canResetSheet
= !canResetSheet
;
2300 // we're done if we don't select an alternative sheet
2301 // or we found the sheet we selected
2302 if (sheetUsed
.isEmpty() ||
2303 (!canResetSheet
&& tokenizer()) ||
2304 m_availableSheets
.contains(sheetUsed
)) {
2308 // the alternative sheet we used doesn't exist anymore
2309 // so try from scratch again
2311 view()->part()->d
->m_sheetUsed
.clear();
2312 if (!m_preferredStylesheetSet
.isEmpty() && !(sheetUsed
== m_preferredStylesheetSet
))
2313 sheetUsed
= m_preferredStylesheetSet
.string();
2319 // Include programmatically added style sheets
2320 if (m_addedStyleSheets
) {
2321 foreach (StyleSheetImpl
* sh
, m_addedStyleSheets
->styleSheets
) {
2322 if (sh
->isCSSStyleSheet() && !sh
->disabled())
2323 m_styleSheets
->add(sh
);
2327 // De-reference all the stylesheets in the old list
2328 foreach ( StyleSheetImpl
* sh
, oldStyleSheets
)
2331 rebuildStyleSelector();
2334 void DocumentImpl::rebuildStyleSelector()
2336 // Create a new style selector
2337 delete m_styleSelector
;
2338 QString usersheet
= m_usersheet
;
2339 if ( m_view
&& m_view
->mediaType() == "print" )
2340 usersheet
+= m_printSheet
;
2341 m_styleSelector
= new CSSStyleSelector( this, usersheet
, m_styleSheets
, m_url
,
2344 m_styleSelectorDirty
= false;
2347 void DocumentImpl::setBaseURL(const KUrl
& _baseURL
)
2349 m_baseURL
= _baseURL
;
2351 m_elemSheet
->setHref( baseURL().url() );
2354 void DocumentImpl::setHoverNode(NodeImpl
*newHoverNode
)
2356 NodeImpl
* oldHoverNode
= m_hoverNode
;
2357 if (newHoverNode
) newHoverNode
->ref();
2358 m_hoverNode
= newHoverNode
;
2359 if ( oldHoverNode
) oldHoverNode
->deref();
2362 void DocumentImpl::setActiveNode(NodeImpl
* newActiveNode
)
2364 NodeImpl
* oldActiveNode
= m_activeNode
;
2365 if (newActiveNode
) newActiveNode
->ref();
2366 m_activeNode
= newActiveNode
;
2367 if ( oldActiveNode
) oldActiveNode
->deref();
2370 void DocumentImpl::quietResetFocus()
2372 assert(m_focusNode
!= this);
2374 if (m_focusNode
->active())
2377 m_focusNode
->setFocus(false);
2378 m_focusNode
->deref();
2382 //We're blurring. Better clear the Qt focus/give it to the view...
2387 void DocumentImpl::setFocusNode(NodeImpl
*newFocusNode
)
2389 // don't process focus changes while detaching
2390 if( !m_render
) return;
2392 // Make sure newFocusNode is actually in this document
2393 if (newFocusNode
&& (newFocusNode
->getDocument() != this))
2396 if (m_focusNode
!= newFocusNode
) {
2397 NodeImpl
*oldFocusNode
= m_focusNode
;
2398 // Set focus on the new node
2399 m_focusNode
= newFocusNode
;
2400 // Remove focus from the existing focus node (if any)
2402 if (oldFocusNode
->active())
2403 oldFocusNode
->setActive(false);
2405 oldFocusNode
->setFocus(false);
2407 oldFocusNode
->dispatchHTMLEvent(EventImpl::BLUR_EVENT
,false,false);
2408 oldFocusNode
->dispatchUIEvent(EventImpl::DOMFOCUSOUT_EVENT
);
2410 if ((oldFocusNode
== this) && oldFocusNode
->hasOneRef()) {
2411 oldFocusNode
->deref(); // deletes this
2415 oldFocusNode
->deref();
2421 m_focusNode
->dispatchHTMLEvent(EventImpl::FOCUS_EVENT
,false,false);
2422 if (m_focusNode
!= newFocusNode
) return;
2423 m_focusNode
->dispatchUIEvent(EventImpl::DOMFOCUSIN_EVENT
);
2424 if (m_focusNode
!= newFocusNode
) return;
2425 m_focusNode
->setFocus();
2426 if (m_focusNode
!= newFocusNode
) return;
2428 // eww, I suck. set the qt focus correctly
2429 // ### find a better place in the code for this
2431 if (!m_focusNode
->renderer() || !m_focusNode
->renderer()->isWidget())
2433 else if (static_cast<RenderWidget
*>(m_focusNode
->renderer())->widget())
2435 if (view()->isVisible())
2436 static_cast<RenderWidget
*>(m_focusNode
->renderer())->widget()->setFocus();
2440 //We're blurring. Better clear the Qt focus/give it to the view...
2449 void DocumentImpl::setCSSTarget(NodeImpl
* n
)
2451 if (n
== m_cssTarget
)
2455 m_cssTarget
->setChanged();
2456 m_cssTarget
->deref();
2465 void DocumentImpl::attachNodeIterator(NodeIteratorImpl
*ni
)
2467 m_nodeIterators
.append(ni
);
2470 void DocumentImpl::detachNodeIterator(NodeIteratorImpl
*ni
)
2472 int i
= m_nodeIterators
.indexOf(ni
);
2474 m_nodeIterators
.removeAt(i
);
2477 void DocumentImpl::notifyBeforeNodeRemoval(NodeImpl
*n
)
2479 QListIterator
<NodeIteratorImpl
*> it(m_nodeIterators
);
2480 while (it
.hasNext())
2481 it
.next()->notifyBeforeNodeRemoval(n
);
2484 bool DocumentImpl::isURLAllowed(const QString
& url
) const
2486 KHTMLPart
*thisPart
= part();
2488 KUrl
newURL(completeURL(url
));
2489 newURL
.setRef(QString());
2491 if (KHTMLGlobal::defaultHTMLSettings()->isAdFiltered( newURL
.url() ))
2494 // Prohibit non-file URLs if we are asked to.
2495 if (!thisPart
|| thisPart
->onlyLocalReferences() && newURL
.protocol() != "file" && newURL
.protocol() != "data")
2498 // do we allow this suburl ?
2499 if ( !kapp
|| (newURL
.protocol() != "javascript" && !KAuthorized::authorizeUrlAction("redirect", thisPart
->url(), newURL
)) )
2502 // We allow one level of self-reference because some sites depend on that.
2503 // But we don't allow more than one.
2504 bool foundSelfReference
= false;
2505 for (KHTMLPart
*part
= thisPart
; part
; part
= part
->parentPart()) {
2506 KUrl partURL
= part
->url();
2507 partURL
.setRef(QString());
2508 if (partURL
== newURL
) {
2509 if (foundSelfReference
)
2511 foundSelfReference
= true;
2518 void DocumentImpl::setDesignMode(bool b
)
2521 part()->setEditable(b
);
2524 bool DocumentImpl::designMode() const
2526 return part() ? part()->isEditable() : false;
2529 EventImpl
*DocumentImpl::createEvent(const DOMString
&eventType
, int &exceptioncode
)
2531 if (eventType
== "UIEvents" || eventType
== "UIEvent")
2532 return new UIEventImpl();
2533 else if (eventType
== "MouseEvents" || eventType
== "MouseEvent")
2534 return new MouseEventImpl();
2535 else if (eventType
== "TextEvent")
2536 return new TextEventImpl();
2537 else if (eventType
== "KeyboardEvent")
2538 return new KeyboardEventImpl();
2539 else if (eventType
== "MutationEvents" || eventType
== "MutationEvent")
2540 return new MutationEventImpl();
2541 else if (eventType
== "HTMLEvents" || eventType
== "Events" ||
2542 eventType
== "HTMLEvent" || eventType
== "Event")
2543 return new EventImpl();
2545 exceptioncode
= DOMException::NOT_SUPPORTED_ERR
;
2550 CSSStyleDeclarationImpl
*DocumentImpl::getOverrideStyle(ElementImpl
* /*elt*/, DOMStringImpl
* /*pseudoElt*/)
2555 void DocumentImpl::abort()
2558 assert(m_inSyncLoad
->isRunning());
2559 m_inSyncLoad
->exit();
2562 if (m_loadingXMLDoc
)
2563 m_loadingXMLDoc
->deref(this);
2564 m_loadingXMLDoc
= 0;
2567 void DocumentImpl::load(const DOMString
&uri
)
2570 assert(m_inSyncLoad
->isRunning());
2571 m_inSyncLoad
->exit();
2574 m_hadLoadError
= false;
2575 if (m_loadingXMLDoc
)
2576 m_loadingXMLDoc
->deref(this);
2578 // Use the document loader to retrieve the XML file. We use CachedCSSStyleSheet because
2579 // this is an easy way to retrieve an arbitrary text file... it is not specific to
2582 // ### Note: By loading the XML document this way we do not get the proper decoding
2583 // of the data retrieved from the server based on the character set, as happens with
2584 // HTML files. Need to look into a way of using the decoder in CachedCSSStyleSheet.
2585 m_docLoading
= true;
2586 m_loadingXMLDoc
= m_docLoader
->requestStyleSheet(uri
.string(),QString(),"text/xml");
2588 if (!m_loadingXMLDoc
) {
2589 m_docLoading
= false;
2593 m_loadingXMLDoc
->ref(this);
2595 if (!m_async
&& m_docLoading
) {
2596 assert(!m_inSyncLoad
);
2597 m_inSyncLoad
= new QEventLoop();
2598 m_inSyncLoad
->exec();
2599 // returning from event loop:
2600 assert(!m_inSyncLoad
->isRunning());
2601 delete m_inSyncLoad
;
2606 void DocumentImpl::loadXML(const DOMString
&source
)
2612 dispatchHTMLEvent(EventImpl::LOAD_EVENT
,false,false);
2615 void DocumentImpl::setStyleSheet(const DOM::DOMString
&url
, const DOM::DOMString
&sheet
, const DOM::DOMString
&/*charset*/, const DOM::DOMString
&mimetype
)
2617 if (!m_hadLoadError
) {
2618 m_url
= url
.string();
2619 loadXML(khtml::isAcceptableCSSMimetype(mimetype
) ? sheet
: "");
2622 m_docLoading
= false;
2624 assert(m_inSyncLoad
->isRunning());
2625 m_inSyncLoad
->exit();
2628 assert(m_loadingXMLDoc
!= 0);
2629 m_loadingXMLDoc
->deref(this);
2630 m_loadingXMLDoc
= 0;
2633 void DocumentImpl::error(int err
, const QString
&text
)
2635 m_docLoading
= false;
2637 assert(m_inSyncLoad
->isRunning());
2638 m_inSyncLoad
->exit();
2641 m_hadLoadError
= true;
2643 int exceptioncode
= 0;
2644 EventImpl
*evt
= new EventImpl(EventImpl::ERROR_EVENT
,false,false);
2646 evt
->setMessage(KIO::buildErrorString(err
,text
));
2648 evt
->setMessage(text
);
2650 dispatchEvent(evt
,exceptioncode
,true);
2653 assert(m_loadingXMLDoc
!= 0);
2654 m_loadingXMLDoc
->deref(this);
2655 m_loadingXMLDoc
= 0;
2658 void DocumentImpl::defaultEventHandler(EventImpl
*evt
)
2660 // if any html event listeners are registered on the window, then dispatch them here
2661 if (m_windowEventListeners
.listeners
&& !evt
->propagationStopped()) {
2663 QList
<RegisteredEventListener
>::iterator it
;
2665 //Grab a copy in case of clear
2666 QList
<RegisteredEventListener
> listeners
= *m_windowEventListeners
.listeners
;
2668 for (it
= listeners
.begin(); it
!= listeners
.end(); ++it
) {
2669 //Check to make sure it didn't get removed. KDE4: use Java-style iterators
2670 if (!m_windowEventListeners
.stillContainsListener(*it
))
2673 if ((*it
).eventName
== evt
->name()) {
2674 // currentTarget must be 0 in khtml for kjs_events to set "this" correctly.
2675 // (this is how we identify events dispatched to the window, like window.onmousedown)
2676 // ## currentTarget is unimplemented in IE, and is "window" in Mozilla (how? not a DOM node)
2677 evt
->setCurrentTarget(0);
2678 (*it
).listener
->handleEvent(ev
);
2682 if ( evt
->id() == EventImpl::KHTML_CONTENTLOADED_EVENT
&& !evt
->propagationStopped() && !evt
->defaultPrevented() )
2686 void DocumentImpl::setHTMLWindowEventListener(EventName id
, EventListener
*listener
)
2688 m_windowEventListeners
.setHTMLEventListener(id
, listener
);
2691 void DocumentImpl::setHTMLWindowEventListener(unsigned id
, EventListener
*listener
)
2693 m_windowEventListeners
.setHTMLEventListener(EventName::fromId(id
), listener
);
2696 EventListener
*DocumentImpl::getHTMLWindowEventListener(EventName id
)
2698 return m_windowEventListeners
.getHTMLEventListener(id
);
2701 EventListener
*DocumentImpl::getHTMLWindowEventListener(unsigned id
)
2703 return m_windowEventListeners
.getHTMLEventListener(EventName::fromId(id
));
2706 void DocumentImpl::addWindowEventListener(EventName id
, EventListener
*listener
, const bool useCapture
)
2708 m_windowEventListeners
.addEventListener(id
, listener
, useCapture
);
2711 void DocumentImpl::removeWindowEventListener(EventName id
, EventListener
*listener
, bool useCapture
)
2713 m_windowEventListeners
.removeEventListener(id
, listener
, useCapture
);
2716 bool DocumentImpl::hasWindowEventListener(EventName id
)
2718 return m_windowEventListeners
.hasEventListener(id
);
2721 EventListener
*DocumentImpl::createHTMLEventListener(const QString
& code
, const QString
& name
, NodeImpl
* node
)
2723 return part() ? part()->createHTMLEventListener(code
, name
, node
) : 0;
2726 void DocumentImpl::dispatchImageLoadEventSoon(HTMLImageElementImpl
*image
)
2728 m_imageLoadEventDispatchSoonList
.append(image
);
2729 if (!m_imageLoadEventTimer
) {
2730 m_imageLoadEventTimer
= startTimer(0);
2734 void DocumentImpl::removeImage(HTMLImageElementImpl
*image
)
2736 // Remove instances of this image from both lists.
2737 m_imageLoadEventDispatchSoonList
.removeAll(image
);
2738 m_imageLoadEventDispatchingList
.removeAll(image
);
2739 if (m_imageLoadEventDispatchSoonList
.isEmpty() && m_imageLoadEventTimer
) {
2740 killTimer(m_imageLoadEventTimer
);
2741 m_imageLoadEventTimer
= 0;
2745 void DocumentImpl::dispatchImageLoadEventsNow()
2747 // need to avoid re-entering this function; if new dispatches are
2748 // scheduled before the parent finishes processing the list, they
2749 // will set a timer and eventually be processed
2750 if (!m_imageLoadEventDispatchingList
.isEmpty()) {
2754 if (m_imageLoadEventTimer
) {
2755 killTimer(m_imageLoadEventTimer
);
2756 m_imageLoadEventTimer
= 0;
2759 m_imageLoadEventDispatchingList
= m_imageLoadEventDispatchSoonList
;
2760 m_imageLoadEventDispatchSoonList
.clear();
2761 for (QLinkedListIterator
<HTMLImageElementImpl
*> it(m_imageLoadEventDispatchingList
); it
.hasNext(); )
2762 it
.next()->dispatchLoadEvent();
2763 m_imageLoadEventDispatchingList
.clear();
2766 void DocumentImpl::timerEvent(QTimerEvent
*)
2768 dispatchImageLoadEventsNow();
2771 /*void DocumentImpl::setDecoderCodec(const QTextCodec *codec)
2773 m_decoderMibEnum = codec->mibEnum();
2776 ElementImpl
*DocumentImpl::ownerElement() const
2778 KHTMLPart
*childPart
= part();
2781 ChildFrame
*childFrame
= childPart
->d
->m_frame
;
2784 ElementImpl
*el
= childFrame
->m_partContainerElement
;
2788 DOMString
DocumentImpl::domain() const
2790 if ( m_domain
.isEmpty() ) // not set yet (we set it on demand to save time and space)
2791 m_domain
= URL().host(); // Initially set to the host
2795 void DocumentImpl::setDomain(const DOMString
&newDomain
)
2797 if ( m_domain
.isEmpty() ) // not set yet (we set it on demand to save time and space)
2798 m_domain
= URL().host().toLower(); // Initially set to the host
2800 if ( m_domain
.isEmpty() /*&& part() && part()->openedByJS()*/ )
2801 m_domain
= newDomain
.lower();
2803 // Both NS and IE specify that changing the domain is only allowed when
2804 // the new domain is a suffix of the old domain.
2805 int oldLength
= m_domain
.length();
2806 int newLength
= newDomain
.length();
2807 if ( newLength
< oldLength
) // e.g. newDomain=kde.org (7) and m_domain=www.kde.org (11)
2809 DOMString test
= m_domain
.copy();
2810 DOMString reference
= newDomain
.lower();
2811 if ( test
[oldLength
- newLength
- 1] == '.' ) // Check that it's a subdomain, not e.g. "de.org"
2813 test
.remove( 0, oldLength
- newLength
); // now test is "kde.org" from m_domain
2814 if ( test
== reference
) // and we check that it's the same thing as newDomain
2815 m_domain
= reference
;
2820 DOMString
DocumentImpl::toString() const
2824 for (NodeImpl
*child
= firstChild(); child
!= NULL
; child
= child
->nextSibling()) {
2825 result
+= child
->toString();
2831 void DOM::DocumentImpl::setRestoreState( const QStringList
&s
)
2834 m_stateRestorePos
= 0;
2837 KHTMLView
* DOM::DocumentImpl::view() const
2842 KHTMLPart
* DOM::DocumentImpl::part() const
2844 // ### TODO: make this independent from a KHTMLView one day.
2845 return view() ? view()->part() : 0;
2848 NodeListImpl::Cache
* DOM::DocumentImpl::acquireCachedNodeListInfo(
2849 NodeListImpl::CacheFactory
* factory
, NodeImpl
* base
, int type
)
2851 //### might want to flush the dict when the version number
2853 NodeListImpl::CacheKey
key(base
, type
);
2855 //Check to see if we have this sort of item cached.
2856 NodeListImpl::Cache
* cached
=
2857 (type
== NodeListImpl::UNCACHEABLE
) ? 0 : m_nodeListCache
.value(key
.hash());
2860 if (cached
->key
== key
) {
2861 cached
->ref(); //Add the nodelist's reference
2864 //Conflict. Drop our reference to the old item.
2869 //Nothing to reuse, make a new item.
2870 NodeListImpl::Cache
* newInfo
= factory();
2872 newInfo
->clear(this);
2873 newInfo
->ref(); //Add the nodelist's reference
2875 if (type
!= NodeListImpl::UNCACHEABLE
) {
2876 newInfo
->ref(); //Add the cache's reference
2877 m_nodeListCache
.insert(key
.hash(), newInfo
);
2883 void DOM::DocumentImpl::releaseCachedNodeListInfo(NodeListImpl::Cache
* entry
)
2888 // ----------------------------------------------------------------------------
2889 // Support for Javascript execCommand, and related methods
2891 JSEditor
*DocumentImpl::jsEditor()
2894 m_jsEditor
= new JSEditor(this);
2898 bool DocumentImpl::execCommand(const DOMString
&command
, bool userInterface
, const DOMString
&value
)
2900 return jsEditor()->execCommand(jsEditor()->commandImp(command
), userInterface
, value
);
2903 bool DocumentImpl::queryCommandEnabled(const DOMString
&command
)
2905 return jsEditor()->queryCommandEnabled(jsEditor()->commandImp(command
));
2908 bool DocumentImpl::queryCommandIndeterm(const DOMString
&command
)
2910 return jsEditor()->queryCommandIndeterm(jsEditor()->commandImp(command
));
2913 bool DocumentImpl::queryCommandState(const DOMString
&command
)
2915 return jsEditor()->queryCommandState(jsEditor()->commandImp(command
));
2918 bool DocumentImpl::queryCommandSupported(const DOMString
&command
)
2920 return jsEditor()->queryCommandSupported(jsEditor()->commandImp(command
));
2923 DOMString
DocumentImpl::queryCommandValue(const DOMString
&command
)
2925 return jsEditor()->queryCommandValue(jsEditor()->commandImp(command
));
2928 // ----------------------------------------------------------------------------
2930 DocumentFragmentImpl::DocumentFragmentImpl(DocumentImpl
*doc
) : NodeBaseImpl(doc
)
2934 DocumentFragmentImpl::DocumentFragmentImpl(const DocumentFragmentImpl
&other
)
2935 : NodeBaseImpl(other
)
2939 DOMString
DocumentFragmentImpl::nodeName() const
2941 return "#document-fragment";
2944 unsigned short DocumentFragmentImpl::nodeType() const
2946 return Node::DOCUMENT_FRAGMENT_NODE
;
2949 // DOM Section 1.1.1
2950 bool DocumentFragmentImpl::childTypeAllowed( unsigned short type
)
2953 case Node::ELEMENT_NODE
:
2954 case Node::PROCESSING_INSTRUCTION_NODE
:
2955 case Node::COMMENT_NODE
:
2956 case Node::TEXT_NODE
:
2957 case Node::CDATA_SECTION_NODE
:
2958 case Node::ENTITY_REFERENCE_NODE
:
2966 DOMString
DocumentFragmentImpl::toString() const
2970 for (NodeImpl
*child
= firstChild(); child
!= NULL
; child
= child
->nextSibling()) {
2971 if (child
->nodeType() == Node::COMMENT_NODE
|| child
->nodeType() == Node::PROCESSING_INSTRUCTION_NODE
)
2973 result
+= child
->toString();
2979 NodeImpl
*DocumentFragmentImpl::cloneNode ( bool deep
)
2981 DocumentFragmentImpl
*clone
= new DocumentFragmentImpl( docPtr() );
2983 cloneChildNodes(clone
);
2988 // ----------------------------------------------------------------------------
2990 DocumentTypeImpl::DocumentTypeImpl(DOMImplementationImpl
*implementation
, DocumentImpl
*doc
,
2991 const DOMString
&qualifiedName
, const DOMString
&publicId
,
2992 const DOMString
&systemId
)
2993 : NodeImpl(doc
), m_implementation(implementation
),
2994 m_qualifiedName(qualifiedName
), m_publicId(publicId
), m_systemId(systemId
)
2996 m_implementation
->ref();
3001 // if doc is 0, it is not attached to a document and / or
3002 // therefore does not provide entities or notations. (DOM Level 3)
3005 DocumentTypeImpl::~DocumentTypeImpl()
3007 m_implementation
->deref();
3009 m_entities
->deref();
3011 m_notations
->deref();
3014 DOMString
DocumentTypeImpl::toString() const
3016 DOMString result
= "<!DOCTYPE ";
3017 result
+= m_qualifiedName
;
3018 if (!m_publicId
.isEmpty()) {
3019 result
+= " PUBLIC \"";
3020 result
+= m_publicId
;
3022 result
+= m_systemId
;
3024 } else if (!m_systemId
.isEmpty()) {
3025 result
+= " SYSTEM \"";
3026 result
+= m_systemId
;
3030 if (!m_subset
.isEmpty()) {
3041 DOMString
DocumentTypeImpl::nodeName() const
3046 unsigned short DocumentTypeImpl::nodeType() const
3048 return Node::DOCUMENT_TYPE_NODE
;
3051 // DOM Section 1.1.1
3052 bool DocumentTypeImpl::childTypeAllowed( unsigned short /*type*/ )
3057 NodeImpl
*DocumentTypeImpl::cloneNode ( bool /*deep*/ )
3059 DocumentTypeImpl
*clone
= new DocumentTypeImpl(implementation(),
3063 // ### copy entities etc.
3067 NamedNodeMapImpl
* DocumentTypeImpl::entities() const
3069 if ( !m_entities
) {
3070 m_entities
= new GenericRONamedNodeMapImpl( docPtr() );
3076 NamedNodeMapImpl
* DocumentTypeImpl::notations() const
3078 if ( !m_notations
) {
3079 m_notations
= new GenericRONamedNodeMapImpl( docPtr() );
3085 #include "dom_docimpl.moc"