1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 /**
8  * Implementation of some generic iterators over ancestor nodes.
9  *
10  * Note that these keep raw pointers to the nodes they iterate from, and as
11  * such the DOM should not be mutated while they're in use. There are debug
12  * assertions (via nsMutationGuard) that check this in debug builds.
13  */
14 
15 #ifndef mozilla_dom_AncestorIterator_h
16 #define mozilla_dom_AncestorIterator_h
17 
18 #include "nsINode.h"
19 #include "nsIContentInlines.h"
20 #include "FilteredNodeIterator.h"
21 
22 namespace mozilla {
23 namespace dom {
24 
25 #ifdef DEBUG
26 #  define MUTATION_GUARD(class_name_) \
27     nsMutationGuard mMutationGuard;   \
28     ~class_name_() { MOZ_ASSERT(!mMutationGuard.Mutated(0)); }
29 #else
30 #  define MUTATION_GUARD(class_name_)
31 #endif
32 
33 #define DEFINE_ANCESTOR_ITERATOR(name_, method_)                         \
34   class Inclusive##name_ {                                               \
35     using Self = Inclusive##name_;                                       \
36                                                                          \
37    public:                                                               \
38     explicit Inclusive##name_(const nsINode& aNode)                      \
39         : mCurrent(const_cast<nsINode*>(&aNode)) {}                      \
40     Self& begin() { return *this; }                                      \
41     std::nullptr_t end() const { return nullptr; }                       \
42     bool operator!=(std::nullptr_t) const { return !!mCurrent; }         \
43     void operator++() { mCurrent = mCurrent->method_(); }                \
44     nsINode* operator*() { return mCurrent; }                            \
45                                                                          \
46     MUTATION_GUARD(Inclusive##name_)                                     \
47                                                                          \
48    protected:                                                            \
49     explicit Inclusive##name_(nsINode* aCurrent) : mCurrent(aCurrent) {} \
50     nsINode* mCurrent;                                                   \
51   };                                                                     \
52   class name_ : public Inclusive##name_ {                                \
53    public:                                                               \
54     using Super = Inclusive##name_;                                      \
55     explicit name_(const nsINode& aNode)                                 \
56         : Inclusive##name_(aNode.method_()) {}                           \
57   };                                                                     \
58   template <typename T>                                                  \
59   class name_##OfTypeIterator : public FilteredNodeIterator<T, name_> {  \
60    public:                                                               \
61     explicit name_##OfTypeIterator(const nsINode& aNode)                 \
62         : FilteredNodeIterator<T, name_>(aNode) {}                       \
63   };                                                                     \
64   template <typename T>                                                  \
65   class Inclusive##name_##OfTypeIterator                                 \
66       : public FilteredNodeIterator<T, Inclusive##name_> {               \
67    public:                                                               \
68     explicit Inclusive##name_##OfTypeIterator(const nsINode& aNode)      \
69         : FilteredNodeIterator<T, Inclusive##name_>(aNode) {}            \
70   };
71 
72 DEFINE_ANCESTOR_ITERATOR(Ancestors, GetParentNode)
73 DEFINE_ANCESTOR_ITERATOR(FlatTreeAncestors, GetFlattenedTreeParentNode)
74 
75 #undef MUTATION_GUARD
76 
77 }  // namespace dom
78 }  // namespace mozilla
79 
80 template <typename T>
AncestorsOfType()81 inline mozilla::dom::AncestorsOfTypeIterator<T> nsINode::AncestorsOfType()
82     const {
83   return mozilla::dom::AncestorsOfTypeIterator<T>(*this);
84 }
85 
86 template <typename T>
87 inline mozilla::dom::InclusiveAncestorsOfTypeIterator<T>
InclusiveAncestorsOfType()88 nsINode::InclusiveAncestorsOfType() const {
89   return mozilla::dom::InclusiveAncestorsOfTypeIterator<T>(*this);
90 }
91 
92 template <typename T>
93 inline mozilla::dom::FlatTreeAncestorsOfTypeIterator<T>
FlatTreeAncestorsOfType()94 nsINode::FlatTreeAncestorsOfType() const {
95   return mozilla::dom::FlatTreeAncestorsOfTypeIterator<T>(*this);
96 }
97 
98 template <typename T>
99 inline mozilla::dom::InclusiveFlatTreeAncestorsOfTypeIterator<T>
InclusiveFlatTreeAncestorsOfType()100 nsINode::InclusiveFlatTreeAncestorsOfType() const {
101   return mozilla::dom::InclusiveFlatTreeAncestorsOfTypeIterator<T>(*this);
102 }
103 
104 template <typename T>
FirstAncestorOfType()105 inline T* nsINode::FirstAncestorOfType() const {
106   return *(AncestorsOfType<T>());
107 }
108 
109 #endif  // mozilla_dom_AncestorIterator.h
110