diff options
Diffstat (limited to 'khtml/xml/dom_nodeimpl.cpp')
-rw-r--r-- | khtml/xml/dom_nodeimpl.cpp | 2068 |
1 files changed, 0 insertions, 2068 deletions
diff --git a/khtml/xml/dom_nodeimpl.cpp b/khtml/xml/dom_nodeimpl.cpp deleted file mode 100644 index 5febe695e..000000000 --- a/khtml/xml/dom_nodeimpl.cpp +++ /dev/null @@ -1,2068 +0,0 @@ -/* - * 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) 2003-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 "misc/htmlattrs.h" -#include "misc/htmltags.h" -#include "xml/dom_elementimpl.h" -#include "xml/dom_textimpl.h" -#include "xml/dom2_eventsimpl.h" -#include "xml/dom_docimpl.h" -#include "xml/dom_nodeimpl.h" -#include "xml/dom_restyler.h" - -#include <kglobal.h> -#include <kdebug.h> - -#include "rendering/render_text.h" -#include "rendering/render_flow.h" -#include "rendering/render_line.h" - -#include "ecma/kjs_proxy.h" -#include "khtmlview.h" -#include "khtml_part.h" -#include "dom_nodeimpl.h" - -// from khtml_caret_p.h -namespace khtml { -void /*KDE_NO_EXPORT*/ mapDOMPosToRenderPos(DOM::NodeImpl *node, long offset, - khtml::RenderObject *&r, long &r_ofs, bool &outside, bool &outsideEnd); -} - -using namespace DOM; -using namespace khtml; - -NodeImpl::NodeImpl(DocumentImpl *doc) - : m_document(doc), - m_previous(0), - m_next(0), - m_render(0), - m_tabIndex( 0 ), - m_hasId( false ), - m_attached(false), - m_closed(false), - m_changed( false ), - m_hasChangedChild( false ), - m_changedAscendentAttribute( false ), - m_inDocument( false ), - m_hasAnchor( false ), - m_specified( false ), - m_hovered( false ), - m_focused( false ), - m_active( false ), - m_implicit( false ), - m_htmlCompat( false ), - m_hasClassList( false ), - m_hasClass( false ) -{ -} - -NodeImpl::~NodeImpl() -{ - if (m_render) - detach(); - if (m_previous) - m_previous->setNextSibling(0); - if (m_next) - m_next->setPreviousSibling(0); -} - -DOMString NodeImpl::nodeValue() const -{ - return DOMString(); -} - -void NodeImpl::setNodeValue( const DOMString &/*_nodeValue*/, int &/*exceptioncode*/ ) -{ - // by default nodeValue is null, so setting it has no effect - // don't throw NO_MODIFICATION_ALLOWED_ERR from here, DOMTS-Core-Level1's hc_nodevalue03 - // (createEntityReference().setNodeValue())) says it would be wrong. - // This must be done by subclasses instead. -} - -DOMString NodeImpl::nodeName() const -{ - return DOMString(); -} - -unsigned short NodeImpl::nodeType() const -{ - return 0; -} - -NodeListImpl *NodeImpl::childNodes() -{ - return new ChildNodeListImpl(this); -} - -NodeImpl *NodeImpl::firstChild() const -{ - return 0; -} - -NodeImpl *NodeImpl::lastChild() const -{ - return 0; -} - -NodeImpl *NodeImpl::insertBefore( NodeImpl *, NodeImpl *, int &exceptioncode ) -{ - exceptioncode = DOMException::HIERARCHY_REQUEST_ERR; - return 0; -} - -void NodeImpl::replaceChild( NodeImpl *, NodeImpl *, int &exceptioncode ) -{ - exceptioncode = DOMException::HIERARCHY_REQUEST_ERR; -} - -void NodeImpl::removeChild( NodeImpl *, int &exceptioncode ) -{ - exceptioncode = DOMException::NOT_FOUND_ERR; -} - -NodeImpl *NodeImpl::appendChild( NodeImpl *, int &exceptioncode ) -{ - exceptioncode = DOMException::HIERARCHY_REQUEST_ERR; - return 0; -} - -bool NodeImpl::hasChildNodes( ) const -{ - return false; -} - -void NodeImpl::normalize () -{ - // ### normalize attributes? (when we store attributes using child nodes) - int exceptioncode = 0; - NodeImpl *child = firstChild(); - - // Recursively go through the subtree beneath us, normalizing all nodes. In the case - // where there are two adjacent text nodes, they are merged together - while (child) { - NodeImpl *nextChild = child->nextSibling(); - - if (nextChild && child->nodeType() == Node::TEXT_NODE && nextChild->nodeType() == Node::TEXT_NODE) { - // Current child and the next one are both text nodes... merge them - TextImpl *currentText = static_cast<TextImpl*>(child); - TextImpl *nextText = static_cast<TextImpl*>(nextChild); - - currentText->appendData(nextText->data(),exceptioncode); - if (exceptioncode) - return; - - removeChild(nextChild,exceptioncode); - if (exceptioncode) - return; - } - else { - child->normalize(); - child = nextChild; - } - } -} - -DOMString NodeImpl::prefix() const -{ - // For nodes other than elements and attributes, the prefix is always null - return DOMString(); -} - -DOMString NodeImpl::namespaceURI() const -{ - return DOMString(); -} - -void NodeImpl::setPrefix(const DOMString &/*_prefix*/, int &exceptioncode ) -{ - // The spec says that for nodes other than elements and attributes, prefix is always null. - // It does not say what to do when the user tries to set the prefix on another type of - // node, however mozilla throws a NAMESPACE_ERR exception - exceptioncode = DOMException::NAMESPACE_ERR; -} - -DOMString NodeImpl::localName() const -{ - return DOMString(); -} - -void NodeImpl::setFirstChild(NodeImpl *) -{ -} - -void NodeImpl::setLastChild(NodeImpl *) -{ -} - -NodeImpl *NodeImpl::addChild(NodeImpl *) -{ - return 0; -} - -void NodeImpl::getCaret(int offset, bool override, int &_x, int &_y, int &width, int &height) -{ - if (m_render) { - RenderObject *r; - long r_ofs; - bool outside, outsideEnd; -#if 0 -kdDebug(6200) << "getCaret: node " << this << " " << nodeName().string() << " offset: " << offset << endl; -#endif - mapDOMPosToRenderPos(this, offset, r, r_ofs, outside, outsideEnd); -#if 0 -kdDebug(6200) << "getCaret: r " << r << " " << (r?r->renderName():TQString::null) << " r_ofs: " << r_ofs << " outside " << outside << " outsideEnd " << outsideEnd << endl; -#endif - if (r) { - r->caretPos(r_ofs, override*RenderObject::CFOverride - + outside*RenderObject::CFOutside - + outsideEnd*RenderObject::CFOutsideEnd, _x, _y, width, height); - } else - _x = _y = height = -1, width = 1; - } else _x = _y = height = -1, width = 1; -} - -TQRect NodeImpl::getRect() const -{ - int _x, _y; - if(m_render && m_render->absolutePosition(_x, _y)) - return TQRect( _x + m_render->inlineXPos(), _y + m_render->inlineYPos(), - m_render->width(), m_render->height() + renderer()->borderTopExtra() + renderer()->borderBottomExtra() ); - - return TQRect(); -} - -void NodeImpl::setChanged(bool b) -{ - if (b && !attached()) // changed compared to what? - return; - - m_changed = b; - if ( b ) { - NodeImpl *p = parentNode(); - while ( p ) { - p->setHasChangedChild( true ); - p = p->parentNode(); - } - getDocument()->setDocumentChanged(); - } -} - -bool NodeImpl::isInline() const -{ - if (m_render) return m_render->style()->display() == khtml::INLINE; - return !isElementNode(); -} - - -unsigned long NodeImpl::nodeIndex() const -{ - NodeImpl *_tempNode = previousSibling(); - unsigned long count=0; - for( count=0; _tempNode; count++ ) - _tempNode = _tempNode->previousSibling(); - return count; -} - -void NodeImpl::addEventListener(int id, EventListener *listener, const bool useCapture) -{ - switch (id) { - case EventImpl::DOMSUBTREEMODIFIED_EVENT: - getDocument()->addListenerType(DocumentImpl::DOMSUBTREEMODIFIED_LISTENER); - break; - case EventImpl::DOMNODEINSERTED_EVENT: - getDocument()->addListenerType(DocumentImpl::DOMNODEINSERTED_LISTENER); - break; - case EventImpl::DOMNODEREMOVED_EVENT: - getDocument()->addListenerType(DocumentImpl::DOMNODEREMOVED_LISTENER); - break; - case EventImpl::DOMNODEREMOVEDFROMDOCUMENT_EVENT: - getDocument()->addListenerType(DocumentImpl::DOMNODEREMOVEDFROMDOCUMENT_LISTENER); - break; - case EventImpl::DOMNODEINSERTEDINTODOCUMENT_EVENT: - getDocument()->addListenerType(DocumentImpl::DOMNODEINSERTEDINTODOCUMENT_LISTENER); - break; - case EventImpl::DOMATTRMODIFIED_EVENT: - getDocument()->addListenerType(DocumentImpl::DOMATTRMODIFIED_LISTENER); - break; - case EventImpl::DOMCHARACTERDATAMODIFIED_EVENT: - getDocument()->addListenerType(DocumentImpl::DOMCHARACTERDATAMODIFIED_LISTENER); - break; - default: - break; - } - - m_regdListeners.addEventListener(id, listener, useCapture); -} - -void NodeImpl::removeEventListener(int id, EventListener *listener, bool useCapture) -{ - m_regdListeners.removeEventListener(id, listener, useCapture); -} - -void NodeImpl::setHTMLEventListener(int id, EventListener *listener) -{ - m_regdListeners.setHTMLEventListener(id, listener); -} - -EventListener *NodeImpl::getHTMLEventListener(int id) -{ - return m_regdListeners.getHTMLEventListener(id); -} - -void NodeImpl::dispatchEvent(EventImpl *evt, int &exceptioncode, bool tempEvent) -{ - evt->setTarget(this); - - // Since event handling code could cause this object to be deleted, grab a reference to the view now - KHTMLView *view = getDocument()->view(); - - dispatchGenericEvent( evt, exceptioncode ); - - // If tempEvent is true, this means that the DOM implementation will not be storing a reference to the event, i.e. - // there is no way to retrieve it from javascript if a script does not already have a reference to it in a variable. - // So there is no need for the interpreter to keep the event in its cache - if (tempEvent && view && view->part() && view->part()->jScript()) - view->part()->jScript()->finishedWithEvent(evt); -} - -void NodeImpl::dispatchGenericEvent( EventImpl *evt, int &/*exceptioncode */) -{ - // ### check that type specified - - // work out what nodes to send event to - TQPtrList<NodeImpl> nodeChain; - NodeImpl *n; - for (n = this; n; n = n->parentNode()) { - n->ref(); - nodeChain.prepend(n); - } - - // trigger any capturing event handlers on our way down - evt->setEventPhase(Event::CAPTURING_PHASE); - TQPtrListIterator<NodeImpl> it(nodeChain); - for (; it.current() && it.current() != this && !evt->propagationStopped(); ++it) { - evt->setCurrentTarget(it.current()); - it.current()->handleLocalEvents(evt,true); - } - - // dispatch to the actual target node - it.toLast(); - NodeImpl* propagationSentinel = 0; - if (!evt->propagationStopped()) { - evt->setEventPhase(Event::AT_TARGET); - evt->setCurrentTarget(it.current()); - it.current()->handleLocalEvents(evt, true); - if (!evt->propagationStopped()) - it.current()->handleLocalEvents(evt,false); - else - propagationSentinel = it.current(); - } - --it; - - if (evt->bubbles()) { - evt->setEventPhase(Event::BUBBLING_PHASE); - for (; it.current() && !evt->propagationStopped(); --it) { - if (evt->propagationStopped()) propagationSentinel = it.current(); - evt->setCurrentTarget(it.current()); - it.current()->handleLocalEvents(evt,false); - } - - // now we call all default event handlers (this is not part of DOM - it is internal to khtml) - evt->setCurrentTarget(0); - evt->setEventPhase(0); // I guess this is correct, the spec does not seem to say - for (it.toLast(); it.current() && it.current() != propagationSentinel && - !evt->defaultPrevented() && !evt->defaultHandled(); --it) - it.current()->defaultEventHandler(evt); - - if (evt->id() == EventImpl::CLICK_EVENT && !evt->defaultPrevented() && - static_cast<MouseEventImpl*>( evt )->button() == 0) // LMB click - dispatchUIEvent(EventImpl::DOMACTIVATE_EVENT, static_cast<UIEventImpl*>(evt)->detail()); - } - - // copy this over into a local variable, as the following deref() calls might cause this to be deleted. - DocumentImpl *doc = m_document.get(); - doc->ref(); - - // deref all nodes in chain - it.toFirst(); - for (; it.current(); ++it) - it.current()->deref(); // this may delete us - - DocumentImpl::updateDocumentsRendering(); - doc->deref(); -} - -bool NodeImpl::dispatchHTMLEvent(int _id, bool canBubbleArg, bool cancelableArg) -{ - int exceptioncode = 0; - EventImpl* const evt = new EventImpl(static_cast<EventImpl::EventId>(_id),canBubbleArg,cancelableArg); - evt->ref(); - dispatchEvent(evt,exceptioncode,true); - bool ret = !evt->defaultPrevented(); - evt->deref(); - return ret; -} - -void NodeImpl::dispatchWindowEvent(int _id, bool canBubbleArg, bool cancelableArg) -{ - int exceptioncode = 0; - EventImpl* const evt = new EventImpl(static_cast<EventImpl::EventId>(_id),canBubbleArg,cancelableArg); - evt->setTarget( 0 ); - evt->ref(); - DocumentImpl *doc = getDocument(); - doc->ref(); - dispatchGenericEvent( evt, exceptioncode ); - if (!evt->defaultPrevented() && doc) - doc->defaultEventHandler(evt); - - if (_id == EventImpl::LOAD_EVENT && !evt->propagationStopped() && doc) { - // For onload events, send them to the enclosing frame only. - // This is a DOM extension and is independent of bubbling/capturing rules of - // the DOM. You send the event only to the enclosing frame. It does not - // bubble through the parent document. - DOM::ElementImpl* elt = doc->ownerElement(); - if (elt && (elt->getDocument()->domain().isNull() || - elt->getDocument()->domain() == doc->domain())) { - // We also do a security check, since we don't want to allow the enclosing - // iframe to see loads of child documents in other domains. - evt->setCurrentTarget(elt); - - // Capturing first. - elt->handleLocalEvents(evt,true); - - // Bubbling second. - if (!evt->propagationStopped()) - elt->handleLocalEvents(evt,false); - } - } - - doc->deref(); - evt->deref(); -} - -void NodeImpl::dispatchMouseEvent(TQMouseEvent *_mouse, int overrideId, int overrideDetail) -{ - bool cancelable = true; - int detail = overrideDetail; // defaults to 0 - EventImpl::EventId evtId = EventImpl::UNKNOWN_EVENT; - if (overrideId) { - evtId = static_cast<EventImpl::EventId>(overrideId); - } - else { - switch (_mouse->type()) { - case TQEvent::MouseButtonPress: - evtId = EventImpl::MOUSEDOWN_EVENT; - break; - case TQEvent::MouseButtonRelease: - evtId = EventImpl::MOUSEUP_EVENT; - break; - case TQEvent::MouseButtonDblClick: - evtId = EventImpl::CLICK_EVENT; - detail = 1; // ### support for multiple double clicks - break; - case TQEvent::MouseMove: - evtId = EventImpl::MOUSEMOVE_EVENT; - cancelable = false; - break; - default: - break; - } - } - if (evtId == EventImpl::UNKNOWN_EVENT) - return; // shouldn't happen - - - int exceptioncode = 0; - int pageX = _mouse->x(); - int pageY = _mouse->y(); - int clientX = pageX; - int clientY = pageY; - if ( getDocument()->view() ) - getDocument()->view()->viewportToContents( clientX, clientY, pageX, pageY ); - - int screenX = _mouse->globalX(); - int screenY = _mouse->globalY(); - - int button = -1; - switch (_mouse->button()) { - case Qt::LeftButton: - button = 0; - break; - case Qt::MidButton: - button = 1; - break; - case Qt::RightButton: - button = 2; - break; - default: - break; - } - bool ctrlKey = (_mouse->state() & TQt::ControlButton); - bool altKey = (_mouse->state() & TQt::AltButton); - bool shiftKey = (_mouse->state() & TQt::ShiftButton); - bool metaKey = false; // ### qt support? - - EventImpl* const evt = new MouseEventImpl(evtId,true,cancelable,getDocument()->defaultView(), - detail,screenX,screenY,clientX,clientY,pageX,pageY,ctrlKey,altKey,shiftKey,metaKey, - button,0); - evt->ref(); - dispatchEvent(evt,exceptioncode,true); - evt->deref(); -} - -void NodeImpl::dispatchUIEvent(int _id, int detail) -{ - assert (!( (_id != EventImpl::DOMFOCUSIN_EVENT && - _id != EventImpl::DOMFOCUSOUT_EVENT && - _id != EventImpl::DOMACTIVATE_EVENT))); - - bool cancelable = false; - if (_id == EventImpl::DOMACTIVATE_EVENT) - cancelable = true; - - int exceptioncode = 0; - UIEventImpl* const evt = new UIEventImpl(static_cast<EventImpl::EventId>(_id),true, - cancelable,getDocument()->defaultView(),detail); - evt->ref(); - dispatchEvent(evt,exceptioncode,true); - evt->deref(); -} - -void NodeImpl::dispatchSubtreeModifiedEvent() -{ - childrenChanged(); - getDocument()->incDOMTreeVersion(); - if (!getDocument()->hasListenerType(DocumentImpl::DOMSUBTREEMODIFIED_LISTENER)) - return; - int exceptioncode = 0; - MutationEventImpl* const evt = new MutationEventImpl(EventImpl::DOMSUBTREEMODIFIED_EVENT,true, - false,0,DOMString(),DOMString(),DOMString(),0); - evt->ref(); - dispatchEvent(evt,exceptioncode,true); - evt->deref(); -} - -bool NodeImpl::dispatchKeyEvent(TQKeyEvent *key, bool keypress) -{ - int exceptioncode = 0; - //kdDebug(6010) << "DOM::NodeImpl: dispatching keyboard event" << endl; - EventImpl* keyEventImpl; - if (keypress) - keyEventImpl = new TextEventImpl(key, getDocument()->defaultView()); - else - keyEventImpl = new KeyboardEventImpl(key, getDocument()->defaultView()); - keyEventImpl->ref(); - dispatchEvent(keyEventImpl,exceptioncode,true); - bool r = keyEventImpl->defaultHandled() || keyEventImpl->defaultPrevented(); - keyEventImpl->deref(); - return r; -} - -void NodeImpl::handleLocalEvents(EventImpl *evt, bool useCapture) -{ - if (!m_regdListeners.listeners) - return; - - Event ev = evt; - // removeEventListener (e.g. called from a JS event listener) might - // invalidate the item after the current iterator (which "it" is pointing to). - // So we make a copy of the list. - TQValueList<RegisteredEventListener> listeners = *m_regdListeners.listeners; - TQValueList<RegisteredEventListener>::iterator it; - for (it = listeners.begin(); it != listeners.end(); ++it) { - //Check whether this got removed...KDE4: use Java-style iterators - if (!m_regdListeners.stillContainsListener(*it)) - continue; - - RegisteredEventListener& current = (*it); - if (current.id == evt->id() && current.useCapture == useCapture) - current.listener->handleEvent(ev); - - // ECMA legacy hack - if (current.useCapture == useCapture && evt->id() == EventImpl::CLICK_EVENT) { - MouseEventImpl* me = static_cast<MouseEventImpl*>(evt); - if (me->button() == 0) { - // To find whether to call onclick or ondblclick, we can't - // * use me->detail(), it's 2 when clicking twice w/o moving, even very slowly - // * use me->qEvent(), it's not available when using initMouseEvent/dispatchEvent - // So we currently store a bool in MouseEventImpl. If anyone needs to trigger - // dblclicks from the DOM API, we'll need a timer here (well in the doc). - if ( ( !me->isDoubleClick() && current.id == EventImpl::KHTML_ECMA_CLICK_EVENT) || - ( me->isDoubleClick() && current.id == EventImpl::KHTML_ECMA_DBLCLICK_EVENT) ) - current.listener->handleEvent(ev); - } - } - } -} - -void NodeImpl::defaultEventHandler(EventImpl *) -{ -} - -unsigned long NodeImpl::childNodeCount() -{ - return 0; -} - -NodeImpl *NodeImpl::childNode(unsigned long /*index*/) -{ - return 0; -} - -NodeImpl *NodeImpl::traverseNextNode(NodeImpl *stayWithin) const -{ - if (firstChild() || stayWithin == this) - return firstChild(); - else if (nextSibling()) - return nextSibling(); - else { - const NodeImpl *n = this; - while (n && !n->nextSibling() && (!stayWithin || n->parentNode() != stayWithin)) - n = n->parentNode(); - if (n) - return n->nextSibling(); - } - return 0; -} - -NodeImpl *NodeImpl::traversePreviousNode() const -{ - if (previousSibling()) { - NodeImpl *n = previousSibling(); - while (n->lastChild()) - n = n->lastChild(); - return n; - } - else if (parentNode()) { - return parentNode(); - } - else { - return 0; - } -} - -void NodeImpl::checkSetPrefix(const DOMString &_prefix, int &exceptioncode) -{ - // Perform error checking as required by spec for setting Node.prefix. Used by - // ElementImpl::setPrefix() and AttrImpl::setPrefix() - - // INVALID_CHARACTER_ERR: Raised if the specified prefix contains an illegal character. - if (!Element::khtmlValidPrefix(_prefix)) { - exceptioncode = DOMException::INVALID_CHARACTER_ERR; - return; - } - - // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. - if (isReadOnly()) { - exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR; - return; - } - - // NAMESPACE_ERR: - Raised if the specified prefix is malformed - // - if the namespaceURI of this node is null, - // - if the specified prefix is "xml" and the namespaceURI of this node is different from - // "http://www.w3.org/XML/1998/namespace", - // - if this node is an attribute and the specified prefix is "xmlns" and - // the namespaceURI of this node is different from "http://www.w3.org/2000/xmlns/", - // - or if this node is an attribute and the qualifiedName of this node is "xmlns" [Namespaces]. - if (Element::khtmlMalformedPrefix(_prefix) || (namespacePart(id()) == defaultNamespace && id() > ID_LAST_TAG) || - (_prefix == "xml" && namespaceURI() != "http://www.w3.org/XML/1998/namespace")) { - exceptioncode = DOMException::NAMESPACE_ERR; - return; - } -} - -void NodeImpl::checkAddChild(NodeImpl *newChild, int &exceptioncode) -{ - // Perform error checking as required by spec for adding a new child. Used by - // appendChild(), replaceChild() and insertBefore() - - // Not mentioned in spec: throw NOT_FOUND_ERR if newChild is null - if (!newChild) { - exceptioncode = DOMException::NOT_FOUND_ERR; - return; - } - - // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly - if (isReadOnly()) { - exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR; - return; - } - - // WRONG_DOCUMENT_ERR: Raised if newChild was created from a different document than the one that - // created this node. - // We assume that if newChild is a DocumentFragment, all children are created from the same document - // as the fragment itself (otherwise they could not have been added as children) - if (newChild->getDocument() != getDocument()) { - exceptioncode = DOMException::WRONG_DOCUMENT_ERR; - return; - } - - // HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not allow children of the type of the - // newChild node, or if the node to append is one of this node's ancestors. - - // check for ancestor/same node - if (isAncestor(newChild)) { - exceptioncode = DOMException::HIERARCHY_REQUEST_ERR; - return; - } - - // check node allowed - if (newChild->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) { - // newChild is a DocumentFragment... check all its children instead of newChild itself - NodeImpl *child; - for (child = newChild->firstChild(); child; child = child->nextSibling()) { - if (!childTypeAllowed(child->nodeType())) { - exceptioncode = DOMException::HIERARCHY_REQUEST_ERR; - return; - } - } - } - else { - // newChild is not a DocumentFragment... check if it's allowed directly - if(!childTypeAllowed(newChild->nodeType())) { - exceptioncode = DOMException::HIERARCHY_REQUEST_ERR; - return; - } - } -} - -bool NodeImpl::isAncestor( NodeImpl *other ) -{ - // Return true if other is the same as this node or an ancestor of it, otherwise false - NodeImpl *n; - for (n = this; n; n = n->parentNode()) { - if (n == other) - return true; - } - return false; -} - -bool NodeImpl::childAllowed( NodeImpl *newChild ) -{ - return childTypeAllowed(newChild->nodeType()); -} - -NodeImpl::StyleChange NodeImpl::diff( khtml::RenderStyle *s1, khtml::RenderStyle *s2 ) -{ - // This method won't work when a style contains noninherited properties with "inherit" value. - StyleChange ch = NoInherit; - - EDisplay display1 = s1 ? s1->display() : NONE; - EDisplay display2 = s2 ? s2->display() : NONE; - EPosition position1 = s1 ? s1->position() : STATIC; - EPosition position2 = s2 ? s2->position() : STATIC; - - if (display1 != display2 || position1 != position2) - ch = Detach; - else if ( !s1 || !s2 ) - ch = Inherit; - else if ( *s1 == *s2 ) - ch = NoChange; - else if (s1->useNormalContent() != s2->useNormalContent()) - ch = Detach; // when we add generated content all children must be detached - else if ( s1->inheritedNotEqual( s2 ) ) - ch = Inherit; - - // Because the first-letter implementation is so f..ked up, the easiest way - // to update first-letter is to remove the entire node and readd it. - if (ch < Detach && pseudoDiff(s1, s2, khtml::RenderStyle::FIRST_LETTER)) - ch = Detach; - // If the other pseudoStyles have changed, we want to return NoInherit - if (ch == NoChange && pseudoDiff(s1, s2, khtml::RenderStyle::BEFORE)) - ch = NoInherit; - if (ch == NoChange && pseudoDiff(s1, s2, khtml::RenderStyle::AFTER)) - ch = NoInherit; - if (ch == NoChange && pseudoDiff(s1, s2, khtml::RenderStyle::MARKER)) - ch = NoInherit; - if (ch == NoChange && pseudoDiff(s1, s2, khtml::RenderStyle::SELECTION)) - ch = NoInherit; - if (ch == NoChange && pseudoDiff(s1, s2, khtml::RenderStyle::FIRST_LINE)) - ch = NoInherit; - - return ch; -} - -bool NodeImpl::pseudoDiff( khtml::RenderStyle *s1, khtml::RenderStyle *s2, unsigned int pid) -{ - khtml::RenderStyle *ps1 = s1 ? s1->getPseudoStyle((khtml::RenderStyle::PseudoId)pid) : 0; - khtml::RenderStyle *ps2 = s2 ? s2->getPseudoStyle((khtml::RenderStyle::PseudoId)pid) : 0; - - if (ps1 == ps2) - return false; - else - if (ps1 && ps2) { - if (*ps1 == *ps2) - return false; - else - return true; - } - else - return true; -} - -void NodeImpl::close() -{ - if (m_render) m_render->close(); - m_closed = true; -} - -void NodeImpl::attach() -{ - assert(!attached()); - assert(!m_render || (m_render->style() && m_render->parent())); - if (m_render) // set states to match node - { - if (closed()) m_render->close(); - if (hovered()) m_render->setMouseInside(); - } - getDocument()->incDOMTreeVersion(); - m_attached = true; -} - -void NodeImpl::detach() -{ -// assert(m_attached); - - if ( m_render ) - m_render->detach(); - - m_render = 0; - getDocument()->incDOMTreeVersion(); - m_attached = false; -} - -bool NodeImpl::maintainsState() -{ - return false; -} - -TQString NodeImpl::state() -{ - return TQString::null; -} - -void NodeImpl::restoreState(const TQString &/*state*/) -{ -} - -void NodeImpl::insertedIntoDocument() -{ - setInDocument(true); -} - -void NodeImpl::removedFromDocument() -{ - setInDocument(false); -} - -void NodeImpl::childrenChanged() -{ - if (parentNode()) - parentNode()->childrenChanged(); -} - -bool NodeImpl::isReadOnly() -{ - // Entity & Entity Reference nodes and their descendants are read-only - NodeImpl *n = this; - while (n) { - if (n->nodeType() == Node::ENTITY_NODE || - n->nodeType() == Node::ENTITY_REFERENCE_NODE) - return true; - n = n->parentNode(); - } - return false; -} - -RenderObject * NodeImpl::previousRenderer() -{ - for (NodeImpl *n = previousSibling(); n; n = n->previousSibling()) { - if (n->renderer()) - return n->renderer(); - } - return 0; -} - -RenderObject * NodeImpl::nextRenderer() -{ - for (NodeImpl *n = nextSibling(); n; n = n->nextSibling()) { - if (n->renderer()) - return n->renderer(); - } - return 0; -} - -void NodeImpl::createRendererIfNeeded() -{ -#ifdef APPLE_CHANGES - if (!getDocument()->shouldCreateRenderers()) - return; -#endif - - assert(!m_render); - - NodeImpl *parent = parentNode(); - assert(parent); - - RenderObject *parentRenderer = parent->renderer(); - if (parentRenderer && parentRenderer->childAllowed()) { - RenderStyle *style = styleForRenderer(parentRenderer); - style->ref(); - if (rendererIsNeeded(style)) { - m_render = createRenderer(getDocument()->renderArena(), style); - m_render->setStyle(style); - parentRenderer->addChild(m_render, nextRenderer()); - } - style->deref(); - } -} - -RenderStyle *NodeImpl::styleForRenderer(RenderObject *parent) -{ - return parent->style(); -} - -bool NodeImpl::rendererIsNeeded(RenderStyle *style) -{ - return (getDocument()->documentElement() == this) || (style->display() != NONE); -} - -RenderObject *NodeImpl::createRenderer(RenderArena* /*arena*/, RenderStyle* /*style*/) -{ - assert(false); - return 0; -} - -bool NodeImpl::contentEditable() const -{ - RenderObject *r = renderer(); - if (!r || !r->style()) return false; - return r->style()->userInput() == UI_ENABLED; -} - -long NodeImpl::minOffset() const -{ - // Arrgh! You'd think *every* offset starts at zero, but loo, - // therefore we need this method - return renderer() ? renderer()->minOffset() : 0; -} - -long NodeImpl::maxOffset() const -{ - return const_cast<NodeImpl *>(this)->childNodeCount(); -// return renderer() ? renderer()->maxOffset() : 1; -} - -DOMStringImpl* NodeImpl::textContent() const -{ - TQString out; - for (NodeImpl *child = firstChild(); child != 0; child = child->nextSibling()) { - short type = child->nodeType(); - if (type != Node::COMMENT_NODE && type != Node::PROCESSING_INSTRUCTION_NODE) { - DOMStringImpl* kidText = child->textContent(); - if (kidText) - out += TQConstString(kidText->s, kidText->l).string(); - delete kidText; - } - } - return new DOMStringImpl(out.unicode(), out.length()); -} - -//------------------------------------------------------------------------- - -NodeBaseImpl::~NodeBaseImpl() -{ - //kdDebug( 6020 ) << "NodeBaseImpl destructor" << endl; - // we have to tell all children, that the parent has died... - NodeImpl *n; - NodeImpl *next; - - for( n = _first; n != 0; n = next ) { - next = n->nextSibling(); - n->setPreviousSibling(0); - n->setNextSibling(0); - n->setParent(0); - if ( !n->refCount() ) - delete n; - } -} - - -NodeImpl *NodeBaseImpl::firstChild() const -{ - return _first; -} - -NodeImpl *NodeBaseImpl::lastChild() const -{ - return _last; -} - -NodeImpl *NodeBaseImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode ) -{ - exceptioncode = 0; - - // insertBefore(...,null) is equivalent to appendChild() - if(!refChild) - return appendChild(newChild, exceptioncode); - - // Make sure adding the new child is ok - checkAddChild(newChild, exceptioncode); - if (exceptioncode) - return 0; - - // NOT_FOUND_ERR: Raised if refChild is not a child of this node - if (refChild->parentNode() != this) { - exceptioncode = DOMException::NOT_FOUND_ERR; - return 0; - } - - bool isFragment = newChild->nodeType() == Node::DOCUMENT_FRAGMENT_NODE; - - // If newChild is a DocumentFragment with no children.... there's nothing to do. - // Just return the document fragment - if (isFragment && !newChild->firstChild()) - return newChild; - - // Now actually add the child(ren) - NodeImpl *nextChild; - NodeImpl *child = isFragment ? newChild->firstChild() : newChild; - - NodeImpl *prev = refChild->previousSibling(); - if ( prev == newChild || refChild == newChild ) // nothing to do - return newChild; - - while (child) { - nextChild = isFragment ? child->nextSibling() : 0; - - // If child is already present in the tree, first remove it - NodeImpl *newParent = child->parentNode(); - - //...guard it in case we need to move it.. - SharedPtr<NodeImpl> guard(child); - - if(newParent) - newParent->removeChild( child, exceptioncode ); - if ( exceptioncode ) - return 0; - - // Add child in the correct position - if (prev) - prev->setNextSibling(child); - else - _first = child; - refChild->setPreviousSibling(child); - child->setParent(this); - child->setPreviousSibling(prev); - child->setNextSibling(refChild); - - // Add child to the rendering tree - // ### should we detach() it first if it's already attached? - if (attached() && !child->attached()) - child->attach(); - - // Dispatch the mutation events - dispatchChildInsertedEvents(child,exceptioncode); - - prev = child; - child = nextChild; - } - - structureChanged(); - - // ### set style in case it's attached - dispatchSubtreeModifiedEvent(); - return newChild; -} - -void NodeBaseImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode ) -{ - exceptioncode = 0; - - if ( oldChild == newChild ) // nothing to do - return; - - // Make sure adding the new child is ok - checkAddChild(newChild, exceptioncode); - if (exceptioncode) - return; - - // NOT_FOUND_ERR: Raised if oldChild is not a child of this node. - if (!oldChild || oldChild->parentNode() != this) { - exceptioncode = DOMException::NOT_FOUND_ERR; - return; - } - - bool isFragment = newChild->nodeType() == Node::DOCUMENT_FRAGMENT_NODE; - NodeImpl *nextChild; - NodeImpl *child = isFragment ? newChild->firstChild() : newChild; - - - // Remove the old child - NodeImpl *prev = oldChild->previousSibling(); - NodeImpl *next = oldChild->nextSibling(); - - removeChild(oldChild, exceptioncode); - if (exceptioncode) - return; - - // Add the new child(ren) - while (child) { - nextChild = isFragment ? child->nextSibling() : 0; - - // If child is already present in the tree, first remove it - NodeImpl *newParent = child->parentNode(); - if ( child == next ) - next = child->nextSibling(); - if ( child == prev ) - prev = child->previousSibling(); - //...guard it in case we need to move it.. - SharedPtr<NodeImpl> guard(child); - if(newParent) - newParent->removeChild( child, exceptioncode ); - if (exceptioncode) - return; - - // Add child in the correct position - if (prev) prev->setNextSibling(child); - if (next) next->setPreviousSibling(child); - if(!prev) _first = child; - if(!next) _last = child; - child->setParent(this); - child->setPreviousSibling(prev); - child->setNextSibling(next); - - // Add child to the rendering tree - // ### should we detach() it first if it's already attached? - if (attached() && !child->attached()) - child->attach(); - - // Dispatch the mutation events - dispatchChildInsertedEvents(child,exceptioncode); - - prev = child; - child = nextChild; - } - - structureChanged(); - - // ### set style in case it's attached - dispatchSubtreeModifiedEvent(); - return; -} - -void NodeBaseImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode ) -{ - exceptioncode = 0; - - // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. - if (isReadOnly()) { - exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR; - return; - } - - // NOT_FOUND_ERR: Raised if oldChild is not a child of this node. - if (!oldChild || oldChild->parentNode() != this) { - exceptioncode = DOMException::NOT_FOUND_ERR; - return; - } - - dispatchChildRemovalEvents(oldChild,exceptioncode); - if (exceptioncode) - return; - - SharedPtr<NodeImpl> memManage(oldChild); //Make sure to free if needed - - // Remove from rendering tree - if (oldChild->attached()) - oldChild->detach(); - - // Remove the child - NodeImpl *prev, *next; - prev = oldChild->previousSibling(); - next = oldChild->nextSibling(); - - if(next) next->setPreviousSibling(prev); - if(prev) prev->setNextSibling(next); - if(_first == oldChild) _first = next; - if(_last == oldChild) _last = prev; - - oldChild->setPreviousSibling(0); - oldChild->setNextSibling(0); - oldChild->setParent(0); - - structureChanged(); - - // Dispatch post-removal mutation events - dispatchSubtreeModifiedEvent(); - - NodeImpl *p = this; - while (p->parentNode()) - p = p->parentNode(); - if (p->nodeType() == Node::DOCUMENT_NODE) { - for (NodeImpl *c = oldChild; c; c = c->traverseNextNode(oldChild)) - c->removedFromDocument(); - } -} - -void NodeBaseImpl::removeChildren() -{ - bool inDoc = inDocument(); - NodeImpl *n, *next; - for( n = _first, _first = 0; n; n = next ) - { - next = n->nextSibling(); - if (n->attached()) - n->detach(); - n->setPreviousSibling(0); - n->setNextSibling(0); - n->setParent(0); - - if ( inDoc ) - for ( NodeImpl* c = n; c; c = c->traverseNextNode( n ) ) - c->removedFromDocument(); - - if( !n->refCount() ) - delete n; - } - _last = 0; -} - - -NodeImpl *NodeBaseImpl::appendChild ( NodeImpl *newChild, int &exceptioncode ) -{ - exceptioncode = 0; - - // Make sure adding the new child is ok - checkAddChild(newChild, exceptioncode); - if (exceptioncode) - return 0; - - if ( newChild == _last ) // nothing to do - return newChild; - - bool isFragment = newChild->nodeType() == Node::DOCUMENT_FRAGMENT_NODE; - - // If newChild is a DocumentFragment with no children.... there's nothing to do. - // Just return the document fragment - if (isFragment && !newChild->firstChild()) - return newChild; - - // Now actually add the child(ren) - NodeImpl *nextChild; - NodeImpl *child = isFragment ? newChild->firstChild() : newChild; - - while (child) { - nextChild = isFragment ? child->nextSibling() : 0; - - // If child is already present in the tree, first remove it - NodeImpl *oldParent = child->parentNode(); - SharedPtr<NodeImpl> guard(child); //Guard in case we move it - if(oldParent) { - oldParent->removeChild( child, exceptioncode ); - if (exceptioncode) - return 0; - } - - // Append child to the end of the list - child->setParent(this); - - if(_last) - { - child->setPreviousSibling(_last); - _last->setNextSibling(child); - _last = child; - } - else - { - _first = _last = child; - } - - // Add child to the rendering tree - // ### should we detach() it first if it's already attached? - if (attached() && !child->attached()) - child->attach(); - - // Dispatch the mutation events - dispatchChildInsertedEvents(child,exceptioncode); - - child = nextChild; - } - - backwardsStructureChanged(); - - // ### set style in case it's attached - dispatchSubtreeModifiedEvent(); - return newChild; -} - -bool NodeBaseImpl::hasChildNodes ( ) const -{ - return _first != 0; -} - -// not part of the DOM -void NodeBaseImpl::setFirstChild(NodeImpl *child) -{ - _first = child; -} - -void NodeBaseImpl::setLastChild(NodeImpl *child) -{ - _last = child; -} - -// check for same source document: -bool NodeBaseImpl::checkSameDocument( NodeImpl *newChild, int &exceptioncode ) -{ - exceptioncode = 0; - DocumentImpl *ownerDocThis = getDocument(); - DocumentImpl *ownerDocNew = newChild->getDocument(); - if(ownerDocThis != ownerDocNew) { - kdDebug(6010)<< "not same document, newChild = " << newChild << "document = " << getDocument() << endl; - exceptioncode = DOMException::WRONG_DOCUMENT_ERR; - return true; - } - return false; -} - -// check for being child: -bool NodeBaseImpl::checkIsChild( NodeImpl *oldChild, int &exceptioncode ) -{ - if(!oldChild || oldChild->parentNode() != this) { - exceptioncode = DOMException::NOT_FOUND_ERR; - return true; - } - return false; -} - -NodeImpl *NodeBaseImpl::addChild(NodeImpl *newChild) -{ - // do not add applyChanges here! This function is only used during parsing - - // short check for consistency with DTD - if(getDocument()->isHTMLDocument() && !childAllowed(newChild)) - { - //kdDebug( 6020 ) << "AddChild failed! id=" << id() << ", child->id=" << newChild->id() << endl; - return 0; - } - - // just add it... - newChild->setParent(this); - - if(_last) - { - newChild->setPreviousSibling(_last); - _last->setNextSibling(newChild); - _last = newChild; - } - else - { - _first = _last = newChild; - } - - if (inDocument()) - newChild->insertedIntoDocument(); - childrenChanged(); - - if(newChild->nodeType() == Node::ELEMENT_NODE) - return newChild; - return this; -} - -void NodeBaseImpl::attach() -{ - NodeImpl *child = _first; - while(child != 0) - { - child->attach(); - child = child->nextSibling(); - } - NodeImpl::attach(); -} - -void NodeBaseImpl::detach() -{ - NodeImpl *child = _first; - while(child != 0) - { - NodeImpl* prev = child; - child = child->nextSibling(); - prev->detach(); - } - NodeImpl::detach(); -} - -void NodeBaseImpl::cloneChildNodes(NodeImpl *clone) -{ - int exceptioncode = 0; - NodeImpl *n; - for(n = firstChild(); n && !exceptioncode; n = n->nextSibling()) - { - clone->appendChild(n->cloneNode(true),exceptioncode); - } -} - -// I don't like this way of implementing the method, but I didn't find any -// other way. Lars -bool NodeBaseImpl::getUpperLeftCorner(int &xPos, int &yPos) const -{ - if (!m_render) - return false; - RenderObject *o = m_render; - xPos = yPos = 0; - if ( !o->isInline() || o->isReplaced() ) { - o->absolutePosition( xPos, yPos ); - return true; - } - - // find the next text/image child, to get a position - while(o) { - if(o->firstChild()) - o = o->firstChild(); - else if(o->nextSibling()) - o = o->nextSibling(); - else { - RenderObject *next = 0; - while(!next) { - o = o->parent(); - if(!o) return false; - next = o->nextSibling(); - } - o = next; - } - if((o->isText() && !o->isBR()) || o->isReplaced()) { - o->container()->absolutePosition( xPos, yPos ); - if (o->isText()) { - xPos += o->inlineXPos(); - yPos += o->inlineYPos(); - } else { - xPos += o->xPos(); - yPos += o->yPos(); - } - return true; - } - } - return true; -} - -bool NodeBaseImpl::getLowerRightCorner(int &xPos, int &yPos) const -{ - if (!m_render) - return false; - - RenderObject *o = m_render; - xPos = yPos = 0; - if (!o->isInline() || o->isReplaced()) - { - o->absolutePosition( xPos, yPos ); - xPos += o->width(); - yPos += o->height() + o->borderTopExtra() + o->borderBottomExtra(); - return true; - } - // find the last text/image child, to get a position - while(o) { - if(o->lastChild()) - o = o->lastChild(); - else if(o->previousSibling()) - o = o->previousSibling(); - else { - RenderObject *prev = 0; - while(!prev) { - o = o->parent(); - if(!o) return false; - prev = o->previousSibling(); - } - o = prev; - } - if((o->isText() && !o->isBR()) || o->isReplaced()) { - o->container()->absolutePosition(xPos, yPos); - if (o->isText()) { - xPos += o->inlineXPos() + o->width(); - yPos += o->inlineYPos() + o->height(); - } else { - xPos += o->xPos() + o->width(); - yPos += o->yPos() + o->height(); - } - return true; - } - } - return true; -} - -void NodeBaseImpl::setFocus(bool received) -{ - if (m_focused == received) return; - - NodeImpl::setFocus(received); - - // note that we need to recalc the style - setChanged(); // *:focus is a default style, so we just assume personal dependency - if (isElementNode()) { - getDocument()->dynamicDomRestyler().restyleDepedent(static_cast<ElementImpl*>(this), OtherStateDependency); - } -} - -void NodeBaseImpl::setActive(bool down) -{ - if (down == active()) return; - - NodeImpl::setActive(down); - - // note that we need to recalc the style - if (isElementNode()) - getDocument()->dynamicDomRestyler().restyleDepedent(static_cast<ElementImpl*>(this), ActiveDependency); -} - -void NodeBaseImpl::setHovered(bool hover) -{ - if (hover == hovered()) return; - - NodeImpl::setHovered(hover); - - // note that we need to recalc the style - if (isElementNode()) - getDocument()->dynamicDomRestyler().restyleDepedent(static_cast<ElementImpl*>(this), HoverDependency); -} - -unsigned long NodeBaseImpl::childNodeCount() -{ - unsigned long count = 0; - NodeImpl *n; - for (n = firstChild(); n; n = n->nextSibling()) - count++; - return count; -} - -NodeImpl *NodeBaseImpl::childNode(unsigned long index) -{ - unsigned long i; - NodeImpl *n = firstChild(); - for (i = 0; n && i < index; i++) - n = n->nextSibling(); - return n; -} - -void NodeBaseImpl::dispatchChildInsertedEvents( NodeImpl *child, int &exceptioncode ) -{ - if (getDocument()->hasListenerType(DocumentImpl::DOMNODEINSERTED_LISTENER)) { - MutationEventImpl* const evt = new MutationEventImpl(EventImpl::DOMNODEINSERTED_EVENT,true,false,this,DOMString(),DOMString(),DOMString(),0); - evt->ref(); - child->dispatchEvent(evt,exceptioncode,true); - evt->deref(); - if (exceptioncode) - return; - } - - // dispatch the DOMNodeInsertedIntoDocument event to all descendants - bool hasInsertedListeners = getDocument()->hasListenerType(DocumentImpl::DOMNODEINSERTEDINTODOCUMENT_LISTENER); - NodeImpl *p = this; - while (p->parentNode()) - p = p->parentNode(); - if (p->nodeType() == Node::DOCUMENT_NODE) { - for (NodeImpl *c = child; c; c = c->traverseNextNode(child)) { - c->insertedIntoDocument(); - - if (hasInsertedListeners) { - MutationEventImpl* const evt = new MutationEventImpl(EventImpl::DOMNODEINSERTEDINTODOCUMENT_EVENT,false,false,0,DOMString(),DOMString(),DOMString(),0); - evt->ref(); - c->dispatchEvent(evt,exceptioncode,true); - evt->deref(); - if (exceptioncode) - return; - } - } - } -} - -void NodeBaseImpl::dispatchChildRemovalEvents( NodeImpl *child, int &exceptioncode ) -{ - // Dispatch pre-removal mutation events - getDocument()->notifyBeforeNodeRemoval(child); // ### use events instead - if (getDocument()->hasListenerType(DocumentImpl::DOMNODEREMOVED_LISTENER)) { - MutationEventImpl* const evt = new MutationEventImpl(EventImpl::DOMNODEREMOVED_EVENT,true,false,this,DOMString(),DOMString(),DOMString(),0); - evt->ref(); - child->dispatchEvent(evt,exceptioncode,true); - evt->deref(); - if (exceptioncode) - return; - } - - bool hasRemovalListeners = getDocument()->hasListenerType(DocumentImpl::DOMNODEREMOVEDFROMDOCUMENT_LISTENER); - - // dispatch the DOMNodeRemovedFromDocument event to all descendants - NodeImpl *p = this; - while (p->parentNode()) - p = p->parentNode(); - if (p->nodeType() == Node::DOCUMENT_NODE) { - for (NodeImpl *c = child; c; c = c->traverseNextNode(child)) { - if (hasRemovalListeners) { - MutationEventImpl* const evt = new MutationEventImpl(EventImpl::DOMNODEREMOVEDFROMDOCUMENT_EVENT,false,false,0,DOMString(),DOMString(),DOMString(),0); - evt->ref(); - c->dispatchEvent(evt,exceptioncode,true); - evt->deref(); - if (exceptioncode) - return; - } - } - } -} - -void NodeBaseImpl::setTextContent( const DOMString &text, int& exceptioncode ) -{ - // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. - if (isReadOnly()) { - exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR; - return; - } - - removeChildren(); - - if ( !text.isEmpty() && !text.isNull() ) { - TextImpl *t = new TextImpl( docPtr(), text.implementation() ); - appendChild( t, exceptioncode ); - } -} - -// --------------------------------------------------------------------------- -NodeImpl *NodeListImpl::item( unsigned long index ) const -{ - unsigned long requestIndex = index; - - m_cache->updateNodeListInfo(m_refNode->getDocument()); - - NodeImpl* n; - bool usedCache = false; - if (m_cache->current.node) { - //Compute distance from the requested index to the cache node - long cacheDist = QABS(long(index) - long(m_cache->position)); - - if (cacheDist < (long)index) { //Closer to the cached position - usedCache = true; - if (index >= m_cache->position) { //Go ahead - unsigned long relIndex = index - m_cache->position; - n = recursiveItem(m_refNode, m_cache->current.node, relIndex); - } else { //Go backwards - unsigned long relIndex = m_cache->position - index; - n = recursiveItemBack(m_refNode, m_cache->current.node, relIndex); - } - } - } - - if (!usedCache) - n = recursiveItem(m_refNode, m_refNode->firstChild(), index); - - //We always update the cache state, to make starting iteration - //where it was left off easy. - m_cache->current.node = n; - m_cache->position = requestIndex; - return n; -} - -unsigned long NodeListImpl::length() const -{ - m_cache->updateNodeListInfo(m_refNode->getDocument()); - if (!m_cache->hasLength) { - m_cache->length = calcLength( m_refNode ); - m_cache->hasLength = true; - } - return m_cache->length; -} - -unsigned long NodeListImpl::calcLength(NodeImpl *start) const -{ - unsigned long len = 0; - for(NodeImpl *n = start->firstChild(); n != 0; n = n->nextSibling()) { - bool recurse = true; - if (nodeMatches(n, recurse)) - len++; - if (recurse) - len+= NodeListImpl::calcLength(n); - } - - return len; -} - -NodeListImpl::NodeListImpl( NodeImpl *n, int type, CacheFactory* factory ) -{ - m_refNode = n; - m_refNode->ref(); - - m_cache = m_refNode->getDocument()->acquireCachedNodeListInfo( - factory ? factory : Cache::make, - n, type ); -} - -NodeListImpl::~NodeListImpl() -{ - m_refNode->getDocument()->releaseCachedNodeListInfo(m_cache); - m_refNode->deref(); -} - - -/** - Next item in the pre-order walk of tree from node, but not going outside - absStart -*/ -static NodeImpl* helperNext(NodeImpl* node, NodeImpl* absStart) -{ - //Walk up until we wind a sibling to go to. - while (!node->nextSibling() && node != absStart) - node = node->parentNode(); - - if (node != absStart) - return node->nextSibling(); - else - return 0; -} - -NodeImpl *NodeListImpl::recursiveItem ( NodeImpl* absStart, NodeImpl *start, unsigned long &offset ) const -{ - for(NodeImpl *n = start; n != 0; n = helperNext(n, absStart)) { - bool recurse = true; - if (nodeMatches(n, recurse)) - if (!offset--) - return n; - - NodeImpl *depthSearch = recurse ? recursiveItem(n, n->firstChild(), offset) : 0; - if (depthSearch) - return depthSearch; - } - - return 0; // no matching node in this subtree -} - - -NodeImpl *NodeListImpl::recursiveItemBack ( NodeImpl* absStart, NodeImpl *start, unsigned long &offset ) const -{ - //### it might be cleaner/faster to split nodeMatches and recursion - //filtering. - bool dummy = true; - NodeImpl* n = start; - - do { - bool recurse = true; - - //Check whether the current node matches. - if (nodeMatches(n, dummy)) - if (!offset--) - return n; - - if (n->previousSibling()) { - //Move to the last node of this whole subtree that we should recurse into - n = n->previousSibling(); - recurse = true; - - while (n->lastChild()) { - (void)nodeMatches(n, recurse); - if (!recurse) - break; //Don't go there - n = n->lastChild(); - } - } else { - //We're done with this whole subtree, so move up - n = n->parentNode(); - } - } - while (n && n != absStart); - - return 0; -} - - -NodeListImpl::Cache::~Cache() -{} - -void NodeListImpl::Cache::clear(DocumentImpl* doc) -{ - hasLength = false; - current.node = 0; - version = doc->domTreeVersion(); -} - -void NodeListImpl::Cache::updateNodeListInfo(DocumentImpl* doc) -{ - //If version doesn't match, clear - if (doc->domTreeVersion() != version) - clear(doc); -} - -ChildNodeListImpl::ChildNodeListImpl( NodeImpl *n ): NodeListImpl(n, CHILD_NODES) -{} - -bool ChildNodeListImpl::nodeMatches( NodeImpl* /*testNode*/, bool& doRecurse ) const -{ - doRecurse = false; - return true; -} - -TagNodeListImpl::TagNodeListImpl( NodeImpl *n, NodeImpl::Id id ) - : NodeListImpl(n, UNCACHEABLE), - m_id(id), - m_namespaceAware(false) -{ - // An id of 0 here means "*" (match all nodes) - m_matchAllNames = (id == 0); - m_matchAllNamespaces = false; -} - -TagNodeListImpl::TagNodeListImpl( NodeImpl *n, const DOMString &namespaceURI, const DOMString &localName ) - : NodeListImpl(n, UNCACHEABLE), - m_id(0), - m_namespaceURI(namespaceURI), - m_localName(localName), - m_namespaceAware(true) -{ - m_matchAllNames = (localName == "*"); - m_matchAllNamespaces = (namespaceURI == "*"); -} - - -bool TagNodeListImpl::nodeMatches( NodeImpl *testNode, bool& /*doRecurse*/ ) const -{ - if ( testNode->nodeType() != Node::ELEMENT_NODE ) return false; - if (m_namespaceAware) - return (m_matchAllNamespaces || testNode->namespaceURI() == m_namespaceURI) && - (m_matchAllNames || testNode->localName() == m_localName); - else { - NodeImpl::Id testId = testNode->id(); - //we have to strip the namespaces if we compare in a namespace unaware fashion - if ( !m_namespaceAware ) testId = localNamePart(testId); - return (m_id == 0 || m_id == testId); - } -} - -NameNodeListImpl::NameNodeListImpl(NodeImpl *n, const DOMString &t ) - : NodeListImpl(n, UNCACHEABLE), - nodeName(t) -{} - -bool NameNodeListImpl::nodeMatches( NodeImpl *testNode, bool& /*doRecurse*/ ) const -{ - if ( testNode->nodeType() != Node::ELEMENT_NODE ) return false; - return static_cast<ElementImpl *>(testNode)->getAttribute(ATTR_NAME) == nodeName; -} - -// --------------------------------------------------------------------------- - -NamedNodeMapImpl::NamedNodeMapImpl() -{ -} - -NamedNodeMapImpl::~NamedNodeMapImpl() -{ -} - -// ---------------------------------------------------------------------------- - -GenericRONamedNodeMapImpl::GenericRONamedNodeMapImpl(DocumentImpl* doc) - : NamedNodeMapImpl() -{ - m_doc = doc; - m_contents = new TQPtrList<NodeImpl>; -} - -GenericRONamedNodeMapImpl::~GenericRONamedNodeMapImpl() -{ - while (!m_contents->isEmpty()) - m_contents->take(0)->deref(); - - delete m_contents; -} - -NodeImpl *GenericRONamedNodeMapImpl::getNamedItem ( NodeImpl::Id id, bool /*nsAware*/, DOMStringImpl* /*qName*/ ) const -{ - // ## do we need namespace support in this class? - TQPtrListIterator<NodeImpl> it(*m_contents); - for (; it.current(); ++it) - if (it.current()->id() == id) - return it.current(); - return 0; -} - -Node GenericRONamedNodeMapImpl::setNamedItem ( NodeImpl* /*arg*/, bool /*nsAware*/, DOMStringImpl* /*qName*/, int &exceptioncode ) -{ - // can't modify this list through standard DOM functions - // NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly - exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR; - return 0; -} - -Node GenericRONamedNodeMapImpl::removeNamedItem ( NodeImpl::Id /*id*/, bool /*nsAware*/, DOMStringImpl* /*qName*/, int &exceptioncode ) -{ - // can't modify this list through standard DOM functions - // NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly - exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR; - return 0; -} - -NodeImpl *GenericRONamedNodeMapImpl::item ( unsigned long index ) const -{ - if (index >= m_contents->count()) - return 0; - - return m_contents->at(index); -} - -unsigned long GenericRONamedNodeMapImpl::length( ) const -{ - return m_contents->count(); -} - -void GenericRONamedNodeMapImpl::addNode(NodeImpl *n) -{ - // The spec says that in the case of duplicates we only keep the first one - if (getNamedItem(n->id(), false, 0)) - return; - - n->ref(); - m_contents->append(n); -} - -NodeImpl::Id GenericRONamedNodeMapImpl::mapId(DOMStringImpl* namespaceURI, - DOMStringImpl* localName, bool readonly) -{ - if (!m_doc) - return 0; - - return m_doc->getId(NodeImpl::ElementId, - namespaceURI, 0, localName, readonly, - false /*don't lookupHTML*/); -} - -// ----------------------------------------------------------------------------- - -void RegisteredListenerList::addEventListener(int id, EventListener *listener, const bool useCapture) -{ - RegisteredEventListener rl(static_cast<EventImpl::EventId>(id),listener,useCapture); - if (!listeners) - listeners = new TQValueList<RegisteredEventListener>; - - // if this id/listener/useCapture combination is already registered, do nothing. - // the DOM2 spec says that "duplicate instances are discarded", and this keeps - // the listener order intact. - TQValueList<RegisteredEventListener>::iterator it; - for (it = listeners->begin(); it != listeners->end(); ++it) - if (*it == rl) - return; - - listeners->append(rl); -} - -void RegisteredListenerList::removeEventListener(int id, EventListener *listener, bool useCapture) -{ - if (!listeners) // nothing to remove - return; - - RegisteredEventListener rl(static_cast<EventImpl::EventId>(id),listener,useCapture); - - TQValueList<RegisteredEventListener>::iterator it; - for (it = listeners->begin(); it != listeners->end(); ++it) - if (*it == rl) { - listeners->remove(it); - return; - } -} - -bool RegisteredListenerList::isHTMLEventListener(EventListener* listener) -{ - return (listener->eventListenerType() == "_khtml_HTMLEventListener"); -} - -void RegisteredListenerList::setHTMLEventListener(int id, EventListener *listener) -{ - if (!listeners) - listeners = new TQValueList<RegisteredEventListener>; - - TQValueList<RegisteredEventListener>::iterator it; - if (!listener) { - for (it = listeners->begin(); it != listeners->end(); ++it) { - if ((*it).id == id && isHTMLEventListener((*it).listener)) { - listeners->remove(it); - break; - } - } - return; - } - - // if this event already has a registered handler, insert the new one in - // place of the old one, to preserve the order. - RegisteredEventListener rl(static_cast<EventImpl::EventId>(id),listener,false); - - int i; - for (i = 0, it = listeners->begin(); it != listeners->end(); ++it, ++i) - if ((*it).id == id && isHTMLEventListener((*it).listener)) { - listeners->insert(it, rl); - listeners->remove(it); - return; - } - - listeners->append(rl); -} - -EventListener *RegisteredListenerList::getHTMLEventListener(int id) -{ - if (!listeners) - return 0; - - TQValueList<RegisteredEventListener>::iterator it; - for (it = listeners->begin(); it != listeners->end(); ++it) - if ((*it).id == id && isHTMLEventListener((*it).listener)) { - return (*it).listener; - } - return 0; -} - -bool RegisteredListenerList::hasEventListener(int id) -{ - if (!listeners) - return false; - - TQValueList<RegisteredEventListener>::iterator it; - for (it = listeners->begin(); it != listeners->end(); ++it) - if ((*it).id == id) - return true; - - return false; -} - -void RegisteredListenerList::clear() -{ - delete listeners; - listeners = 0; -} - -bool RegisteredListenerList::stillContainsListener(const RegisteredEventListener& listener) -{ - if (!listeners) - return false; - return listeners->find(listener) != listeners->end(); -} - -RegisteredListenerList::~RegisteredListenerList() { - delete listeners; listeners = 0; -} |