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 | |
30 | namespace WebCore { |
31 | |
32 | namespace NodeTraversal { |
33 | |
34 | Node* previousIncludingPseudo(const Node& current, const Node* stayWithin) |
35 | { |
36 | Node* previous; |
37 | if (¤t == 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 | |
47 | Node* nextIncludingPseudo(const Node& current, const Node* stayWithin) |
48 | { |
49 | Node* next; |
50 | if ((next = current.pseudoAwareFirstChild())) |
51 | return next; |
52 | if (¤t == 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 | |
66 | Node* nextIncludingPseudoSkippingChildren(const Node& current, const Node* stayWithin) |
67 | { |
68 | Node* next; |
69 | if (¤t == 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 | |
83 | Node* 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 | |
93 | Node* nextAncestorSibling(const Node& current, const Node* stayWithin) |
94 | { |
95 | ASSERT(!current.nextSibling()); |
96 | ASSERT(¤t != 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 | |
106 | Node* 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 | |
116 | Node* deepLastChild(Node& node) |
117 | { |
118 | Node* lastChild = &node; |
119 | while (lastChild->lastChild()) |
120 | lastChild = lastChild->lastChild(); |
121 | return lastChild; |
122 | } |
123 | |
124 | Node* previousSkippingChildren(const Node& current, const Node* stayWithin) |
125 | { |
126 | if (¤t == 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 | |
139 | Node* nextPostOrder(const Node& current, const Node* stayWithin) |
140 | { |
141 | if (¤t == 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 | |
151 | static 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 | |
163 | Node* previousPostOrder(const Node& current, const Node* stayWithin) |
164 | { |
165 | if (current.lastChild()) |
166 | return current.lastChild(); |
167 | if (¤t == stayWithin) |
168 | return nullptr; |
169 | if (current.previousSibling()) |
170 | return current.previousSibling(); |
171 | return previousAncestorSiblingPostOrder(current, stayWithin); |
172 | } |
173 | |
174 | Node* previousSkippingChildrenPostOrder(const Node& current, const Node* stayWithin) |
175 | { |
176 | if (¤t == stayWithin) |
177 | return nullptr; |
178 | if (current.previousSibling()) |
179 | return current.previousSibling(); |
180 | return previousAncestorSiblingPostOrder(current, stayWithin); |
181 | } |
182 | |
183 | } |
184 | } |
185 | |