📄 dom_nodeimpl.cpp
字号:
/**
* This file is part of the DOM implementation for KDE.
*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2001 Dirk Mueller (mueller@kde.org)
* Copyright (C) 2004 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#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
using namespace DOM;
using namespace khtml;
NodeImpl::NodeImpl(DocumentPtr *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_styleElement( false ),
m_implicit( 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();
if (m_regdListeners && !m_regdListeners->isEmpty() && getDocument() && !inDocument())
getDocument()->unregisterDisconnectedNodeWithEventListeners(this);
delete m_regdListeners;
delete m_nodeLists;
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 &/*_nodeValue*/, int &exceptioncode )
{
// NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
if (isReadOnly()) {
exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
return;
}
// be default nodeValue is null, so setting it has no effect
}
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)
{
exceptioncode = 0;
if (!parentNode()) {
exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
return;
}
parentNode()->removeChild(this, exceptioncode);
}
bool NodeImpl::hasChildNodes( ) const
{
return false;
}
void NodeImpl::normalize ()
{
// ### normalize attributes? (when we store attributes using child nodes)
int exceptioncode = 0;
NodeImpl *child = firstChild();
// Recursively go through the subtree beneath us, normalizing all nodes. In the case
// where there are two adjacent text nodes, they are merged together
while (child) {
NodeImpl *nextChild = child->nextSibling();
if (nextChild && child->nodeType() == Node::TEXT_NODE && nextChild->nodeType() == Node::TEXT_NODE) {
// Current child and the next one are both text nodes... merge them
TextImpl *currentText = static_cast<TextImpl*>(child);
TextImpl *nextText = static_cast<TextImpl*>(nextChild);
currentText->appendData(nextText->data(),exceptioncode);
if (exceptioncode)
return;
removeChild(nextChild,exceptioncode);
if (exceptioncode)
return;
}
else {
child->normalize();
child = nextChild;
}
}
}
DOMString NodeImpl::prefix() const
{
// For nodes other than elements and attributes, the prefix is always null
return DOMString();
}
void NodeImpl::setPrefix(const DOMString &/*_prefix*/, int &exceptioncode )
{
// The spec says that for nodes other than elements and attributes, prefix is always null.
// It does not say what to do when the user tries to set the prefix on another type of
// node, however mozilla throws a NAMESPACE_ERR exception
exceptioncode = DOMException::NAMESPACE_ERR;
}
DOMString NodeImpl::localName() const
{
return DOMString();
}
void NodeImpl::setFirstChild(NodeImpl *)
{
}
void NodeImpl::setLastChild(NodeImpl *)
{
}
NodeImpl *NodeImpl::addChild(NodeImpl *)
{
return 0;
}
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()) // changed compared to what?
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();
// remove existing identical listener set with identical arguments - the DOM2
// spec says that "duplicate instances are discarded" in this case.
removeEventListener(id,listener,useCapture);
// adding the first one
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) // nothing to remove
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());
// removed last
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) // nothing to remove
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());
// removed last
if (m_regdListeners->isEmpty() && getDocument() && !inDocument())
getDocument()->unregisterDisconnectedNodeWithEventListeners(this);
return;
}
}
void NodeImpl::setHTMLEventListener(int id, EventListener *listener)
{
// in case we already have it, we don't want removeHTMLEventListener to destroy it
if (listener)
listener->ref();
removeHTMLEventListener(id);
if (listener)
{
addEventListener(id,listener,false);
listener->deref();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -