#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_nodeimpl.h"
#include "css/cssstyleselector.h"
#include <kglobal.h>
#include <kdebug.h>
#include "rendering/render_text.h"
#include "ecma/kjs_binding.h"
#include "ecma/kjs_proxy.h"
#include "khtmlview.h"
#include "khtml_part.h"
using namespace DOM;
using namespace khtml;
const Q_UINT32 NodeImpl::IdNSMask = 0xffff0000;
const Q_UINT32 NodeImpl::IdLocalMask = 0x0000ffff;
NodeImpl::NodeImpl(DocumentPtr *doc)
: document(doc),
m_previous(0),
m_next(0),
m_render(0),
m_regdListeners( 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_styleElement( false ),
m_implicit( false ),
m_rendererNeedsClose( false )
{
if (document)
document->ref();
}
void NodeImpl::setDocument(DocumentPtr *doc)
{
if (inDocument())
return;
if (doc)
doc->ref();
if (document)
document->deref();
document = doc;
}
NodeImpl::~NodeImpl()
{
if (m_render)
detach();
delete m_regdListeners;
if (document)
document->deref();
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::insertBefore( NodeImpl *, NodeImpl *, int &exceptioncode )
{
exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
return 0;
}
NodeImpl *NodeImpl::replaceChild( NodeImpl *, NodeImpl *, int &exceptioncode )
{
exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
return 0;
}
NodeImpl *NodeImpl::removeChild( NodeImpl *, int &exceptioncode )
{
exceptioncode = DOMException::NOT_FOUND_ERR;
return 0;
}
NodeImpl *NodeImpl::appendChild( NodeImpl *, int &exceptioncode )
{
exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
return 0;
}
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;
removeChild(nextChild,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();
}
void NodeImpl::setFirstChild(NodeImpl *)
{
}
void NodeImpl::setLastChild(NodeImpl *)
{
}
NodeImpl *NodeImpl::addChild(NodeImpl *)
{
return 0;
}
QString NodeImpl::toHTML() const
{
NodeImpl* fc = firstChild();
if ( fc )
return fc->recursive_toHTML(true);
return "";
}
static QString escapeHTML( const QString& in )
{
QString s;
for ( unsigned int i = 0; i < in.length(); ++i ) {
switch( in[i].latin1() ) {
case '&':
s += "&";
break;
case '<':
s += "<";
break;
case '>':
s += ">";
break;
default:
s += in[i];
}
}
return s;
}
QString NodeImpl::recursive_toHTML(bool start) const
{
QString me = "";
if ( nodeType() == Node::TEXT_NODE )
me = escapeHTML( nodeValue().string() );
else
{
NodeImpl* temp = previousSibling();
if(temp)
{
if( !start && (temp->nodeType() != Node::TEXT_NODE && nodeType() != Node::TEXT_NODE ) )
me = QString(" ") + QChar('<') + nodeName().string();
else
me = QChar('<') + nodeName().string();
}
else
me = QChar('<') + nodeName().string();
if( nodeType() == Node::ELEMENT_NODE )
{
const ElementImpl *el = static_cast<const ElementImpl *>(this);
NamedNodeMap attrs = el->attributes();
unsigned long lmap = attrs.length();
for( unsigned int j=0; j<lmap; j++ )
me += " " + attrs.item(j).nodeName().string() + "=\"" + attrs.item(j).nodeValue().string() + "\"";
}
if( firstChild() == 0 ) { if (isHTMLElement()) {
me +=">";
} else {
me +="/>";
}
} else {
NodeImpl* temp = nextSibling();
if(temp)
{
if( (temp->nodeType() != Node::TEXT_NODE) )
me += ">\n";
else
me += ">";
}
else
me += ">";
}
}
NodeImpl* n;
if( (n = firstChild()) )
{
me += n->recursive_toHTML( );
if ( nodeType() != Node::TEXT_NODE )
me += "</" + nodeName().string() + ">\n";
}
if( (n = nextSibling()) )
me += n->recursive_toHTML( );
return me;
}
void NodeImpl::getCursor(int offset, int &_x, int &_y, int &height)
{
if(m_render) m_render->cursorPos(offset, _x, _y, height);
else _x = _y = height = -1;
}
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)
{
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);
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());
return;
}
}
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());
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)
{
evt->setTarget(this);
KHTMLPart *part = document->document()->part();
KHTMLView *view = document->document()->view();
if (view)
view->ref();
bool ret = dispatchGenericEvent( evt, exceptioncode );
if (tempEvent && part && part->jScript())
part->jScript()->finishedWithEvent(evt);
if (view)
view->deref();
return ret;
}
bool NodeImpl::dispatchGenericEvent( EventImpl *evt, int &)
{
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);
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);
}
}
evt->setCurrentTarget(0);
evt->setEventPhase(0);
if (evt->bubbles()) {
it.toLast();
for (; it.current() && !evt->propagationStopped() && !evt->defaultPrevented() && !evt->defaultHandled(); --it)
it.current()->defaultEventHandler(evt);
}
if (!evt->defaultPrevented() && !disabled())
if (evt->id() == EventImpl::KHTML_CLICK_EVENT)
dispatchUIEvent(EventImpl::DOMACTIVATE_EVENT, 1);
else if (evt->id() == EventImpl::KHTML_DBLCLICK_EVENT)
dispatchUIEvent(EventImpl::DOMACTIVATE_EVENT, 2);
it.toFirst();
for (; it.current(); ++it)
it.current()->deref();
DocumentImpl::updateDocumentsRendering();
return !evt->defaultPrevented(); }
bool NodeImpl::dispatchHTMLEvent(int _id, bool canBubbleArg, bool cancelableArg)
{
int exceptioncode = 0;
EventImpl *evt = new EventImpl(static_cast<EventImpl::EventId>(_id),canBubbleArg,cancelableArg);
evt->ref();
bool r = dispatchEvent(evt,exceptioncode,true);
evt->deref();
return r;
}
bool NodeImpl::dispatchWindowEvent(int _id, bool canBubbleArg, bool cancelableArg)
{
int exceptioncode = 0;
EventImpl *evt = new EventImpl(static_cast<EventImpl::EventId>(_id),canBubbleArg,cancelableArg);
evt->setTarget( 0 );
evt->ref();
DocumentPtr *doc = document;
doc->ref();
bool r = dispatchGenericEvent( evt, exceptioncode );
if (!evt->defaultPrevented() && doc->document())
doc->document()->defaultEventHandler(evt);
if (_id == EventImpl::LOAD_EVENT && !evt->propagationStopped() && doc->document()) {
DOM::ElementImpl* elt = doc->document()->ownerElement();
if (elt && (elt->getDocument()->domain().isNull() ||
elt->getDocument()->domain() == doc->document()->domain())) {
evt->setCurrentTarget(elt);
elt->handleLocalEvents(evt,true);
if (!evt->propagationStopped())
elt->handleLocalEvents(evt,false);
r = !evt->defaultPrevented();
}
}
doc->deref();
evt->deref();
return r;
}
bool NodeImpl::dispatchMouseEvent(QMouseEvent *_mouse, int overrideId, int overrideDetail)
{
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;
detail = 1; break;
case QEvent::MouseMove:
evtId = EventImpl::MOUSEMOVE_EVENT;
cancelable = false;
break;
default:
break;
}
}
if (evtId == EventImpl::UNKNOWN_EVENT)
return false;
int exceptioncode = 0;
int clientX = _mouse->x(); int clientY = _mouse->y();
int screenX = _mouse->globalX();
int screenY = _mouse->globalY();
int button = -1;
switch (_mouse->button()) {
case Qt::LeftButton:
button = 0;
break;
case Qt::MidButton:
button = 1;
break;
case Qt::RightButton:
button = 2;
break;
default:
break;
}
bool ctrlKey = (_mouse->state() & Qt::ControlButton);
bool altKey = (_mouse->state() & Qt::AltButton);
bool shiftKey = (_mouse->state() & Qt::ShiftButton);
bool metaKey = false;
EventImpl *evt = new MouseEventImpl(evtId,true,cancelable,getDocument()->defaultView(),
detail,screenX,screenY,clientX,clientY,ctrlKey,altKey,shiftKey,metaKey,
button,0);
evt->ref();
bool r = dispatchEvent(evt,exceptioncode,true);
evt->deref();
return r;
}
bool NodeImpl::dispatchUIEvent(int _id, int detail)
{
assert (!( (_id != EventImpl::DOMFOCUSIN_EVENT &&
_id != EventImpl::DOMFOCUSOUT_EVENT &&
_id != EventImpl::DOMACTIVATE_EVENT)));
bool cancelable = false;
if (_id == EventImpl::DOMACTIVATE_EVENT)
cancelable = true;
int exceptioncode = 0;
UIEventImpl *evt = new UIEventImpl(static_cast<EventImpl::EventId>(_id),true,
cancelable,getDocument()->defaultView(),detail);
evt->ref();
bool r = dispatchEvent(evt,exceptioncode,true);
evt->deref();
return r;
}
bool NodeImpl::dispatchSubtreeModifiedEvent()
{
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)
{
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::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()
{
return 0;
}
NodeImpl *NodeImpl::childNode(unsigned long )
{
return 0;
}
NodeImpl *NodeImpl::traverseNextNode(NodeImpl *stayWithin) const
{
if (firstChild())
return firstChild();
else if (nextSibling())
return nextSibling();
else {
const NodeImpl *n = this;
while (n && !n->nextSibling() && (!stayWithin || n->parentNode() != stayWithin))
n = n->parentNode();
if (n && (!stayWithin || n->parentNode() != 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;
}
}
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) || (!(id() & IdNSMask) && 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 (isAncestor(newChild)) {
exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
return;
}
if (shouldAdoptChild) {
KJS::ScriptInterpreter::updateDOMObjectDocument(newChild, newChild->getDocument(), getDocument());
newChild->setDocument(getDocument()->docPtr());
}
}
bool NodeImpl::isAncestor( NodeImpl *other )
{
NodeImpl *n;
for (n = this; n; n = n->parentNode()) {
if (n == other)
return true;
}
return false;
}
bool NodeImpl::childAllowed( NodeImpl *newChild )
{
return childTypeAllowed(newChild->nodeType());
}
NodeImpl::StyleChange NodeImpl::diff( khtml::RenderStyle *s1, khtml::RenderStyle *s2 ) 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::closeRenderer()
{
assert(!m_rendererNeedsClose);
if (m_render)
m_render->close();
else
m_rendererNeedsClose = true;
}
void NodeImpl::attach()
{
assert(!attached());
assert(!m_render || (m_render->style() && m_render->parent()));
if (m_render && m_rendererNeedsClose) {
m_render->close();
m_rendererNeedsClose = false;
}
m_attached = true;
}
void NodeImpl::detach()
{
if (m_render)
m_render->detach();
m_render = 0;
m_attached = false;
}
bool NodeImpl::maintainsState()
{
return false;
}
QString NodeImpl::state()
{
return QString::null;
}
void NodeImpl::restoreState(QStringList &)
{
}
void NodeImpl::insertedIntoDocument()
{
setInDocument(true);
}
void NodeImpl::removedFromDocument()
{
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;
}
RenderObject * NodeImpl::previousRenderer()
{
for (NodeImpl *n = previousSibling(); n; n = n->previousSibling()) {
if (n->renderer())
return n->renderer();
}
return 0;
}
RenderObject * NodeImpl::nextRenderer()
{
for (NodeImpl *n = nextSibling(); n; n = n->nextSibling()) {
if (n->renderer())
return n->renderer();
}
return 0;
}
void NodeImpl::createRendererIfNeeded()
{
#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();
if (rendererIsNeeded(style)) {
m_render = createRenderer(getDocument()->renderArena(), style);
m_render->setStyle(style);
parentRenderer->addChild(m_render, nextRenderer());
}
style->deref();
}
}
RenderStyle *NodeImpl::styleForRenderer(RenderObject *parent)
{
return parent->style();
}
bool NodeImpl::rendererIsNeeded(RenderStyle *style)
{
return (getDocument()->documentElement() == this) || (style->display() != NONE);
}
RenderObject *NodeImpl::createRenderer(RenderArena *arena, RenderStyle *style)
{
assert(false);
return 0;
}
NodeBaseImpl::NodeBaseImpl(DocumentPtr *doc)
: NodeImpl(doc)
{
_first = _last = 0;
}
NodeBaseImpl::~NodeBaseImpl()
{
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;
}
}
if (topLevel) {
while ((n = head) != 0) {
next = n->nextSibling();
n->setNextSibling(0);
head = next;
if (next == 0)
tail = 0;
delete n;
}
alreadyInsideDestructor = false;
}
}
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);
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;
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;
if (prev)
prev->setNextSibling(child);
else
_first = child;
refChild->setPreviousSibling(child);
child->setParent(this);
child->setPreviousSibling(prev);
child->setNextSibling(refChild);
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;
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;
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);
if (attached() && !child->attached())
child->attach();
dispatchChildInsertedEvents(child,exceptioncode);
prev = child;
child = nextChild;
}
getDocument()->setDocumentChanged(true);
dispatchSubtreeModifiedEvent();
return oldChild;
}
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;
}
getDocument()->notifyBeforeNodeRemoval(oldChild); 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;
}
dispatchChildRemovalEvents(oldChild,exceptioncode);
if (exceptioncode)
return 0;
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);
getDocument()->setDocumentChanged(true);
dispatchSubtreeModifiedEvent();
NodeImpl *p = this;
while (p->parentNode())
p = p->parentNode();
if (p->nodeType() == Node::DOCUMENT_NODE) {
for (NodeImpl *c = oldChild; c; c = c->traverseNextNode(oldChild))
c->removedFromDocument();
}
return oldChild;
}
void NodeBaseImpl::removeChildren()
{
NodeImpl *n, *next;
for( n = _first; n != 0; n = next )
{
next = n->nextSibling();
if (n->attached())
n->detach();
n->setPreviousSibling(0);
n->setNextSibling(0);
n->setParent(0);
if( !n->refCount() )
delete n;
}
_first = _last = 0;
}
NodeImpl *NodeBaseImpl::appendChild ( NodeImpl *newChild, int &exceptioncode )
{
exceptioncode = 0;
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;
}
child->setParent(this);
if(_last)
{
child->setPreviousSibling(_last);
_last->setNextSibling(child);
_last = child;
}
else
{
_first = _last = child;
}
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)
{
if(!isXMLElementNode() && !newChild->isXMLElementNode() && !childAllowed(newChild))
{
return 0;
}
newChild->setParent(this);
if(_last)
{
newChild->setPreviousSibling(_last);
_last->setNextSibling(newChild);
_last = newChild;
}
else
{
_first = _last = newChild;
}
newChild->insertedIntoDocument();
childrenChanged();
if(newChild->nodeType() == Node::ELEMENT_NODE)
return newChild;
return this;
}
void NodeBaseImpl::attach()
{
NodeImpl *child = _first;
while(child != 0)
{
child->attach();
child = child->nextSibling();
}
NodeImpl::attach();
}
void NodeBaseImpl::detach()
{
NodeImpl *child = _first;
while(child != 0)
{
NodeImpl* prev = child;
child = child->nextSibling();
prev->detach();
}
NodeImpl::detach();
}
void NodeBaseImpl::cloneChildNodes(NodeImpl *clone)
{
int exceptioncode = 0;
NodeImpl *n;
for(n = firstChild(); n && !exceptioncode; n = n->nextSibling())
{
clone->appendChild(n->cloneNode(true),exceptioncode);
}
}
NodeListImpl* NodeBaseImpl::getElementsByTagNameNS ( DOMStringImpl* namespaceURI,
DOMStringImpl* localName )
{
if (!localName) return 0;
NodeImpl::Id idMask = NodeImpl::IdNSMask | NodeImpl::IdLocalMask;
if (localName->l && localName->s[0] == '*')
idMask &= ~NodeImpl::IdLocalMask;
if (namespaceURI && namespaceURI->l && namespaceURI->s[0] == '*')
idMask &= ~NodeImpl::IdNSMask;
Id id = 0; if ( (idMask & NodeImpl::IdLocalMask) || 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->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, yPos;
if (!getUpperLeftCorner(xPos,yPos))
{
xPos=0;
yPos=0;
}
int xEnd, yEnd;
if (!getLowerRightCorner(xEnd,yEnd))
{
if (xPos)
xEnd = xPos;
if (yPos)
yEnd = yPos;
}
else
{
if (xPos==0)
xPos = xEnd;
if (yPos==0)
yPos = yEnd;
}
if ( xEnd <= xPos || yEnd <= yPos )
return QRect( QPoint( xPos, yPos ), QSize() );
return QRect(xPos, yPos, xEnd - xPos, yEnd - yPos);
}
void NodeBaseImpl::setFocus(bool received)
{
if (m_focused == received) return;
NodeImpl::setFocus(received);
setChanged();
}
void NodeBaseImpl::setActive(bool down)
{
if (down == active()) return;
NodeImpl::setActive(down);
if (m_render && m_render->style()->affectedByActiveRules())
setChanged();
}
unsigned long NodeBaseImpl::childNodeCount()
{
unsigned long count = 0;
NodeImpl *n;
for (n = firstChild(); n; n = n->nextSibling())
count++;
return count;
}
NodeImpl *NodeBaseImpl::childNode(unsigned long index)
{
unsigned long i;
NodeImpl *n = firstChild();
for (i = 0; i < index; i++)
n = n->nextSibling();
return n;
}
void NodeBaseImpl::dispatchChildInsertedEvents( NodeImpl *child, int &exceptioncode )
{
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);
NodeImpl *p = this;
while (p->parentNode())
p = p->parentNode();
if (p->nodeType() == Node::DOCUMENT_NODE) {
for (NodeImpl *c = child; c; c = c->traverseNextNode(child)) {
c->insertedIntoDocument();
if (hasInsertedListeners) {
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);
NodeImpl *p = this;
while (p->parentNode())
p = p->parentNode();
if (p->nodeType() == Node::DOCUMENT_NODE) {
for (NodeImpl *c = child; c; c = c->traverseNextNode(child)) {
if (hasRemovalListeners) {
c->dispatchEvent(new MutationEventImpl(EventImpl::DOMNODEREMOVEDFROMDOCUMENT_EVENT,
false,false,0,DOMString(),DOMString(),DOMString(),0),exceptioncode,true);
if (exceptioncode)
return;
}
}
}
}
NodeImpl *NodeListImpl::item( unsigned long ) const
{
return 0;
}
unsigned long NodeListImpl::length() const
{
return 0;
}
unsigned long NodeListImpl::recursiveLength(NodeImpl *start) const
{
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);
}
}
return len;
}
NodeImpl *NodeListImpl::recursiveItem ( NodeImpl *start, unsigned long &offset ) const
{
for(NodeImpl *n = start->firstChild(); n != 0; n = n->nextSibling()) {
if ( n->nodeType() == Node::ELEMENT_NODE ) {
if (nodeMatches(n))
if (!offset--)
return n;
NodeImpl *depthSearch= recursiveItem(n, offset);
if (depthSearch)
return depthSearch;
}
}
return 0; }
ChildNodeListImpl::ChildNodeListImpl( NodeImpl *n )
{
refNode = n;
refNode->ref();
}
ChildNodeListImpl::~ChildNodeListImpl()
{
refNode->deref();
}
unsigned long ChildNodeListImpl::length() const
{
unsigned long len = 0;
NodeImpl *n;
for(n = refNode->firstChild(); n != 0; n = n->nextSibling())
len++;
return len;
}
NodeImpl *ChildNodeListImpl::item ( unsigned long index ) const
{
unsigned int pos = 0;
NodeImpl *n = refNode->firstChild();
while( n != 0 && pos < index )
{
n = n->nextSibling();
pos++;
}
return n;
}
bool ChildNodeListImpl::nodeMatches( NodeImpl * ) const
{
return true;
}
TagNodeListImpl::TagNodeListImpl(NodeImpl *n, NodeImpl::Id _id, NodeImpl::Id _idMask )
: refNode(n), m_id(_id & _idMask), m_idMask(_idMask)
{
refNode->ref();
}
TagNodeListImpl::~TagNodeListImpl()
{
refNode->deref();
}
unsigned long TagNodeListImpl::length() const
{
return recursiveLength( refNode );
}
NodeImpl *TagNodeListImpl::item ( unsigned long index ) const
{
return recursiveItem( refNode, index );
}
bool TagNodeListImpl::nodeMatches( NodeImpl *testNode ) const
{
return ( testNode->isElementNode() &&
(testNode->id() & m_idMask) == m_id);
}
NameNodeListImpl::NameNodeListImpl(NodeImpl *n, const DOMString &t )
: nodeName(t)
{
refNode= n;
refNode->ref();
}
NameNodeListImpl::~NameNodeListImpl()
{
refNode->deref();
}
unsigned long NameNodeListImpl::length() const
{
return recursiveLength( refNode );
}
NodeImpl *NameNodeListImpl::item ( unsigned long index ) const
{
return recursiveItem( refNode, index );
}
bool NameNodeListImpl::nodeMatches( NodeImpl *testNode ) const
{
return static_cast<ElementImpl *>(testNode)->getAttribute(ATTR_NAME) == nodeName;
}
NamedNodeMapImpl::NamedNodeMapImpl()
{
}
NamedNodeMapImpl::~NamedNodeMapImpl()
{
}
#if 0
GenericRONamedNodeMapImpl::GenericRONamedNodeMapImpl(DocumentPtr* 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