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#include "config.h"
26#include "NodeTraversal.h"
27
28#include "PseudoElement.h"
29
30namespace WebCore {
31
32namespace NodeTraversal {
33
34Node* previousIncludingPseudo(const Node& current, const Node* stayWithin)
35{
36 Node* previous;
37 if (&current == stayWithin)
38 return nullptr;
39 if ((previous = current.pseudoAwarePreviousSibling())) {
40 while (previous->pseudoAwareLastChild())
41 previous = previous->pseudoAwareLastChild();
42 return previous;
43 }
44 return is<PseudoElement>(current) ? downcast<PseudoElement>(current).hostElement() : current.parentNode();
45}
46
47Node* nextIncludingPseudo(const Node& current, const Node* stayWithin)
48{
49 Node* next;
50 if ((next = current.pseudoAwareFirstChild()))
51 return next;
52 if (&current == stayWithin)
53 return nullptr;
54 if ((next = current.pseudoAwareNextSibling()))
55 return next;
56 const Node* ancestor = is<PseudoElement>(current) ? downcast<PseudoElement>(current).hostElement() : current.parentNode();
57 for (; ancestor; ancestor = ancestor->parentNode()) {
58 if (ancestor == stayWithin)
59 return nullptr;
60 if ((next = ancestor->pseudoAwareNextSibling()))
61 return next;
62 }
63 return nullptr;
64}
65
66Node* nextIncludingPseudoSkippingChildren(const Node& current, const Node* stayWithin)
67{
68 Node* next;
69 if (&current == stayWithin)
70 return nullptr;
71 if ((next = current.pseudoAwareNextSibling()))
72 return next;
73 const Node* ancestor = is<PseudoElement>(current) ? downcast<PseudoElement>(current).hostElement() : current.parentNode();
74 for (; ancestor; ancestor = ancestor->parentNode()) {
75 if (ancestor == stayWithin)
76 return nullptr;
77 if ((next = ancestor->pseudoAwareNextSibling()))
78 return next;
79 }
80 return nullptr;
81}
82
83Node* nextAncestorSibling(const Node& current)
84{
85 ASSERT(!current.nextSibling());
86 for (auto* ancestor = current.parentNode(); ancestor; ancestor = ancestor->parentNode()) {
87 if (ancestor->nextSibling())
88 return ancestor->nextSibling();
89 }
90 return nullptr;
91}
92
93Node* nextAncestorSibling(const Node& current, const Node* stayWithin)
94{
95 ASSERT(!current.nextSibling());
96 ASSERT(&current != stayWithin);
97 for (auto* ancestor = current.parentNode(); ancestor; ancestor = ancestor->parentNode()) {
98 if (ancestor == stayWithin)
99 return nullptr;
100 if (ancestor->nextSibling())
101 return ancestor->nextSibling();
102 }
103 return nullptr;
104}
105
106Node* last(const ContainerNode& current)
107{
108 Node* node = current.lastChild();
109 if (!node)
110 return nullptr;
111 while (node->lastChild())
112 node = node->lastChild();
113 return node;
114}
115
116Node* deepLastChild(Node& node)
117{
118 Node* lastChild = &node;
119 while (lastChild->lastChild())
120 lastChild = lastChild->lastChild();
121 return lastChild;
122}
123
124Node* previousSkippingChildren(const Node& current, const Node* stayWithin)
125{
126 if (&current == stayWithin)
127 return nullptr;
128 if (current.previousSibling())
129 return current.previousSibling();
130 for (auto* ancestor = current.parentNode(); ancestor; ancestor = ancestor->parentNode()) {
131 if (ancestor == stayWithin)
132 return nullptr;
133 if (ancestor->previousSibling())
134 return ancestor->previousSibling();
135 }
136 return nullptr;
137}
138
139Node* nextPostOrder(const Node& current, const Node* stayWithin)
140{
141 if (&current == stayWithin)
142 return nullptr;
143 if (!current.nextSibling())
144 return current.parentNode();
145 Node* next = current.nextSibling();
146 while (next->firstChild())
147 next = next->firstChild();
148 return next;
149}
150
151static Node* previousAncestorSiblingPostOrder(const Node& current, const Node* stayWithin)
152{
153 ASSERT(!current.previousSibling());
154 for (auto* ancestor = current.parentNode(); ancestor; ancestor = ancestor->parentNode()) {
155 if (ancestor == stayWithin)
156 return nullptr;
157 if (ancestor->previousSibling())
158 return ancestor->previousSibling();
159 }
160 return nullptr;
161}
162
163Node* previousPostOrder(const Node& current, const Node* stayWithin)
164{
165 if (current.lastChild())
166 return current.lastChild();
167 if (&current == stayWithin)
168 return nullptr;
169 if (current.previousSibling())
170 return current.previousSibling();
171 return previousAncestorSiblingPostOrder(current, stayWithin);
172}
173
174Node* previousSkippingChildrenPostOrder(const Node& current, const Node* stayWithin)
175{
176 if (&current == stayWithin)
177 return nullptr;
178 if (current.previousSibling())
179 return current.previousSibling();
180 return previousAncestorSiblingPostOrder(current, stayWithin);
181}
182
183}
184}
185