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 "core/dom/TreeWalker.h" 27 28 #include "bindings/v8/ExceptionState.h" 29 #include "bindings/v8/ScriptState.h" 30 #include "core/dom/ContainerNode.h" 31 #include "core/dom/ExceptionCode.h" 32 #include "core/dom/NodeFilter.h" 33 #include "core/dom/NodeTraversal.h" 34 #include "wtf/PassRefPtr.h" 35 36 namespace WebCore { 37 38 TreeWalker::TreeWalker(PassRefPtr<Node> rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter) 39 : Traversal(rootNode, whatToShow, filter) 40 , m_current(root()) 41 { 42 ScriptWrappable::init(this); 43 } 44 45 void TreeWalker::setCurrentNode(PassRefPtr<Node> node, ExceptionState& es) 46 { 47 if (!node) { 48 es.throwDOMException(NotSupportedError); 49 return; 50 } 51 m_current = node; 52 } 53 54 inline Node* TreeWalker::setCurrent(PassRefPtr<Node> node) 55 { 56 m_current = node; 57 return m_current.get(); 58 } 59 60 Node* TreeWalker::parentNode(ScriptState* state) 61 { 62 RefPtr<Node> node = m_current; 63 while (node != root()) { 64 node = node->parentNode(); 65 if (!node) 66 return 0; 67 short acceptNodeResult = acceptNode(state, node.get()); 68 if (state && state->hadException()) 69 return 0; 70 if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) 71 return setCurrent(node.release()); 72 } 73 return 0; 74 } 75 76 Node* TreeWalker::firstChild(ScriptState* state) 77 { 78 for (RefPtr<Node> node = m_current->firstChild(); node; ) { 79 short acceptNodeResult = acceptNode(state, node.get()); 80 if (state && state->hadException()) 81 return 0; 82 switch (acceptNodeResult) { 83 case NodeFilter::FILTER_ACCEPT: 84 m_current = node.release(); 85 return m_current.get(); 86 case NodeFilter::FILTER_SKIP: 87 if (node->firstChild()) { 88 node = node->firstChild(); 89 continue; 90 } 91 break; 92 case NodeFilter::FILTER_REJECT: 93 break; 94 } 95 do { 96 if (node->nextSibling()) { 97 node = node->nextSibling(); 98 break; 99 } 100 ContainerNode* parent = node->parentNode(); 101 if (!parent || parent == root() || parent == m_current) 102 return 0; 103 node = parent; 104 } while (node); 105 } 106 return 0; 107 } 108 109 Node* TreeWalker::lastChild(ScriptState* state) 110 { 111 for (RefPtr<Node> node = m_current->lastChild(); node; ) { 112 short acceptNodeResult = acceptNode(state, node.get()); 113 if (state && state->hadException()) 114 return 0; 115 switch (acceptNodeResult) { 116 case NodeFilter::FILTER_ACCEPT: 117 m_current = node.release(); 118 return m_current.get(); 119 case NodeFilter::FILTER_SKIP: 120 if (node->lastChild()) { 121 node = node->lastChild(); 122 continue; 123 } 124 break; 125 case NodeFilter::FILTER_REJECT: 126 break; 127 } 128 do { 129 if (node->previousSibling()) { 130 node = node->previousSibling(); 131 break; 132 } 133 ContainerNode* parent = node->parentNode(); 134 if (!parent || parent == root() || parent == m_current) 135 return 0; 136 node = parent; 137 } while (node); 138 } 139 return 0; 140 } 141 142 Node* TreeWalker::previousSibling(ScriptState* state) 143 { 144 RefPtr<Node> node = m_current; 145 if (node == root()) 146 return 0; 147 while (1) { 148 for (RefPtr<Node> sibling = node->previousSibling(); sibling; ) { 149 short acceptNodeResult = acceptNode(state, sibling.get()); 150 if (state && state->hadException()) 151 return 0; 152 switch (acceptNodeResult) { 153 case NodeFilter::FILTER_ACCEPT: 154 m_current = sibling.release(); 155 return m_current.get(); 156 case NodeFilter::FILTER_SKIP: 157 if (sibling->lastChild()) { 158 sibling = sibling->lastChild(); 159 node = sibling; 160 continue; 161 } 162 break; 163 case NodeFilter::FILTER_REJECT: 164 break; 165 } 166 sibling = sibling->previousSibling(); 167 } 168 node = node->parentNode(); 169 if (!node || node == root()) 170 return 0; 171 short acceptNodeResult = acceptNode(state, node.get()); 172 if (state && state->hadException()) 173 return 0; 174 if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) 175 return 0; 176 } 177 } 178 179 Node* TreeWalker::nextSibling(ScriptState* state) 180 { 181 RefPtr<Node> node = m_current; 182 if (node == root()) 183 return 0; 184 while (1) { 185 for (RefPtr<Node> sibling = node->nextSibling(); sibling; ) { 186 short acceptNodeResult = acceptNode(state, sibling.get()); 187 if (state && state->hadException()) 188 return 0; 189 switch (acceptNodeResult) { 190 case NodeFilter::FILTER_ACCEPT: 191 m_current = sibling.release(); 192 return m_current.get(); 193 case NodeFilter::FILTER_SKIP: 194 if (sibling->firstChild()) { 195 sibling = sibling->firstChild(); 196 node = sibling; 197 continue; 198 } 199 break; 200 case NodeFilter::FILTER_REJECT: 201 break; 202 } 203 sibling = sibling->nextSibling(); 204 } 205 node = node->parentNode(); 206 if (!node || node == root()) 207 return 0; 208 short acceptNodeResult = acceptNode(state, node.get()); 209 if (state && state->hadException()) 210 return 0; 211 if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) 212 return 0; 213 } 214 } 215 216 Node* TreeWalker::previousNode(ScriptState* state) 217 { 218 RefPtr<Node> node = m_current; 219 while (node != root()) { 220 while (Node* previousSibling = node->previousSibling()) { 221 node = previousSibling; 222 short acceptNodeResult = acceptNode(state, node.get()); 223 if (state && state->hadException()) 224 return 0; 225 if (acceptNodeResult == NodeFilter::FILTER_REJECT) 226 continue; 227 while (Node* lastChild = node->lastChild()) { 228 node = lastChild; 229 acceptNodeResult = acceptNode(state, node.get()); 230 if (state && state->hadException()) 231 return 0; 232 if (acceptNodeResult == NodeFilter::FILTER_REJECT) 233 break; 234 } 235 if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) { 236 m_current = node.release(); 237 return m_current.get(); 238 } 239 } 240 if (node == root()) 241 return 0; 242 ContainerNode* parent = node->parentNode(); 243 if (!parent) 244 return 0; 245 node = parent; 246 short acceptNodeResult = acceptNode(state, node.get()); 247 if (state && state->hadException()) 248 return 0; 249 if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) 250 return setCurrent(node.release()); 251 } 252 return 0; 253 } 254 255 Node* TreeWalker::nextNode(ScriptState* state) 256 { 257 RefPtr<Node> node = m_current; 258 Children: 259 while (Node* firstChild = node->firstChild()) { 260 node = firstChild; 261 short acceptNodeResult = acceptNode(state, node.get()); 262 if (state && state->hadException()) 263 return 0; 264 if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) 265 return setCurrent(node.release()); 266 if (acceptNodeResult == NodeFilter::FILTER_REJECT) 267 break; 268 } 269 while (Node* nextSibling = NodeTraversal::nextSkippingChildren(node.get(), root())) { 270 node = nextSibling; 271 short acceptNodeResult = acceptNode(state, node.get()); 272 if (state && state->hadException()) 273 return 0; 274 if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) 275 return setCurrent(node.release()); 276 if (acceptNodeResult == NodeFilter::FILTER_SKIP) 277 goto Children; 278 } 279 return 0; 280 } 281 282 } // namespace WebCore 283