• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
7  *
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.
12  *
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.
17  *
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.
22  *
23  */
24 
25 #include "config.h"
26 #include "NodeIterator.h"
27 
28 #include "Document.h"
29 #include "ExceptionCode.h"
30 #include "NodeFilter.h"
31 #include "ScriptState.h"
32 
33 namespace WebCore {
34 
NodePointer()35 NodeIterator::NodePointer::NodePointer()
36 {
37 }
38 
NodePointer(PassRefPtr<Node> n,bool b)39 NodeIterator::NodePointer::NodePointer(PassRefPtr<Node> n, bool b)
40     : node(n)
41     , isPointerBeforeNode(b)
42 {
43 }
44 
clear()45 void NodeIterator::NodePointer::clear()
46 {
47     node.clear();
48 }
49 
moveToNext(Node * root)50 bool NodeIterator::NodePointer::moveToNext(Node* root)
51 {
52     if (!node)
53         return false;
54     if (isPointerBeforeNode) {
55         isPointerBeforeNode = false;
56         return true;
57     }
58     node = node->traverseNextNode(root);
59     return node;
60 }
61 
moveToPrevious(Node * root)62 bool NodeIterator::NodePointer::moveToPrevious(Node* root)
63 {
64     if (!node)
65         return false;
66     if (!isPointerBeforeNode) {
67         isPointerBeforeNode = true;
68         return true;
69     }
70     node = node->traversePreviousNode(root);
71     return node;
72 }
73 
NodeIterator(PassRefPtr<Node> rootNode,unsigned whatToShow,PassRefPtr<NodeFilter> filter,bool expandEntityReferences)74 NodeIterator::NodeIterator(PassRefPtr<Node> rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter, bool expandEntityReferences)
75     : Traversal(rootNode, whatToShow, filter, expandEntityReferences)
76     , m_referenceNode(root(), true)
77     , m_detached(false)
78 {
79     root()->document()->attachNodeIterator(this);
80 }
81 
~NodeIterator()82 NodeIterator::~NodeIterator()
83 {
84     root()->document()->detachNodeIterator(this);
85 }
86 
nextNode(ScriptState * state,ExceptionCode & ec)87 PassRefPtr<Node> NodeIterator::nextNode(ScriptState* state, ExceptionCode& ec)
88 {
89     if (m_detached) {
90         ec = INVALID_STATE_ERR;
91         return 0;
92     }
93 
94     RefPtr<Node> result;
95 
96     m_candidateNode = m_referenceNode;
97     while (m_candidateNode.moveToNext(root())) {
98         // NodeIterators treat the DOM tree as a flat list of nodes.
99         // In other words, FILTER_REJECT does not pass over descendants
100         // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
101         RefPtr<Node> provisionalResult = m_candidateNode.node;
102         bool nodeWasAccepted = acceptNode(state, provisionalResult.get()) == NodeFilter::FILTER_ACCEPT;
103         if (state && state->hadException())
104             break;
105         if (nodeWasAccepted) {
106             m_referenceNode = m_candidateNode;
107             result = provisionalResult.release();
108             break;
109         }
110     }
111 
112     m_candidateNode.clear();
113     return result.release();
114 }
115 
previousNode(ScriptState * state,ExceptionCode & ec)116 PassRefPtr<Node> NodeIterator::previousNode(ScriptState* state, ExceptionCode& ec)
117 {
118     if (m_detached) {
119         ec = INVALID_STATE_ERR;
120         return 0;
121     }
122 
123     RefPtr<Node> result;
124 
125     m_candidateNode = m_referenceNode;
126     while (m_candidateNode.moveToPrevious(root())) {
127         // NodeIterators treat the DOM tree as a flat list of nodes.
128         // In other words, FILTER_REJECT does not pass over descendants
129         // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
130         RefPtr<Node> provisionalResult = m_candidateNode.node;
131         bool nodeWasAccepted = acceptNode(state, provisionalResult.get()) == NodeFilter::FILTER_ACCEPT;
132         if (state && state->hadException())
133             break;
134         if (nodeWasAccepted) {
135             m_referenceNode = m_candidateNode;
136             result = provisionalResult.release();
137             break;
138         }
139     }
140 
141     m_candidateNode.clear();
142     return result.release();
143 }
144 
detach()145 void NodeIterator::detach()
146 {
147     root()->document()->detachNodeIterator(this);
148     m_detached = true;
149     m_referenceNode.node.clear();
150 }
151 
nodeWillBeRemoved(Node * removedNode)152 void NodeIterator::nodeWillBeRemoved(Node* removedNode)
153 {
154     updateForNodeRemoval(removedNode, m_candidateNode);
155     updateForNodeRemoval(removedNode, m_referenceNode);
156 }
157 
updateForNodeRemoval(Node * removedNode,NodePointer & referenceNode) const158 void NodeIterator::updateForNodeRemoval(Node* removedNode, NodePointer& referenceNode) const
159 {
160     ASSERT(!m_detached);
161     ASSERT(removedNode);
162     ASSERT(root()->document() == removedNode->document());
163 
164     // Iterator is not affected if the removed node is the reference node and is the root.
165     // or if removed node is not the reference node, or the ancestor of the reference node.
166     if (!removedNode->isDescendantOf(root()))
167         return;
168     bool willRemoveReferenceNode = removedNode == referenceNode.node;
169     bool willRemoveReferenceNodeAncestor = referenceNode.node && referenceNode.node->isDescendantOf(removedNode);
170     if (!willRemoveReferenceNode && !willRemoveReferenceNodeAncestor)
171         return;
172 
173     if (referenceNode.isPointerBeforeNode) {
174         Node* node = removedNode->traverseNextNode(root());
175         if (node) {
176             // Move out from under the node being removed if the reference node is
177             // a descendant of the node being removed.
178             if (willRemoveReferenceNodeAncestor) {
179                 while (node && node->isDescendantOf(removedNode))
180                     node = node->traverseNextNode(root());
181             }
182             if (node)
183                 referenceNode.node = node;
184         } else {
185             node = removedNode->traversePreviousNode(root());
186             if (node) {
187                 // Move out from under the node being removed if the reference node is
188                 // a descendant of the node being removed.
189                 if (willRemoveReferenceNodeAncestor) {
190                     while (node && node->isDescendantOf(removedNode))
191                         node = node->traversePreviousNode(root());
192                 }
193                 if (node) {
194                     // Removing last node.
195                     // Need to move the pointer after the node preceding the
196                     // new reference node.
197                     referenceNode.node = node;
198                     referenceNode.isPointerBeforeNode = false;
199                 }
200             }
201         }
202     } else {
203         Node* node = removedNode->traversePreviousNode(root());
204         if (node) {
205             // Move out from under the node being removed if the reference node is
206             // a descendant of the node being removed.
207             if (willRemoveReferenceNodeAncestor) {
208                 while (node && node->isDescendantOf(removedNode))
209                     node = node->traversePreviousNode(root());
210             }
211             if (node)
212                 referenceNode.node = node;
213         } else {
214             node = removedNode->traverseNextNode(root());
215             // Move out from under the node being removed if the reference node is
216             // a descendant of the node being removed.
217             if (willRemoveReferenceNodeAncestor) {
218                 while (node && node->isDescendantOf(removedNode))
219                     node = node->traversePreviousNode(root());
220             }
221             if (node)
222                 referenceNode.node = node;
223         }
224     }
225 }
226 
227 
228 } // namespace WebCore
229