📄 dom2_traversalimpl.cpp
字号:
/**
* This file is part of the DOM implementation for KDE.
*
* (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
* (C) 2001 Peter Kelly (pmk@post.com)
* 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/dom2_traversalimpl.h"
#include "dom/dom_exception.h"
#include "xml/dom_docimpl.h"
#include "htmltags.h"
namespace DOM {
NodeFilterImpl::NodeFilterImpl(NodeFilterCondition *condition)
: m_condition(condition)
{
if (m_condition)
m_condition->ref();
}
NodeFilterImpl::~NodeFilterImpl()
{
if (m_condition)
m_condition->deref();
}
short NodeFilterImpl::acceptNode(const Node &node) const
{
// cast to short silences "enumeral and non-enumeral types in return" warning
return m_condition ? m_condition->acceptNode(node) : static_cast<short>(NodeFilter::FILTER_ACCEPT);
}
// --------------------------------------------------------------
TraversalImpl::TraversalImpl(NodeImpl *rootNode, long whatToShow, NodeFilterImpl *nodeFilter, bool expandEntityReferences)
: m_root(rootNode), m_whatToShow(whatToShow), m_filter(nodeFilter), m_expandEntityReferences(expandEntityReferences)
{
if (root())
root()->ref();
if (filter())
filter()->ref();
}
TraversalImpl::~TraversalImpl()
{
if (root())
root()->deref();
if (filter())
filter()->deref();
}
short TraversalImpl::acceptNode(NodeImpl *node) const
{
// FIXME: If XML is implemented we have to check expandEntityRerefences in this function.
// The bid twiddling here is done to map DOM node types, which are given as integers from
// 1 through 12, to whatToShow bit masks.
if (node && ((1 << (node->nodeType()-1)) & m_whatToShow) != 0)
// cast to short silences "enumeral and non-enumeral types in return" warning
return m_filter ? m_filter->acceptNode(node) : static_cast<short>(NodeFilter::FILTER_ACCEPT);
return NodeFilter::FILTER_SKIP;
}
// --------------------------------------------------------------
NodeIteratorImpl::NodeIteratorImpl(NodeImpl *rootNode, long whatToShow, NodeFilterImpl *filter, bool expandEntityReferences)
:TraversalImpl(rootNode, whatToShow, filter, expandEntityReferences), m_referenceNode(0), m_beforeReferenceNode(true), m_detached(false), m_doc(0)
{
if (root()) {
setDocument(root()->getDocument());
if (document()) {
document()->attachNodeIterator(this);
document()->ref();
}
}
}
NodeIteratorImpl::~NodeIteratorImpl()
{
if (referenceNode())
referenceNode()->deref();
if (document()) {
document()->detachNodeIterator(this);
document()->deref();
}
}
NodeImpl *NodeIteratorImpl::findNextNode(NodeImpl *node) const
{
while ((node = node->traverseNextNode())) {
// NodeIterators treat the DOM tree as a flat list of nodes.
// In other words, FILTER_REJECT does not pass over descendants
// of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
if (acceptNode(node) == NodeFilter::FILTER_ACCEPT)
break;
}
return node;
}
NodeImpl *NodeIteratorImpl::nextNode(int &exceptioncode)
{
if (detached()) {
exceptioncode = DOMException::INVALID_STATE_ERR;
return 0;
}
NodeImpl *node = referenceNode() ? referenceNode() : root();
if (!pointerBeforeReferenceNode() || acceptNode(node) != NodeFilter::FILTER_ACCEPT)
node = findNextNode(node);
if (node)
setReferenceNode(node);
setPointerBeforeReferenceNode(false);
return node;
}
NodeImpl *NodeIteratorImpl::findPreviousNode(NodeImpl *node) const
{
while ((node = node->traversePreviousNode())) {
// NodeIterators treat the DOM tree as a flat list of nodes.
// In other words, FILTER_REJECT does not pass over descendants
// of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
if (acceptNode(node) == NodeFilter::FILTER_ACCEPT)
break;
}
return node;
}
NodeImpl *NodeIteratorImpl::previousNode(int &exceptioncode)
{
NodeImpl *node = referenceNode() ? referenceNode() : root();
if (pointerBeforeReferenceNode() || acceptNode(node) != NodeFilter::FILTER_ACCEPT)
node = findPreviousNode(node);
if (node)
setReferenceNode(node);
setPointerBeforeReferenceNode();
return node;
}
void NodeIteratorImpl::detach(int &/*exceptioncode*/)
{
if (!detached() && document())
document()->detachNodeIterator(this);
setDetached();
}
void NodeIteratorImpl::setReferenceNode(NodeImpl *node)
{
if (node == m_referenceNode)
return;
NodeImpl *old = m_referenceNode;
m_referenceNode = node;
if (m_referenceNode)
m_referenceNode->ref();
if (old)
old->deref();
}
void NodeIteratorImpl::setDocument(DocumentImpl *doc)
{
if (doc == m_doc)
return;
DocumentImpl *old = m_doc;
m_doc = doc;
if (m_doc)
m_doc->ref();
if (old)
old->deref();
}
void NodeIteratorImpl::notifyBeforeNodeRemoval(NodeImpl *willRemove)
{
// Iterator is not affected if the removed node is the reference node and is the root.
// or if removed node is not the reference node, or the ancestor of the reference node.
if (!willRemove || willRemove == root())
return;
bool willRemoveReferenceNode = willRemove == referenceNode();
bool willRemoveReferenceNodeAncestor = referenceNode() && referenceNode()->isAncestor(willRemove);
if (!willRemoveReferenceNode && !willRemoveReferenceNodeAncestor)
return;
if (pointerBeforeReferenceNode()) {
NodeImpl *node = findNextNode(willRemove);
if (node) {
// Move out from under the node being removed if the reference node is
// a descendant of the node being removed.
if (willRemoveReferenceNodeAncestor) {
while (node && node->isAncestor(willRemove))
node = findNextNode(node);
}
if (node)
setReferenceNode(node);
}
else {
node = findPreviousNode(willRemove);
if (node) {
// Move out from under the node being removed if the reference node is
// a descendant of the node being removed.
if (willRemoveReferenceNodeAncestor) {
while (node && node->isAncestor(willRemove))
node = findPreviousNode(node);
}
if (node) {
// Removing last node.
// Need to move the pointer after the node preceding the
// new reference node.
setReferenceNode(node);
setPointerBeforeReferenceNode(false);
}
}
}
}
else {
NodeImpl *node = findPreviousNode(willRemove);
if (node) {
// Move out from under the node being removed if the reference node is
// a descendant of the node being removed.
if (willRemoveReferenceNodeAncestor) {
while (node && node->isAncestor(willRemove))
node = findPreviousNode(node);
}
if (node)
setReferenceNode(node);
}
else {
node = findNextNode(willRemove);
// Move out from under the node being removed if the reference node is
// a descendant of the node being removed.
if (willRemoveReferenceNodeAncestor) {
while (node && node->isAncestor(willRemove))
node = findPreviousNode(node);
}
if (node)
setReferenceNode(node);
}
}
}
// --------------------------------------------------------------
TreeWalkerImpl::TreeWalkerImpl(NodeImpl *rootNode, long whatToShow, NodeFilterImpl *filter, bool expandEntityReferences)
: TraversalImpl(rootNode, whatToShow, filter, expandEntityReferences), m_current(rootNode)
{
if (currentNode())
currentNode()->ref();
}
TreeWalkerImpl::~TreeWalkerImpl()
{
if (currentNode())
currentNode()->deref();
}
void TreeWalkerImpl::setCurrentNode(NodeImpl *node, int &exceptioncode)
{
if (!node) {
exceptioncode = DOMException::NOT_SUPPORTED_ERR;
return;
}
if (node == m_current)
return;
NodeImpl *old = m_current;
m_current = node;
if (m_current)
m_current->ref();
if (old)
old->deref();
}
void TreeWalkerImpl::setCurrentNode(NodeImpl *node)
{
assert(node);
int dummy;
setCurrentNode(node, dummy);
}
NodeImpl *TreeWalkerImpl::parentNode()
{
NodeImpl *result = 0;
for (NodeImpl *node = currentNode()->parentNode(); node && node != root(); node = node->parentNode()) {
if (acceptNode(node) == NodeFilter::FILTER_ACCEPT) {
setCurrentNode(node);
result = node;
break;
}
}
return result;
}
NodeImpl *TreeWalkerImpl::firstChild()
{
NodeImpl *result = 0;
for (NodeImpl *node = currentNode()->firstChild(); node; node = node->nextSibling()) {
if (acceptNode(node) == NodeFilter::FILTER_ACCEPT) {
setCurrentNode(node);
result = node;
break;
}
}
return result;
}
NodeImpl *TreeWalkerImpl::lastChild()
{
NodeImpl *result = 0;
for (NodeImpl *node = currentNode()->lastChild(); node; node = node->previousSibling()) {
if (acceptNode(node) == NodeFilter::FILTER_ACCEPT) {
setCurrentNode(node);
result = node;
break;
}
}
return result;
}
NodeImpl *TreeWalkerImpl::previousSibling()
{
NodeImpl *result = 0;
for (NodeImpl *node = currentNode()->previousSibling(); node; node = node->previousSibling()) {
if (acceptNode(node) == NodeFilter::FILTER_ACCEPT) {
setCurrentNode(node);
result = node;
break;
}
}
return result;
}
NodeImpl *TreeWalkerImpl::nextSibling()
{
NodeImpl *result = 0;
for (NodeImpl *node = currentNode()->nextSibling(); node; node = node->nextSibling()) {
if (acceptNode(node) == NodeFilter::FILTER_ACCEPT) {
setCurrentNode(node);
result = node;
break;
}
}
return result;
}
NodeImpl *TreeWalkerImpl::previousNode()
{
NodeImpl *result = 0;
for (NodeImpl *node = currentNode()->traversePreviousNode(); node; node = node->traversePreviousNode()) {
if (acceptNode(node) == NodeFilter::FILTER_ACCEPT && !ancestorRejected(node)) {
setCurrentNode(node);
result = node;
break;
}
}
return result;
}
NodeImpl *TreeWalkerImpl::nextNode()
{
NodeImpl *result = 0;
for (NodeImpl *node = currentNode()->traverseNextNode(); node; node = node->traverseNextNode()) {
if (acceptNode(node) == NodeFilter::FILTER_ACCEPT && !ancestorRejected(node)) {
setCurrentNode(node);
result = node;
break;
}
}
return result;
}
bool TreeWalkerImpl::ancestorRejected(const NodeImpl *node) const
{
for (NodeImpl *a = node->parentNode(); a && a != root(); a = a->parentNode())
if (acceptNode(a) == NodeFilter::FILTER_REJECT)
return true;
return false;
}
} // namespace DOM
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -