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