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.
26 #include "NodeIterator.h"
28 #include <runtime/ExecState.h>
30 #include "ExceptionCode.h"
31 #include "NodeFilter.h"
37 NodeIterator::NodePointer::NodePointer()
41 NodeIterator::NodePointer::NodePointer(PassRefPtr
<Node
> n
, bool b
)
43 , isPointerBeforeNode(b
)
47 void NodeIterator::NodePointer::clear()
52 bool NodeIterator::NodePointer::moveToNext(Node
* root
)
56 if (isPointerBeforeNode
) {
57 isPointerBeforeNode
= false;
60 node
= node
->traverseNextNode(root
);
64 bool NodeIterator::NodePointer::moveToPrevious(Node
* root
)
68 if (!isPointerBeforeNode
) {
69 isPointerBeforeNode
= true;
72 node
= node
->traversePreviousNode(root
);
76 NodeIterator::NodeIterator(PassRefPtr
<Node
> rootNode
, unsigned whatToShow
, PassRefPtr
<NodeFilter
> filter
, bool expandEntityReferences
)
77 : Traversal(rootNode
, whatToShow
, filter
, expandEntityReferences
)
78 , m_referenceNode(root(), true)
81 root()->document()->attachNodeIterator(this);
84 NodeIterator::~NodeIterator()
86 root()->document()->detachNodeIterator(this);
89 PassRefPtr
<Node
> NodeIterator::nextNode(ExecState
* exec
, ExceptionCode
& ec
)
92 ec
= INVALID_STATE_ERR
;
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())
107 if (nodeWasAccepted
) {
108 m_referenceNode
= m_candidateNode
;
109 result
= provisionalResult
.release();
114 m_candidateNode
.clear();
115 return result
.release();
118 PassRefPtr
<Node
> NodeIterator::previousNode(ExecState
* exec
, ExceptionCode
& ec
)
121 ec
= INVALID_STATE_ERR
;
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())
136 if (nodeWasAccepted
) {
137 m_referenceNode
= m_candidateNode
;
138 result
= provisionalResult
.release();
143 m_candidateNode
.clear();
144 return result
.release();
147 void NodeIterator::detach()
149 root()->document()->detachNodeIterator(this);
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
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()))
170 bool willRemoveReferenceNode
= removedNode
== referenceNode
.node
;
171 bool willRemoveReferenceNodeAncestor
= referenceNode
.node
&& referenceNode
.node
->isDescendantOf(removedNode
);
172 if (!willRemoveReferenceNode
&& !willRemoveReferenceNodeAncestor
)
175 if (referenceNode
.isPointerBeforeNode
) {
176 Node
* node
= removedNode
->traverseNextNode(root());
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());
185 referenceNode
.node
= node
;
187 node
= removedNode
->traversePreviousNode(root());
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());
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;
205 Node
* node
= removedNode
->traversePreviousNode(root());
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());
214 referenceNode
.node
= node
;
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());
224 referenceNode
.node
= node
;
230 } // namespace WebCore