Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 "core/dom/NodeIterator.h"
27
28 #include "bindings/core/v8/ExceptionState.h"
29 #include "core/dom/Document.h"
30 #include "core/dom/ExceptionCode.h"
31 #include "core/dom/NodeTraversal.h"
32
33 namespace blink {
34
35 NodeIterator::NodePointer::NodePointer()
36 {
37 }
38
39 NodeIterator::NodePointer::NodePointer(PassRefPtrWillBeRawPtr<Node> n, bool b)
40     : node(n)
41     , isPointerBeforeNode(b)
42 {
43 }
44
45 void NodeIterator::NodePointer::clear()
46 {
47     node.clear();
48 }
49
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 = NodeTraversal::next(*node, root);
59     return node;
60 }
61
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 = NodeTraversal::previous(*node, root);
71     return node;
72 }
73
74 NodeIterator::NodeIterator(PassRefPtrWillBeRawPtr<Node> rootNode, unsigned whatToShow, PassRefPtrWillBeRawPtr<NodeFilter> filter)
75     : NodeIteratorBase(rootNode, whatToShow, filter)
76     , m_referenceNode(root(), true)
77 {
78     root()->document().attachNodeIterator(this);
79 }
80
81 #if !ENABLE(OILPAN)
82 NodeIterator::~NodeIterator()
83 {
84     root()->document().detachNodeIterator(this);
85 }
86 #endif
87
88 PassRefPtrWillBeRawPtr<Node> NodeIterator::nextNode(ExceptionState& exceptionState)
89 {
90     RefPtrWillBeRawPtr<Node> result = nullptr;
91
92     m_candidateNode = m_referenceNode;
93     while (m_candidateNode.moveToNext(root())) {
94         // NodeIterators treat the DOM tree as a flat list of nodes.
95         // In other words, FILTER_REJECT does not pass over descendants
96         // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
97         RefPtrWillBeRawPtr<Node> provisionalResult = m_candidateNode.node;
98         bool nodeWasAccepted = acceptNode(provisionalResult.get(), exceptionState) == NodeFilter::FILTER_ACCEPT;
99         if (exceptionState.hadException())
100             break;
101         if (nodeWasAccepted) {
102             m_referenceNode = m_candidateNode;
103             result = provisionalResult.release();
104             break;
105         }
106     }
107
108     m_candidateNode.clear();
109     return result.release();
110 }
111
112 PassRefPtrWillBeRawPtr<Node> NodeIterator::previousNode(ExceptionState& exceptionState)
113 {
114     RefPtrWillBeRawPtr<Node> result = nullptr;
115
116     m_candidateNode = m_referenceNode;
117     while (m_candidateNode.moveToPrevious(root())) {
118         // NodeIterators treat the DOM tree as a flat list of nodes.
119         // In other words, FILTER_REJECT does not pass over descendants
120         // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
121         RefPtrWillBeRawPtr<Node> provisionalResult = m_candidateNode.node;
122         bool nodeWasAccepted = acceptNode(provisionalResult.get(), exceptionState) == NodeFilter::FILTER_ACCEPT;
123         if (exceptionState.hadException())
124             break;
125         if (nodeWasAccepted) {
126             m_referenceNode = m_candidateNode;
127             result = provisionalResult.release();
128             break;
129         }
130     }
131
132     m_candidateNode.clear();
133     return result.release();
134 }
135
136 void NodeIterator::detach()
137 {
138     // This is now a no-op as per the DOM specification.
139 }
140
141 void NodeIterator::nodeWillBeRemoved(Node& removedNode)
142 {
143     updateForNodeRemoval(removedNode, m_candidateNode);
144     updateForNodeRemoval(removedNode, m_referenceNode);
145 }
146
147 void NodeIterator::updateForNodeRemoval(Node& removedNode, NodePointer& referenceNode) const
148 {
149     ASSERT(root()->document() == removedNode.document());
150
151     // Iterator is not affected if the removed node is the reference node and is the root.
152     // or if removed node is not the reference node, or the ancestor of the reference node.
153     if (!removedNode.isDescendantOf(root()))
154         return;
155     bool willRemoveReferenceNode = removedNode == referenceNode.node.get();
156     bool willRemoveReferenceNodeAncestor = referenceNode.node && referenceNode.node->isDescendantOf(&removedNode);
157     if (!willRemoveReferenceNode && !willRemoveReferenceNodeAncestor)
158         return;
159
160     if (referenceNode.isPointerBeforeNode) {
161         Node* node = NodeTraversal::next(removedNode, root());
162         if (node) {
163             // Move out from under the node being removed if the new reference
164             // node is a descendant of the node being removed.
165             while (node && node->isDescendantOf(&removedNode))
166                 node = NodeTraversal::next(*node, root());
167             if (node)
168                 referenceNode.node = node;
169         } else {
170             node = NodeTraversal::previous(removedNode, root());
171             if (node) {
172                 // Move out from under the node being removed if the reference node is
173                 // a descendant of the node being removed.
174                 if (willRemoveReferenceNodeAncestor) {
175                     while (node && node->isDescendantOf(&removedNode))
176                         node = NodeTraversal::previous(*node, root());
177                 }
178                 if (node) {
179                     // Removing last node.
180                     // Need to move the pointer after the node preceding the
181                     // new reference node.
182                     referenceNode.node = node;
183                     referenceNode.isPointerBeforeNode = false;
184                 }
185             }
186         }
187     } else {
188         Node* node = NodeTraversal::previous(removedNode, root());
189         if (node) {
190             // Move out from under the node being removed if the reference node is
191             // a descendant of the node being removed.
192             if (willRemoveReferenceNodeAncestor) {
193                 while (node && node->isDescendantOf(&removedNode))
194                     node = NodeTraversal::previous(*node, root());
195             }
196             if (node)
197                 referenceNode.node = node;
198         } else {
199             // FIXME: This branch doesn't appear to have any LayoutTests.
200             node = NodeTraversal::next(removedNode, root());
201             // Move out from under the node being removed if the reference node is
202             // a descendant of the node being removed.
203             if (willRemoveReferenceNodeAncestor) {
204                 while (node && node->isDescendantOf(&removedNode))
205                     node = NodeTraversal::previous(*node, root());
206             }
207             if (node)
208                 referenceNode.node = node;
209         }
210     }
211 }
212
213 void NodeIterator::trace(Visitor* visitor)
214 {
215     visitor->trace(m_referenceNode);
216     visitor->trace(m_candidateNode);
217     NodeIteratorBase::trace(visitor);
218 }
219
220 } // namespace blink