Home | History | Annotate | Download | only in dom
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2001 Dirk Mueller (mueller (at) kde.org)
      5  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
      6  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
      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 #ifndef NodeTraversal_h
     26 #define NodeTraversal_h
     27 
     28 #include "core/dom/Element.h"
     29 
     30 namespace WebCore {
     31 
     32 namespace ElementTraversal {
     33 
     34 // First element child of the node.
     35 Element* firstWithin(const Node*);
     36 Element* firstWithin(const ContainerNode*);
     37 
     38 // Pre-order traversal skipping non-element nodes.
     39 Element* next(const Node*);
     40 Element* next(const Node*, const Node* stayWithin);
     41 Element* next(const ContainerNode*);
     42 Element* next(const ContainerNode*, const Node* stayWithin);
     43 
     44 // Like next, but skips children.
     45 Element* nextSkippingChildren(const Node*);
     46 Element* nextSkippingChildren(const Node*, const Node* stayWithin);
     47 Element* nextSkippingChildren(const ContainerNode*);
     48 Element* nextSkippingChildren(const ContainerNode*, const Node* stayWithin);
     49 
     50 // Pre-order traversal including the pseudo-elements.
     51 Element* previousIncludingPseudo(const Node*, const Node* stayWithin = 0);
     52 Element* nextIncludingPseudo(const Node*, const Node* stayWithin = 0);
     53 Element* nextIncludingPseudoSkippingChildren(const Node*, const Node* stayWithin = 0);
     54 
     55 // Utility function to traverse only the element and pseudo-element siblings of a node.
     56 Element* pseudoAwarePreviousSibling(const Node*);
     57 
     58 }
     59 
     60 namespace NodeTraversal {
     61 
     62 // Does a pre-order traversal of the tree to find the next node after this one.
     63 // This uses the same order that tags appear in the source file. If the stayWithin
     64 // argument is non-null, the traversal will stop once the specified node is reached.
     65 // This can be used to restrict traversal to a particular sub-tree.
     66 Node* next(const Node*);
     67 Node* next(const Node*, const Node* stayWithin);
     68 Node* next(const ContainerNode*);
     69 Node* next(const ContainerNode*, const Node* stayWithin);
     70 
     71 // Like next, but skips children and starts with the next sibling.
     72 Node* nextSkippingChildren(const Node*);
     73 Node* nextSkippingChildren(const Node*, const Node* stayWithin);
     74 Node* nextSkippingChildren(const ContainerNode*);
     75 Node* nextSkippingChildren(const ContainerNode*, const Node* stayWithin);
     76 
     77 // Does a reverse pre-order traversal to find the node that comes before the current one in document order
     78 Node* previous(const Node*, const Node* stayWithin = 0);
     79 
     80 // Like previous, but skips children and starts with the next sibling.
     81 Node* previousSkippingChildren(const Node*, const Node* stayWithin = 0);
     82 
     83 // Like next, but visits parents after their children.
     84 Node* nextPostOrder(const Node*, const Node* stayWithin = 0);
     85 
     86 // Like previous/previousSkippingChildren, but visits parents before their children.
     87 Node* previousPostOrder(const Node*, const Node* stayWithin = 0);
     88 Node* previousSkippingChildrenPostOrder(const Node*, const Node* stayWithin = 0);
     89 
     90 // Pre-order traversal including the pseudo-elements.
     91 Node* previousIncludingPseudo(const Node*, const Node* stayWithin = 0);
     92 Node* nextIncludingPseudo(const Node*, const Node* stayWithin = 0);
     93 Node* nextIncludingPseudoSkippingChildren(const Node*, const Node* stayWithin = 0);
     94 
     95 }
     96 
     97 namespace ElementTraversal {
     98 template <class NodeType>
     99 inline Element* firstElementWithinTemplate(NodeType* current)
    100 {
    101     // Except for the root containers, only elements can have element children.
    102     Node* node = current->firstChild();
    103     while (node && !node->isElementNode())
    104         node = node->nextSibling();
    105     return toElement(node);
    106 }
    107 inline Element* firstWithin(const ContainerNode* current) { return firstElementWithinTemplate(current); }
    108 inline Element* firstWithin(const Node* current) { return firstElementWithinTemplate(current); }
    109 
    110 template <class NodeType>
    111 inline Element* traverseNextElementTemplate(NodeType* current)
    112 {
    113     Node* node = NodeTraversal::next(current);
    114     while (node && !node->isElementNode())
    115         node = NodeTraversal::nextSkippingChildren(node);
    116     return toElement(node);
    117 }
    118 inline Element* next(const ContainerNode* current) { return traverseNextElementTemplate(current); }
    119 inline Element* next(const Node* current) { return traverseNextElementTemplate(current); }
    120 
    121 template <class NodeType>
    122 inline Element* traverseNextElementTemplate(NodeType* current, const Node* stayWithin)
    123 {
    124     Node* node = NodeTraversal::next(current, stayWithin);
    125     while (node && !node->isElementNode())
    126         node = NodeTraversal::nextSkippingChildren(node, stayWithin);
    127     return toElement(node);
    128 }
    129 inline Element* next(const ContainerNode* current, const Node* stayWithin) { return traverseNextElementTemplate(current, stayWithin); }
    130 inline Element* next(const Node* current, const Node* stayWithin) { return traverseNextElementTemplate(current, stayWithin); }
    131 
    132 template <class NodeType>
    133 inline Element* traverseNextElementSkippingChildrenTemplate(NodeType* current)
    134 {
    135     Node* node = NodeTraversal::nextSkippingChildren(current);
    136     while (node && !node->isElementNode())
    137         node = NodeTraversal::nextSkippingChildren(node);
    138     return toElement(node);
    139 }
    140 inline Element* nextSkippingChildren(const ContainerNode* current) { return traverseNextElementSkippingChildrenTemplate(current); }
    141 inline Element* nextSkippingChildren(const Node* current) { return traverseNextElementSkippingChildrenTemplate(current); }
    142 
    143 template <class NodeType>
    144 inline Element* traverseNextElementSkippingChildrenTemplate(NodeType* current, const Node* stayWithin)
    145 {
    146     Node* node = NodeTraversal::nextSkippingChildren(current, stayWithin);
    147     while (node && !node->isElementNode())
    148         node = NodeTraversal::nextSkippingChildren(node, stayWithin);
    149     return toElement(node);
    150 }
    151 inline Element* nextSkippingChildren(const ContainerNode* current, const Node* stayWithin) { return traverseNextElementSkippingChildrenTemplate(current, stayWithin); }
    152 inline Element* nextSkippingChildren(const Node* current, const Node* stayWithin) { return traverseNextElementSkippingChildrenTemplate(current, stayWithin); }
    153 
    154 inline Element* previousIncludingPseudo(const Node* current, const Node* stayWithin)
    155 {
    156     Node* node = NodeTraversal::previousIncludingPseudo(current, stayWithin);
    157     while (node && !node->isElementNode())
    158         node = NodeTraversal::previousIncludingPseudo(node, stayWithin);
    159     return toElement(node);
    160 }
    161 
    162 inline Element* nextIncludingPseudo(const Node* current, const Node* stayWithin)
    163 {
    164     Node* node = NodeTraversal::nextIncludingPseudo(current, stayWithin);
    165     while (node && !node->isElementNode())
    166         node = NodeTraversal::nextIncludingPseudo(node, stayWithin);
    167     return toElement(node);
    168 }
    169 
    170 inline Element* nextIncludingPseudoSkippingChildren(const Node* current, const Node* stayWithin)
    171 {
    172     Node* node = NodeTraversal::nextIncludingPseudoSkippingChildren(current, stayWithin);
    173     while (node && !node->isElementNode())
    174         node = NodeTraversal::nextIncludingPseudoSkippingChildren(node, stayWithin);
    175     return toElement(node);
    176 }
    177 
    178 inline Element* pseudoAwarePreviousSibling(const Node* current)
    179 {
    180     Node* node = current->pseudoAwarePreviousSibling();
    181     while (node && !node->isElementNode())
    182         node = node->pseudoAwarePreviousSibling();
    183     return toElement(node);
    184 }
    185 
    186 }
    187 
    188 namespace NodeTraversal {
    189 
    190 Node* nextAncestorSibling(const Node*);
    191 Node* nextAncestorSibling(const Node*, const Node* stayWithin);
    192 
    193 template <class NodeType>
    194 inline Node* traverseNextTemplate(NodeType* current)
    195 {
    196     if (current->firstChild())
    197         return current->firstChild();
    198     if (current->nextSibling())
    199         return current->nextSibling();
    200     return nextAncestorSibling(current);
    201 }
    202 inline Node* next(const Node* current) { return traverseNextTemplate(current); }
    203 inline Node* next(const ContainerNode* current) { return traverseNextTemplate(current); }
    204 
    205 template <class NodeType>
    206 inline Node* traverseNextTemplate(NodeType* current, const Node* stayWithin)
    207 {
    208     if (current->firstChild())
    209         return current->firstChild();
    210     if (current == stayWithin)
    211         return 0;
    212     if (current->nextSibling())
    213         return current->nextSibling();
    214     return nextAncestorSibling(current, stayWithin);
    215 }
    216 inline Node* next(const Node* current, const Node* stayWithin) { return traverseNextTemplate(current, stayWithin); }
    217 inline Node* next(const ContainerNode* current, const Node* stayWithin) { return traverseNextTemplate(current, stayWithin); }
    218 
    219 template <class NodeType>
    220 inline Node* traverseNextSkippingChildrenTemplate(NodeType* current)
    221 {
    222     if (current->nextSibling())
    223         return current->nextSibling();
    224     return nextAncestorSibling(current);
    225 }
    226 inline Node* nextSkippingChildren(const Node* current) { return traverseNextSkippingChildrenTemplate(current); }
    227 inline Node* nextSkippingChildren(const ContainerNode* current) { return traverseNextSkippingChildrenTemplate(current); }
    228 
    229 template <class NodeType>
    230 inline Node* traverseNextSkippingChildrenTemplate(NodeType* current, const Node* stayWithin)
    231 {
    232     if (current == stayWithin)
    233         return 0;
    234     if (current->nextSibling())
    235         return current->nextSibling();
    236     return nextAncestorSibling(current, stayWithin);
    237 }
    238 inline Node* nextSkippingChildren(const Node* current, const Node* stayWithin) { return traverseNextSkippingChildrenTemplate(current, stayWithin); }
    239 inline Node* nextSkippingChildren(const ContainerNode* current, const Node* stayWithin) { return traverseNextSkippingChildrenTemplate(current, stayWithin); }
    240 
    241 }
    242 
    243 }
    244 
    245 #endif
    246