2 * This file is part of the DOM implementation for KDE.
4 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5 * (C) 1999 Antti Koivisto (koivisto@kde.org)
6 * (C) 2001 Dirk Mueller (mueller@kde.org)
7 * Copyright (C) 2004 Apple Computer, Inc.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
25 #include "xml/dom_nodeimpl.h"
27 #include "dom/dom_exception.h"
28 #include "misc/htmlattrs.h"
29 #include "misc/htmltags.h"
30 #include "xml/dom_elementimpl.h"
31 #include "xml/dom_textimpl.h"
32 #include "xml/dom2_eventsimpl.h"
33 #include "xml/dom_docimpl.h"
34 #include "xml/dom_position.h"
35 #include "xml/dom2_rangeimpl.h"
36 #include "css/csshelper.h"
37 #include "css/cssstyleselector.h"
38 #include "editing/html_interchange.h"
39 #include "editing/selection.h"
44 #include "rendering/render_object.h"
45 #include "rendering/render_text.h"
47 #include "ecma/kjs_binding.h"
48 #include "ecma/kjs_proxy.h"
49 #include "khtmlview.h"
50 #include "khtml_part.h"
55 #include "xbl/xbl_binding_manager.h"
59 #include "KWQAssertions.h"
60 #include "KWQLogging.h"
62 #define ASSERT(assertion) assert(assertion)
63 #define LOG(channel, formatAndArgs...) ((void)0)
67 using namespace khtml;
69 NodeImpl::NodeImpl(DocumentPtr *doc)
82 m_hasChangedChild( false ),
83 m_inDocument( false ),
88 m_styleElement( false ),
95 void NodeImpl::setDocument(DocumentPtr *doc)
109 NodeImpl::~NodeImpl()
113 if (m_regdListeners && !m_regdListeners->isEmpty() && getDocument() && !inDocument())
114 getDocument()->unregisterDisconnectedNodeWithEventListeners(this);
115 delete m_regdListeners;
120 m_previous->setNextSibling(0);
122 m_next->setPreviousSibling(0);
125 DOMString NodeImpl::nodeValue() const
130 void NodeImpl::setNodeValue( const DOMString &/*_nodeValue*/, int &exceptioncode )
132 // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
134 exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
138 // be default nodeValue is null, so setting it has no effect
141 DOMString NodeImpl::nodeName() const
146 unsigned short NodeImpl::nodeType() const
151 NodeListImpl *NodeImpl::childNodes()
153 return new ChildNodeListImpl(this);
156 NodeImpl *NodeImpl::firstChild() const
161 NodeImpl *NodeImpl::lastChild() const
166 NodeImpl *NodeImpl::lastDescendent() const
168 NodeImpl *n = const_cast<NodeImpl *>(this);
169 while (n && n->lastChild())
174 NodeImpl *NodeImpl::insertBefore( NodeImpl *newChild, NodeImpl *, int &exceptioncode )
178 exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
182 NodeImpl *NodeImpl::replaceChild( NodeImpl *newChild, NodeImpl *, int &exceptioncode )
186 exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
190 NodeImpl *NodeImpl::removeChild( NodeImpl *, int &exceptioncode )
192 exceptioncode = DOMException::NOT_FOUND_ERR;
196 NodeImpl *NodeImpl::appendChild( NodeImpl *newChild, int &exceptioncode )
200 exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
204 void NodeImpl::remove(int &exceptioncode)
208 exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
212 parentNode()->removeChild(this, exceptioncode);
215 bool NodeImpl::hasChildNodes( ) const
220 void NodeImpl::normalize ()
222 // ### normalize attributes? (when we store attributes using child nodes)
223 int exceptioncode = 0;
224 NodeImpl *child = firstChild();
226 // Recursively go through the subtree beneath us, normalizing all nodes. In the case
227 // where there are two adjacent text nodes, they are merged together
229 NodeImpl *nextChild = child->nextSibling();
231 if (nextChild && child->nodeType() == Node::TEXT_NODE && nextChild->nodeType() == Node::TEXT_NODE) {
232 // Current child and the next one are both text nodes... merge them
233 TextImpl *currentText = static_cast<TextImpl*>(child);
234 TextImpl *nextText = static_cast<TextImpl*>(nextChild);
236 currentText->appendData(nextText->data(),exceptioncode);
240 removeChild(nextChild,exceptioncode);
251 DOMString NodeImpl::prefix() const
253 // For nodes other than elements and attributes, the prefix is always null
257 void NodeImpl::setPrefix(const DOMString &/*_prefix*/, int &exceptioncode )
259 // The spec says that for nodes other than elements and attributes, prefix is always null.
260 // It does not say what to do when the user tries to set the prefix on another type of
261 // node, however mozilla throws a NAMESPACE_ERR exception
262 exceptioncode = DOMException::NAMESPACE_ERR;
265 DOMString NodeImpl::localName() const
270 void NodeImpl::setFirstChild(NodeImpl *)
274 void NodeImpl::setLastChild(NodeImpl *)
278 NodeImpl *NodeImpl::addChild(NodeImpl *)
283 bool NodeImpl::isContentEditable() const
285 return m_parent ? m_parent->isContentEditable() : false;
288 QRect NodeImpl::getRect() const
291 if(m_render && m_render->absolutePosition(_x, _y))
292 return QRect( _x, _y, m_render->width(), m_render->height() );
297 void NodeImpl::setChanged(bool b)
299 if (b && !attached()) // changed compared to what?
304 NodeImpl *p = parentNode();
306 p->setHasChangedChild( true );
309 getDocument()->setDocumentChanged(true);
313 bool NodeImpl::isInline() const
315 if (m_render) return m_render->style()->display() == khtml::INLINE;
316 return !isElementNode();
319 bool NodeImpl::isFocusable() const
324 bool NodeImpl::isKeyboardFocusable() const
326 return isFocusable();
329 bool NodeImpl::isMouseFocusable() const
331 return isFocusable();
334 unsigned long NodeImpl::nodeIndex() const
336 NodeImpl *_tempNode = previousSibling();
337 unsigned long count=0;
338 for( count=0; _tempNode; count++ )
339 _tempNode = _tempNode->previousSibling();
343 void NodeImpl::addEventListener(int id, EventListener *listener, const bool useCapture)
345 if (getDocument() && !getDocument()->attached())
349 case EventImpl::DOMSUBTREEMODIFIED_EVENT:
350 getDocument()->addListenerType(DocumentImpl::DOMSUBTREEMODIFIED_LISTENER);
352 case EventImpl::DOMNODEINSERTED_EVENT:
353 getDocument()->addListenerType(DocumentImpl::DOMNODEINSERTED_LISTENER);
355 case EventImpl::DOMNODEREMOVED_EVENT:
356 getDocument()->addListenerType(DocumentImpl::DOMNODEREMOVED_LISTENER);
358 case EventImpl::DOMNODEREMOVEDFROMDOCUMENT_EVENT:
359 getDocument()->addListenerType(DocumentImpl::DOMNODEREMOVEDFROMDOCUMENT_LISTENER);
361 case EventImpl::DOMNODEINSERTEDINTODOCUMENT_EVENT:
362 getDocument()->addListenerType(DocumentImpl::DOMNODEINSERTEDINTODOCUMENT_LISTENER);
364 case EventImpl::DOMATTRMODIFIED_EVENT:
365 getDocument()->addListenerType(DocumentImpl::DOMATTRMODIFIED_LISTENER);
367 case EventImpl::DOMCHARACTERDATAMODIFIED_EVENT:
368 getDocument()->addListenerType(DocumentImpl::DOMCHARACTERDATAMODIFIED_LISTENER);
374 RegisteredEventListener *rl = new RegisteredEventListener(static_cast<EventImpl::EventId>(id),listener,useCapture);
375 if (!m_regdListeners) {
376 m_regdListeners = new QPtrList<RegisteredEventListener>;
377 m_regdListeners->setAutoDelete(true);
382 // remove existing identical listener set with identical arguments - the DOM2
383 // spec says that "duplicate instances are discarded" in this case.
384 removeEventListener(id,listener,useCapture);
386 // adding the first one
387 if (m_regdListeners->isEmpty() && getDocument() && !inDocument())
388 getDocument()->registerDisconnectedNodeWithEventListeners(this);
390 m_regdListeners->append(rl);
394 void NodeImpl::removeEventListener(int id, EventListener *listener, bool useCapture)
396 if (!m_regdListeners) // nothing to remove
399 RegisteredEventListener rl(static_cast<EventImpl::EventId>(id),listener,useCapture);
401 QPtrListIterator<RegisteredEventListener> it(*m_regdListeners);
402 for (; it.current(); ++it)
403 if (*(it.current()) == rl) {
404 m_regdListeners->removeRef(it.current());
406 if (m_regdListeners->isEmpty() && getDocument() && !inDocument())
407 getDocument()->unregisterDisconnectedNodeWithEventListeners(this);
412 void NodeImpl::removeAllEventListeners()
414 delete m_regdListeners;
418 void NodeImpl::removeHTMLEventListener(int id)
420 if (!m_regdListeners) // nothing to remove
423 QPtrListIterator<RegisteredEventListener> it(*m_regdListeners);
424 for (; it.current(); ++it)
425 if (it.current()->id == id &&
426 it.current()->listener->eventListenerType() == "_khtml_HTMLEventListener") {
427 m_regdListeners->removeRef(it.current());
429 if (m_regdListeners->isEmpty() && getDocument() && !inDocument())
430 getDocument()->unregisterDisconnectedNodeWithEventListeners(this);
435 void NodeImpl::setHTMLEventListener(int id, EventListener *listener)
437 // in case we already have it, we don't want removeHTMLEventListener to destroy it
440 removeHTMLEventListener(id);
443 addEventListener(id,listener,false);
448 EventListener *NodeImpl::getHTMLEventListener(int id)
450 if (!m_regdListeners)
453 QPtrListIterator<RegisteredEventListener> it(*m_regdListeners);
454 for (; it.current(); ++it)
455 if (it.current()->id == id &&
456 it.current()->listener->eventListenerType() == "_khtml_HTMLEventListener") {
457 return it.current()->listener;
463 bool NodeImpl::dispatchEvent(EventImpl *evt, int &exceptioncode, bool tempEvent)
467 evt->setTarget(this);
469 // We've had at least one report of a crash on a page where document is nil here.
470 // Unfortunately that page no longer exists, but we'll make this code robust against
472 // FIXME: Much code in this class assumes document is non-nil; it would be better to
473 // ensure that document can never be nil.
474 KHTMLPart *part = nil;
475 KHTMLView *view = nil;
477 if (document && document->document()) {
478 part = document->document()->part();
479 view = document->document()->view();
480 // Since event handling code could cause this object to be deleted, grab a reference to the view now
485 bool ret = dispatchGenericEvent( evt, exceptioncode );
487 // If tempEvent is true, this means that the DOM implementation will not be storing a reference to the event, i.e.
488 // there is no way to retrieve it from javascript if a script does not already have a reference to it in a variable.
489 // So there is no need for the interpreter to keep the event in it's cache
490 if (tempEvent && part && part->jScript())
491 part->jScript()->finishedWithEvent(evt);
501 bool NodeImpl::dispatchGenericEvent( EventImpl *evt, int &/*exceptioncode */)
505 // ### check that type specified
507 // work out what nodes to send event to
508 QPtrList<NodeImpl> nodeChain;
510 for (n = this; n; n = n->parentNode()) {
512 nodeChain.prepend(n);
515 // trigger any capturing event handlers on our way down
516 evt->setEventPhase(Event::CAPTURING_PHASE);
517 QPtrListIterator<NodeImpl> it(nodeChain);
518 for (; it.current() && it.current() != this && !evt->propagationStopped(); ++it) {
519 evt->setCurrentTarget(it.current());
520 it.current()->handleLocalEvents(evt,true);
523 // dispatch to the actual target node
525 if (!evt->propagationStopped()) {
526 evt->setEventPhase(Event::AT_TARGET);
527 evt->setCurrentTarget(it.current());
529 // Capturing first. -dwh
530 it.current()->handleLocalEvents(evt,true);
532 // Bubbling second. -dwh
533 if (!evt->propagationStopped())
534 it.current()->handleLocalEvents(evt,false);
538 // ok, now bubble up again (only non-capturing event handlers will be called)
539 // ### recalculate the node chain here? (e.g. if target node moved in document by previous event handlers)
540 // no. the DOM specs says:
541 // The chain of EventTargets from the event target to the top of the tree
542 // is determined before the initial dispatch of the event.
543 // If modifications occur to the tree during event processing,
544 // event flow will proceed based on the initial state of the tree.
546 // since the initial dispatch is before the capturing phase,
547 // there's no need to recalculate the node chain.
550 if (evt->bubbles()) {
551 evt->setEventPhase(Event::BUBBLING_PHASE);
552 for (; it.current() && !evt->propagationStopped() && !evt->getCancelBubble(); --it) {
553 evt->setCurrentTarget(it.current());
554 it.current()->handleLocalEvents(evt,false);
558 evt->setCurrentTarget(0);
559 evt->setEventPhase(0); // I guess this is correct, the spec does not seem to say
560 // anything about the default event handler phase.
563 if (evt->bubbles()) {
564 // now we call all default event handlers (this is not part of DOM - it is internal to khtml)
567 for (; it.current() && !evt->propagationStopped() && !evt->defaultPrevented() && !evt->defaultHandled(); --it)
568 it.current()->defaultEventHandler(evt);
571 // deref all nodes in chain
573 for (; it.current(); ++it)
574 it.current()->deref(); // this may delete us
576 DocumentImpl::updateDocumentsRendering();
578 bool defaultPrevented = evt->defaultPrevented();
582 return !defaultPrevented; // ### what if defaultPrevented was called before dispatchEvent?
585 bool NodeImpl::dispatchHTMLEvent(int _id, bool canBubbleArg, bool cancelableArg)
587 int exceptioncode = 0;
588 EventImpl *evt = new EventImpl(static_cast<EventImpl::EventId>(_id),canBubbleArg,cancelableArg);
589 return dispatchEvent(evt,exceptioncode,true);
592 bool NodeImpl::dispatchWindowEvent(int _id, bool canBubbleArg, bool cancelableArg)
594 int exceptioncode = 0;
595 EventImpl *evt = new EventImpl(static_cast<EventImpl::EventId>(_id),canBubbleArg,cancelableArg);
598 DocumentPtr *doc = document;
600 bool r = dispatchGenericEvent( evt, exceptioncode );
601 if (!evt->defaultPrevented() && doc->document())
602 doc->document()->defaultEventHandler(evt);
604 if (_id == EventImpl::LOAD_EVENT && !evt->propagationStopped() && doc->document()) {
605 // For onload events, send them to the enclosing frame only.
606 // This is a DOM extension and is independent of bubbling/capturing rules of
607 // the DOM. You send the event only to the enclosing frame. It does not
608 // bubble through the parent document.
609 ElementImpl* elt = doc->document()->ownerElement();
610 if (elt && (elt->getDocument()->domain().isNull() ||
611 elt->getDocument()->domain() == doc->document()->domain())) {
612 // We also do a security check, since we don't want to allow the enclosing
613 // iframe to see loads of child documents in other domains.
614 evt->setCurrentTarget(elt);
617 elt->handleLocalEvents(evt,true);
620 if (!evt->propagationStopped())
621 elt->handleLocalEvents(evt,false);
622 r = !evt->defaultPrevented();
632 bool NodeImpl::dispatchMouseEvent(QMouseEvent *_mouse, int overrideId, int overrideDetail)
634 bool cancelable = true;
635 int detail = overrideDetail; // defaults to 0
636 EventImpl::EventId evtId = EventImpl::UNKNOWN_EVENT;
638 evtId = static_cast<EventImpl::EventId>(overrideId);
641 switch (_mouse->type()) {
642 case QEvent::MouseButtonPress:
643 evtId = EventImpl::MOUSEDOWN_EVENT;
645 case QEvent::MouseButtonRelease:
646 evtId = EventImpl::MOUSEUP_EVENT;
648 case QEvent::MouseButtonDblClick:
649 evtId = EventImpl::CLICK_EVENT;
651 detail = _mouse->clickCount();
653 detail = 1; // ### support for multiple double clicks
656 case QEvent::MouseMove:
657 evtId = EventImpl::MOUSEMOVE_EVENT;
664 if (evtId == EventImpl::UNKNOWN_EVENT)
665 return false; // shouldn't happen
668 int exceptioncode = 0;
671 // Careful here - our viewportToContents() converts points from NSEvents, in NSWindow coord system to
672 // our khtmlview's coord system. This works for QMouseEvents coming from Cocoa because those events
673 // hold the location from the NSEvent. The QMouseEvent param here was made by other khtml code, so it
674 // will be a "proper" QT event with coords in terms of this widget. So in WebCore it would never be
675 // right to pass coords from _mouse to viewportToContents().
677 // int clientX, clientY;
678 // viewportToContents(_mouse->x(), _mouse->y(), clientX, clientY);
679 int clientX = _mouse->x(); // ### adjust to be relative to view
680 int clientY = _mouse->y(); // ### adjust to be relative to view
685 KHTMLView *view = document->document()->view();
687 // This gets us as far as NSWindow coords
688 QPoint windowLoc = view->contentsToViewport(_mouse->pos());
689 // Then from NSWindow coords to screen coords
690 QPoint screenLoc = view->viewportToGlobal(windowLoc);
691 screenX = screenLoc.x();
692 screenY = screenLoc.y();
694 screenX = _mouse->x();
695 screenY = _mouse->y();
698 int screenX = _mouse->globalX();
699 int screenY = _mouse->globalY();
703 switch (_mouse->button()) {
710 case Qt::RightButton:
716 bool ctrlKey = (_mouse->state() & Qt::ControlButton);
717 bool altKey = (_mouse->state() & Qt::AltButton);
718 bool shiftKey = (_mouse->state() & Qt::ShiftButton);
719 bool metaKey = (_mouse->state() & Qt::MetaButton);
721 bool swallowEvent = false;
723 EventImpl *me = new MouseEventImpl(evtId,true,cancelable,getDocument()->defaultView(),
724 detail,screenX,screenY,clientX,clientY,ctrlKey,altKey,shiftKey,metaKey,
727 dispatchEvent(me, exceptioncode, true);
728 bool defaultHandled = me->defaultHandled();
729 bool defaultPrevented = me->defaultPrevented();
730 if (defaultHandled || defaultPrevented)
735 // Special case: If it's a click event, we also send the KHTML_CLICK or KHTML_DBLCLICK event. This is not part
736 // of the DOM specs, but is used for compatibility with the traditional onclick="" and ondblclick="" attributes,
737 // as there is no way to tell the difference between single & double clicks using DOM (only the click count is
738 // stored, which is not necessarily the same)
739 if (evtId == EventImpl::CLICK_EVENT) {
740 evtId = EventImpl::KHTML_CLICK_EVENT;
742 me = new MouseEventImpl(EventImpl::KHTML_CLICK_EVENT,
743 true,cancelable,getDocument()->defaultView(),
744 detail,screenX,screenY,clientX,clientY,
745 ctrlKey,altKey,shiftKey,metaKey,
749 me->setDefaultHandled();
750 dispatchEvent(me,exceptioncode,true);
751 if (me->defaultHandled())
752 defaultHandled = true;
753 if (me->defaultPrevented())
754 defaultPrevented = true;
755 if (me->defaultHandled() || me->defaultPrevented())
759 if (_mouse->isDoubleClick()) {
760 me = new MouseEventImpl(EventImpl::KHTML_DBLCLICK_EVENT,
761 true,cancelable,getDocument()->defaultView(),
762 detail,screenX,screenY,clientX,clientY,
763 ctrlKey,altKey,shiftKey,metaKey,
767 me->setDefaultHandled();
768 dispatchEvent(me,exceptioncode,true);
769 if (me->defaultHandled() || me->defaultPrevented())
776 // Also send a DOMActivate event, which causes things like form submissions to occur.
777 if (evtId == EventImpl::KHTML_CLICK_EVENT && !defaultPrevented && !disabled())
778 dispatchUIEvent(EventImpl::DOMACTIVATE_EVENT, detail);
783 bool NodeImpl::dispatchUIEvent(int _id, int detail)
785 assert (!( (_id != EventImpl::DOMFOCUSIN_EVENT &&
786 _id != EventImpl::DOMFOCUSOUT_EVENT &&
787 _id != EventImpl::DOMACTIVATE_EVENT)));
789 bool cancelable = false;
790 if (_id == EventImpl::DOMACTIVATE_EVENT)
793 int exceptioncode = 0;
794 UIEventImpl *evt = new UIEventImpl(static_cast<EventImpl::EventId>(_id),true,
795 cancelable,getDocument()->defaultView(),detail);
796 return dispatchEvent(evt,exceptioncode,true);
799 void NodeImpl::registerNodeList(NodeListImpl *list)
802 m_nodeLists = new QPtrDict<NodeListImpl>;
805 m_nodeLists->insert(list, list);
808 void NodeImpl::unregisterNodeList(NodeListImpl *list)
813 m_nodeLists->remove(list);
816 void NodeImpl::notifyLocalNodeListsSubtreeModified()
821 QPtrDictIterator<NodeListImpl> i(*m_nodeLists);
823 while (NodeListImpl *list = i.current()) {
824 list->rootNodeSubtreeModified();
829 void NodeImpl::notifyNodeListsSubtreeModified()
831 for (NodeImpl *n = this; n; n = n->parentNode()) {
832 n->notifyLocalNodeListsSubtreeModified();
836 bool NodeImpl::dispatchSubtreeModifiedEvent(bool sendChildrenChanged)
838 notifyNodeListsSubtreeModified();
839 if (sendChildrenChanged)
841 if (!getDocument()->hasListenerType(DocumentImpl::DOMSUBTREEMODIFIED_LISTENER))
843 int exceptioncode = 0;
844 return dispatchEvent(new MutationEventImpl(EventImpl::DOMSUBTREEMODIFIED_EVENT,
845 true,false,0,DOMString(),DOMString(),DOMString(),0),exceptioncode,true);
848 bool NodeImpl::dispatchKeyEvent(QKeyEvent *key)
850 int exceptioncode = 0;
851 //kdDebug(6010) << "DOM::NodeImpl: dispatching keyboard event" << endl;
852 KeyboardEventImpl *keyboardEventImpl = new KeyboardEventImpl(key, getDocument()->defaultView());
853 keyboardEventImpl->ref();
854 bool r = dispatchEvent(keyboardEventImpl,exceptioncode,true);
857 // we want to return false if default is prevented (already taken care of)
858 // or if the element is default-handled by the DOM. Otherwise we let it just
859 // let it get handled by AppKit
860 if (keyboardEventImpl->defaultHandled())
862 // the default event handler should accept() the internal QKeyEvent
863 // to prevent the view from further evaluating it.
864 if (!keyboardEventImpl->defaultPrevented() && !keyboardEventImpl->qKeyEvent->isAccepted())
868 keyboardEventImpl->deref();
872 void NodeImpl::handleLocalEvents(EventImpl *evt, bool useCapture)
874 if (!m_regdListeners)
877 if (disabled() && evt->isMouseEvent())
880 QPtrList<RegisteredEventListener> listenersCopy = *m_regdListeners;
881 QPtrListIterator<RegisteredEventListener> it(listenersCopy);
883 for (; it.current(); ++it) {
884 if (it.current()->id == evt->id() && it.current()->useCapture == useCapture)
885 it.current()->listener->handleEvent(ev, false);
890 void NodeImpl::defaultEventHandler(EventImpl *evt)
894 unsigned long NodeImpl::childNodeCount() const
899 NodeImpl *NodeImpl::childNode(unsigned long /*index*/)
904 NodeImpl *NodeImpl::traverseNextNode(const NodeImpl *stayWithin) const
907 assert(!stayWithin || firstChild()->isAncestor(stayWithin));
910 if (this == stayWithin)
913 assert(!stayWithin || nextSibling()->isAncestor(stayWithin));
914 return nextSibling();
916 const NodeImpl *n = this;
917 while (n && !n->nextSibling() && (!stayWithin || n->parentNode() != stayWithin))
920 assert(!stayWithin || !n->nextSibling() || n->nextSibling()->isAncestor(stayWithin));
921 return n->nextSibling();
926 NodeImpl *NodeImpl::traverseNextSibling(const NodeImpl *stayWithin) const
928 if (this == stayWithin)
931 assert(!stayWithin || nextSibling()->isAncestor(stayWithin));
932 return nextSibling();
934 const NodeImpl *n = this;
935 while (n && !n->nextSibling() && (!stayWithin || n->parentNode() != stayWithin))
938 assert(!stayWithin || !n->nextSibling() || n->nextSibling()->isAncestor(stayWithin));
939 return n->nextSibling();
944 NodeImpl *NodeImpl::traversePreviousNode() const
946 if (previousSibling()) {
947 NodeImpl *n = previousSibling();
948 while (n->lastChild())
952 else if (parentNode()) {
960 NodeImpl *NodeImpl::traversePreviousNodePostOrder(const NodeImpl *stayWithin) const
963 assert(!stayWithin || lastChild()->isAncestor(stayWithin));
966 if (this == stayWithin)
968 if (previousSibling()) {
969 assert(!stayWithin || previousSibling()->isAncestor(stayWithin));
970 return previousSibling();
972 const NodeImpl *n = this;
973 while (n && !n->previousSibling() && (!stayWithin || n->parentNode() != stayWithin))
976 assert(!stayWithin || !n->previousSibling() || n->previousSibling()->isAncestor(stayWithin));
977 return n->previousSibling();
982 void NodeImpl::checkSetPrefix(const DOMString &_prefix, int &exceptioncode)
984 // Perform error checking as required by spec for setting Node.prefix. Used by
985 // ElementImpl::setPrefix() and AttrImpl::setPrefix()
987 // INVALID_CHARACTER_ERR: Raised if the specified prefix contains an illegal character.
988 if (!Element::khtmlValidPrefix(_prefix)) {
989 exceptioncode = DOMException::INVALID_CHARACTER_ERR;
993 // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
995 exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
999 // NAMESPACE_ERR: - Raised if the specified prefix is malformed
1000 // - if the namespaceURI of this node is null,
1001 // - if the specified prefix is "xml" and the namespaceURI of this node is different from
1002 // "http://www.w3.org/XML/1998/namespace",
1003 // - if this node is an attribute and the specified prefix is "xmlns" and
1004 // the namespaceURI of this node is different from "http://www.w3.org/2000/xmlns/",
1005 // - or if this node is an attribute and the qualifiedName of this node is "xmlns" [Namespaces].
1006 if (Element::khtmlMalformedPrefix(_prefix) || (namespacePart(id()) == noNamespace && id() > ID_LAST_TAG) ||
1007 (_prefix == "xml" && DOMString(getDocument()->namespaceURI(id())) != "http://www.w3.org/XML/1998/namespace")) {
1008 exceptioncode = DOMException::NAMESPACE_ERR;
1013 void NodeImpl::checkAddChild(NodeImpl *newChild, int &exceptioncode)
1015 // Perform error checking as required by spec for adding a new child. Used by
1016 // appendChild(), replaceChild() and insertBefore()
1018 // Not mentioned in spec: throw NOT_FOUND_ERR if newChild is null
1020 exceptioncode = DOMException::NOT_FOUND_ERR;
1024 // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly
1026 exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
1030 bool shouldAdoptChild = false;
1032 // WRONG_DOCUMENT_ERR: Raised if newChild was created from a different document than the one that
1033 // created this node.
1034 // We assume that if newChild is a DocumentFragment, all children are created from the same document
1035 // as the fragment itself (otherwise they could not have been added as children)
1036 if (newChild->getDocument() != getDocument()) {
1037 // but if the child is not in a document yet then loosen the
1038 // restriction, so that e.g. creating an element with the Option()
1039 // constructor and then adding it to a different document works,
1040 // as it does in Mozilla and Mac IE.
1041 if (!newChild->inDocument()) {
1042 shouldAdoptChild = true;
1044 exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
1049 // HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not allow children of the type of the
1050 // newChild node, or if the node to append is one of this node's ancestors.
1052 // check for ancestor/same node
1053 if (newChild == this || isAncestor(newChild)) {
1054 exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
1058 // only do this once we know there won't be an exception
1059 if (shouldAdoptChild) {
1060 KJS::ScriptInterpreter::updateDOMObjectDocument(newChild, newChild->getDocument(), getDocument());
1061 newChild->setDocument(getDocument()->docPtr());
1065 bool NodeImpl::isAncestor(const NodeImpl *other) const
1067 // Return true if other is an ancestor of this, otherwise false
1068 for (const NodeImpl *n = parentNode(); n; n = n->parentNode()) {
1075 bool NodeImpl::childAllowed( NodeImpl *newChild )
1077 return childTypeAllowed(newChild->nodeType());
1080 NodeImpl::StyleChange NodeImpl::diff( khtml::RenderStyle *s1, khtml::RenderStyle *s2 ) const
1082 // FIXME: The behavior of this function is just totally wrong. It doesn't handle
1083 // explicit inheritance of non-inherited properties and so you end up not re-resolving
1084 // style in cases where you need to.
1085 StyleChange ch = NoInherit;
1086 EDisplay display1 = s1 ? s1->display() : NONE;
1087 bool fl1 = s1 ? s1->hasPseudoStyle(RenderStyle::FIRST_LETTER) : false;
1088 EDisplay display2 = s2 ? s2->display() : NONE;
1089 bool fl2 = s2 ? s2->hasPseudoStyle(RenderStyle::FIRST_LETTER) : false;
1090 if (display1 != display2 || fl1 != fl2)
1092 else if ( !s1 || !s2 )
1094 else if ( *s1 == *s2 )
1096 else if ( s1->inheritedNotEqual( s2 ) )
1102 void NodeImpl::dump(QTextStream *stream, QString ind) const
1104 // ### implement dump() for all appropriate subclasses
1106 if (m_hasId) { *stream << " hasId"; }
1107 if (m_hasClass) { *stream << " hasClass"; }
1108 if (m_hasStyle) { *stream << " hasStyle"; }
1109 if (m_specified) { *stream << " specified"; }
1110 if (m_focused) { *stream << " focused"; }
1111 if (m_active) { *stream << " active"; }
1112 if (m_styleElement) { *stream << " styleElement"; }
1113 if (m_implicit) { *stream << " implicit"; }
1115 *stream << " tabIndex=" << m_tabIndex;
1116 if (m_regdListeners)
1117 *stream << " #regdListeners=" << m_regdListeners->count(); // ### more detail
1120 NodeImpl *child = firstChild();
1123 *stream << ind << child->nodeName().string().ascii() << ": ";
1124 child->dump(stream,ind+" ");
1125 child = child->nextSibling();
1130 void NodeImpl::attach()
1132 assert(!attached());
1133 assert(!m_render || (m_render->style() && m_render->parent()));
1134 getDocument()->incDOMTreeVersion();
1138 void NodeImpl::detach()
1140 // assert(m_attached);
1146 DocumentImpl *doc = getDocument();
1148 doc->incDOMTreeVersion();
1152 bool NodeImpl::maintainsState()
1157 QString NodeImpl::state()
1159 return QString::null;
1162 void NodeImpl::restoreState(QStringList &/*states*/)
1166 void NodeImpl::insertedIntoDocument()
1168 if (m_regdListeners && !m_regdListeners->isEmpty() && getDocument())
1169 getDocument()->unregisterDisconnectedNodeWithEventListeners(this);
1171 setInDocument(true);
1174 void NodeImpl::removedFromDocument()
1176 if (m_regdListeners && !m_regdListeners->isEmpty() && getDocument())
1177 getDocument()->registerDisconnectedNodeWithEventListeners(this);
1179 setInDocument(false);
1182 void NodeImpl::childrenChanged()
1186 bool NodeImpl::disabled() const
1191 bool NodeImpl::isReadOnly()
1193 // Entity & Entity Reference nodes and their descendants are read-only
1196 if (n->nodeType() == Node::ENTITY_NODE ||
1197 n->nodeType() == Node::ENTITY_REFERENCE_NODE)
1199 n = n->parentNode();
1204 NodeImpl *NodeImpl::previousEditable() const
1206 NodeImpl *node = previousLeafNode();
1208 if (node->isContentEditable())
1210 node = node->previousLeafNode();
1215 NodeImpl *NodeImpl::nextEditable() const
1217 NodeImpl *node = nextLeafNode();
1219 if (node->isContentEditable())
1221 node = node->nextLeafNode();
1226 RenderObject * NodeImpl::previousRenderer()
1228 for (NodeImpl *n = previousSibling(); n; n = n->previousSibling()) {
1230 return n->renderer();
1235 RenderObject * NodeImpl::nextRenderer()
1237 // Avoid an O(n^2) problem with this function by not checking for nextRenderer() when the parent element hasn't even
1238 // been attached yet.
1239 if (parent() && !parent()->attached())
1242 for (NodeImpl *n = nextSibling(); n; n = n->nextSibling()) {
1244 return n->renderer();
1249 bool NodeImpl::isAtomicNode() const
1251 return !hasChildNodes() || (id() == ID_OBJECT && renderer() && renderer()->isReplaced());
1254 NodeImpl *NodeImpl::previousNodeConsideringAtomicNodes() const
1256 if (previousSibling()) {
1257 NodeImpl *n = previousSibling();
1258 while (!n->isAtomicNode() && n->lastChild())
1262 else if (parentNode()) {
1263 return parentNode();
1270 NodeImpl *NodeImpl::nextNodeConsideringAtomicNodes() const
1272 if (!isAtomicNode() && firstChild())
1273 return firstChild();
1275 return nextSibling();
1276 const NodeImpl *n = this;
1277 while (n && !n->nextSibling())
1278 n = n->parentNode();
1280 return n->nextSibling();
1284 NodeImpl *NodeImpl::previousLeafNode() const
1286 NodeImpl *node = previousNodeConsideringAtomicNodes();
1288 if (node->isAtomicNode())
1290 node = node->previousNodeConsideringAtomicNodes();
1295 NodeImpl *NodeImpl::nextLeafNode() const
1297 NodeImpl *node = nextNodeConsideringAtomicNodes();
1299 if (node->isAtomicNode())
1301 node = node->nextNodeConsideringAtomicNodes();
1306 void NodeImpl::createRendererIfNeeded()
1310 if (!getDocument()->shouldCreateRenderers())
1314 assert(!attached());
1317 NodeImpl *parent = parentNode();
1320 RenderObject *parentRenderer = parent->renderer();
1321 if (parentRenderer && parentRenderer->canHaveChildren()) {
1322 RenderStyle *style = styleForRenderer(parentRenderer);
1324 #ifndef KHTML_NO_XBL
1325 bool resolveStyle = false;
1326 if (getDocument()->bindingManager()->loadBindings(this, style->bindingURIs(), true, &resolveStyle) &&
1327 rendererIsNeeded(style)) {
1330 style = styleForRenderer(parentRenderer);
1333 if (rendererIsNeeded(style)) {
1335 m_render = createRenderer(getDocument()->renderArena(), style);
1336 m_render->setStyle(style);
1337 parentRenderer->addChild(m_render, nextRenderer());
1338 #ifndef KHTML_NO_XBL
1339 } // avoid confusing the change log code parser by having two close braces to match the two open braces above
1343 style->deref(getDocument()->renderArena());
1347 RenderStyle *NodeImpl::styleForRenderer(RenderObject *parent)
1349 return parent->style();
1352 bool NodeImpl::rendererIsNeeded(RenderStyle *style)
1354 return (getDocument()->documentElement() == this) || (style->display() != NONE);
1357 RenderObject *NodeImpl::createRenderer(RenderArena *arena, RenderStyle *style)
1363 long NodeImpl::maxOffset() const
1368 long NodeImpl::caretMinOffset() const
1370 return renderer() ? renderer()->caretMinOffset() : 0;
1373 long NodeImpl::caretMaxOffset() const
1375 return renderer() ? renderer()->caretMaxOffset() : 1;
1378 unsigned long NodeImpl::caretMaxRenderedOffset() const
1380 return renderer() ? renderer()->caretMaxRenderedOffset() : 1;
1383 long NodeImpl::previousOffset (long current) const
1385 return renderer() ? renderer()->previousOffset(current) : current - 1;
1388 long NodeImpl::nextOffset (long current) const
1390 return renderer() ? renderer()->nextOffset(current) : current + 1;
1393 bool NodeImpl::isBlockFlow() const
1395 return renderer() && renderer()->isBlockFlow();
1398 bool NodeImpl::isEditableBlock() const
1400 return isContentEditable() && isBlockFlow();
1403 ElementImpl *NodeImpl::enclosingBlockFlowElement() const
1405 NodeImpl *n = const_cast<NodeImpl *>(this);
1407 return static_cast<ElementImpl *>(n);
1410 n = n->parentNode();
1413 if (n->isBlockFlow() || n->id() == ID_BODY)
1414 return static_cast<ElementImpl *>(n);
1419 ElementImpl *NodeImpl::enclosingInlineElement() const
1421 NodeImpl *n = const_cast<NodeImpl *>(this);
1425 p = n->parentNode();
1426 if (!p || p->isBlockFlow() || p->id() == ID_BODY)
1427 return static_cast<ElementImpl *>(n);
1428 // Also stop if any previous sibling is a block
1429 for (NodeImpl *sibling = n->previousSibling(); sibling; sibling = sibling->previousSibling()) {
1430 if (sibling->isBlockFlow())
1431 return static_cast<ElementImpl *>(n);
1435 ASSERT_NOT_REACHED();
1439 ElementImpl *NodeImpl::rootEditableElement() const
1441 if (!isContentEditable())
1444 NodeImpl *n = const_cast<NodeImpl *>(this);
1445 if (n->id() == ID_BODY)
1446 return static_cast<ElementImpl *>(n);
1448 NodeImpl *result = n->isEditableBlock() ? n : 0;
1450 n = n->parentNode();
1451 if (!n || !n->isContentEditable())
1453 if (n->id() == ID_BODY) {
1457 if (n->isBlockFlow())
1460 return static_cast<ElementImpl *>(result);
1463 bool NodeImpl::inSameRootEditableElement(NodeImpl *n)
1465 return n ? rootEditableElement() == n->rootEditableElement() : false;
1468 bool NodeImpl::inSameContainingBlockFlowElement(NodeImpl *n)
1470 return n ? enclosingBlockFlowElement() == n->enclosingBlockFlowElement() : false;
1474 NodeImpl::Id NodeImpl::identifier() const
1481 void NodeImpl::displayNode(const char *prefix)
1486 fprintf(stderr, "%s%s\t%p \"%s\"\n", prefix, nodeName().string().latin1(), this, nodeValue().string().latin1());
1488 fprintf(stderr, "%s%s\t%p\n", prefix, nodeName().string().latin1(), this);
1491 void NodeImpl::displayTree()
1493 NodeImpl *rootNode = rootEditableElement() ? : this;
1496 for (node = rootNode; node; node = node->traverseNextNode()) {
1499 fprintf(stderr, "*");
1500 for (tmpNode = node; tmpNode && tmpNode != rootNode; tmpNode = tmpNode->parentNode())
1501 fprintf(stderr, "\t");
1502 node->displayNode(0);
1506 void NodeImpl::formatForDebugger(char *buffer, unsigned length) const
1512 if (s.length() == 0)
1517 strncpy(buffer, result.string().latin1(), length - 1);
1521 //-------------------------------------------------------------------------
1523 NodeBaseImpl::NodeBaseImpl(DocumentPtr *doc)
1530 NodeBaseImpl::~NodeBaseImpl()
1532 //kdDebug( 6020 ) << "NodeBaseImpl destructor" << endl;
1534 // Avoid deep recursion when destroying the node tree.
1535 static bool alreadyInsideDestructor;
1536 bool topLevel = !alreadyInsideDestructor;
1538 alreadyInsideDestructor = true;
1540 // List of nodes to be deleted.
1541 static NodeImpl *head;
1542 static NodeImpl *tail;
1544 // We have to tell all children that their parent has died.
1548 for( n = _first; n != 0; n = next ) {
1549 next = n->nextSibling();
1550 n->setPreviousSibling(0);
1551 n->setNextSibling(0);
1554 if ( !n->refCount() ) {
1555 // Add the node to the list of nodes to be deleted.
1556 // Reuse the nextSibling pointer for this purpose.
1558 tail->setNextSibling(n);
1565 // Only for the top level call, do the actual deleting.
1567 while ((n = head) != 0) {
1568 next = n->nextSibling();
1569 n->setNextSibling(0);
1578 alreadyInsideDestructor = false;
1583 NodeImpl *NodeBaseImpl::firstChild() const
1588 NodeImpl *NodeBaseImpl::lastChild() const
1593 NodeImpl *NodeBaseImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
1597 // insertBefore(...,null) is equivalent to appendChild()
1599 return appendChild(newChild, exceptioncode);
1601 Node protectNewChild(newChild); // make sure the new child is ref'd and deref'd so we don't leak it
1603 // Make sure adding the new child is ok
1604 checkAddChild(newChild, exceptioncode);
1608 // NOT_FOUND_ERR: Raised if refChild is not a child of this node
1609 if (refChild->parentNode() != this) {
1610 exceptioncode = DOMException::NOT_FOUND_ERR;
1614 bool isFragment = newChild->nodeType() == Node::DOCUMENT_FRAGMENT_NODE;
1616 // If newChild is a DocumentFragment with no children.... there's nothing to do.
1617 // Just return the document fragment
1618 if (isFragment && !newChild->firstChild())
1619 return (newChild->hasOneRef() && !newChild->parent()) ? 0 : newChild;
1621 // Now actually add the child(ren)
1622 NodeImpl *nextChild;
1623 NodeImpl *child = isFragment ? newChild->firstChild() : newChild;
1625 NodeImpl *prev = refChild->previousSibling();
1626 if ( prev == newChild || refChild == newChild ) // nothing to do
1630 nextChild = isFragment ? child->nextSibling() : 0;
1632 // If child is already present in the tree, first remove it
1633 NodeImpl *newParent = child->parentNode();
1635 newParent->removeChild( child, exceptioncode );
1636 if ( exceptioncode )
1639 // Add child in the correct position
1641 prev->setNextSibling(child);
1644 refChild->setPreviousSibling(child);
1645 child->setParent(this);
1646 child->setPreviousSibling(prev);
1647 child->setNextSibling(refChild);
1649 // Add child to the rendering tree
1650 // ### should we detach() it first if it's already attached?
1651 if (attached() && !child->attached())
1654 // Dispatch the mutation events
1655 dispatchChildInsertedEvents(child,exceptioncode);
1661 getDocument()->setDocumentChanged(true);
1662 dispatchSubtreeModifiedEvent();
1666 NodeImpl *NodeBaseImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
1670 Node protectNewChild(newChild); // make sure the new child is ref'd and deref'd so we don't leak it
1672 if ( oldChild == newChild ) // nothing to do
1675 // Make sure adding the new child is ok
1676 checkAddChild(newChild, exceptioncode);
1680 // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
1681 if (!oldChild || oldChild->parentNode() != this) {
1682 exceptioncode = DOMException::NOT_FOUND_ERR;
1686 bool isFragment = newChild->nodeType() == Node::DOCUMENT_FRAGMENT_NODE;
1687 NodeImpl *nextChild;
1688 NodeImpl *child = isFragment ? newChild->firstChild() : newChild;
1690 // Remove the old child
1691 NodeImpl *prev = oldChild->previousSibling();
1692 NodeImpl *next = oldChild->nextSibling();
1694 removeChild(oldChild, exceptioncode);
1698 // Add the new child(ren)
1700 nextChild = isFragment ? child->nextSibling() : 0;
1702 // If child is already present in the tree, first remove it
1703 NodeImpl *newParent = child->parentNode();
1705 newParent->removeChild( child, exceptioncode );
1709 // Add child in the correct position
1710 if (prev) prev->setNextSibling(child);
1711 if (next) next->setPreviousSibling(child);
1712 if(!prev) _first = child;
1713 if(!next) _last = child;
1714 child->setParent(this);
1715 child->setPreviousSibling(prev);
1716 child->setNextSibling(next);
1718 // Add child to the rendering tree
1719 // ### should we detach() it first if it's already attached?
1720 if (attached() && !child->attached())
1723 // Dispatch the mutation events
1724 dispatchChildInsertedEvents(child,exceptioncode);
1730 // ### set style in case it's attached
1731 getDocument()->setDocumentChanged(true);
1732 dispatchSubtreeModifiedEvent();
1736 NodeImpl *NodeBaseImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
1740 // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
1742 exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
1746 // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
1747 if (!oldChild || oldChild->parentNode() != this) {
1748 exceptioncode = DOMException::NOT_FOUND_ERR;
1752 // Dispatch pre-removal mutation events
1753 getDocument()->notifyBeforeNodeRemoval(oldChild); // ### use events instead
1754 if (getDocument()->hasListenerType(DocumentImpl::DOMNODEREMOVED_LISTENER)) {
1755 oldChild->dispatchEvent(new MutationEventImpl(EventImpl::DOMNODEREMOVED_EVENT,
1756 true,false,this,DOMString(),DOMString(),DOMString(),0),exceptioncode,true);
1761 dispatchChildRemovalEvents(oldChild,exceptioncode);
1765 // Remove from rendering tree
1766 if (oldChild->attached())
1770 NodeImpl *prev, *next;
1771 prev = oldChild->previousSibling();
1772 next = oldChild->nextSibling();
1774 if(next) next->setPreviousSibling(prev);
1775 if(prev) prev->setNextSibling(next);
1776 if(_first == oldChild) _first = next;
1777 if(_last == oldChild) _last = prev;
1779 oldChild->setPreviousSibling(0);
1780 oldChild->setNextSibling(0);
1781 oldChild->setParent(0);
1783 getDocument()->setDocumentChanged(true);
1785 // Dispatch post-removal mutation events
1786 dispatchSubtreeModifiedEvent();
1788 if (oldChild->inDocument())
1789 oldChild->removedFromDocument();
1794 void NodeBaseImpl::removeChildren()
1797 while (NodeImpl *n = _first) {
1798 NodeImpl *next = n->nextSibling();
1802 // Fire removed from document mutation events.
1803 dispatchChildRemovalEvents(n, exceptionCode);
1807 n->setPreviousSibling(0);
1808 n->setNextSibling(0);
1811 if (n->inDocument())
1812 n->removedFromDocument();
1820 // Dispatch a single post-removal mutation event denoting a modified subtree.
1821 dispatchSubtreeModifiedEvent();
1825 NodeImpl *NodeBaseImpl::appendChild ( NodeImpl *newChild, int &exceptioncode )
1829 Node protectNewChild(newChild); // make sure the new child is ref'd and deref'd so we don't leak it
1831 // Make sure adding the new child is ok
1832 checkAddChild(newChild, exceptioncode);
1836 if ( newChild == _last ) // nothing to do
1839 bool isFragment = newChild->nodeType() == Node::DOCUMENT_FRAGMENT_NODE;
1841 // If newChild is a DocumentFragment with no children.... there's nothing to do.
1842 // Just return the document fragment
1843 if (isFragment && !newChild->firstChild())
1846 // Now actually add the child(ren)
1847 NodeImpl *nextChild;
1848 NodeImpl *child = isFragment ? newChild->firstChild() : newChild;
1851 nextChild = isFragment ? child->nextSibling() : 0;
1853 // If child is already present in the tree, first remove it
1854 NodeImpl *oldParent = child->parentNode();
1856 oldParent->removeChild( child, exceptioncode );
1861 // Append child to the end of the list
1862 child->setParent(this);
1866 child->setPreviousSibling(_last);
1867 _last->setNextSibling(child);
1872 _first = _last = child;
1875 // Add child to the rendering tree
1876 // ### should we detach() it first if it's already attached?
1877 if (attached() && !child->attached())
1880 // Dispatch the mutation events
1881 dispatchChildInsertedEvents(child,exceptioncode);
1886 getDocument()->setDocumentChanged(true);
1887 // ### set style in case it's attached
1888 dispatchSubtreeModifiedEvent();
1892 bool NodeBaseImpl::hasChildNodes ( ) const
1897 // not part of the DOM
1898 void NodeBaseImpl::setFirstChild(NodeImpl *child)
1903 void NodeBaseImpl::setLastChild(NodeImpl *child)
1908 // check for same source document:
1909 bool NodeBaseImpl::checkSameDocument( NodeImpl *newChild, int &exceptioncode )
1912 DocumentImpl *ownerDocThis = getDocument();
1913 DocumentImpl *ownerDocNew = getDocument();
1914 if(ownerDocThis != ownerDocNew) {
1915 kdDebug(6010)<< "not same document, newChild = " << newChild << "document = " << getDocument() << endl;
1916 exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
1922 // check for being (grand-..)father:
1923 // ### remove in favor or isAncestor()
1924 bool NodeBaseImpl::checkNoOwner( NodeImpl *newChild, int &exceptioncode )
1926 //check if newChild is parent of this...
1928 for( n = this; (n != getDocument()) && (n!= 0); n = n->parentNode() )
1930 exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
1936 // check for being child:
1937 bool NodeBaseImpl::checkIsChild( NodeImpl *oldChild, int &exceptioncode )
1939 if(!oldChild || oldChild->parentNode() != this) {
1940 exceptioncode = DOMException::NOT_FOUND_ERR;
1946 NodeImpl *NodeBaseImpl::addChild(NodeImpl *newChild)
1948 // do not add applyChanges here! This function is only used during parsing
1950 Node protectNewChild(newChild); // make sure the new child is ref'd and deref'd so we don't leak it
1952 // short check for consistency with DTD
1953 if(!isXMLElementNode() && !newChild->isXMLElementNode() && !childAllowed(newChild))
1955 //kdDebug( 6020 ) << "AddChild failed! id=" << id() << ", child->id=" << newChild->id() << endl;
1960 newChild->setParent(this);
1964 newChild->setPreviousSibling(_last);
1965 _last->setNextSibling(newChild);
1970 _first = _last = newChild;
1974 newChild->insertedIntoDocument();
1977 if(newChild->nodeType() == Node::ELEMENT_NODE)
1982 void NodeBaseImpl::attach()
1984 NodeImpl *child = _first;
1988 child = child->nextSibling();
1993 void NodeBaseImpl::detach()
1995 NodeImpl *child = _first;
1998 NodeImpl* prev = child;
1999 child = child->nextSibling();
2005 void NodeBaseImpl::insertedIntoDocument()
2007 NodeImpl::insertedIntoDocument();
2008 for (NodeImpl *child = _first; child; child = child->nextSibling())
2009 child->insertedIntoDocument();
2012 void NodeBaseImpl::removedFromDocument()
2014 NodeImpl::removedFromDocument();
2015 for (NodeImpl *child = _first; child; child = child->nextSibling())
2016 child->removedFromDocument();
2019 void NodeBaseImpl::cloneChildNodes(NodeImpl *clone)
2021 int exceptioncode = 0;
2023 for(n = firstChild(); n && !exceptioncode; n = n->nextSibling())
2025 clone->appendChild(n->cloneNode(true),exceptioncode);
2029 NodeListImpl* NodeBaseImpl::getElementsByTagNameNS ( DOMStringImpl* namespaceURI,
2030 DOMStringImpl* localName )
2032 if (!localName) return 0;
2034 NodeImpl::Id idMask = namespaceMask | localNameMask;
2035 if (localName->l && localName->s[0] == '*')
2036 idMask &= ~localNameMask;
2037 if (!namespaceURI || (namespaceURI->l && namespaceURI->s[0] == '*'))
2038 idMask &= ~namespaceMask;
2040 Id id = 0; // 0 means "all items"
2041 if ( (idMask & localNameMask) || namespaceURI ) // not getElementsByTagName("*")
2043 id = getDocument()->tagId( namespaceURI, localName, true);
2044 if ( !id ) // not found -> we want to return an empty list, not "all items"
2045 id = (Id)-1; // HACK. HEAD has a cleaner implementation of TagNodeListImpl it seems.
2048 return new TagNodeListImpl( this, id, idMask );
2051 // I don't like this way of implementing the method, but I didn't find any
2053 bool NodeBaseImpl::getUpperLeftCorner(int &xPos, int &yPos) const
2057 RenderObject *o = m_render;
2059 if ( !o->isInline() || o->isReplaced() ) {
2060 o->absolutePosition( xPos, yPos );
2064 // find the next text/image child, to get a position
2067 o = o->firstChild();
2068 else if(o->nextSibling())
2069 o = o->nextSibling();
2071 RenderObject *next = 0;
2074 if(!o) return false;
2075 next = o->nextSibling();
2079 if((o->isText() && !o->isBR()) || o->isReplaced()) {
2080 o->container()->absolutePosition( xPos, yPos );
2082 xPos += static_cast<RenderText *>(o)->minXPos();
2092 bool NodeBaseImpl::getLowerRightCorner(int &xPos, int &yPos) const
2097 RenderObject *o = m_render;
2099 if (!o->isInline() || o->isReplaced())
2101 o->absolutePosition( xPos, yPos );
2103 yPos += o->height();
2106 // find the last text/image child, to get a position
2110 else if(o->previousSibling())
2111 o = o->previousSibling();
2113 RenderObject *prev = 0;
2116 if(!o) return false;
2117 prev = o->previousSibling();
2121 if(o->isText() || o->isReplaced()) {
2122 o->container()->absolutePosition(xPos, yPos);
2124 xPos += static_cast<RenderText *>(o)->minXPos() + o->width();
2126 xPos += o->xPos()+o->width();
2127 yPos += o->yPos()+o->height();
2134 QRect NodeBaseImpl::getRect() const
2137 if (!getUpperLeftCorner(xPos,yPos))
2143 if (!getLowerRightCorner(xEnd,yEnd))
2157 if ( xEnd <= xPos || yEnd <= yPos )
2158 return QRect( QPoint( xPos, yPos ), QSize() );
2160 return QRect(xPos, yPos, xEnd - xPos, yEnd - yPos);
2163 void NodeBaseImpl::setFocus(bool received)
2165 if (m_focused == received) return;
2167 NodeImpl::setFocus(received);
2169 if (received && isEditableBlock() && !hasChildNodes()) {
2170 getDocument()->part()->setSelection(Selection(Position(this, 0), DOWNSTREAM));
2173 // note that we need to recalc the style
2177 void NodeBaseImpl::setActive(bool down)
2179 if (down == active()) return;
2181 NodeImpl::setActive(down);
2183 // note that we need to recalc the style
2184 if (m_render && m_render->style()->affectedByActiveRules())
2188 unsigned long NodeBaseImpl::childNodeCount() const
2190 unsigned long count = 0;
2192 for (n = firstChild(); n; n = n->nextSibling())
2197 NodeImpl *NodeBaseImpl::childNode(unsigned long index)
2200 NodeImpl *n = firstChild();
2201 for (i = 0; n != 0 && i < index; i++)
2202 n = n->nextSibling();
2206 void NodeBaseImpl::dispatchChildInsertedEvents( NodeImpl *child, int &exceptioncode )
2209 while (p->parentNode())
2210 p = p->parentNode();
2212 if (p->nodeType() == Node::DOCUMENT_NODE) {
2213 for (NodeImpl *c = child; c; c = c->traverseNextNode(child)) {
2214 c->insertedIntoDocument();
2218 if (getDocument()->hasListenerType(DocumentImpl::DOMNODEINSERTED_LISTENER)) {
2219 child->dispatchEvent(new MutationEventImpl(EventImpl::DOMNODEINSERTED_EVENT,
2220 true,false,this,DOMString(),DOMString(),DOMString(),0),exceptioncode,true);
2225 // dispatch the DOMNodeInsertedIntoDocument event to all descendants
2226 bool hasInsertedListeners = getDocument()->hasListenerType(DocumentImpl::DOMNODEINSERTEDINTODOCUMENT_LISTENER);
2228 if (hasInsertedListeners && p->nodeType() == Node::DOCUMENT_NODE) {
2229 for (NodeImpl *c = child; c; c = c->traverseNextNode(child)) {
2230 c->dispatchEvent(new MutationEventImpl(EventImpl::DOMNODEINSERTEDINTODOCUMENT_EVENT,
2231 false,false,0,DOMString(),DOMString(),DOMString(),0),exceptioncode,true);
2238 void NodeBaseImpl::dispatchChildRemovalEvents( NodeImpl *child, int &exceptioncode )
2240 // Dispatch pre-removal mutation events
2241 getDocument()->notifyBeforeNodeRemoval(child); // ### use events instead
2242 if (getDocument()->hasListenerType(DocumentImpl::DOMNODEREMOVED_LISTENER)) {
2243 child->dispatchEvent(new MutationEventImpl(EventImpl::DOMNODEREMOVED_EVENT,
2244 true,false,this,DOMString(),DOMString(),DOMString(),0),exceptioncode,true);
2249 bool hasRemovalListeners = getDocument()->hasListenerType(DocumentImpl::DOMNODEREMOVEDFROMDOCUMENT_LISTENER);
2251 // dispatch the DOMNodeRemovedFromDocument event to all descendants
2253 for (NodeImpl *c = child; c; c = c->traverseNextNode(child)) {
2254 if (hasRemovalListeners) {
2255 c->dispatchEvent(new MutationEventImpl(EventImpl::DOMNODEREMOVEDFROMDOCUMENT_EVENT,
2256 false,false,0,DOMString(),DOMString(),DOMString(),0),exceptioncode,true);
2264 // ---------------------------------------------------------------------------
2267 NodeListImpl::NodeListImpl(NodeImpl *_rootNode)
2268 : rootNode(_rootNode),
2269 isLengthCacheValid(false),
2270 isItemCacheValid(false)
2273 rootNode->registerNodeList(this);
2276 NodeListImpl::~NodeListImpl()
2278 rootNode->unregisterNodeList(this);
2282 unsigned long NodeListImpl::recursiveLength( NodeImpl *start ) const
2287 if (isLengthCacheValid && start == rootNode) {
2288 return cachedLength;
2291 unsigned long len = 0;
2293 for(NodeImpl *n = start->firstChild(); n != 0; n = n->nextSibling()) {
2294 if ( n->nodeType() == Node::ELEMENT_NODE ) {
2297 len+= recursiveLength(n);
2301 if (start == rootNode) {
2303 isLengthCacheValid = true;
2309 NodeImpl *NodeListImpl::recursiveItem ( unsigned long offset, NodeImpl *start) const
2311 int remainingOffset = offset;
2313 start = rootNode->firstChild();
2314 if (isItemCacheValid) {
2315 if (offset == lastItemOffset) {
2317 } else if (offset > lastItemOffset) {
2319 remainingOffset -= lastItemOffset;
2324 NodeImpl *n = start;
2327 if ( n->nodeType() == Node::ELEMENT_NODE ) {
2328 if (nodeMatches(n)) {
2329 if (!remainingOffset) {
2331 lastItemOffset = offset;
2332 isItemCacheValid = 1;
2339 n = n->traverseNextNode(rootNode);
2342 return 0; // no matching node in this subtree
2345 NodeImpl *NodeListImpl::itemById (const DOMString& elementId) const
2347 if (rootNode->isDocumentNode() || rootNode->inDocument()) {
2348 NodeImpl *node = rootNode->getDocument()->getElementById(elementId);
2350 if (node == NULL || !nodeMatches(node))
2353 for (NodeImpl *p = node->parentNode(); p; p = p->parentNode()) {
2361 unsigned long l = length();
2363 for ( unsigned long i = 0; i < l; i++ ) {
2364 NodeImpl *node = item(i);
2366 if ( static_cast<ElementImpl *>(node)->getIDAttribute() == elementId ) {
2375 void NodeListImpl::rootNodeSubtreeModified()
2377 isLengthCacheValid = false;
2378 isItemCacheValid = false;
2382 ChildNodeListImpl::ChildNodeListImpl( NodeImpl *n )
2387 unsigned long ChildNodeListImpl::length() const
2389 unsigned long len = 0;
2391 for(n = rootNode->firstChild(); n != 0; n = n->nextSibling())
2397 NodeImpl *ChildNodeListImpl::item ( unsigned long index ) const
2399 unsigned int pos = 0;
2400 NodeImpl *n = rootNode->firstChild();
2402 while( n != 0 && pos < index )
2404 n = n->nextSibling();
2411 bool ChildNodeListImpl::nodeMatches(NodeImpl *testNode) const
2413 return testNode->parentNode() == rootNode;
2416 TagNodeListImpl::TagNodeListImpl(NodeImpl *n, NodeImpl::Id _id, NodeImpl::Id _idMask )
2418 m_id(_id & _idMask),
2423 unsigned long TagNodeListImpl::length() const
2425 return recursiveLength();
2428 NodeImpl *TagNodeListImpl::item ( unsigned long index ) const
2430 return recursiveItem( index );
2433 bool TagNodeListImpl::nodeMatches( NodeImpl *testNode ) const
2435 return ( testNode->isElementNode() &&
2436 (testNode->id() & m_idMask) == m_id);
2439 NameNodeListImpl::NameNodeListImpl(NodeImpl *n, const DOMString &t )
2440 : NodeListImpl(n), nodeName(t)
2444 unsigned long NameNodeListImpl::length() const
2446 return recursiveLength();
2449 NodeImpl *NameNodeListImpl::item ( unsigned long index ) const
2451 return recursiveItem( index );
2454 bool NameNodeListImpl::nodeMatches( NodeImpl *testNode ) const
2456 return static_cast<ElementImpl *>(testNode)->getAttribute(ATTR_NAME) == nodeName;
2459 // ---------------------------------------------------------------------------
2461 NamedNodeMapImpl::NamedNodeMapImpl()
2465 NamedNodeMapImpl::~NamedNodeMapImpl()
2469 // ----------------------------------------------------------------------------
2473 GenericRONamedNodeMapImpl::GenericRONamedNodeMapImpl(DocumentPtr* doc)
2474 : NamedNodeMapImpl()
2476 m_doc = doc->document();
2477 m_contents = new QPtrList<NodeImpl>;
2480 GenericRONamedNodeMapImpl::~GenericRONamedNodeMapImpl()
2482 while (m_contents->count() > 0)
2483 m_contents->take(0)->deref();
2488 NodeImpl *GenericRONamedNodeMapImpl::getNamedItem ( const DOMString &name, int &/*exceptioncode*/ ) const
2490 QPtrListIterator<NodeImpl> it(*m_contents);
2491 for (; it.current(); ++it)
2492 if (it.current()->nodeName() == name)
2493 return it.current();
2497 Node GenericRONamedNodeMapImpl::setNamedItem ( const Node &/*arg*/, int &exceptioncode )
2499 // can't modify this list through standard DOM functions
2500 // NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly
2501 exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
2505 Node GenericRONamedNodeMapImpl::removeNamedItem ( const DOMString &/*name*/, int &exceptioncode )
2507 // can't modify this list through standard DOM functions
2508 // NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly
2509 exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
2513 NodeImpl *GenericRONamedNodeMapImpl::item ( unsigned long index ) const
2515 // ### check this when calling from javascript using -1 = 2^sizeof(int)-1
2516 // (also for other similar methods)
2517 if (index >= m_contents->count())
2520 return m_contents->at(index);
2523 unsigned long GenericRONamedNodeMapImpl::length( ) const
2525 return m_contents->count();
2528 NodeImpl *GenericRONamedNodeMapImpl::getNamedItemNS( const DOMString &namespaceURI,
2529 const DOMString &localName,
2530 int &/*exceptioncode*/ ) const
2532 NodeImpl::Id searchId = m_doc->tagId(namespaceURI.implementation(),
2533 localName.implementation(), true);
2535 QPtrListIterator<NodeImpl> it(*m_contents);
2536 for (; it.current(); ++it)
2537 if (it.current()->id() == searchId)
2538 return it.current();
2543 NodeImpl *GenericRONamedNodeMapImpl::setNamedItemNS( NodeImpl */*arg*/, int &exceptioncode )
2545 // can't modify this list through standard DOM functions
2546 // NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly
2547 exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
2551 NodeImpl *GenericRONamedNodeMapImpl::removeNamedItemNS( const DOMString &/*namespaceURI*/,
2552 const DOMString &/*localName*/,
2553 int &exceptioncode )
2555 // can't modify this list through standard DOM functions
2556 exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
2560 void GenericRONamedNodeMapImpl::addNode(NodeImpl *n)
2562 // The spec says that in the case of duplicates we only keep the first one
2563 int exceptioncode = 0;
2564 if (getNamedItem(n->nodeName(),exceptioncode))
2568 m_contents->append(n);