1/*
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 ElementTraversal_h
26#define ElementTraversal_h
27
28#include "core/dom/Element.h"
29#include "core/dom/NodeTraversal.h"
30
31namespace WebCore {
32
33namespace ElementTraversal {
34
35// First element child of the node.
36Element* firstWithin(const Node&);
37Element* firstWithin(const ContainerNode&);
38
39// Pre-order traversal skipping non-element nodes.
40Element* next(const Node&);
41Element* next(const Node&, const Node* stayWithin);
42Element* next(const ContainerNode&);
43Element* next(const ContainerNode&, const Node* stayWithin);
44
45// Like next, but skips children.
46Element* nextSkippingChildren(const Node&);
47Element* nextSkippingChildren(const Node&, const Node* stayWithin);
48Element* nextSkippingChildren(const ContainerNode&);
49Element* nextSkippingChildren(const ContainerNode&, const Node* stayWithin);
50
51// Pre-order traversal including the pseudo-elements.
52Element* previousIncludingPseudo(const Node&, const Node* stayWithin = 0);
53Element* nextIncludingPseudo(const Node&, const Node* stayWithin = 0);
54Element* nextIncludingPseudoSkippingChildren(const Node&, const Node* stayWithin = 0);
55
56// Utility function to traverse only the element and pseudo-element siblings of a node.
57Element* pseudoAwarePreviousSibling(const Node&);
58
59template <class NodeType>
60inline Element* firstElementWithinTemplate(NodeType& current)
61{
62    // Except for the root containers, only elements can have element children.
63    Node* node = current.firstChild();
64    while (node && !node->isElementNode())
65        node = node->nextSibling();
66    return toElement(node);
67}
68inline Element* firstWithin(const ContainerNode& current) { return firstElementWithinTemplate(current); }
69inline Element* firstWithin(const Node& current) { return firstElementWithinTemplate(current); }
70
71template <class NodeType>
72inline Element* traverseNextElementTemplate(NodeType& current)
73{
74    Node* node = NodeTraversal::next(current);
75    while (node && !node->isElementNode())
76        node = NodeTraversal::nextSkippingChildren(*node);
77    return toElement(node);
78}
79inline Element* next(const ContainerNode& current) { return traverseNextElementTemplate(current); }
80inline Element* next(const Node& current) { return traverseNextElementTemplate(current); }
81
82template <class NodeType>
83inline Element* traverseNextElementTemplate(NodeType& current, const Node* stayWithin)
84{
85    Node* node = NodeTraversal::next(current, stayWithin);
86    while (node && !node->isElementNode())
87        node = NodeTraversal::nextSkippingChildren(*node, stayWithin);
88    return toElement(node);
89}
90inline Element* next(const ContainerNode& current, const Node* stayWithin) { return traverseNextElementTemplate(current, stayWithin); }
91inline Element* next(const Node& current, const Node* stayWithin) { return traverseNextElementTemplate(current, stayWithin); }
92
93template <class NodeType>
94inline Element* traverseNextElementSkippingChildrenTemplate(NodeType& current)
95{
96    Node* node = NodeTraversal::nextSkippingChildren(current);
97    while (node && !node->isElementNode())
98        node = NodeTraversal::nextSkippingChildren(*node);
99    return toElement(node);
100}
101inline Element* nextSkippingChildren(const ContainerNode& current) { return traverseNextElementSkippingChildrenTemplate(current); }
102inline Element* nextSkippingChildren(const Node& current) { return traverseNextElementSkippingChildrenTemplate(current); }
103
104template <class NodeType>
105inline Element* traverseNextElementSkippingChildrenTemplate(NodeType& current, const Node* stayWithin)
106{
107    Node* node = NodeTraversal::nextSkippingChildren(current, stayWithin);
108    while (node && !node->isElementNode())
109        node = NodeTraversal::nextSkippingChildren(*node, stayWithin);
110    return toElement(node);
111}
112inline Element* nextSkippingChildren(const ContainerNode& current, const Node* stayWithin) { return traverseNextElementSkippingChildrenTemplate(current, stayWithin); }
113inline Element* nextSkippingChildren(const Node& current, const Node* stayWithin) { return traverseNextElementSkippingChildrenTemplate(current, stayWithin); }
114
115inline Element* previousIncludingPseudo(const Node& current, const Node* stayWithin)
116{
117    Node* node = NodeTraversal::previousIncludingPseudo(current, stayWithin);
118    while (node && !node->isElementNode())
119        node = NodeTraversal::previousIncludingPseudo(*node, stayWithin);
120    return toElement(node);
121}
122
123inline Element* nextIncludingPseudo(const Node& current, const Node* stayWithin)
124{
125    Node* node = NodeTraversal::nextIncludingPseudo(current, stayWithin);
126    while (node && !node->isElementNode())
127        node = NodeTraversal::nextIncludingPseudo(*node, stayWithin);
128    return toElement(node);
129}
130
131inline Element* nextIncludingPseudoSkippingChildren(const Node& current, const Node* stayWithin)
132{
133    Node* node = NodeTraversal::nextIncludingPseudoSkippingChildren(current, stayWithin);
134    while (node && !node->isElementNode())
135        node = NodeTraversal::nextIncludingPseudoSkippingChildren(*node, stayWithin);
136    return toElement(node);
137}
138
139inline Element* pseudoAwarePreviousSibling(const Node& current)
140{
141    Node* node = current.pseudoAwarePreviousSibling();
142    while (node && !node->isElementNode())
143        node = node->pseudoAwarePreviousSibling();
144    return toElement(node);
145}
146
147}
148
149}
150
151#endif
152