1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
10 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
11 * Copyright (C) 2012, Google, Inc. All rights reserved.
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 * Library General Public License for more details.
22 *
23 * You should have received a copy of the GNU Library General Public License
24 * along with this library; see the file COPYING.LIB.  If not, write to
25 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
27 */
28
29#ifndef SiblingTraversalStrategies_h
30#define SiblingTraversalStrategies_h
31
32#include "core/dom/Element.h"
33#include "core/dom/ElementTraversal.h"
34#include "core/rendering/style/RenderStyle.h"
35
36namespace blink {
37
38class DOMSiblingTraversalStrategy {
39public:
40    bool isFirstChild(Element&) const;
41    bool isLastChild(Element&) const;
42    bool isFirstOfType(Element&, const QualifiedName&) const;
43    bool isLastOfType(Element&, const QualifiedName&) const;
44
45    int countElementsBefore(Element&) const;
46    int countElementsAfter(Element&) const;
47    int countElementsOfTypeBefore(Element&, const QualifiedName&) const;
48    int countElementsOfTypeAfter(Element&, const QualifiedName&) const;
49
50private:
51    class HasTagName {
52    public:
53        explicit HasTagName(const QualifiedName& tagName) : m_tagName(tagName) { }
54        bool operator() (const Element& element) const { return element.hasTagName(m_tagName); }
55    private:
56        const QualifiedName& m_tagName;
57    };
58};
59
60inline bool DOMSiblingTraversalStrategy::isFirstChild(Element& element) const
61{
62    return !ElementTraversal::previousSibling(element);
63}
64
65inline bool DOMSiblingTraversalStrategy::isLastChild(Element& element) const
66{
67    return !ElementTraversal::nextSibling(element);
68}
69
70inline bool DOMSiblingTraversalStrategy::isFirstOfType(Element& element, const QualifiedName& type) const
71{
72    return !ElementTraversal::previousSibling(element, HasTagName(type));
73}
74
75inline bool DOMSiblingTraversalStrategy::isLastOfType(Element& element, const QualifiedName& type) const
76{
77    return !ElementTraversal::nextSibling(element, HasTagName(type));
78}
79
80inline int DOMSiblingTraversalStrategy::countElementsBefore(Element& element) const
81{
82    int count = 0;
83    for (const Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(*sibling))
84        count++;
85
86    return count;
87}
88
89inline int DOMSiblingTraversalStrategy::countElementsOfTypeBefore(Element& element, const QualifiedName& type) const
90{
91    int count = 0;
92    for (const Element* sibling = ElementTraversal::previousSibling(element, HasTagName(type)); sibling; sibling = ElementTraversal::previousSibling(*sibling, HasTagName(type)))
93        ++count;
94    return count;
95}
96
97inline int DOMSiblingTraversalStrategy::countElementsAfter(Element& element) const
98{
99    int count = 0;
100    for (const Element* sibling = ElementTraversal::nextSibling(element); sibling; sibling = ElementTraversal::nextSibling(*sibling))
101        ++count;
102    return count;
103}
104
105inline int DOMSiblingTraversalStrategy::countElementsOfTypeAfter(Element& element, const QualifiedName& type) const
106{
107    int count = 0;
108    for (const Element* sibling = ElementTraversal::nextSibling(element, HasTagName(type)); sibling; sibling = ElementTraversal::nextSibling(*sibling, HasTagName(type)))
109        ++count;
110    return count;
111}
112
113class ShadowDOMSiblingTraversalStrategy FINAL {
114    STACK_ALLOCATED();
115public:
116    ShadowDOMSiblingTraversalStrategy(const WillBeHeapVector<RawPtrWillBeMember<Node>, 32>& siblings, int nth)
117        : m_siblings(siblings)
118        , m_nth(nth)
119    {
120    }
121
122    bool isFirstChild(Element&) const;
123    bool isLastChild(Element&) const;
124    bool isFirstOfType(Element&, const QualifiedName&) const;
125    bool isLastOfType(Element&, const QualifiedName&) const;
126
127    int countElementsBefore(Element&) const;
128    int countElementsAfter(Element&) const;
129    int countElementsOfTypeBefore(Element&, const QualifiedName&) const;
130    int countElementsOfTypeAfter(Element&, const QualifiedName&) const;
131
132private:
133    const WillBeHeapVector<RawPtrWillBeMember<Node>, 32>& m_siblings;
134    int m_nth;
135};
136
137inline bool ShadowDOMSiblingTraversalStrategy::isFirstChild(Element& element) const
138{
139    ASSERT(element == toElement(m_siblings[m_nth]));
140
141    for (int i = m_nth - 1; i >= 0; --i) {
142        if (m_siblings[i]->isElementNode())
143            return false;
144    }
145
146    return true;
147}
148
149inline bool ShadowDOMSiblingTraversalStrategy::isLastChild(Element& element) const
150{
151    ASSERT(element == toElement(m_siblings[m_nth]));
152
153    for (size_t i = m_nth + 1; i < m_siblings.size(); ++i) {
154        if (m_siblings[i]->isElementNode())
155            return false;
156    }
157
158    return true;
159}
160
161inline bool ShadowDOMSiblingTraversalStrategy::isFirstOfType(Element& element, const QualifiedName& type) const
162{
163    ASSERT(element == toElement(m_siblings[m_nth]));
164
165    for (int i = m_nth - 1; i >= 0; --i) {
166        if (m_siblings[i]->isElementNode() && toElement(m_siblings[i])->hasTagName(type))
167            return false;
168    }
169
170    return true;
171}
172
173inline bool ShadowDOMSiblingTraversalStrategy::isLastOfType(Element& element, const QualifiedName& type) const
174{
175    ASSERT(element == toElement(m_siblings[m_nth]));
176
177    for (size_t i = m_nth + 1; i < m_siblings.size(); ++i) {
178        if (m_siblings[i]->isElementNode() && toElement(m_siblings[i])->hasTagName(type))
179            return false;
180    }
181
182    return true;
183}
184
185inline int ShadowDOMSiblingTraversalStrategy::countElementsBefore(Element& element) const
186{
187    ASSERT(element == toElement(m_siblings[m_nth]));
188
189    int count = 0;
190    for (int i = m_nth - 1; i >= 0; --i) {
191        if (m_siblings[i]->isElementNode())
192            ++count;
193    }
194
195    return count;
196}
197
198inline int ShadowDOMSiblingTraversalStrategy::countElementsAfter(Element& element) const
199{
200    ASSERT(element == toElement(m_siblings[m_nth]));
201
202    int count = 0;
203    for (size_t i = m_nth + 1; i < m_siblings.size(); ++i) {
204        if (m_siblings[i]->isElementNode())
205            return ++count;
206    }
207
208    return count;
209}
210
211inline int ShadowDOMSiblingTraversalStrategy::countElementsOfTypeBefore(Element& element, const QualifiedName& type) const
212{
213    ASSERT(element == toElement(m_siblings[m_nth]));
214
215    int count = 0;
216    for (int i = m_nth - 1; i >= 0; --i) {
217        if (m_siblings[i]->isElementNode() && toElement(m_siblings[i])->hasTagName(type))
218            ++count;
219    }
220
221    return count;
222}
223
224inline int ShadowDOMSiblingTraversalStrategy::countElementsOfTypeAfter(Element& element, const QualifiedName& type) const
225{
226    ASSERT(element == toElement(m_siblings[m_nth]));
227
228    int count = 0;
229    for (size_t i = m_nth + 1; i < m_siblings.size(); ++i) {
230        if (m_siblings[i]->isElementNode() && toElement(m_siblings[i])->hasTagName(type))
231            return ++count;
232    }
233
234    return count;
235}
236
237}
238
239#endif
240