#include "xml/dom_nodeimpl.h"
#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_position.h"
#include "xml/dom2_rangeimpl.h"
#include "css/csshelper.h"
#include "css/cssstyleselector.h"
#include "editing/html_interchange.h"
#include "editing/selection.h"
#include <kglobal.h>
#include <kdebug.h>
#include "rendering/render_object.h"
#include "rendering/render_text.h"
#include "ecma/kjs_binding.h"
#include "ecma/kjs_proxy.h"
#include "khtmlview.h"
#include "khtml_part.h"
#include "html/dtd.h"
#ifndef KHTML_NO_XBL
#include "xbl/xbl_binding_manager.h"
#endif
#if APPLE_CHANGES
#include "KWQAssertions.h"
#include "KWQLogging.h"
#else
#define ASSERT(assertion) assert(assertion)
#define LOG(channel, formatAndArgs...) ((void)0)
#endif
#ifndef NDEBUG
static int gEventDispatchForbidden;
#define forbidEventDispatch() gEventDispatchForbidden += 1
#define allowEventDispatch() assert(gEventDispatchForbidden > 0); gEventDispatchForbidden -= 1
#define eventDispatchForbidden() (gEventDispatchForbidden > 0)
#else
#define forbidEventDispatch()
#define allowEventDispatch()
#define eventDispatchForbidden()
#endif NDEBUG
using namespace DOM;
using namespace khtml;
NodeImpl::NodeImpl(DocumentImpl *doc)
: document(doc),
m_previous(0),
m_next(0),
m_render(0),
m_regdListeners( 0 ),
m_nodeLists( 0 ),
m_tabIndex( 0 ),
m_hasId( false ),
m_hasClass( false ),
m_hasStyle( false ),
m_attached(false),
m_changed( false ),
m_hasChangedChild( false ),
m_inDocument( false ),
m_hasAnchor( false ),
m_specified( false ),
m_focused( false ),
m_active( false ),
m_hovered(false),
m_inActiveChain( false ),
m_styleElement( false ),
m_implicit(false),
m_inDetach(false),
m_inSubtreeMark(false)
{
}
void NodeImpl::setDocument(DocumentImpl *doc)
{
if (inDocument())
return;
document = doc;
}
NodeImpl::~NodeImpl()
{
if (m_render)
detach();
if (m_regdListeners && !m_regdListeners->isEmpty() && getDocument() && !inDocument())
getDocument()->unregisterDisconnectedNodeWithEventListeners(this);
delete m_regdListeners;
delete m_nodeLists;
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 &, int &exceptioncode )
{
if (isReadOnly()) {
exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
return;
}
}
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::lastDescendent() const
{
NodeImpl *n = const_cast<NodeImpl *>(this);
while (n && n->lastChild())
n = n->lastChild();
return n;
}
NodeImpl *NodeImpl::insertBefore( NodeImpl *newChild, NodeImpl *, int &exceptioncode )
{
newChild->ref();
newChild->deref();
exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
return 0;
}
NodeImpl *NodeImpl::replaceChild( NodeImpl *newChild, NodeImpl *, int &exceptioncode )
{
newChild->ref();
newChild->deref();
exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
return 0;
}
NodeImpl *NodeImpl::removeChild( NodeImpl *, int &exceptioncode )
{
exceptioncode = DOMException::NOT_FOUND_ERR;
return 0;
}
NodeImpl *NodeImpl::appendChild( NodeImpl *newChild, int &exceptioncode )
{
newChild->ref();
newChild->deref();
exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
return 0;
}
void NodeImpl::remove(int &exceptioncode)
{
ref();
if (NodeImpl *p = parentNode())
p->removeChild(this, exceptioncode);
else
exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
deref();
}
bool NodeImpl::hasChildNodes( ) const
{
return false;
}
void NodeImpl::normalize ()
{
int exceptioncode = 0;
NodeImpl *child = firstChild();
while (child) {
NodeImpl *nextChild = child->nextSibling();
if (nextChild && child->nodeType() == Node::TEXT_NODE && nextChild->nodeType() == Node::TEXT_NODE) {
TextImpl *currentText = static_cast<TextImpl*>(child);
TextImpl *nextText = static_cast<TextImpl*>(nextChild);
currentText->appendData(nextText->data(),exceptioncode);
if (exceptioncode)
return;
nextChild->remove(exceptioncode);
if (exceptioncode)
return;
}
else {
child->normalize();
child = nextChild;
}
}
}
DOMString NodeImpl::prefix() const
{
return DOMString();
}
void NodeImpl::setPrefix(const DOMString &, int &exceptioncode )
{
exceptioncode = DOMException::NAMESPACE_ERR;
}
DOMString NodeImpl::localName() const
{
return DOMString();
}
DOMString NodeImpl::namespaceURI() const
{
return DOMString();
}
void NodeImpl::setFirstChild(NodeImpl *)
{
}
void NodeImpl::setLastChild(NodeImpl *)
{
}
NodeImpl *NodeImpl::addChild(NodeImpl *)
{
return 0;
}
bool NodeImpl::isContentEditable() const
{
return m_parent ? m_parent->isContentEditable() : false;
}
QRect NodeImpl::getRect() const
{
int _x, _y;
if(m_render && m_render->absolutePosition(_x, _y))
return QRect( _x, _y, m_render->width(), m_render->height() );
return QRect();
}
void NodeImpl::setChanged(bool b)
{
if (b && !attached()) return;
m_changed = b;
if ( b ) {
NodeImpl *p = parentNode();
while ( p ) {
p->setHasChangedChild( true );
p = p->parentNode();
}
getDocument()->setDocumentChanged(true);
}
}
bool NodeImpl::isInline() const
{
if (m_render) return m_render->style()->display() == khtml::INLINE;
return !isElementNode();
}
bool NodeImpl::isFocusable() const
{
return false;
}
bool NodeImpl::isKeyboardFocusable() const
{
return isFocusable();
}
bool NodeImpl::isMouseFocusable() const
{
return isFocusable();
}
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)
{
if (getDocument() && !getDocument()->attached())
return;
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;
}
RegisteredEventListener *rl = new RegisteredEventListener(static_cast<EventImpl::EventId>(id),listener,useCapture);
if (!m_regdListeners) {
m_regdListeners = new QPtrList<RegisteredEventListener>;
m_regdListeners->setAutoDelete(true);
}
listener->ref();
removeEventListener(id,listener,useCapture);
if (m_regdListeners->isEmpty() && getDocument() && !inDocument())
getDocument()->registerDisconnectedNodeWithEventListeners(this);
m_regdListeners->append(rl);
listener->deref();
}
void NodeImpl::removeEventListener(int id, EventListener *listener, bool useCapture)
{
if (!m_regdListeners) return;
RegisteredEventListener rl(static_cast<EventImpl::EventId>(id),listener,useCapture);
QPtrListIterator<RegisteredEventListener> it(*m_regdListeners);
for (; it.current(); ++it)
if (*(it.current()) == rl) {
m_regdListeners->removeRef(it.current());
if (m_regdListeners->isEmpty() && getDocument() && !inDocument())
getDocument()->unregisterDisconnectedNodeWithEventListeners(this);
return;
}
}
void NodeImpl::removeAllEventListeners()
{
delete m_regdListeners;
m_regdListeners = 0;
}
void NodeImpl::removeHTMLEventListener(int id)
{
if (!m_regdListeners) return;
QPtrListIterator<RegisteredEventListener> it(*m_regdListeners);
for (; it.current(); ++it)
if (it.current()->id == id &&
it.current()->listener->eventListenerType() == "_khtml_HTMLEventListener") {
m_regdListeners->removeRef(it.current());
if (m_regdListeners->isEmpty() && getDocument() && !inDocument())
getDocument()->unregisterDisconnectedNodeWithEventListeners(this);
return;
}
}
void NodeImpl::setHTMLEventListener(int id, EventListener *listener)
{
if (listener)
listener->ref();
removeHTMLEventListener(id);
if (listener)
{
addEventListener(id,listener,false);
listener->deref();
}
}
EventListener *NodeImpl::getHTMLEventListener(int id)
{
if (!m_regdListeners)
return 0;
QPtrListIterator<RegisteredEventListener> it(*m_regdListeners);
for (; it.current(); ++it)
if (it.current()->id == id &&
it.current()->listener->eventListenerType() == "_khtml_HTMLEventListener") {
return it.current()->listener;
}
return 0;
}
bool NodeImpl::dispatchEvent(EventImpl *evt, int &exceptioncode, bool tempEvent)
{
assert(!eventDispatchForbidden());
evt->ref();
evt->setTarget(this);
KHTMLPart *part = nil;
KHTMLView *view = nil;
if (DocumentImpl *doc = getDocument()) {
part = doc->part();
view = doc->view();
if (view)
view->ref();
}
bool ret = dispatchGenericEvent( evt, exceptioncode );
if (tempEvent && part && part->jScript())
part->jScript()->finishedWithEvent(evt);
if (view)
view->deref();
evt->deref();
return ret;
}
bool NodeImpl::dispatchGenericEvent( EventImpl *evt, int &)
{
assert(!eventDispatchForbidden());
evt->ref();
QPtrList<NodeImpl> nodeChain;
NodeImpl *n;
for (n = this; n; n = n->parentNode()) {
n->ref();
nodeChain.prepend(n);
}
evt->setEventPhase(Event::CAPTURING_PHASE);
QPtrListIterator<NodeImpl> it(nodeChain);
it.toFirst();
if (evt->id() != EventImpl::LOAD_EVENT && it.current()->isDocumentNode() && !evt->propagationStopped()) {
static_cast<DocumentImpl*>(it.current())->handleWindowEvent(evt, true);
}
for (; it.current() && it.current() != this && !evt->propagationStopped(); ++it) {
evt->setCurrentTarget(it.current());
it.current()->handleLocalEvents(evt,true);
}
it.toLast();
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);
}
--it;
if (evt->bubbles()) {
evt->setEventPhase(Event::BUBBLING_PHASE);
for (; it.current() && !evt->propagationStopped() && !evt->getCancelBubble(); --it) {
evt->setCurrentTarget(it.current());
it.current()->handleLocalEvents(evt,false);
}
it.toFirst();
if (evt->id() != EventImpl::LOAD_EVENT && it.current()->isDocumentNode() && !evt->propagationStopped() && !evt->getCancelBubble()) {
evt->setCurrentTarget(it.current());
static_cast<DocumentImpl*>(it.current())->handleWindowEvent(evt, false);
}
}
evt->setCurrentTarget(0);
evt->setEventPhase(0);
if (evt->bubbles()) {
it.toLast();
for (; it.current() && !evt->defaultPrevented() && !evt->defaultHandled(); --it)
it.current()->defaultEventHandler(evt);
}
it.toFirst();
for (; it.current(); ++it)
it.current()->deref();
DocumentImpl::updateDocumentsRendering();
bool defaultPrevented = evt->defaultPrevented();
evt->deref();
return !defaultPrevented; }
bool NodeImpl::dispatchHTMLEvent(int _id, bool canBubbleArg, bool cancelableArg)
{
assert(!eventDispatchForbidden());
int exceptioncode = 0;
EventImpl *evt = new EventImpl(static_cast<EventImpl::EventId>(_id),canBubbleArg,cancelableArg);
return dispatchEvent(evt,exceptioncode,true);
}
void NodeImpl::dispatchWindowEvent(int _id, bool canBubbleArg, bool cancelableArg)
{
assert(!eventDispatchForbidden());
khtml::SharedPtr<EventImpl> evt = new EventImpl(static_cast<EventImpl::EventId>(_id),canBubbleArg,cancelableArg);
khtml::SharedPtr<DocumentImpl> doc = getDocument();
evt->setTarget(doc.get());
doc->handleWindowEvent(evt.get(), true);
doc->handleWindowEvent(evt.get(), false);
if (_id == EventImpl::LOAD_EVENT && !evt->propagationStopped() && doc) {
ElementImpl* elt = doc->ownerElement();
if (elt && (elt->getDocument()->domain().isNull() ||
elt->getDocument()->domain() == doc->domain())) {
evt->setCurrentTarget(elt);
elt->handleLocalEvents(evt.get(), true);
if (!evt->propagationStopped())
elt->handleLocalEvents(evt.get(), false);
}
}
}
bool NodeImpl::dispatchMouseEvent(QMouseEvent *_mouse, int overrideId, int overrideDetail, bool isSimulated)
{
assert(!eventDispatchForbidden());
bool cancelable = true;
int detail = overrideDetail; EventImpl::EventId evtId = EventImpl::UNKNOWN_EVENT;
if (overrideId) {
evtId = static_cast<EventImpl::EventId>(overrideId);
}
else {
switch (_mouse->type()) {
case QEvent::MouseButtonPress:
evtId = EventImpl::MOUSEDOWN_EVENT;
break;
case QEvent::MouseButtonRelease:
evtId = EventImpl::MOUSEUP_EVENT;
break;
case QEvent::MouseButtonDblClick:
evtId = EventImpl::CLICK_EVENT;
#if APPLE_CHANGES
detail = _mouse->clickCount();
#else
detail = 1; #endif
break;
case QEvent::MouseMove:
evtId = EventImpl::MOUSEMOVE_EVENT;
cancelable = false;
break;
default:
break;
}
}
if (evtId == EventImpl::UNKNOWN_EVENT)
return false;
int exceptioncode = 0;
#if APPLE_CHANGES
#endif
int clientX = _mouse->x(); int clientY = _mouse->y();
#if APPLE_CHANGES
int screenX;
int screenY;
KHTMLView *view = getDocument()->view();
if (view) {
QPoint windowLoc = view->contentsToViewport(_mouse->pos());
QPoint screenLoc = view->viewportToGlobal(windowLoc);
screenX = screenLoc.x();
screenY = screenLoc.y();
} else {
screenX = _mouse->x();
screenY = _mouse->y();
}
#else
int screenX = _mouse->globalX();
int screenY = _mouse->globalY();
#endif
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() & Qt::ControlButton);
bool altKey = (_mouse->state() & Qt::AltButton);
bool shiftKey = (_mouse->state() & Qt::ShiftButton);
bool metaKey = (_mouse->state() & Qt::MetaButton);
bool swallowEvent = false;
EventImpl *me = new MouseEventImpl(evtId,true,cancelable,getDocument()->defaultView(),
detail,screenX,screenY,clientX,clientY,ctrlKey,altKey,shiftKey,metaKey,
button, 0, 0, isSimulated);
me->ref();
dispatchEvent(me, exceptioncode, true);
bool defaultHandled = me->defaultHandled();
bool defaultPrevented = me->defaultPrevented();
if (defaultHandled || defaultPrevented)
swallowEvent = true;
me->deref();
#if APPLE_CHANGES
if (evtId == EventImpl::CLICK_EVENT && _mouse->isDoubleClick()) {
me = new MouseEventImpl(EventImpl::DBLCLICK_EVENT,
true,cancelable,getDocument()->defaultView(),
detail,screenX,screenY,clientX,clientY,
ctrlKey,altKey,shiftKey,metaKey,
button,0);
me->ref();
if (defaultHandled)
me->setDefaultHandled();
dispatchEvent(me,exceptioncode,true);
if (me->defaultHandled() || me->defaultPrevented())
swallowEvent = true;
me->deref();
}
#endif
if (evtId == EventImpl::CLICK_EVENT && !defaultPrevented && !disabled())
dispatchUIEvent(EventImpl::DOMACTIVATE_EVENT, detail);
return swallowEvent;
}
bool NodeImpl::dispatchUIEvent(int _id, int detail)
{
assert(!eventDispatchForbidden());
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;
if (getDocument()) {
UIEventImpl *evt = new UIEventImpl(static_cast<EventImpl::EventId>(_id),true,
cancelable,getDocument()->defaultView(),detail);
return dispatchEvent(evt,exceptioncode,true);
}
return false;
}
void NodeImpl::registerNodeList(NodeListImpl *list)
{
if (!m_nodeLists) {
m_nodeLists = new QPtrDict<NodeListImpl>;
}
m_nodeLists->insert(list, list);
}
void NodeImpl::unregisterNodeList(NodeListImpl *list)
{
if (!m_nodeLists)
return;
m_nodeLists->remove(list);
}
void NodeImpl::notifyLocalNodeListsSubtreeModified()
{
if (!m_nodeLists)
return;
QPtrDictIterator<NodeListImpl> i(*m_nodeLists);
while (NodeListImpl *list = i.current()) {
list->rootNodeSubtreeModified();
++i;
}
}
void NodeImpl::notifyNodeListsSubtreeModified()
{
for (NodeImpl *n = this; n; n = n->parentNode()) {
n->notifyLocalNodeListsSubtreeModified();
}
}
bool NodeImpl::dispatchSubtreeModifiedEvent(bool sendChildrenChanged)
{
assert(!eventDispatchForbidden());
notifyNodeListsSubtreeModified();
if (sendChildrenChanged)
childrenChanged();
if (!getDocument()->hasListenerType(DocumentImpl::DOMSUBTREEMODIFIED_LISTENER))
return false;
int exceptioncode = 0;
return dispatchEvent(new MutationEventImpl(EventImpl::DOMSUBTREEMODIFIED_EVENT,
true,false,0,DOMString(),DOMString(),DOMString(),0),exceptioncode,true);
}
bool NodeImpl::dispatchKeyEvent(QKeyEvent *key)
{
assert(!eventDispatchForbidden());
int exceptioncode = 0;
KeyboardEventImpl *keyboardEventImpl = new KeyboardEventImpl(key, getDocument()->defaultView());
keyboardEventImpl->ref();
bool r = dispatchEvent(keyboardEventImpl,exceptioncode,true);
#if APPLE_CHANGES
if (keyboardEventImpl->defaultHandled())
#else
if (!keyboardEventImpl->defaultPrevented() && !keyboardEventImpl->qKeyEvent->isAccepted())
#endif
r = false;
keyboardEventImpl->deref();
return r;
}
void NodeImpl::dispatchWheelEvent(QWheelEvent *e)
{
assert(!eventDispatchForbidden());
if (e->delta() == 0)
return;
DocumentImpl *doc = getDocument();
if (!doc)
return;
KHTMLView *view = getDocument()->view();
if (!view)
return;
int x;
int y;
view->viewportToContents(e->x(), e->y(), x, y);
int state = e->state();
WheelEventImpl *we = new WheelEventImpl(e->orientation() == Qt::Horizontal, e->delta(),
getDocument()->defaultView(), e->globalX(), e->globalY(), x, y,
state & Qt::ControlButton, state & Qt::AltButton, state & Qt::ShiftButton, state & Qt::MetaButton);
int exceptionCode = 0;
if (!dispatchEvent(we, exceptionCode, true))
e->accept();
}
void NodeImpl::handleLocalEvents(EventImpl *evt, bool useCapture)
{
if (!m_regdListeners)
return;
if (disabled() && evt->isMouseEvent())
return;
QPtrList<RegisteredEventListener> listenersCopy = *m_regdListeners;
QPtrListIterator<RegisteredEventListener> it(listenersCopy);
Event ev = evt;
for (; it.current(); ++it) {
if (it.current()->id == evt->id() && it.current()->useCapture == useCapture)
it.current()->listener->handleEvent(ev, false);
}
}
void NodeImpl::defaultEventHandler(EventImpl *evt)
{
}
unsigned long NodeImpl::childNodeCount() const
{
return 0;
}
NodeImpl *NodeImpl::childNode(unsigned long )
{
return 0;
}
NodeImpl *NodeImpl::traverseNextNode(const NodeImpl *stayWithin) const
{
if (firstChild()) {
assert(!stayWithin || firstChild()->isAncestor(stayWithin));
return firstChild();
}
if (this == stayWithin)
return 0;
if (nextSibling()) {
assert(!stayWithin || nextSibling()->isAncestor(stayWithin));
return nextSibling();
}
const NodeImpl *n = this;
while (n && !n->nextSibling() && (!stayWithin || n->parentNode() != stayWithin))
n = n->parentNode();
if (n) {
assert(!stayWithin || !n->nextSibling() || n->nextSibling()->isAncestor(stayWithin));
return n->nextSibling();
}
return 0;
}
NodeImpl *NodeImpl::traverseNextSibling(const NodeImpl *stayWithin) const
{
if (this == stayWithin)
return 0;
if (nextSibling()) {
assert(!stayWithin || nextSibling()->isAncestor(stayWithin));
return nextSibling();
}
const NodeImpl *n = this;
while (n && !n->nextSibling() && (!stayWithin || n->parentNode() != stayWithin))
n = n->parentNode();
if (n) {
assert(!stayWithin || !n->nextSibling() || n->nextSibling()->isAncestor(stayWithin));
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;
}
}
NodeImpl *NodeImpl::traversePreviousNodePostOrder(const NodeImpl *stayWithin) const
{
if (lastChild()) {
assert(!stayWithin || lastChild()->isAncestor(stayWithin));
return lastChild();
}
if (this == stayWithin)
return 0;
if (previousSibling()) {
assert(!stayWithin || previousSibling()->isAncestor(stayWithin));
return previousSibling();
}
const NodeImpl *n = this;
while (n && !n->previousSibling() && (!stayWithin || n->parentNode() != stayWithin))
n = n->parentNode();
if (n) {
assert(!stayWithin || !n->previousSibling() || n->previousSibling()->isAncestor(stayWithin));
return n->previousSibling();
}
return 0;
}
void NodeImpl::checkSetPrefix(const DOMString &_prefix, int &exceptioncode)
{
if (!Element::khtmlValidPrefix(_prefix)) {
exceptioncode = DOMException::INVALID_CHARACTER_ERR;
return;
}
if (isReadOnly()) {
exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
return;
}
if (Element::khtmlMalformedPrefix(_prefix) || (namespacePart(id()) == noNamespace && id() > ID_LAST_TAG) ||
(_prefix == "xml" && DOMString(getDocument()->namespaceURI(id())) != "http://www.w3.org/XML/1998/namespace")) {
exceptioncode = DOMException::NAMESPACE_ERR;
return;
}
}
void NodeImpl::checkAddChild(NodeImpl *newChild, int &exceptioncode)
{
if (!newChild) {
exceptioncode = DOMException::NOT_FOUND_ERR;
return;
}
if (isReadOnly()) {
exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
return;
}
bool shouldAdoptChild = false;
if (newChild->getDocument() != getDocument()) {
if (!newChild->inDocument()) {
shouldAdoptChild = true;
} else {
exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
return;
}
}
if (newChild == this || isAncestor(newChild)) {
exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
return;
}
if (shouldAdoptChild) {
KJS::ScriptInterpreter::updateDOMNodeDocument(newChild, newChild->getDocument(), getDocument());
newChild->setDocument(getDocument());
}
}
bool NodeImpl::isAncestor(const NodeImpl *other) const
{
for (const NodeImpl *n = parentNode(); 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 ) const
{
StyleChange ch = NoInherit;
EDisplay display1 = s1 ? s1->display() : NONE;
bool fl1 = s1 ? s1->hasPseudoStyle(RenderStyle::FIRST_LETTER) : false;
EDisplay display2 = s2 ? s2->display() : NONE;
bool fl2 = s2 ? s2->hasPseudoStyle(RenderStyle::FIRST_LETTER) : false;
if (display1 != display2 || fl1 != fl2)
ch = Detach;
else if ( !s1 || !s2 )
ch = Inherit;
else if ( *s1 == *s2 )
ch = NoChange;
else if ( s1->inheritedNotEqual( s2 ) )
ch = Inherit;
return ch;
}
#ifndef NDEBUG
void NodeImpl::dump(QTextStream *stream, QString ind) const
{
if (m_hasId) { *stream << " hasId"; }
if (m_hasClass) { *stream << " hasClass"; }
if (m_hasStyle) { *stream << " hasStyle"; }
if (m_specified) { *stream << " specified"; }
if (m_focused) { *stream << " focused"; }
if (m_active) { *stream << " active"; }
if (m_styleElement) { *stream << " styleElement"; }
if (m_implicit) { *stream << " implicit"; }
*stream << " tabIndex=" << m_tabIndex;
if (m_regdListeners)
*stream << " #regdListeners=" << m_regdListeners->count(); *stream << endl;
NodeImpl *child = firstChild();
while( child != 0 )
{
*stream << ind << child->nodeName().string().ascii() << ": ";
child->dump(stream,ind+" ");
child = child->nextSibling();
}
}
#endif
void NodeImpl::attach()
{
assert(!attached());
assert(!m_render || (m_render->style() && m_render->parent()));
getDocument()->incDOMTreeVersion();
m_attached = true;
}
void NodeImpl::willRemove()
{
}
void NodeImpl::detach()
{
m_inDetach = true;
if (m_render)
m_render->detach();
m_render = 0;
DocumentImpl *doc = getDocument();
if (doc)
doc->incDOMTreeVersion();
m_attached = false;
m_inDetach = false;
}
bool NodeImpl::maintainsState()
{
return false;
}
QString NodeImpl::state()
{
return QString::null;
}
void NodeImpl::restoreState(QStringList &)
{
}
void NodeImpl::insertedIntoDocument()
{
if (m_regdListeners && !m_regdListeners->isEmpty() && getDocument())
getDocument()->unregisterDisconnectedNodeWithEventListeners(this);
setInDocument(true);
}
void NodeImpl::removedFromDocument()
{
if (m_regdListeners && !m_regdListeners->isEmpty() && getDocument())
getDocument()->registerDisconnectedNodeWithEventListeners(this);
setInDocument(false);
}
void NodeImpl::childrenChanged()
{
}
bool NodeImpl::disabled() const
{
return false;
}
bool NodeImpl::isReadOnly()
{
NodeImpl *n = this;
while (n) {
if (n->nodeType() == Node::ENTITY_NODE ||
n->nodeType() == Node::ENTITY_REFERENCE_NODE)
return true;
n = n->parentNode();
}
return false;
}
NodeImpl *NodeImpl::previousEditable() const
{
NodeImpl *node = previousLeafNode();
while (node) {
if (node->isContentEditable())
return node;
node = node->previousLeafNode();
}
return 0;
}
NodeImpl *NodeImpl::nextEditable() const
{
NodeImpl *node = nextLeafNode();
while (node) {
if (node->isContentEditable())
return node;
node = node->nextLeafNode();
}
return 0;
}
RenderObject * NodeImpl::previousRenderer()
{
for (NodeImpl *n = previousSibling(); n; n = n->previousSibling()) {
if (n->renderer())
return n->renderer();
}
return 0;
}
RenderObject * NodeImpl::nextRenderer()
{
if (parent() && !parent()->attached())
return 0;
for (NodeImpl *n = nextSibling(); n; n = n->nextSibling()) {
if (n->renderer())
return n->renderer();
}
return 0;
}
bool NodeImpl::isAtomicNode() const
{
return !hasChildNodes() || (id() == ID_OBJECT && renderer() && renderer()->isReplaced());
}
NodeImpl *NodeImpl::previousNodeConsideringAtomicNodes() const
{
if (previousSibling()) {
NodeImpl *n = previousSibling();
while (!n->isAtomicNode() && n->lastChild())
n = n->lastChild();
return n;
}
else if (parentNode()) {
return parentNode();
}
else {
return 0;
}
}
NodeImpl *NodeImpl::nextNodeConsideringAtomicNodes() const
{
if (!isAtomicNode() && firstChild())
return firstChild();
if (nextSibling())
return nextSibling();
const NodeImpl *n = this;
while (n && !n->nextSibling())
n = n->parentNode();
if (n)
return n->nextSibling();
return 0;
}
NodeImpl *NodeImpl::previousLeafNode() const
{
NodeImpl *node = previousNodeConsideringAtomicNodes();
while (node) {
if (node->isAtomicNode())
return node;
node = node->previousNodeConsideringAtomicNodes();
}
return 0;
}
NodeImpl *NodeImpl::nextLeafNode() const
{
NodeImpl *node = nextNodeConsideringAtomicNodes();
while (node) {
if (node->isAtomicNode())
return node;
node = node->nextNodeConsideringAtomicNodes();
}
return 0;
}
void NodeImpl::createRendererIfNeeded()
{
#if APPLE_CHANGES
if (!getDocument()->shouldCreateRenderers())
return;
#endif
assert(!attached());
assert(!m_render);
NodeImpl *parent = parentNode();
assert(parent);
RenderObject *parentRenderer = parent->renderer();
if (parentRenderer && parentRenderer->canHaveChildren()) {
RenderStyle *style = styleForRenderer(parentRenderer);
style->ref();
#ifndef KHTML_NO_XBL
bool resolveStyle = false;
if (getDocument()->bindingManager()->loadBindings(this, style->bindingURIs(), true, &resolveStyle) &&
rendererIsNeeded(style)) {
if (resolveStyle) {
style->deref();
style = styleForRenderer(parentRenderer);
}
#else
if (rendererIsNeeded(style)) {
#endif
m_render = createRenderer(getDocument()->renderArena(), style);
m_render->setStyle(style);
parentRenderer->addChild(m_render, nextRenderer());
#ifndef KHTML_NO_XBL
} #else
}
#endif
style->deref(getDocument()->renderArena());
}
}
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;
}
long NodeImpl::maxOffset() const
{
return 1;
}
long NodeImpl::maxDeepOffset() const
{
if (isTextNode())
return static_cast<const TextImpl*>(this)->length();
if (id() == ID_BR || (renderer() && renderer()->isReplaced()))
return 1;
return childNodeCount();
}
long NodeImpl::caretMinOffset() const
{
return renderer() ? renderer()->caretMinOffset() : 0;
}
long NodeImpl::caretMaxOffset() const
{
return renderer() ? renderer()->caretMaxOffset() : 1;
}
unsigned long NodeImpl::caretMaxRenderedOffset() const
{
return renderer() ? renderer()->caretMaxRenderedOffset() : 1;
}
long NodeImpl::previousOffset (long current) const
{
return renderer() ? renderer()->previousOffset(current) : current - 1;
}
long NodeImpl::nextOffset (long current) const
{
return renderer() ? renderer()->nextOffset(current) : current + 1;
}
bool NodeImpl::isBlockFlow() const
{
return renderer() && renderer()->isBlockFlow();
}
bool NodeImpl::isBlockFlowOrTable() const
{
return renderer() && (renderer()->isBlockFlow() || renderer()->isTable());
}
bool NodeImpl::isEditableBlock() const
{
return isContentEditable() && isBlockFlow();
}
ElementImpl *NodeImpl::enclosingBlockFlowOrTableElement() const
{
NodeImpl *n = const_cast<NodeImpl *>(this);
if (isBlockFlowOrTable())
return static_cast<ElementImpl *>(n);
while (1) {
n = n->parentNode();
if (!n)
break;
if (n->isBlockFlowOrTable() || n->id() == ID_BODY)
return static_cast<ElementImpl *>(n);
}
return 0;
}
ElementImpl *NodeImpl::enclosingBlockFlowElement() const
{
NodeImpl *n = const_cast<NodeImpl *>(this);
if (isBlockFlow())
return static_cast<ElementImpl *>(n);
while (1) {
n = n->parentNode();
if (!n)
break;
if (n->isBlockFlow() || n->id() == ID_BODY)
return static_cast<ElementImpl *>(n);
}
return 0;
}
ElementImpl *NodeImpl::enclosingInlineElement() const
{
NodeImpl *n = const_cast<NodeImpl *>(this);
NodeImpl *p;
while (1) {
p = n->parentNode();
if (!p || p->isBlockFlow() || p->id() == ID_BODY)
return static_cast<ElementImpl *>(n);
for (NodeImpl *sibling = n->previousSibling(); sibling; sibling = sibling->previousSibling()) {
if (sibling->isBlockFlow())
return static_cast<ElementImpl *>(n);
}
n = p;
}
ASSERT_NOT_REACHED();
return 0;
}
ElementImpl *NodeImpl::rootEditableElement() const
{
if (!isContentEditable())
return 0;
NodeImpl *n = const_cast<NodeImpl *>(this);
if (n->id() == ID_BODY)
return static_cast<ElementImpl *>(n);
NodeImpl *result = n->isEditableBlock() ? n : 0;
while (1) {
n = n->parentNode();
if (!n || !n->isContentEditable())
break;
if (n->id() == ID_BODY) {
result = n;
break;
}
if (n->isBlockFlow())
result = n;
}
return static_cast<ElementImpl *>(result);
}
bool NodeImpl::inSameRootEditableElement(NodeImpl *n)
{
return n ? rootEditableElement() == n->rootEditableElement() : false;
}
bool NodeImpl::inSameContainingBlockFlowElement(NodeImpl *n)
{
return n ? enclosingBlockFlowElement() == n->enclosingBlockFlowElement() : false;
}
#if APPLE_CHANGES
NodeImpl::Id NodeImpl::identifier() const
{
return id();
}
#endif
#ifndef NDEBUG
void NodeImpl::displayNode(const char *prefix)
{
if (!prefix)
prefix = "";
if (isTextNode())
fprintf(stderr, "%s%s\t%p \"%s\"\n", prefix, nodeName().string().latin1(), this, nodeValue().string().latin1());
else
fprintf(stderr, "%s%s\t%p\n", prefix, nodeName().string().latin1(), this);
}
void NodeImpl::displayTree()
{
NodeImpl *rootNode = rootEditableElement() ? : this;
NodeImpl *node;
for (node = rootNode; node; node = node->traverseNextNode()) {
NodeImpl *tmpNode;
if (node == this)
fprintf(stderr, "*");
for (tmpNode = node; tmpNode && tmpNode != rootNode; tmpNode = tmpNode->parentNode())
fprintf(stderr, "\t");
node->displayNode(0);
}
}
void NodeImpl::formatForDebugger(char *buffer, unsigned length) const
{
DOMString result;
DOMString s;
s = nodeName();
if (s.length() == 0)
result += "<none>";
else
result += s;
strncpy(buffer, result.string().latin1(), length - 1);
}
#endif
NodeBaseImpl::NodeBaseImpl(DocumentImpl *doc)
: NodeImpl(doc)
{
_first = _last = 0;
}
void NodeBaseImpl::removeAllChildren()
{
static bool alreadyInsideDestructor;
bool topLevel = !alreadyInsideDestructor;
if (topLevel)
alreadyInsideDestructor = true;
static NodeImpl *head;
static NodeImpl *tail;
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() ) {
if (tail)
tail->setNextSibling(n);
else
head = n;
tail = n;
} else if (n->inDocument())
n->removedFromDocument();
}
if (topLevel) {
while ((n = head) != 0) {
next = n->nextSibling();
n->setNextSibling(0);
head = next;
if (next == 0)
tail = 0;
delete n;
}
alreadyInsideDestructor = false;
_first = 0;
_last = 0;
}
}
NodeBaseImpl::~NodeBaseImpl()
{
removeAllChildren();
}
NodeImpl *NodeBaseImpl::firstChild() const
{
return _first;
}
NodeImpl *NodeBaseImpl::lastChild() const
{
return _last;
}
NodeImpl *NodeBaseImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
{
exceptioncode = 0;
if(!refChild)
return appendChild(newChild, exceptioncode);
Node protectNewChild(newChild);
checkAddChild(newChild, exceptioncode);
if (exceptioncode)
return 0;
if (refChild->parentNode() != this) {
exceptioncode = DOMException::NOT_FOUND_ERR;
return 0;
}
bool isFragment = newChild->nodeType() == Node::DOCUMENT_FRAGMENT_NODE;
if (isFragment && !newChild->firstChild())
return (newChild->hasOneRef() && !newChild->parent()) ? 0 : newChild;
NodeImpl *nextChild;
NodeImpl *child = isFragment ? newChild->firstChild() : newChild;
NodeImpl *prev = refChild->previousSibling();
if ( prev == newChild || refChild == newChild ) return newChild;
while (child) {
nextChild = isFragment ? child->nextSibling() : 0;
NodeImpl *newParent = child->parentNode();
if (newParent)
newParent->removeChild( child, exceptioncode );
if (exceptioncode)
return 0;
forbidEventDispatch();
if (prev)
prev->setNextSibling(child);
else
_first = child;
refChild->setPreviousSibling(child);
child->setParent(this);
child->setPreviousSibling(prev);
child->setNextSibling(refChild);
allowEventDispatch();
if (attached() && !child->attached())
child->attach();
dispatchChildInsertedEvents(child,exceptioncode);
prev = child;
child = nextChild;
}
getDocument()->setDocumentChanged(true);
dispatchSubtreeModifiedEvent();
return newChild;
}
NodeImpl *NodeBaseImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
{
exceptioncode = 0;
Node protectNewChild(newChild);
if ( oldChild == newChild ) return oldChild;
checkAddChild(newChild, exceptioncode);
if (exceptioncode)
return 0;
if (!oldChild || oldChild->parentNode() != this) {
exceptioncode = DOMException::NOT_FOUND_ERR;
return 0;
}
bool isFragment = newChild->nodeType() == Node::DOCUMENT_FRAGMENT_NODE;
NodeImpl *nextChild;
NodeImpl *child = isFragment ? newChild->firstChild() : newChild;
NodeImpl *prev = oldChild->previousSibling();
NodeImpl *next = oldChild->nextSibling();
removeChild(oldChild, exceptioncode);
if (exceptioncode)
return 0;
while (child) {
nextChild = isFragment ? child->nextSibling() : 0;
NodeImpl *newParent = child->parentNode();
if (newParent)
newParent->removeChild( child, exceptioncode );
if (exceptioncode)
return 0;
forbidEventDispatch();
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);
allowEventDispatch();
if (attached() && !child->attached())
child->attach();
dispatchChildInsertedEvents(child,exceptioncode);
prev = child;
child = nextChild;
}
getDocument()->setDocumentChanged(true);
dispatchSubtreeModifiedEvent();
return oldChild;
}
void NodeBaseImpl::willRemove()
{
for (NodeImpl *n = _first; n != 0; n = n->nextSibling()) {
n->willRemove();
}
}
int NodeBaseImpl::willRemoveChild(NodeImpl *child)
{
int exceptionCode = 0;
dispatchChildRemovalEvents(child, exceptionCode);
if (exceptionCode)
return exceptionCode;
if (child->attached())
child->willRemove();
return 0;
}
NodeImpl *NodeBaseImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
{
exceptioncode = 0;
if (isReadOnly()) {
exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
return 0;
}
if (!oldChild || oldChild->parentNode() != this) {
exceptioncode = DOMException::NOT_FOUND_ERR;
return 0;
}
if (getDocument()->hasListenerType(DocumentImpl::DOMNODEREMOVED_LISTENER)) {
oldChild->dispatchEvent(new MutationEventImpl(EventImpl::DOMNODEREMOVED_EVENT,
true,false,this,DOMString(),DOMString(),DOMString(),0),exceptioncode,true);
if (exceptioncode)
return 0;
}
exceptioncode = willRemoveChild(oldChild);
if (exceptioncode)
return 0;
forbidEventDispatch();
if (oldChild->attached())
oldChild->detach();
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);
allowEventDispatch();
getDocument()->setDocumentChanged(true);
dispatchSubtreeModifiedEvent();
if (oldChild->inDocument())
oldChild->removedFromDocument();
return oldChild;
}
void NodeBaseImpl::removeChildren()
{
NodeImpl *n;
if (!_first)
return;
for (n = _first; n != 0; n = n->nextSibling())
willRemoveChild(n);
forbidEventDispatch();
while ((n = _first) != 0) {
NodeImpl *next = n->nextSibling();
n->ref();
n->setPreviousSibling(0);
n->setNextSibling(0);
n->setParent(0);
_first = next;
if (n == _last)
_last = 0;
if (n->attached())
n->detach();
if (n->inDocument())
n->removedFromDocument();
n->deref();
}
allowEventDispatch();
dispatchSubtreeModifiedEvent();
}
NodeImpl *NodeBaseImpl::appendChild ( NodeImpl *newChild, int &exceptioncode )
{
exceptioncode = 0;
Node protectNewChild(newChild);
checkAddChild(newChild, exceptioncode);
if (exceptioncode)
return 0;
if ( newChild == _last ) return newChild;
bool isFragment = newChild->nodeType() == Node::DOCUMENT_FRAGMENT_NODE;
if (isFragment && !newChild->firstChild())
return newChild;
NodeImpl *nextChild;
NodeImpl *child = isFragment ? newChild->firstChild() : newChild;
while (child) {
nextChild = isFragment ? child->nextSibling() : 0;
NodeImpl *oldParent = child->parentNode();
if(oldParent) {
oldParent->removeChild( child, exceptioncode );
if (exceptioncode)
return 0;
}
forbidEventDispatch();
child->setParent(this);
if (_last) {
child->setPreviousSibling(_last);
_last->setNextSibling(child);
_last = child;
} else
_first = _last = child;
allowEventDispatch();
if (attached() && !child->attached())
child->attach();
dispatchChildInsertedEvents(child,exceptioncode);
child = nextChild;
}
getDocument()->setDocumentChanged(true);
dispatchSubtreeModifiedEvent();
return newChild;
}
bool NodeBaseImpl::hasChildNodes ( ) const
{
return _first != 0;
}
void NodeBaseImpl::setFirstChild(NodeImpl *child)
{
_first = child;
}
void NodeBaseImpl::setLastChild(NodeImpl *child)
{
_last = child;
}
bool NodeBaseImpl::checkSameDocument( NodeImpl *newChild, int &exceptioncode )
{
exceptioncode = 0;
DocumentImpl *ownerDocThis = getDocument();
DocumentImpl *ownerDocNew = getDocument();
if(ownerDocThis != ownerDocNew) {
kdDebug(6010)<< "not same document, newChild = " << newChild << "document = " << getDocument() << endl;
exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
return true;
}
return false;
}
bool NodeBaseImpl::checkNoOwner( NodeImpl *newChild, int &exceptioncode )
{
NodeImpl *n;
for( n = this; (n != getDocument()) && (n!= 0); n = n->parentNode() )
if(n == newChild) {
exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
return true;
}
return false;
}
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)
{
Node protectNewChild(newChild);
if(!isXMLElementNode() && !newChild->isXMLElementNode() && !childAllowed(newChild))
{
return 0;
}
forbidEventDispatch();
newChild->setParent(this);
if(_last) {
newChild->setPreviousSibling(_last);
_last->setNextSibling(newChild);
_last = newChild;
} else
_first = _last = newChild;
allowEventDispatch();
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::insertedIntoDocument()
{
NodeImpl::insertedIntoDocument();
for (NodeImpl *child = _first; child; child = child->nextSibling())
child->insertedIntoDocument();
}
void NodeBaseImpl::removedFromDocument()
{
NodeImpl::removedFromDocument();
for (NodeImpl *child = _first; child; child = child->nextSibling())
child->removedFromDocument();
}
void NodeBaseImpl::cloneChildNodes(NodeImpl *clone)
{
int exceptioncode = 0;
NodeImpl *n;
for(n = firstChild(); n && !exceptioncode; n = n->nextSibling())
{
clone->appendChild(n->cloneNode(true),exceptioncode);
}
}
NodeListImpl* NodeBaseImpl::getElementsByTagNameNS ( DOMStringImpl* namespaceURI,
DOMStringImpl* localName )
{
if (!localName) return 0;
NodeImpl::Id idMask = namespaceMask | localNameMask;
if (localName->l && localName->s[0] == '*')
idMask &= ~localNameMask;
if (!namespaceURI || (namespaceURI->l && namespaceURI->s[0] == '*'))
idMask &= ~namespaceMask;
Id id = 0; if ( (idMask & localNameMask) || namespaceURI ) {
id = getDocument()->tagId( namespaceURI, localName, true);
if ( !id ) id = (Id)-1; }
return new TagNodeListImpl( this, id, idMask );
}
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;
}
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->parent()->element() == this && o->isText() && !o->isBR() && !static_cast<RenderText*>(o)->firstTextBox()) {
}
else if((o->isText() && !o->isBR()) || o->isReplaced()) {
o->container()->absolutePosition( xPos, yPos );
if (o->isText())
xPos += static_cast<RenderText *>(o)->minXPos();
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();
return true;
}
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->isReplaced()) {
o->container()->absolutePosition(xPos, yPos);
if (o->isText())
xPos += static_cast<RenderText *>(o)->minXPos() + o->width();
else
xPos += o->xPos()+o->width();
yPos += o->yPos()+o->height();
return true;
}
}
return true;
}
QRect NodeBaseImpl::getRect() const
{
int xPos = 0, yPos = 0, xEnd = 0, yEnd = 0;
bool foundUpperLeft = getUpperLeftCorner(xPos,yPos);
bool foundLowerRight = getLowerRightCorner(xEnd,yEnd);
if (foundUpperLeft != foundLowerRight)
{
if (foundUpperLeft) {
xEnd = xPos;
yEnd = yPos;
} else {
xPos = xEnd;
yPos = yEnd;
}
}
if (xEnd < xPos)
xEnd = xPos;
if (yEnd < yPos)
yEnd = yPos;
return QRect(xPos, yPos, xEnd - xPos, yEnd - yPos);
}
void NodeBaseImpl::setFocus(bool received)
{
if (m_focused == received) return;
NodeImpl::setFocus(received);
if (received && isEditableBlock() && !hasChildNodes()) {
getDocument()->part()->setSelection(Selection(Position(this, 0), DOWNSTREAM));
}
setChanged();
}
void NodeBaseImpl::setActive(bool down)
{
if (down == active()) return;
NodeImpl::setActive(down);
if (m_render && m_render->style()->affectedByActiveRules())
setChanged();
}
void NodeBaseImpl::setHovered(bool over)
{
if (over == hovered()) return;
NodeImpl::setHovered(over);
if (m_render) {
if (m_render->style()->affectedByHoverRules())
setChanged();
}
}
unsigned long NodeBaseImpl::childNodeCount() const
{
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 != 0 && i < index; i++)
n = n->nextSibling();
return n;
}
void NodeBaseImpl::dispatchChildInsertedEvents( NodeImpl *child, int &exceptioncode )
{
assert(!eventDispatchForbidden());
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 (getDocument()->hasListenerType(DocumentImpl::DOMNODEINSERTED_LISTENER)) {
child->dispatchEvent(new MutationEventImpl(EventImpl::DOMNODEINSERTED_EVENT,
true,false,this,DOMString(),DOMString(),DOMString(),0),exceptioncode,true);
if (exceptioncode)
return;
}
bool hasInsertedListeners = getDocument()->hasListenerType(DocumentImpl::DOMNODEINSERTEDINTODOCUMENT_LISTENER);
if (hasInsertedListeners && p->nodeType() == Node::DOCUMENT_NODE) {
for (NodeImpl *c = child; c; c = c->traverseNextNode(child)) {
c->dispatchEvent(new MutationEventImpl(EventImpl::DOMNODEINSERTEDINTODOCUMENT_EVENT,
false,false,0,DOMString(),DOMString(),DOMString(),0),exceptioncode,true);
if (exceptioncode)
return;
}
}
}
void NodeBaseImpl::dispatchChildRemovalEvents( NodeImpl *child, int &exceptioncode )
{
getDocument()->notifyBeforeNodeRemoval(child);
if (getDocument()->hasListenerType(DocumentImpl::DOMNODEREMOVED_LISTENER)) {
child->dispatchEvent(new MutationEventImpl(EventImpl::DOMNODEREMOVED_EVENT,
true,false,this,DOMString(),DOMString(),DOMString(),0),exceptioncode,true);
if (exceptioncode)
return;
}
bool hasRemovalListeners = getDocument()->hasListenerType(DocumentImpl::DOMNODEREMOVEDFROMDOCUMENT_LISTENER);
if (inDocument()) {
for (NodeImpl *c = child; c; c = c->traverseNextNode(child)) {
if (hasRemovalListeners) {
c->dispatchEvent(new MutationEventImpl(EventImpl::DOMNODEREMOVEDFROMDOCUMENT_EVENT,
false,false,0,DOMString(),DOMString(),DOMString(),0),exceptioncode,true);
if (exceptioncode)
return;
}
}
}
}
NodeListImpl::NodeListImpl(NodeImpl *_rootNode)
: rootNode(_rootNode),
isLengthCacheValid(false),
isItemCacheValid(false)
{
rootNode->ref();
rootNode->registerNodeList(this);
}
NodeListImpl::~NodeListImpl()
{
rootNode->unregisterNodeList(this);
rootNode->deref();
}
unsigned long NodeListImpl::recursiveLength( NodeImpl *start ) const
{
if (!start)
start = rootNode;
if (isLengthCacheValid && start == rootNode) {
return cachedLength;
}
unsigned long len = 0;
for(NodeImpl *n = start->firstChild(); n != 0; n = n->nextSibling()) {
if ( n->nodeType() == Node::ELEMENT_NODE ) {
if (nodeMatches(n))
len++;
len+= recursiveLength(n);
}
}
if (start == rootNode) {
cachedLength = len;
isLengthCacheValid = true;
}
return len;
}
NodeImpl *NodeListImpl::recursiveItem ( unsigned long offset, NodeImpl *start) const
{
int remainingOffset = offset;
if (!start) {
start = rootNode->firstChild();
if (isItemCacheValid) {
if (offset == lastItemOffset) {
return lastItem;
} else if (offset > lastItemOffset) {
start = lastItem;
remainingOffset -= lastItemOffset;
}
}
}
NodeImpl *n = start;
while (n) {
if ( n->nodeType() == Node::ELEMENT_NODE ) {
if (nodeMatches(n)) {
if (!remainingOffset) {
lastItem = n;
lastItemOffset = offset;
isItemCacheValid = 1;
return n;
}
remainingOffset--;
}
}
n = n->traverseNextNode(rootNode);
}
return 0; }
NodeImpl *NodeListImpl::itemById (const DOMString& elementId) const
{
if (rootNode->isDocumentNode() || rootNode->inDocument()) {
NodeImpl *node = rootNode->getDocument()->getElementById(elementId);
if (node == NULL || !nodeMatches(node))
return 0;
for (NodeImpl *p = node->parentNode(); p; p = p->parentNode()) {
if (p == rootNode)
return node;
}
return 0;
}
unsigned long l = length();
for ( unsigned long i = 0; i < l; i++ ) {
NodeImpl *node = item(i);
if ( static_cast<ElementImpl *>(node)->getIDAttribute() == elementId ) {
return node;
}
}
return 0;
}
void NodeListImpl::rootNodeSubtreeModified()
{
isLengthCacheValid = false;
isItemCacheValid = false;
}
ChildNodeListImpl::ChildNodeListImpl( NodeImpl *n )
: NodeListImpl(n)
{
}
unsigned long ChildNodeListImpl::length() const
{
unsigned long len = 0;
NodeImpl *n;
for(n = rootNode->firstChild(); n != 0; n = n->nextSibling())
len++;
return len;
}
NodeImpl *ChildNodeListImpl::item ( unsigned long index ) const
{
unsigned int pos = 0;
NodeImpl *n = rootNode->firstChild();
while( n != 0 && pos < index )
{
n = n->nextSibling();
pos++;
}
return n;
}
bool ChildNodeListImpl::nodeMatches(NodeImpl *testNode) const
{
return testNode->parentNode() == rootNode;
}
TagNodeListImpl::TagNodeListImpl(NodeImpl *n, NodeImpl::Id _id, NodeImpl::Id _idMask )
: NodeListImpl(n),
m_id(_id & _idMask),
m_idMask(_idMask)
{
}
unsigned long TagNodeListImpl::length() const
{
return recursiveLength();
}
NodeImpl *TagNodeListImpl::item ( unsigned long index ) const
{
return recursiveItem( index );
}
bool TagNodeListImpl::nodeMatches( NodeImpl *testNode ) const
{
return ( testNode->isElementNode() &&
(testNode->id() & m_idMask) == m_id);
}
NameNodeListImpl::NameNodeListImpl(NodeImpl *n, const DOMString &t )
: NodeListImpl(n), nodeName(t)
{
}
unsigned long NameNodeListImpl::length() const
{
return recursiveLength();
}
NodeImpl *NameNodeListImpl::item ( unsigned long index ) const
{
return recursiveItem( index );
}
bool NameNodeListImpl::nodeMatches( NodeImpl *testNode ) const
{
return static_cast<ElementImpl *>(testNode)->getAttribute(ATTR_NAME) == nodeName;
}
NamedNodeMapImpl::NamedNodeMapImpl()
{
}
NamedNodeMapImpl::~NamedNodeMapImpl()
{
}
#if 0
GenericRONamedNodeMapImpl::GenericRONamedNodeMapImpl(DocumentImpl* doc)
: NamedNodeMapImpl()
{
m_doc = doc->document();
m_contents = new QPtrList<NodeImpl>;
}
GenericRONamedNodeMapImpl::~GenericRONamedNodeMapImpl()
{
while (m_contents->count() > 0)
m_contents->take(0)->deref();
delete m_contents;
}
NodeImpl *GenericRONamedNodeMapImpl::getNamedItem ( const DOMString &name, int & ) const
{
QPtrListIterator<NodeImpl> it(*m_contents);
for (; it.current(); ++it)
if (it.current()->nodeName() == name)
return it.current();
return 0;
}
Node GenericRONamedNodeMapImpl::setNamedItem ( const Node &, int &exceptioncode )
{
exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
return 0;
}
Node GenericRONamedNodeMapImpl::removeNamedItem ( const DOMString &, int &exceptioncode )
{
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();
}
NodeImpl *GenericRONamedNodeMapImpl::getNamedItemNS( const DOMString &namespaceURI,
const DOMString &localName,
int & ) const
{
NodeImpl::Id searchId = m_doc->tagId(namespaceURI.implementation(),
localName.implementation(), true);
QPtrListIterator<NodeImpl> it(*m_contents);
for (; it.current(); ++it)
if (it.current()->id() == searchId)
return it.current();
return 0;
}
NodeImpl *GenericRONamedNodeMapImpl::setNamedItemNS( NodeImpl *, int &exceptioncode )
{
exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
return 0;
}
NodeImpl *GenericRONamedNodeMapImpl::removeNamedItemNS( const DOMString &,
const DOMString &,
int &exceptioncode )
{
exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
return 0;
}
void GenericRONamedNodeMapImpl::addNode(NodeImpl *n)
{
int exceptioncode = 0;
if (getNamedItem(n->nodeName(),exceptioncode))
return;
n->ref();
m_contents->append(n);
}
#endif