Reinstate active flag for iterators
[WebKit-https.git] / Source / WebCore / dom / NodeIterator.cpp
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 "NodeTraversal.h"
30
31 namespace WebCore {
32
33 inline NodeIterator::NodePointer::NodePointer(Node& node, bool isPointerBeforeNode)
34     : node(&node)
35     , isPointerBeforeNode(isPointerBeforeNode)
36 {
37 }
38
39 inline void NodeIterator::NodePointer::clear()
40 {
41     node = nullptr;
42 }
43
44 inline bool NodeIterator::NodePointer::moveToNext(Node& root)
45 {
46     if (!node)
47         return false;
48     if (isPointerBeforeNode) {
49         isPointerBeforeNode = false;
50         return true;
51     }
52     node = NodeTraversal::next(*node, &root);
53     return node;
54 }
55
56 inline bool NodeIterator::NodePointer::moveToPrevious(Node& root)
57 {
58     if (!node)
59         return false;
60     if (!isPointerBeforeNode) {
61         isPointerBeforeNode = true;
62         return true;
63     }
64     if (node == &root) {
65         node = nullptr;
66         return false;
67     }
68     node = NodeTraversal::previous(*node);
69     return node;
70 }
71
72 inline NodeIterator::NodeIterator(Node& rootNode, unsigned whatToShow, RefPtr<NodeFilter>&& filter)
73     : NodeIteratorBase(rootNode, whatToShow, WTFMove(filter))
74     , m_referenceNode(rootNode, true)
75 {
76     root().document().attachNodeIterator(this);
77 }
78
79 Ref<NodeIterator> NodeIterator::create(Node& rootNode, unsigned whatToShow, RefPtr<NodeFilter>&& filter)
80 {
81     return adoptRef(*new NodeIterator(rootNode, whatToShow, WTFMove(filter)));
82 }
83
84 NodeIterator::~NodeIterator()
85 {
86     root().document().detachNodeIterator(this);
87 }
88
89 ExceptionOr<RefPtr<Node>> NodeIterator::nextNode()
90 {
91     RefPtr<Node> result;
92
93     m_candidateNode = m_referenceNode;
94     while (m_candidateNode.moveToNext(root())) {
95         // NodeIterators treat the DOM tree as a flat list of nodes.
96         // In other words, FILTER_REJECT does not pass over descendants
97         // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
98         RefPtr<Node> provisionalResult = m_candidateNode.node;
99
100         auto filterResult = acceptNode(*provisionalResult);
101         if (filterResult.hasException()) {
102             m_candidateNode.clear();
103             return filterResult.releaseException();
104         }
105
106         bool nodeWasAccepted = filterResult.returnValue() == NodeFilter::FILTER_ACCEPT;
107         if (nodeWasAccepted) {
108             m_referenceNode = m_candidateNode;
109             result = WTFMove(provisionalResult);
110             break;
111         }
112     }
113
114     m_candidateNode.clear();
115     return WTFMove(result);
116 }
117
118 ExceptionOr<RefPtr<Node>> NodeIterator::previousNode()
119 {
120     RefPtr<Node> result;
121
122     m_candidateNode = m_referenceNode;
123     while (m_candidateNode.moveToPrevious(root())) {
124         // NodeIterators treat the DOM tree as a flat list of nodes.
125         // In other words, FILTER_REJECT does not pass over descendants
126         // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
127         RefPtr<Node> provisionalResult = m_candidateNode.node;
128
129         auto filterResult = acceptNode(*provisionalResult);
130         if (filterResult.hasException()) {
131             m_candidateNode.clear();
132             return filterResult.releaseException();
133         }
134
135         bool nodeWasAccepted = filterResult.returnValue() == NodeFilter::FILTER_ACCEPT;
136         if (nodeWasAccepted) {
137             m_referenceNode = m_candidateNode;
138             result = WTFMove(provisionalResult);
139             break;
140         }
141     }
142
143     m_candidateNode.clear();
144     return WTFMove(result);
145 }
146
147 void NodeIterator::nodeWillBeRemoved(Node& removedNode)
148 {
149     updateForNodeRemoval(removedNode, m_candidateNode);
150     updateForNodeRemoval(removedNode, m_referenceNode);
151 }
152
153 void NodeIterator::updateForNodeRemoval(Node& removedNode, NodePointer& referenceNode) const
154 {
155     ASSERT(&root().document() == &removedNode.document());
156
157     // Iterator is not affected if the removed node is the reference node and is the root.
158     // or if removed node is not the reference node, or the ancestor of the reference node.
159     if (!removedNode.isDescendantOf(root()))
160         return;
161     bool willRemoveReferenceNode = &removedNode == referenceNode.node;
162     bool willRemoveReferenceNodeAncestor = referenceNode.node && referenceNode.node->isDescendantOf(removedNode);
163     if (!willRemoveReferenceNode && !willRemoveReferenceNodeAncestor)
164         return;
165
166     if (referenceNode.isPointerBeforeNode) {
167         Node* node = NodeTraversal::next(removedNode, &root());
168         if (node) {
169             // Move out from under the node being removed if the new reference
170             // node is a descendant of the node being removed.
171             while (node && node->isDescendantOf(removedNode))
172                 node = NodeTraversal::next(*node, &root());
173             if (node)
174                 referenceNode.node = node;
175         } else {
176             node = NodeTraversal::previous(removedNode);
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 = NodeTraversal::previous(*node);
183                 }
184                 if (node) {
185                     // Removing last node.
186                     // Need to move the pointer after the node preceding the 
187                     // new reference node.
188                     referenceNode.node = node;
189                     referenceNode.isPointerBeforeNode = false;
190                 }
191             }
192         }
193     } else {
194         Node* node = NodeTraversal::previous(removedNode);
195         if (node) {
196             // Move out from under the node being removed if the reference node is
197             // a descendant of the node being removed.
198             if (willRemoveReferenceNodeAncestor) {
199                 while (node && node->isDescendantOf(removedNode))
200                     node = NodeTraversal::previous(*node);
201             }
202             if (node)
203                 referenceNode.node = node;
204         } else {
205             // FIXME: This branch doesn't appear to have any LayoutTests.
206             node = NodeTraversal::next(removedNode, &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 = NodeTraversal::previous(*node);
212             }
213             if (node)
214                 referenceNode.node = node;
215         }
216     }
217 }
218
219 } // namespace WebCore