1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * Copyright (C) 2000 Frederik Holljen (frederik.holljen (at) hig.no) 4 * Copyright (C) 2001 Peter Kelly (pmk (at) post.com) 5 * Copyright (C) 2006 Samuel Weinig (sam.weinig (at) 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 35 NodeIterator::NodePointer::NodePointer() 36 { 37 } 38 39 NodeIterator::NodePointer::NodePointer(PassRefPtr<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 = node->traverseNextNode(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 = node->traversePreviousNode(root); 71 return node; 72 } 73 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 82 NodeIterator::~NodeIterator() 83 { 84 root()->document()->detachNodeIterator(this); 85 } 86 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 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 145 void NodeIterator::detach() 146 { 147 root()->document()->detachNodeIterator(this); 148 m_detached = true; 149 m_referenceNode.node.clear(); 150 } 151 152 void NodeIterator::nodeWillBeRemoved(Node* removedNode) 153 { 154 updateForNodeRemoval(removedNode, m_candidateNode); 155 updateForNodeRemoval(removedNode, m_referenceNode); 156 } 157 158 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