2008-11-04 Anders Carlsson <andersca@apple.com>
[webkit/qt.git] / WebCore / dom / NodeIterator.cpp
blob4707e9f6c588e703986a52c0e12a426a4e6edc6b
1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
4 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
5 * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
6 * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
25 #include "config.h"
26 #include "NodeIterator.h"
28 #include <runtime/ExecState.h>
29 #include "Document.h"
30 #include "ExceptionCode.h"
31 #include "NodeFilter.h"
33 using namespace JSC;
35 namespace WebCore {
37 NodeIterator::NodePointer::NodePointer()
41 NodeIterator::NodePointer::NodePointer(PassRefPtr<Node> n, bool b)
42 : node(n)
43 , isPointerBeforeNode(b)
47 void NodeIterator::NodePointer::clear()
49 node.clear();
52 bool NodeIterator::NodePointer::moveToNext(Node* root)
54 if (!node)
55 return false;
56 if (isPointerBeforeNode) {
57 isPointerBeforeNode = false;
58 return true;
60 node = node->traverseNextNode(root);
61 return node;
64 bool NodeIterator::NodePointer::moveToPrevious(Node* root)
66 if (!node)
67 return false;
68 if (!isPointerBeforeNode) {
69 isPointerBeforeNode = true;
70 return true;
72 node = node->traversePreviousNode(root);
73 return node;
76 NodeIterator::NodeIterator(PassRefPtr<Node> rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter, bool expandEntityReferences)
77 : Traversal(rootNode, whatToShow, filter, expandEntityReferences)
78 , m_referenceNode(root(), true)
79 , m_detached(false)
81 root()->document()->attachNodeIterator(this);
84 NodeIterator::~NodeIterator()
86 root()->document()->detachNodeIterator(this);
89 PassRefPtr<Node> NodeIterator::nextNode(ExecState* exec, ExceptionCode& ec)
91 if (m_detached) {
92 ec = INVALID_STATE_ERR;
93 return 0;
96 RefPtr<Node> result;
98 m_candidateNode = m_referenceNode;
99 while (m_candidateNode.moveToNext(root())) {
100 // NodeIterators treat the DOM tree as a flat list of nodes.
101 // In other words, FILTER_REJECT does not pass over descendants
102 // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
103 RefPtr<Node> provisionalResult = m_candidateNode.node;
104 bool nodeWasAccepted = acceptNode(exec, provisionalResult.get()) == NodeFilter::FILTER_ACCEPT;
105 if (exec && exec->hadException())
106 break;
107 if (nodeWasAccepted) {
108 m_referenceNode = m_candidateNode;
109 result = provisionalResult.release();
110 break;
114 m_candidateNode.clear();
115 return result.release();
118 PassRefPtr<Node> NodeIterator::previousNode(ExecState* exec, ExceptionCode& ec)
120 if (m_detached) {
121 ec = INVALID_STATE_ERR;
122 return 0;
125 RefPtr<Node> result;
127 m_candidateNode = m_referenceNode;
128 while (m_candidateNode.moveToPrevious(root())) {
129 // NodeIterators treat the DOM tree as a flat list of nodes.
130 // In other words, FILTER_REJECT does not pass over descendants
131 // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
132 RefPtr<Node> provisionalResult = m_candidateNode.node;
133 bool nodeWasAccepted = acceptNode(exec, provisionalResult.get()) == NodeFilter::FILTER_ACCEPT;
134 if (exec && exec->hadException())
135 break;
136 if (nodeWasAccepted) {
137 m_referenceNode = m_candidateNode;
138 result = provisionalResult.release();
139 break;
143 m_candidateNode.clear();
144 return result.release();
147 void NodeIterator::detach()
149 root()->document()->detachNodeIterator(this);
150 m_detached = true;
151 m_referenceNode.node.clear();
154 void NodeIterator::nodeWillBeRemoved(Node* removedNode)
156 updateForNodeRemoval(removedNode, m_candidateNode);
157 updateForNodeRemoval(removedNode, m_referenceNode);
160 void NodeIterator::updateForNodeRemoval(Node* removedNode, NodePointer& referenceNode) const
162 ASSERT(!m_detached);
163 ASSERT(removedNode);
164 ASSERT(root()->document() == removedNode->document());
166 // Iterator is not affected if the removed node is the reference node and is the root.
167 // or if removed node is not the reference node, or the ancestor of the reference node.
168 if (!removedNode->isDescendantOf(root()))
169 return;
170 bool willRemoveReferenceNode = removedNode == referenceNode.node;
171 bool willRemoveReferenceNodeAncestor = referenceNode.node && referenceNode.node->isDescendantOf(removedNode);
172 if (!willRemoveReferenceNode && !willRemoveReferenceNodeAncestor)
173 return;
175 if (referenceNode.isPointerBeforeNode) {
176 Node* node = removedNode->traverseNextNode(root());
177 if (node) {
178 // Move out from under the node being removed if the reference node is
179 // a descendant of the node being removed.
180 if (willRemoveReferenceNodeAncestor) {
181 while (node && node->isDescendantOf(removedNode))
182 node = node->traverseNextNode(root());
184 if (node)
185 referenceNode.node = node;
186 } else {
187 node = removedNode->traversePreviousNode(root());
188 if (node) {
189 // Move out from under the node being removed if the reference node is
190 // a descendant of the node being removed.
191 if (willRemoveReferenceNodeAncestor) {
192 while (node && node->isDescendantOf(removedNode))
193 node = node->traversePreviousNode(root());
195 if (node) {
196 // Removing last node.
197 // Need to move the pointer after the node preceding the
198 // new reference node.
199 referenceNode.node = node;
200 referenceNode.isPointerBeforeNode = false;
204 } else {
205 Node* node = removedNode->traversePreviousNode(root());
206 if (node) {
207 // Move out from under the node being removed if the reference node is
208 // a descendant of the node being removed.
209 if (willRemoveReferenceNodeAncestor) {
210 while (node && node->isDescendantOf(removedNode))
211 node = node->traversePreviousNode(root());
213 if (node)
214 referenceNode.node = node;
215 } else {
216 node = removedNode->traverseNextNode(root());
217 // Move out from under the node being removed if the reference node is
218 // a descendant of the node being removed.
219 if (willRemoveReferenceNodeAncestor) {
220 while (node && node->isDescendantOf(removedNode))
221 node = node->traversePreviousNode(root());
223 if (node)
224 referenceNode.node = node;
230 } // namespace WebCore