blob: c9d5208a22722f08e18450c127f4465ffa999da6 [file] [log] [blame]
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@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
30namespace WebCore {
31
32namespace ElementTraversal {
33
34// First element child of the node.
35Element* firstWithin(const Node*);
36Element* firstWithin(const ContainerNode*);
37
38// Pre-order traversal skipping non-element nodes.
39Element* next(const Node*);
40Element* next(const Node*, const Node* stayWithin);
41Element* next(const ContainerNode*);
42Element* next(const ContainerNode*, const Node* stayWithin);
43
44// Like next, but skips children.
45Element* nextSkippingChildren(const Node*);
46Element* nextSkippingChildren(const Node*, const Node* stayWithin);
47Element* nextSkippingChildren(const ContainerNode*);
48Element* nextSkippingChildren(const ContainerNode*, const Node* stayWithin);
49
50// Pre-order traversal including the pseudo-elements.
51Element* previousIncludingPseudo(const Node*, const Node* stayWithin = 0);
52Element* nextIncludingPseudo(const Node*, const Node* stayWithin = 0);
53Element* nextIncludingPseudoSkippingChildren(const Node*, const Node* stayWithin = 0);
54
55// Utility function to traverse only the element and pseudo-element siblings of a node.
56Element* pseudoAwarePreviousSibling(const Node*);
57
58}
59
60namespace 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.
66Node* next(const Node*);
67Node* next(const Node*, const Node* stayWithin);
68Node* next(const ContainerNode*);
69Node* next(const ContainerNode*, const Node* stayWithin);
70
71// Like next, but skips children and starts with the next sibling.
72Node* nextSkippingChildren(const Node*);
73Node* nextSkippingChildren(const Node*, const Node* stayWithin);
74Node* nextSkippingChildren(const ContainerNode*);
75Node* 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
78Node* previous(const Node*, const Node* stayWithin = 0);
79
80// Like previous, but skips children and starts with the next sibling.
81Node* previousSkippingChildren(const Node*, const Node* stayWithin = 0);
82
83// Like next, but visits parents after their children.
84Node* nextPostOrder(const Node*, const Node* stayWithin = 0);
85
86// Like previous/previousSkippingChildren, but visits parents before their children.
87Node* previousPostOrder(const Node*, const Node* stayWithin = 0);
88Node* previousSkippingChildrenPostOrder(const Node*, const Node* stayWithin = 0);
89
90// Pre-order traversal including the pseudo-elements.
91Node* previousIncludingPseudo(const Node*, const Node* stayWithin = 0);
92Node* nextIncludingPseudo(const Node*, const Node* stayWithin = 0);
93Node* nextIncludingPseudoSkippingChildren(const Node*, const Node* stayWithin = 0);
94
95}
96
97namespace ElementTraversal {
98template <class NodeType>
99inline 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}
107inline Element* firstWithin(const ContainerNode* current) { return firstElementWithinTemplate(current); }
108inline Element* firstWithin(const Node* current) { return firstElementWithinTemplate(current); }
109
110template <class NodeType>
111inline 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}
118inline Element* next(const ContainerNode* current) { return traverseNextElementTemplate(current); }
119inline Element* next(const Node* current) { return traverseNextElementTemplate(current); }
120
121template <class NodeType>
122inline 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}
129inline Element* next(const ContainerNode* current, const Node* stayWithin) { return traverseNextElementTemplate(current, stayWithin); }
130inline Element* next(const Node* current, const Node* stayWithin) { return traverseNextElementTemplate(current, stayWithin); }
131
132template <class NodeType>
133inline 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}
140inline Element* nextSkippingChildren(const ContainerNode* current) { return traverseNextElementSkippingChildrenTemplate(current); }
141inline Element* nextSkippingChildren(const Node* current) { return traverseNextElementSkippingChildrenTemplate(current); }
142
143template <class NodeType>
144inline 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}
151inline Element* nextSkippingChildren(const ContainerNode* current, const Node* stayWithin) { return traverseNextElementSkippingChildrenTemplate(current, stayWithin); }
152inline Element* nextSkippingChildren(const Node* current, const Node* stayWithin) { return traverseNextElementSkippingChildrenTemplate(current, stayWithin); }
153
154inline 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
162inline 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
170inline 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
178inline 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
188namespace NodeTraversal {
189
190Node* nextAncestorSibling(const Node*);
191Node* nextAncestorSibling(const Node*, const Node* stayWithin);
192
193template <class NodeType>
194inline 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}
202inline Node* next(const Node* current) { return traverseNextTemplate(current); }
203inline Node* next(const ContainerNode* current) { return traverseNextTemplate(current); }
Ben Murdoch02772c62013-07-26 10:21:05 +0100204
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100205template <class NodeType>
206inline 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}
216inline Node* next(const Node* current, const Node* stayWithin) { return traverseNextTemplate(current, stayWithin); }
217inline Node* next(const ContainerNode* current, const Node* stayWithin) { return traverseNextTemplate(current, stayWithin); }
218
219template <class NodeType>
220inline Node* traverseNextSkippingChildrenTemplate(NodeType* current)
221{
222 if (current->nextSibling())
223 return current->nextSibling();
224 return nextAncestorSibling(current);
225}
226inline Node* nextSkippingChildren(const Node* current) { return traverseNextSkippingChildrenTemplate(current); }
227inline Node* nextSkippingChildren(const ContainerNode* current) { return traverseNextSkippingChildrenTemplate(current); }
228
229template <class NodeType>
230inline 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}
238inline Node* nextSkippingChildren(const Node* current, const Node* stayWithin) { return traverseNextSkippingChildrenTemplate(current, stayWithin); }
239inline Node* nextSkippingChildren(const ContainerNode* current, const Node* stayWithin) { return traverseNextSkippingChildrenTemplate(current, stayWithin); }
240
241}
242
243}
244
245#endif