From dfe289850f068f19ba4a83ab4e7e22a7e09c13c9 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Sat, 26 Jan 2013 13:17:21 -0600 Subject: Rename a number of libraries and executables to avoid conflicts with KDE4 --- tdehtml/xml/dom_docimpl.cpp | 2892 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2892 insertions(+) create mode 100644 tdehtml/xml/dom_docimpl.cpp (limited to 'tdehtml/xml/dom_docimpl.cpp') diff --git a/tdehtml/xml/dom_docimpl.cpp b/tdehtml/xml/dom_docimpl.cpp new file mode 100644 index 000000000..3ab639867 --- /dev/null +++ b/tdehtml/xml/dom_docimpl.cpp @@ -0,0 +1,2892 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * (C) 2002-2006 Apple Computer, Inc. + * (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "dom/dom_exception.h" + +#include "xml/dom_textimpl.h" +#include "xml/dom_xmlimpl.h" +#include "xml/dom2_rangeimpl.h" +#include "xml/dom2_eventsimpl.h" +#include "xml/xml_tokenizer.h" +#include "html/htmltokenizer.h" +#include "xml/dom_restyler.h" + +#include "css/csshelper.h" +#include "css/cssstyleselector.h" +#include "css/css_stylesheetimpl.h" +#include "misc/htmlhashes.h" +#include "misc/helper.h" +#include "misc/seed.h" +#include "misc/loader.h" +#include "ecma/kjs_proxy.h" +#include "ecma/kjs_binding.h" + +#include +#include +#include +#include +#include + +#include "rendering/counter_tree.h" +#include "rendering/render_canvas.h" +#include "rendering/render_replaced.h" +#include "rendering/render_arena.h" +#include "rendering/render_layer.h" +#include "rendering/render_frames.h" +#include "rendering/render_image.h" + +#include "tdehtmlview.h" +#include "tdehtml_part.h" + +#include +#include +#include +#include "tdehtml_settings.h" +#include "tdehtmlpart_p.h" + +#include "html/html_baseimpl.h" +#include "html/html_blockimpl.h" +#include "html/html_documentimpl.h" +#include "html/html_formimpl.h" +#include "html/html_headimpl.h" +#include "html/html_imageimpl.h" +#include "html/html_listimpl.h" +#include "html/html_miscimpl.h" +#include "html/html_tableimpl.h" +#include "html/html_objectimpl.h" + +#include +#include + +#include +#include "dom_docimpl.h" + +using namespace DOM; +using namespace tdehtml; + +// ------------------------------------------------------------------------ + +DOMImplementationImpl *DOMImplementationImpl::m_instance = 0; + +DOMImplementationImpl::DOMImplementationImpl() +{ +} + +DOMImplementationImpl::~DOMImplementationImpl() +{ +} + +bool DOMImplementationImpl::hasFeature ( const DOMString &feature, const DOMString &version ) +{ + // ### update when we (fully) support the relevant features + TQString lower = feature.string().lower(); + if ((lower == "html" || lower == "xml") && + (version.isEmpty() || version == "1.0" || version == "2.0" || version == "null")) + return true; + + // ## Do we support Core Level 3 ? + if ((lower == "core" ) && + (version.isEmpty() || version == "2.0" || version == "null")) + return true; + + if ((lower == "events" || lower == "uievents" || + lower == "mouseevents" || lower == "mutationevents" || + lower == "htmlevents" || lower == "textevents" ) && + (version.isEmpty() || version == "2.0" || version == "3.0" || version == "null")) + return true; + return false; +} + +DocumentTypeImpl *DOMImplementationImpl::createDocumentType( const DOMString &qualifiedName, const DOMString &publicId, + const DOMString &systemId, int &exceptioncode ) +{ + // Not mentioned in spec: throw NAMESPACE_ERR if no qualifiedName supplied + if (qualifiedName.isNull()) { + exceptioncode = DOMException::NAMESPACE_ERR; + return 0; + } + + // INVALID_CHARACTER_ERR: Raised if the specified qualified name contains an illegal character. + if (!Element::tdehtmlValidQualifiedName(qualifiedName)) { + exceptioncode = DOMException::INVALID_CHARACTER_ERR; + return 0; + } + + // NAMESPACE_ERR: Raised if the qualifiedName is malformed. + // Added special case for the empty string, which seems to be a common pre-DOM2 misuse + if (!qualifiedName.isEmpty() && Element::tdehtmlMalformedQualifiedName(qualifiedName)) { + exceptioncode = DOMException::NAMESPACE_ERR; + return 0; + } + + return new DocumentTypeImpl(this,0,qualifiedName,publicId,systemId); +} + +DOMImplementationImpl* DOMImplementationImpl::getInterface(const DOMString& /*feature*/) const +{ + // ### + return 0; +} + +DocumentImpl *DOMImplementationImpl::createDocument( const DOMString &namespaceURI, const DOMString &qualifiedName, + const DocumentType &doctype, int &exceptioncode ) +{ + exceptioncode = 0; + + if (!checkQualifiedName(qualifiedName, namespaceURI, 0, true/*nameCanBeNull*/, + true /*nameCanBeEmpty, see #61650*/, &exceptioncode) ) + return 0; + + DocumentTypeImpl *dtype = static_cast(doctype.handle()); + // WRONG_DOCUMENT_ERR: Raised if doctype has already been used with a different document or was + // created from a different implementation. + if (dtype && (dtype->getDocument() || dtype->implementation() != this)) { + exceptioncode = DOMException::WRONG_DOCUMENT_ERR; + return 0; + } + + // ### this is completely broken.. without a view it will not work (Dirk) + DocumentImpl *doc = new DocumentImpl(this, 0); + + // now get the interesting parts of the doctype + // ### create new one if not there (currently always there) + if (doc->doctype() && dtype) + doc->doctype()->copyFrom(*dtype); + + // the document must be created empty if all parameters are null + // (or empty for qName/nsURI as a tolerance) - see DOM 3 Core. + if (dtype || !qualifiedName.isEmpty() || !namespaceURI.isEmpty()) { + ElementImpl *element = doc->createElementNS(namespaceURI,qualifiedName); + doc->appendChild(element,exceptioncode); + if (exceptioncode) { + delete element; + delete doc; + return 0; + } + } + return doc; +} + +CSSStyleSheetImpl *DOMImplementationImpl::createCSSStyleSheet(DOMStringImpl* /*title*/, DOMStringImpl *media, + int &/*exceptioncode*/) +{ + // ### TODO : title should be set, and media could have wrong syntax, in which case we should + // generate an exception. + CSSStyleSheetImpl *parent = 0L; + CSSStyleSheetImpl *sheet = new CSSStyleSheetImpl(parent, DOMString()); + sheet->setMedia(new MediaListImpl(sheet, media)); + return sheet; +} + +DocumentImpl *DOMImplementationImpl::createDocument( KHTMLView *v ) +{ + return new DocumentImpl(this, v); +} + +HTMLDocumentImpl *DOMImplementationImpl::createHTMLDocument( KHTMLView *v ) +{ + return new HTMLDocumentImpl(this, v); +} + +DOMImplementationImpl *DOMImplementationImpl::instance() +{ + if (!m_instance) { + m_instance = new DOMImplementationImpl(); + m_instance->ref(); + } + + return m_instance; +} + +// ------------------------------------------------------------------------ + + +ElementMappingCache::ElementMappingCache():m_dict(257) +{ + m_dict.setAutoDelete(true); +} + +void ElementMappingCache::add(const TQString& id, ElementImpl* nd) +{ + if (id.isEmpty()) return; + + ItemInfo* info = m_dict.find(id); + if (info) + { + info->ref++; + info->nd = 0; //Now ambigous + } + else + { + ItemInfo* info = new ItemInfo(); + info->ref = 1; + info->nd = nd; + m_dict.insert(id, info); + } +} + +void ElementMappingCache::set(const TQString& id, ElementImpl* nd) +{ + if (id.isEmpty()) return; + + ItemInfo* info = m_dict.find(id); + info->nd = nd; +} + +void ElementMappingCache::remove(const TQString& id, ElementImpl* nd) +{ + if (id.isEmpty()) return; + + ItemInfo* info = m_dict.find(id); + info->ref--; + if (info->ref == 0) + { + m_dict.take(id); + delete info; + } + else + { + if (info->nd == nd) + info->nd = 0; + } +} + +bool ElementMappingCache::contains(const TQString& id) +{ + if (id.isEmpty()) return false; + return m_dict.find(id); +} + +ElementMappingCache::ItemInfo* ElementMappingCache::get(const TQString& id) +{ + if (id.isEmpty()) return 0; + return m_dict.find(id); +} + +static KStaticDeleter< TQPtrList > s_changedDocumentsDeleter; +TQPtrList * DocumentImpl::changedDocuments; + +// KHTMLView might be 0 +DocumentImpl::DocumentImpl(DOMImplementationImpl *_implementation, KHTMLView *v) + : NodeBaseImpl( 0 ), m_domtree_version(0), m_counterDict(257), + m_imageLoadEventTimer(0) +{ + m_document.resetSkippingRef(this); //Make getDocument return us.. + m_selfOnlyRefCount = 0; + + m_paintDeviceMetrics = 0; + m_paintDevice = 0; + m_decoderMibEnum = 0; + m_textColor = Qt::black; + + m_view = v; + m_renderArena.reset(); + + KHTMLFactory::ref(); + + if ( v ) { + m_docLoader = new DocLoader(v->part(), this ); + setPaintDevice( TQT_TQPAINTDEVICE(m_view) ); + } + else + m_docLoader = new DocLoader( 0, this ); + + visuallyOrdered = false; + m_bParsing = false; + m_docChanged = false; + m_elemSheet = 0; + m_tokenizer = 0; + + // ### this should be created during parsing a + // not during construction. Not sure who added that and why (Dirk) + m_doctype = new DocumentTypeImpl(_implementation, getDocument(), + DOMString() /* qualifiedName */, + DOMString() /* publicId */, + DOMString() /* systemId */); + m_doctype->ref(); + + m_implementation = _implementation; + m_implementation->ref(); + pMode = Strict; + hMode = XHtml; + m_textColor = "#000000"; + m_attrMap = new IdNameMapping(ATTR_LAST_ATTR+1); + m_elementMap = new IdNameMapping(ID_LAST_TAG+1); + m_namespaceMap = new IdNameMapping(1); + TQString xhtml(XHTML_NAMESPACE); + m_namespaceMap->names.insert(emptyNamespace, new DOMStringImpl("")); + m_namespaceMap->names.insert(xhtmlNamespace, new DOMStringImpl(xhtml.unicode(), xhtml.length())); + m_namespaceMap->names[emptyNamespace]->ref(); + m_namespaceMap->names[xhtmlNamespace]->ref(); + m_namespaceMap->count+=2; + m_focusNode = 0; + m_hoverNode = 0; + m_activeNode = 0; + m_defaultView = new AbstractViewImpl(this); + m_defaultView->ref(); + m_listenerTypes = 0; + m_styleSheets = new StyleSheetListImpl; + m_styleSheets->ref(); + m_addedStyleSheets = 0; + m_inDocument = true; + m_styleSelectorDirty = false; + m_styleSelector = 0; + m_counterDict.setAutoDelete(true); + + m_inStyleRecalc = false; + m_pendingStylesheets = 0; + m_ignorePendingStylesheets = false; + m_async = true; + m_hadLoadError = false; + m_docLoading = false; + m_inSyncLoad = false; + m_loadingXMLDoc = 0; + m_cssTarget = 0; + m_dynamicDomRestyler = new tdehtml::DynamicDomRestyler(); +} + +void DocumentImpl::removedLastRef() +{ + if (m_selfOnlyRefCount) { + /* In this case, the only references to us are from children, + so we have a cycle. We'll try to break it by disconnecting the + children from us; this sucks/is wrong, but it's pretty much + the best we can do without tracing. + + Of course, if dumping the children causes the refcount from them to + drop to 0 we can get killed right here, so better hold + a temporary reference, too + */ + DocPtr guard(this); + + // we must make sure not to be retaining any of our children through + // these extra pointers or we will create a reference cycle + if (m_doctype) { + m_doctype->deref(); + m_doctype = 0; + } + + if (m_cssTarget) { + m_cssTarget->deref(); + m_cssTarget = 0; + } + + if (m_focusNode) { + m_focusNode->deref(); + m_focusNode = 0; + } + + if (m_hoverNode) { + m_hoverNode->deref(); + m_hoverNode = 0; + } + + if (m_activeNode) { + m_activeNode->deref(); + m_activeNode = 0; + } + + removeChildren(); + + delete m_tokenizer; + m_tokenizer = 0; + } else { + delete this; + } +} + +DocumentImpl::~DocumentImpl() +{ + //Important: if you need to remove stuff here, + //you may also have to fix removedLastRef() above - M.O. + assert( !m_render ); + + TQIntDictIterator it(m_nodeListCache); + for (; it.current(); ++it) + it.current()->deref(); + + if (m_loadingXMLDoc) + m_loadingXMLDoc->deref(this); + if (changedDocuments && m_docChanged) + changedDocuments->remove(this); + delete m_tokenizer; + m_document.resetSkippingRef(0); + delete m_styleSelector; + delete m_docLoader; + if (m_elemSheet ) m_elemSheet->deref(); + if (m_doctype) + m_doctype->deref(); + m_implementation->deref(); + delete m_paintDeviceMetrics; + delete m_elementMap; + delete m_attrMap; + delete m_namespaceMap; + delete m_dynamicDomRestyler; + m_defaultView->deref(); + m_styleSheets->deref(); + if (m_addedStyleSheets) + m_addedStyleSheets->deref(); + if (m_cssTarget) + m_cssTarget->deref(); + if (m_focusNode) + m_focusNode->deref(); + if ( m_hoverNode ) + m_hoverNode->deref(); + if (m_activeNode) + m_activeNode->deref(); + + m_renderArena.reset(); + + KHTMLFactory::deref(); +} + + +DocumentTypeImpl *DocumentImpl::doctype() const +{ + return m_doctype; +} + +DOMImplementationImpl *DocumentImpl::implementation() const +{ + return m_implementation; +} + +ElementImpl *DocumentImpl::documentElement() const +{ + NodeImpl *n = firstChild(); + while (n && n->nodeType() != Node::ELEMENT_NODE) + n = n->nextSibling(); + return static_cast(n); +} + +ElementImpl *DocumentImpl::createElement( const DOMString &name, int* pExceptioncode ) +{ + Id id = getId( NodeImpl::ElementId, name.implementation(), + false /* allocate */, false /*HTMLDocumentImpl::createElement looked for HTML elements already*/, + pExceptioncode); + if ( pExceptioncode && *pExceptioncode ) + return 0; + + XMLElementImpl* e = new XMLElementImpl( getDocument(), id ); + e->setHTMLCompat( htmlMode() != XHtml ); // Not a real HTML element, but inside an html-compat doc all tags are uppercase. + return e; +} + +AttrImpl *DocumentImpl::createAttribute( const DOMString &tagName, int* pExceptioncode ) +{ + Id id = getId( NodeImpl::AttributeId, tagName.implementation(), + false /* allocate */, isHTMLDocument(), pExceptioncode); + if ( pExceptioncode && *pExceptioncode ) + return 0; + AttrImpl* attr = new AttrImpl( 0, getDocument(), id, DOMString("").implementation()); + attr->setHTMLCompat( htmlMode() != XHtml ); + return attr; +} + +DocumentFragmentImpl *DocumentImpl::createDocumentFragment( ) +{ + return new DocumentFragmentImpl( docPtr() ); +} + +CommentImpl *DocumentImpl::createComment ( DOMStringImpl* data ) +{ + return new CommentImpl( docPtr(), data ); +} + +CDATASectionImpl *DocumentImpl::createCDATASection ( DOMStringImpl* data ) +{ + return new CDATASectionImpl( docPtr(), data ); +} + +ProcessingInstructionImpl *DocumentImpl::createProcessingInstruction ( const DOMString &target, DOMStringImpl* data ) +{ + return new ProcessingInstructionImpl( docPtr(),target,data); +} + +EntityReferenceImpl *DocumentImpl::createEntityReference ( const DOMString &name ) +{ + return new EntityReferenceImpl(docPtr(), name.implementation()); +} + +NodeImpl *DocumentImpl::importNode(NodeImpl *importedNode, bool deep, int &exceptioncode) +{ + NodeImpl *result = 0; + + // Not mentioned in spec: throw NOT_FOUND_ERR if evt is null + if (!importedNode) { + exceptioncode = DOMException::NOT_FOUND_ERR; + return 0; + } + + if(importedNode->nodeType() == Node::ELEMENT_NODE) + { + // Why not use cloneNode? + ElementImpl *otherElem = static_cast(importedNode); + NamedAttrMapImpl *otherMap = static_cast(importedNode)->attributes(true); + + ElementImpl *tempElementImpl; + if (!importedNode->localName().isNull()) + tempElementImpl = createElementNS(otherElem->namespaceURI(),otherElem->nodeName()); + else + tempElementImpl = createElement(otherElem->nodeName()); + result = tempElementImpl; + + + if(otherMap) { + for(unsigned long i = 0; i < otherMap->length(); i++) + { + AttrImpl *otherAttr = otherMap->attrAt(i)->createAttr(otherElem,otherElem->docPtr()); + + if (!otherAttr->localName().isNull()) { + // attr was created via createElementNS() + tempElementImpl->setAttributeNS(otherAttr->namespaceURI(), + otherAttr->name(), + otherAttr->nodeValue(), + exceptioncode); + } + else { + // attr was created via createElement() + tempElementImpl->setAttribute(otherAttr->id(), + otherAttr->nodeValue(), + otherAttr->name(), + exceptioncode); + } + + if(exceptioncode != 0) + break; // ### properly cleanup here + } + } + } + else if(importedNode->nodeType() == Node::TEXT_NODE) + { + result = createTextNode(static_cast(importedNode)->string()); + deep = false; + } + else if(importedNode->nodeType() == Node::CDATA_SECTION_NODE) + { + result = createCDATASection(static_cast(importedNode)->string()); + deep = false; + } + else if(importedNode->nodeType() == Node::ENTITY_REFERENCE_NODE) + result = createEntityReference(importedNode->nodeName()); + else if(importedNode->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) + { + result = createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue().implementation()); + deep = false; + } + else if(importedNode->nodeType() == Node::COMMENT_NODE) + { + result = createComment(static_cast(importedNode)->string()); + deep = false; + } + else if (importedNode->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) + result = createDocumentFragment(); + else + exceptioncode = DOMException::NOT_SUPPORTED_ERR; + + //### FIXME: This should handle Attributes, and a few other things + + if(deep && result) + { + for(Node n = importedNode->firstChild(); !n.isNull(); n = n.nextSibling()) + result->appendChild(importNode(n.handle(), true, exceptioncode), exceptioncode); + } + + return result; +} + +ElementImpl *DocumentImpl::createElementNS( const DOMString &_namespaceURI, const DOMString &_qualifiedName, int* pExceptioncode ) +{ + ElementImpl *e = 0; + int colonPos = -2; + // check NAMESPACE_ERR/INVALID_CHARACTER_ERR + if (pExceptioncode && !checkQualifiedName(_qualifiedName, _namespaceURI, &colonPos, + false/*nameCanBeNull*/, false/*nameCanBeEmpty*/, + pExceptioncode)) + return 0; + DOMString prefix, localName; + splitPrefixLocalName(_qualifiedName.implementation(), prefix, localName, colonPos); + + if ((isHTMLDocument() && _namespaceURI.isNull()) || + (strcasecmp(_namespaceURI, XHTML_NAMESPACE) == 0 && localName == localName.lower())) { + e = createHTMLElement(localName); + if (e) { + int _exceptioncode = 0; + if (!prefix.isNull()) + e->setPrefix(prefix, _exceptioncode); + if ( _exceptioncode ) { + if ( pExceptioncode ) *pExceptioncode = _exceptioncode; + delete e; + return 0; + } + e->setHTMLCompat( _namespaceURI.isNull() && htmlMode() != XHtml ); + } + } + if (!e) { + Id id = getId(NodeImpl::ElementId, _namespaceURI.implementation(), prefix.implementation(), + localName.implementation(), false, false /*HTML already looked up*/); + e = new XMLElementImpl( getDocument(), id, prefix.implementation() ); + } + + return e; +} + +AttrImpl *DocumentImpl::createAttributeNS( const DOMString &_namespaceURI, + const DOMString &_qualifiedName, int* pExceptioncode) +{ + int colonPos = -2; + // check NAMESPACE_ERR/INVALID_CHARACTER_ERR + if (pExceptioncode && !checkQualifiedName(_qualifiedName, _namespaceURI, &colonPos, + false/*nameCanBeNull*/, false/*nameCanBeEmpty*/, + pExceptioncode)) + return 0; + DOMString prefix, localName; + splitPrefixLocalName(_qualifiedName.implementation(), prefix, localName, colonPos); + Id id = getId(NodeImpl::AttributeId, _namespaceURI.implementation(), prefix.implementation(), + localName.implementation(), false, true /*lookupHTML*/); + AttrImpl* attr = new AttrImpl(0, getDocument(), id, DOMString("").implementation(), + prefix.implementation()); + attr->setHTMLCompat( _namespaceURI.isNull() && htmlMode() != XHtml ); + return attr; +} + +ElementImpl *DocumentImpl::getElementById( const DOMString &elementId ) const +{ + TQString stringKey = elementId.string(); + + ElementMappingCache::ItemInfo* info = m_getElementByIdCache.get(stringKey); + + if (!info) + return 0; + + //See if cache has an unambiguous answer. + if (info->nd) + return info->nd; + + //Now we actually have to walk. + TQPtrStack nodeStack; + NodeImpl *current = _first; + + while(1) + { + if(!current) + { + if(nodeStack.isEmpty()) break; + current = nodeStack.pop(); + current = current->nextSibling(); + } + else + { + if(current->isElementNode()) + { + ElementImpl *e = static_cast(current); + if(e->getAttribute(ATTR_ID) == elementId) { + info->nd = e; + return e; + } + } + + NodeImpl *child = current->firstChild(); + if(child) + { + nodeStack.push(current); + current = child; + } + else + { + current = current->nextSibling(); + } + } + } + + assert(0); //If there is no item with such an ID, we should never get here + + //kdDebug() << "WARNING: *DocumentImpl::getElementById not found " << elementId.string() << endl; + + return 0; +} + +void DocumentImpl::setTitle(const DOMString& _title) +{ + if (_title == m_title && !m_title.isNull()) return; + + m_title = _title; + + TQString titleStr = m_title.string(); + for (unsigned int i = 0; i < titleStr.length(); ++i) + if (titleStr[i] < ' ') + titleStr[i] = ' '; + titleStr = titleStr.simplifyWhiteSpace(); + titleStr.compose(); + if ( view() && !view()->part()->parentPart() ) { + if (titleStr.isNull() || titleStr.isEmpty()) { + // empty title... set window caption as the URL + KURL url = m_url; + url.setRef(TQString::null); + url.setQuery(TQString::null); + titleStr = url.prettyURL(); + } + + emit view()->part()->setWindowCaption( KStringHandler::csqueeze( titleStr, 128 ) ); + } +} + +DOMString DocumentImpl::nodeName() const +{ + return "#document"; +} + +unsigned short DocumentImpl::nodeType() const +{ + return Node::DOCUMENT_NODE; +} + +DOMStringImpl* DocumentImpl::textContent() const +{ + return 0; +} + +void DocumentImpl::setTextContent( const DOMString&, int& ) +{} + +ElementImpl *DocumentImpl::createHTMLElement( const DOMString &name ) +{ + uint id = tdehtml::getTagID( name.string().lower().latin1(), name.string().length() ); +// id = makeId(xhtmlNamespace, id); + + ElementImpl *n = 0; + switch(id) + { + case ID_HTML: + n = new HTMLHtmlElementImpl(docPtr()); + break; + case ID_HEAD: + n = new HTMLHeadElementImpl(docPtr()); + break; + case ID_BODY: + n = new HTMLBodyElementImpl(docPtr()); + break; + +// head elements + case ID_BASE: + n = new HTMLBaseElementImpl(docPtr()); + break; + case ID_LINK: + n = new HTMLLinkElementImpl(docPtr()); + break; + case ID_META: + n = new HTMLMetaElementImpl(docPtr()); + break; + case ID_STYLE: + n = new HTMLStyleElementImpl(docPtr()); + break; + case ID_TITLE: + n = new HTMLTitleElementImpl(docPtr()); + break; + +// frames + case ID_FRAME: + n = new HTMLFrameElementImpl(docPtr()); + break; + case ID_FRAMESET: + n = new HTMLFrameSetElementImpl(docPtr()); + break; + case ID_IFRAME: + n = new HTMLIFrameElementImpl(docPtr()); + break; + +// form elements +// ### FIXME: we need a way to set form dependency after we have made the form elements + case ID_FORM: + n = new HTMLFormElementImpl(docPtr(), false); + break; + case ID_BUTTON: + n = new HTMLButtonElementImpl(docPtr()); + break; + case ID_FIELDSET: + n = new HTMLFieldSetElementImpl(docPtr()); + break; + case ID_INPUT: + n = new HTMLInputElementImpl(docPtr()); + break; + case ID_ISINDEX: + n = new HTMLIsIndexElementImpl(docPtr()); + break; + case ID_LABEL: + n = new HTMLLabelElementImpl(docPtr()); + break; + case ID_LEGEND: + n = new HTMLLegendElementImpl(docPtr()); + break; + case ID_OPTGROUP: + n = new HTMLOptGroupElementImpl(docPtr()); + break; + case ID_OPTION: + n = new HTMLOptionElementImpl(docPtr()); + break; + case ID_SELECT: + n = new HTMLSelectElementImpl(docPtr()); + break; + case ID_TEXTAREA: + n = new HTMLTextAreaElementImpl(docPtr()); + break; + +// lists + case ID_DL: + n = new HTMLDListElementImpl(docPtr()); + break; + case ID_DD: + n = new HTMLGenericElementImpl(docPtr(), id); + break; + case ID_DT: + n = new HTMLGenericElementImpl(docPtr(), id); + break; + case ID_UL: + n = new HTMLUListElementImpl(docPtr()); + break; + case ID_OL: + n = new HTMLOListElementImpl(docPtr()); + break; + case ID_DIR: + n = new HTMLDirectoryElementImpl(docPtr()); + break; + case ID_MENU: + n = new HTMLMenuElementImpl(docPtr()); + break; + case ID_LI: + n = new HTMLLIElementImpl(docPtr()); + break; + +// formatting elements (block) + case ID_DIV: + case ID_P: + n = new HTMLDivElementImpl( docPtr(), id ); + break; + case ID_BLOCKQUOTE: + case ID_H1: + case ID_H2: + case ID_H3: + case ID_H4: + case ID_H5: + case ID_H6: + n = new HTMLGenericElementImpl(docPtr(), id); + break; + case ID_HR: + n = new HTMLHRElementImpl(docPtr()); + break; + case ID_PLAINTEXT: + case ID_XMP: + case ID_PRE: + n = new HTMLPreElementImpl(docPtr(), id); + break; + +// font stuff + case ID_BASEFONT: + n = new HTMLBaseFontElementImpl(docPtr()); + break; + case ID_FONT: + n = new HTMLFontElementImpl(docPtr()); + break; + +// ins/del + case ID_DEL: + case ID_INS: + n = new HTMLGenericElementImpl(docPtr(), id); + break; + +// anchor + case ID_A: + n = new HTMLAnchorElementImpl(docPtr()); + break; + +// images + case ID_IMG: + n = new HTMLImageElementImpl(docPtr()); + break; + case ID_MAP: + n = new HTMLMapElementImpl(docPtr()); + /*n = map;*/ + break; + case ID_AREA: + n = new HTMLAreaElementImpl(docPtr()); + break; + +// objects, applets and scripts + case ID_APPLET: + n = new HTMLAppletElementImpl(docPtr()); + break; + case ID_OBJECT: + n = new HTMLObjectElementImpl(docPtr()); + break; + case ID_EMBED: + n = new HTMLEmbedElementImpl(docPtr()); + break; + case ID_PARAM: + n = new HTMLParamElementImpl(docPtr()); + break; + case ID_SCRIPT: + n = new HTMLScriptElementImpl(docPtr()); + break; + +// tables + case ID_TABLE: + n = new HTMLTableElementImpl(docPtr()); + break; + case ID_CAPTION: + n = new HTMLTableCaptionElementImpl(docPtr()); + break; + case ID_COLGROUP: + case ID_COL: + n = new HTMLTableColElementImpl(docPtr(), id); + break; + case ID_TR: + n = new HTMLTableRowElementImpl(docPtr()); + break; + case ID_TD: + case ID_TH: + n = new HTMLTableCellElementImpl(docPtr(), id); + break; + case ID_THEAD: + case ID_TBODY: + case ID_TFOOT: + n = new HTMLTableSectionElementImpl(docPtr(), id, false); + break; + +// inline elements + case ID_BR: + n = new HTMLBRElementImpl(docPtr()); + break; + case ID_Q: + n = new HTMLGenericElementImpl(docPtr(), id); + break; + +// elements with no special representation in the DOM + +// block: + case ID_ADDRESS: + case ID_CENTER: + n = new HTMLGenericElementImpl(docPtr(), id); + break; +// inline + // %fontstyle + case ID_TT: + case ID_U: + case ID_B: + case ID_I: + case ID_S: + case ID_STRIKE: + case ID_BIG: + case ID_SMALL: + + // %phrase + case ID_EM: + case ID_STRONG: + case ID_DFN: + case ID_CODE: + case ID_SAMP: + case ID_KBD: + case ID_VAR: + case ID_CITE: + case ID_ABBR: + case ID_ACRONYM: + + // %special + case ID_SUB: + case ID_SUP: + case ID_SPAN: + case ID_NOBR: + case ID_WBR: + case ID_BDO: + case ID_NOFRAMES: + n = new HTMLGenericElementImpl(docPtr(), id); + break; + + case ID_MARQUEE: + n = new HTMLMarqueeElementImpl(docPtr()); + break; +// text + case ID_TEXT: + kdDebug( 6020 ) << "Use document->createTextNode()" << endl; + break; + + default: + break; + } + return n; +} + +TQString DocumentImpl::nextState() +{ + TQString state; + if (!m_state.isEmpty()) + { + state = m_state.first(); + m_state.remove(m_state.begin()); + } + return state; +} + +TQStringList DocumentImpl::docState() +{ + TQStringList s; + for (TQPtrListIterator it(m_maintainsState); it.current(); ++it) + s.append(it.current()->state()); + + return s; +} + +bool DocumentImpl::unsubmittedFormChanges() +{ + for (TQPtrListIterator it(m_maintainsState); it.current(); ++it) + if (it.current()->state().right(1)=="M") + return true; + + return false; +} + +RangeImpl *DocumentImpl::createRange() +{ + return new RangeImpl( docPtr() ); +} + +NodeIteratorImpl *DocumentImpl::createNodeIterator(NodeImpl *root, unsigned long whatToShow, + NodeFilter &filter, bool entityReferenceExpansion, + int &exceptioncode) +{ + if (!root) { + exceptioncode = DOMException::NOT_SUPPORTED_ERR; + return 0; + } + + return new NodeIteratorImpl(root,whatToShow,filter,entityReferenceExpansion); +} + +TreeWalkerImpl *DocumentImpl::createTreeWalker(NodeImpl *root, unsigned long whatToShow, NodeFilterImpl *filter, + bool entityReferenceExpansion, int &exceptioncode) +{ + if (!root) { + exceptioncode = DOMException::NOT_SUPPORTED_ERR; + return 0; + } + + return new TreeWalkerImpl( root, whatToShow, filter, entityReferenceExpansion ); +} + +void DocumentImpl::setDocumentChanged(bool b) +{ + if (!changedDocuments) + changedDocuments = s_changedDocumentsDeleter.setObject( changedDocuments, new TQPtrList() ); + + if (b && !m_docChanged) + changedDocuments->append(this); + else if (!b && m_docChanged) + changedDocuments->remove(this); + m_docChanged = b; +} + +void DocumentImpl::recalcStyle( StyleChange change ) +{ +// tqDebug("recalcStyle(%p)", this); +// TQTime qt; +// qt.start(); + if (m_inStyleRecalc) + return; // Guard against re-entrancy. -dwh + + m_inStyleRecalc = true; + + if( !m_render ) goto bail_out; + + if ( change == Force ) { + RenderStyle* oldStyle = m_render->style(); + if ( oldStyle ) oldStyle->ref(); + RenderStyle* _style = new RenderStyle(); + _style->setDisplay(BLOCK); + _style->setVisuallyOrdered( visuallyOrdered ); + // ### make the font stuff _really_ work!!!! + + tdehtml::FontDef fontDef; + TQFont f = TDEGlobalSettings::generalFont(); + fontDef.family = f.family(); + fontDef.italic = f.italic(); + fontDef.weight = f.weight(); + if (m_view) { + const KHTMLSettings *settings = m_view->part()->settings(); + TQString stdfont = settings->stdFontName(); + if ( !stdfont.isEmpty() ) + fontDef.family = stdfont; + + fontDef.size = m_styleSelector->fontSizes()[3]; + } + + //kdDebug() << "DocumentImpl::attach: setting to charset " << settings->charset() << endl; + _style->setFontDef(fontDef); + _style->htmlFont().update( paintDeviceMetrics() ); + if ( inCompatMode() ) + _style->setHtmlHacks(true); // enable html specific rendering tricks + + StyleChange ch = diff( _style, oldStyle ); + if(m_render && ch != NoChange) + m_render->setStyle(_style); + else + delete _style; + if ( change != Force ) + change = ch; + + if (oldStyle) + oldStyle->deref(); + } + + NodeImpl *n; + for (n = _first; n; n = n->nextSibling()) + if ( change>= Inherit || n->hasChangedChild() || n->changed() ) + n->recalcStyle( change ); + //kdDebug( 6020 ) << "TIME: recalcStyle() dt=" << qt.elapsed() << endl; + + if (changed() && m_view) + m_view->layout(); + +bail_out: + setChanged( false ); + setHasChangedChild( false ); + setDocumentChanged( false ); + + m_inStyleRecalc = false; +} + +void DocumentImpl::updateRendering() +{ + if (!hasChangedChild()) return; + +// TQTime time; +// time.start(); +// kdDebug() << "UPDATERENDERING: "<")); + } + m_tokenizer->write(text, false); +} + +void DocumentImpl::writeln( const DOMString &text ) +{ + write(text); + write(DOMString("\n")); +} + +void DocumentImpl::finishParsing ( ) +{ + if(m_tokenizer) + m_tokenizer->finish(); +} + +void DocumentImpl::setUserStyleSheet( const TQString& sheet ) +{ + if ( m_usersheet != sheet ) { + m_usersheet = sheet; + updateStyleSelector(); + } +} + +CSSStyleSheetImpl* DocumentImpl::elementSheet() +{ + if (!m_elemSheet) { + m_elemSheet = new CSSStyleSheetImpl(this, baseURL().url() ); + m_elemSheet->ref(); + } + return m_elemSheet; +} + +void DocumentImpl::determineParseMode( const TQString &/*str*/ ) +{ + // For XML documents, use strict parse mode + pMode = Strict; + hMode = XHtml; + kdDebug(6020) << " using strict parseMode" << endl; +} + +NodeImpl *DocumentImpl::nextFocusNode(NodeImpl *fromNode) +{ + unsigned short fromTabIndex; + + if (!fromNode) { + // No starting node supplied; begin with the top of the document + NodeImpl *n; + + int lowestTabIndex = 65535; + for (n = this; n != 0; n = n->traverseNextNode()) { + if (n->isTabFocusable()) { + if ((n->tabIndex() > 0) && (n->tabIndex() < lowestTabIndex)) + lowestTabIndex = n->tabIndex(); + } + } + + if (lowestTabIndex == 65535) + lowestTabIndex = 0; + + // Go to the first node in the document that has the desired tab index + for (n = this; n != 0; n = n->traverseNextNode()) { + if (n->isTabFocusable() && (n->tabIndex() == lowestTabIndex)) + return n; + } + + return 0; + } + else { + fromTabIndex = fromNode->tabIndex(); + } + + if (fromTabIndex == 0) { + // Just need to find the next selectable node after fromNode (in document order) that doesn't have a tab index + NodeImpl *n = fromNode->traverseNextNode(); + while (n && !(n->isTabFocusable() && n->tabIndex() == 0)) + n = n->traverseNextNode(); + return n; + } + else { + // Find the lowest tab index out of all the nodes except fromNode, that is greater than or equal to fromNode's + // tab index. For nodes with the same tab index as fromNode, we are only interested in those that come after + // fromNode in document order. + // If we don't find a suitable tab index, the next focus node will be one with a tab index of 0. + unsigned short lowestSuitableTabIndex = 65535; + NodeImpl *n; + + bool reachedFromNode = false; + for (n = this; n != 0; n = n->traverseNextNode()) { + if (n->isTabFocusable() && + ((reachedFromNode && (n->tabIndex() >= fromTabIndex)) || + (!reachedFromNode && (n->tabIndex() > fromTabIndex))) && + (n->tabIndex() < lowestSuitableTabIndex) && + (n != fromNode)) { + + // We found a selectable node with a tab index at least as high as fromNode's. Keep searching though, + // as there may be another node which has a lower tab index but is still suitable for use. + lowestSuitableTabIndex = n->tabIndex(); + } + + if (n == fromNode) + reachedFromNode = true; + } + + if (lowestSuitableTabIndex == 65535) { + // No next node with a tab index -> just take first node with tab index of 0 + NodeImpl *n = this; + while (n && !(n->isTabFocusable() && n->tabIndex() == 0)) + n = n->traverseNextNode(); + return n; + } + + // Search forwards from fromNode + for (n = fromNode->traverseNextNode(); n != 0; n = n->traverseNextNode()) { + if (n->isTabFocusable() && (n->tabIndex() == lowestSuitableTabIndex)) + return n; + } + + // The next node isn't after fromNode, start from the beginning of the document + for (n = this; n != fromNode; n = n->traverseNextNode()) { + if (n->isTabFocusable() && (n->tabIndex() == lowestSuitableTabIndex)) + return n; + } + + assert(false); // should never get here + return 0; + } +} + +NodeImpl *DocumentImpl::previousFocusNode(NodeImpl *fromNode) +{ + NodeImpl *lastNode = this; + while (lastNode->lastChild()) + lastNode = lastNode->lastChild(); + + if (!fromNode) { + // No starting node supplied; begin with the very last node in the document + NodeImpl *n; + + int highestTabIndex = 0; + for (n = lastNode; n != 0; n = n->traversePreviousNode()) { + if (n->isTabFocusable()) { + if (n->tabIndex() == 0) + return n; + else if (n->tabIndex() > highestTabIndex) + highestTabIndex = n->tabIndex(); + } + } + + // No node with a tab index of 0; just go to the last node with the highest tab index + for (n = lastNode; n != 0; n = n->traversePreviousNode()) { + if (n->isTabFocusable() && (n->tabIndex() == highestTabIndex)) + return n; + } + + return 0; + } + else { + unsigned short fromTabIndex = fromNode->tabIndex(); + + if (fromTabIndex == 0) { + // Find the previous selectable node before fromNode (in document order) that doesn't have a tab index + NodeImpl *n = fromNode->traversePreviousNode(); + while (n && !(n->isTabFocusable() && n->tabIndex() == 0)) + n = n->traversePreviousNode(); + if (n) + return n; + + // No previous nodes with a 0 tab index, go to the last node in the document that has the highest tab index + int highestTabIndex = 0; + for (n = this; n != 0; n = n->traverseNextNode()) { + if (n->isTabFocusable() && (n->tabIndex() > highestTabIndex)) + highestTabIndex = n->tabIndex(); + } + + if (highestTabIndex == 0) + return 0; + + for (n = lastNode; n != 0; n = n->traversePreviousNode()) { + if (n->isTabFocusable() && (n->tabIndex() == highestTabIndex)) + return n; + } + + assert(false); // should never get here + return 0; + } + else { + // Find the lowest tab index out of all the nodes except fromNode, that is less than or equal to fromNode's + // tab index. For nodes with the same tab index as fromNode, we are only interested in those before + // fromNode. + // If we don't find a suitable tab index, then there will be no previous focus node. + unsigned short highestSuitableTabIndex = 0; + NodeImpl *n; + + bool reachedFromNode = false; + for (n = this; n != 0; n = n->traverseNextNode()) { + if (n->isTabFocusable() && + ((!reachedFromNode && (n->tabIndex() <= fromTabIndex)) || + (reachedFromNode && (n->tabIndex() < fromTabIndex))) && + (n->tabIndex() > highestSuitableTabIndex) && + (n != fromNode)) { + + // We found a selectable node with a tab index no higher than fromNode's. Keep searching though, as + // there may be another node which has a higher tab index but is still suitable for use. + highestSuitableTabIndex = n->tabIndex(); + } + + if (n == fromNode) + reachedFromNode = true; + } + + if (highestSuitableTabIndex == 0) { + // No previous node with a tab index. Since the order specified by HTML is nodes with tab index > 0 + // first, this means that there is no previous node. + return 0; + } + + // Search backwards from fromNode + for (n = fromNode->traversePreviousNode(); n != 0; n = n->traversePreviousNode()) { + if (n->isTabFocusable() && (n->tabIndex() == highestSuitableTabIndex)) + return n; + } + // The previous node isn't before fromNode, start from the end of the document + for (n = lastNode; n != fromNode; n = n->traversePreviousNode()) { + if (n->isTabFocusable() && (n->tabIndex() == highestSuitableTabIndex)) + return n; + } + + assert(false); // should never get here + return 0; + } + } +} + +ElementImpl* DocumentImpl::findAccessKeyElement(TQChar c) +{ + c = c.upper(); + for( NodeImpl* n = this; + n != NULL; + n = n->traverseNextNode()) { + if( n->isElementNode()) { + ElementImpl* en = static_cast< ElementImpl* >( n ); + DOMString s = en->getAttribute( ATTR_ACCESSKEY ); + if( s.length() == 1 + && s[ 0 ].upper() == c ) + return en; + } + } + return NULL; +} + +int DocumentImpl::nodeAbsIndex(NodeImpl *node) +{ + assert(node->getDocument() == this); + + int absIndex = 0; + for (NodeImpl *n = node; n && n != this; n = n->traversePreviousNode()) + absIndex++; + return absIndex; +} + +NodeImpl *DocumentImpl::nodeWithAbsIndex(int absIndex) +{ + NodeImpl *n = this; + for (int i = 0; n && (i < absIndex); i++) { + n = n->traverseNextNode(); + } + return n; +} + +void DocumentImpl::processHttpEquiv(const DOMString &equiv, const DOMString &content) +{ + assert(!equiv.isNull() && !content.isNull()); + + KHTMLView *v = getDocument()->view(); + + if(strcasecmp(equiv, "refresh") == 0 && v && v->part()->metaRefreshEnabled()) + { + // get delay and url + TQString str = content.string().stripWhiteSpace(); + int pos = str.find(TQRegExp("[;,]")); + if ( pos == -1 ) + pos = str.find(TQRegExp("[ \t]")); + + bool ok = false; + int delay = kMax( 0, content.implementation()->toInt(&ok) ); + if ( !ok && str.length() && str[0] == '.' ) + ok = true; + + if (pos == -1) // There can be no url (David) + { + if(ok) + v->part()->scheduleRedirection(delay, v->part()->url().url() ); + } else { + pos++; + while(pos < (int)str.length() && str[pos].isSpace()) pos++; + str = str.mid(pos); + if(str.find("url", 0, false ) == 0) str = str.mid(3); + str = str.stripWhiteSpace(); + if ( str.length() && str[0] == '=' ) str = str.mid( 1 ).stripWhiteSpace(); + while(str.length() && + (str[str.length()-1] == ';' || str[str.length()-1] == ',')) + str.setLength(str.length()-1); + str = parseURL( DOMString(str) ).string(); + TQString newURL = getDocument()->completeURL( str ); + if ( ok ) + v->part()->scheduleRedirection(delay, getDocument()->completeURL( str ), delay < 2 || newURL == URL().url()); + } + } + else if(strcasecmp(equiv, "expires") == 0) + { + bool relative = false; + TQString str = content.string().stripWhiteSpace(); + time_t expire_date = KRFCDate::parseDate(str); + if (!expire_date) + { + expire_date = str.toULong(); + relative = true; + } + if (!expire_date) + expire_date = 1; // expire now + if (m_docLoader) + m_docLoader->setExpireDate(expire_date, relative); + } + else if(v && (strcasecmp(equiv, "pragma") == 0 || strcasecmp(equiv, "cache-control") == 0)) + { + TQString str = content.string().lower().stripWhiteSpace(); + KURL url = v->part()->url(); + if ((str == "no-cache") && url.protocol().startsWith("http")) + { + TDEIO::http_update_cache(url, true, 0); + } + } + else if( (strcasecmp(equiv, "set-cookie") == 0)) + { + // ### make setCookie work on XML documents too; e.g. in case of + HTMLDocumentImpl *d = static_cast(this); + d->setCookie(content); + } + else if (strcasecmp(equiv, "default-style") == 0) { + // HTML 4.0 14.3.2 + // http://www.hixie.ch/tests/evil/css/import/main/preferred.html + m_preferredStylesheetSet = content; + updateStyleSelector(); + } + else if (strcasecmp(equiv, "content-language") == 0) { + m_contentLanguage = content.string(); + } +} + +bool DocumentImpl::prepareMouseEvent( bool readonly, int _x, int _y, MouseEvent *ev ) +{ + if ( m_render ) { + assert(m_render->isCanvas()); + RenderObject::NodeInfo renderInfo(readonly, ev->type == MousePress); + bool isInside = m_render->layer()->nodeAtPoint(renderInfo, _x, _y); + ev->innerNode = renderInfo.innerNode(); + ev->innerNonSharedNode = renderInfo.innerNonSharedNode(); + + if (renderInfo.URLElement()) { + assert(renderInfo.URLElement()->isElementNode()); + //tqDebug("urlnode: %s (%d)", getTagName(renderInfo.URLElement()->id()).string().latin1(), renderInfo.URLElement()->id()); + + ElementImpl* e = static_cast(renderInfo.URLElement()); + DOMString href = tdehtml::parseURL(e->getAttribute(ATTR_HREF)); + DOMString target = e->getAttribute(ATTR_TARGET); + + if (!target.isNull() && !href.isNull()) { + ev->target = target; + ev->url = href; + } + else + ev->url = href; + } + + if (!readonly) + updateRendering(); + + return isInside; + } + + + return false; +} + + +// DOM Section 1.1.1 +bool DocumentImpl::childTypeAllowed( unsigned short type ) +{ + switch (type) { + case Node::ATTRIBUTE_NODE: + case Node::CDATA_SECTION_NODE: + case Node::DOCUMENT_FRAGMENT_NODE: + case Node::DOCUMENT_NODE: + case Node::ENTITY_NODE: + case Node::ENTITY_REFERENCE_NODE: + case Node::NOTATION_NODE: + case Node::TEXT_NODE: +// case Node::XPATH_NAMESPACE_NODE: + return false; + case Node::COMMENT_NODE: + case Node::PROCESSING_INSTRUCTION_NODE: + return true; + case Node::DOCUMENT_TYPE_NODE: + case Node::ELEMENT_NODE: + // Documents may contain no more than one of each of these. + // (One Element and one DocumentType.) + for (NodeImpl* c = firstChild(); c; c = c->nextSibling()) + if (c->nodeType() == type) + return false; + return true; + } + return false; +} + +NodeImpl *DocumentImpl::cloneNode ( bool /*deep*/ ) +{ + // Spec says cloning Document nodes is "implementation dependent" + // so we do not support it... + return 0; +} + + +typedef const char* (*NameLookupFunction)(unsigned short id); +typedef int (*IdLookupFunction)(const char *tagStr, int len); + +NodeImpl::Id DocumentImpl::getId( NodeImpl::IdType _type, DOMStringImpl* _nsURI, DOMStringImpl *_prefix, + DOMStringImpl *_name, bool readonly, bool /*lookupHTML*/, int *pExceptioncode) +{ + /*kdDebug() << "DocumentImpl::getId( type: " << _type << ", uri: " << DOMString(_nsURI).string() + << ", prefix: " << DOMString(_prefix).string() << ", name: " << DOMString(_name).string() + << ", readonly: " << readonly + << ", lookupHTML: " << lookupHTML + << ", exceptions: " << (pExceptioncode ? "yes" : "no") + << " )" << endl;*/ + + if(!_name) return 0; + IdNameMapping *map; + IdLookupFunction lookup; + + switch (_type) { + case NodeImpl::ElementId: + map = m_elementMap; + lookup = getTagID; + break; + case NodeImpl::AttributeId: + map = m_attrMap; + lookup = getAttrID; + break; + case NodeImpl::NamespaceId: + if( strcasecmp(_name, XHTML_NAMESPACE) == 0) + return xhtmlNamespace; + if( _name->l == 0) + return emptyNamespace; + // defaultNamespace handled by "if (!_name) return 0" + map = m_namespaceMap; + lookup = 0; + break; + default: + return 0; + } + // Names and attributes with "" + if (_name->l == 0) return 0; + + NodeImpl::Id id, nsid = 0; + TQConstString n(_name->s, _name->l); + bool cs = true; // case sensitive + if (_type != NodeImpl::NamespaceId) { + if (_nsURI) + nsid = getId( NodeImpl::NamespaceId, 0, 0, _nsURI, false, false, 0 ) << 16; + + // Each document maintains a mapping of tag name -> id for every tag name encountered + // in the document. + cs = (htmlMode() == XHtml) || (_nsURI && _type != NodeImpl::AttributeId); + + // First see if it's a HTML element name + // xhtml is lower case - case sensitive, easy to implement + if ( cs && (id = lookup(n.string().ascii(), _name->l)) ) { + map->addAlias(_prefix, _name, cs, id); + return nsid + id; + } + // compatibility: upper case - case insensitive + if ( !cs && (id = lookup(n.string().lower().ascii(), _name->l )) ) { + map->addAlias(_prefix, _name, cs, id); + return nsid + id; + } + } + + // Look in the names array for the name + // compatibility mode has to lookup upper case + TQString name = cs ? n.string() : n.string().upper(); + + if (!_nsURI) { + id = (NodeImpl::Id)(long) map->ids.find( name ); + if (!id && _type != NodeImpl::NamespaceId) { + id = (NodeImpl::Id)(long) map->ids.find( "aliases: " + name ); + } + } else { + id = (NodeImpl::Id)(long) map->ids.find( name ); + if (!readonly && id && _prefix && _prefix->l) { + // we were called in registration mode... check if the alias exists + TQConstString px( _prefix->s, _prefix->l ); + TQString qn("aliases: " + (cs ? px.string() : px.string().upper()) + ":" + name); + if (!map->ids.find( qn )) { + map->ids.insert( qn, (void*)id ); + } + } + } + + if (id) return nsid + id; + + // unknown + if (readonly) return 0; + + if ( pExceptioncode && _type != NodeImpl::NamespaceId && !Element::tdehtmlValidQualifiedName(_name)) { + *pExceptioncode = DOMException::INVALID_CHARACTER_ERR; + return 0; + } + + // Name not found, so let's add it + NodeImpl::Id cid = map->count++ + map->idStart; + map->names.insert( cid, _name ); + _name->ref(); + + map->ids.insert( name, (void*)cid ); + + // and register an alias if needed for DOM1 methods compatibility + map->addAlias(_prefix, _name, cs, cid); + + return nsid + cid; + } + +NodeImpl::Id DocumentImpl::getId( NodeImpl::IdType _type, DOMStringImpl *_nodeName, bool readonly, bool lookupHTML, int *pExceptioncode) +{ + return getId(_type, 0, 0, _nodeName, readonly, lookupHTML, pExceptioncode); +} + +DOMString DocumentImpl::getName( NodeImpl::IdType _type, NodeImpl::Id _id ) const +{ + IdNameMapping *map; + NameLookupFunction lookup; + bool hasNS = (namespacePart(_id) != defaultNamespace); + switch (_type) { + case NodeImpl::ElementId: + map = m_elementMap; + lookup = getTagName; + break; + case NodeImpl::AttributeId: + map = m_attrMap; + lookup = getAttrName; + break; + case NodeImpl::NamespaceId: + if( _id == xhtmlNamespace ) + return XHTML_NAMESPACE; + else + if( _id == emptyNamespace ) + return DOMString(""); + else + if ( _id == defaultNamespace ) + return DOMString(); + map = m_namespaceMap; + lookup = 0; + break; + default: + return DOMString();; + } + _id = localNamePart(_id) ; + if (_id >= map->idStart) { + return map->names[_id]; + } + else if (lookup) { + // ### put them in a cache + if (hasNS) + return DOMString(lookup(_id)).lower(); + else + return lookup(_id); + } else + return DOMString(); +} + +// This method is called whenever a top-level stylesheet has finished loading. +void DocumentImpl::styleSheetLoaded() +{ + // Make sure we knew this sheet was pending, and that our count isn't out of sync. + assert(m_pendingStylesheets > 0); + + m_pendingStylesheets--; + updateStyleSelector(); +} + +DOMString DocumentImpl::selectedStylesheetSet() const +{ + if (!view()) return DOMString(); + + return view()->part()->d->m_sheetUsed; +} + +void DocumentImpl::setSelectedStylesheetSet(const DOMString& s) +{ + // this code is evil + if (view() && view()->part()->d->m_sheetUsed != s.string()) { + view()->part()->d->m_sheetUsed = s.string(); + updateStyleSelector(); + } +} + +void DocumentImpl::addStyleSheet(StyleSheetImpl *sheet, int *exceptioncode) +{ + int excode = 0; + + if (!m_addedStyleSheets) { + m_addedStyleSheets = new StyleSheetListImpl; + m_addedStyleSheets->ref(); + } + + m_addedStyleSheets->add(sheet); + if (sheet->isCSSStyleSheet()) updateStyleSelector(); + + if (exceptioncode) *exceptioncode = excode; +} + +void DocumentImpl::removeStyleSheet(StyleSheetImpl *sheet, int *exceptioncode) +{ + int excode = 0; + bool removed = false; + bool is_css = sheet->isCSSStyleSheet(); + + if (m_addedStyleSheets) { + bool in_main_list = !sheet->hasOneRef(); + removed = m_addedStyleSheets->styleSheets.removeRef(sheet); + sheet->deref(); + + if (m_addedStyleSheets->styleSheets.count() == 0) { + bool reset = m_addedStyleSheets->hasOneRef(); + m_addedStyleSheets->deref(); + if (reset) m_addedStyleSheets = 0; + } + + // remove from main list, too + if (in_main_list) m_styleSheets->remove(sheet); + } + + if (removed) { + if (is_css) updateStyleSelector(); + } else + excode = DOMException::NOT_FOUND_ERR; + + if (exceptioncode) *exceptioncode = excode; +} + +void DocumentImpl::updateStyleSelector(bool shallow) +{ +// kdDebug() << "PENDING " << m_pendingStylesheets << endl; + + // Don't bother updating, since we haven't loaded all our style info yet. + if (m_pendingStylesheets > 0) + return; + + if (shallow) + rebuildStyleSelector(); + else + recalcStyleSelector(); + recalcStyle(Force); +#if 0 + + m_styleSelectorDirty = true; +#endif + if ( renderer() ) + renderer()->setNeedsLayoutAndMinMaxRecalc(); +} + +void DocumentImpl::recalcStyleSelector() +{ + if ( !m_render || !attached() ) return; + + assert(m_pendingStylesheets==0); + + TQPtrList oldStyleSheets = m_styleSheets->styleSheets; + m_styleSheets->styleSheets.clear(); + TQString sheetUsed = view() ? view()->part()->d->m_sheetUsed.replace("&&", "&") : TQString(); + bool autoselect = sheetUsed.isEmpty(); + if (autoselect && !m_preferredStylesheetSet.isEmpty()) + sheetUsed = m_preferredStylesheetSet.string(); + NodeImpl *n; + for (int i=0 ; i<2 ; i++) { + m_availableSheets.clear(); + m_availableSheets << i18n("Basic Page Style"); + bool canResetSheet = false; + + for (n = this; n; n = n->traverseNextNode()) { + StyleSheetImpl *sheet = 0; + + if (n->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) + { + // Processing instruction (XML documents only) + ProcessingInstructionImpl* pi = static_cast(n); + sheet = pi->sheet(); + if (!sheet && !pi->localHref().isEmpty()) + { + // Processing instruction with reference to an element in this document - e.g. + // , with the element + // heading { color: red; } at some location in + // the document + ElementImpl* elem = getElementById(pi->localHref()); + if (elem) { + DOMString sheetText(""); + NodeImpl *c; + for (c = elem->firstChild(); c; c = c->nextSibling()) { + if (c->nodeType() == Node::TEXT_NODE || c->nodeType() == Node::CDATA_SECTION_NODE) + sheetText += c->nodeValue(); + } + + CSSStyleSheetImpl *cssSheet = new CSSStyleSheetImpl(this); + cssSheet->parseString(sheetText); + pi->setStyleSheet(cssSheet); + sheet = cssSheet; + } + } + + } + else if (n->isHTMLElement() && ( n->id() == ID_LINK || n->id() == ID_STYLE) ) { + TQString title; + if ( n->id() == ID_LINK ) { + HTMLLinkElementImpl* l = static_cast(n); + if (l->isCSSStyleSheet()) { + sheet = l->sheet(); + + if (sheet || l->isLoading() || l->isAlternate() ) + title = l->getAttribute(ATTR_TITLE).string(); + + if ((autoselect || title != sheetUsed) && l->isDisabled()) { + sheet = 0; + } else if (!title.isEmpty() && !l->isAlternate() && sheetUsed.isEmpty()) { + sheetUsed = title; + l->setDisabled(false); + } + } + } + else { + //