/work/obj-fuzz/dist/include/mozilla/RangeBoundary.h
Line | Count | Source (jump to first uncovered line) |
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 | | #ifndef mozilla_RangeBoundary_h |
8 | | #define mozilla_RangeBoundary_h |
9 | | |
10 | | #include "nsCOMPtr.h" |
11 | | #include "nsIContent.h" |
12 | | #include "mozilla/Maybe.h" |
13 | | |
14 | | namespace mozilla { |
15 | | |
16 | | template<typename T, typename U> |
17 | | class EditorDOMPointBase; |
18 | | |
19 | | // This class will maintain a reference to the child immediately |
20 | | // before the boundary's offset. We try to avoid computing the |
21 | | // offset as much as possible and just ensure mRef points to the |
22 | | // correct child. |
23 | | // |
24 | | // mParent |
25 | | // | |
26 | | // [child0] [child1] [child2] |
27 | | // / | |
28 | | // mRef mOffset=2 |
29 | | // |
30 | | // If mOffset == 0, mRef is null. |
31 | | // For text nodes, mRef will always be null and the offset will |
32 | | // be kept up-to-date. |
33 | | |
34 | | template<typename ParentType, typename RefType> |
35 | | class RangeBoundaryBase; |
36 | | |
37 | | typedef RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent>> RangeBoundary; |
38 | | typedef RangeBoundaryBase<nsINode*, nsIContent*> RawRangeBoundary; |
39 | | |
40 | | // This class has two specializations, one using reference counting |
41 | | // pointers and one using raw pointers. This helps us avoid unnecessary |
42 | | // AddRef/Release calls. |
43 | | template<typename ParentType, typename RefType> |
44 | | class RangeBoundaryBase |
45 | | { |
46 | | template<typename T, typename U> |
47 | | friend class RangeBoundaryBase; |
48 | | template<typename T, typename U> |
49 | | friend class EditorDOMPointBase; |
50 | | |
51 | | friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&, |
52 | | RangeBoundary&, const char*, |
53 | | uint32_t); |
54 | | friend void ImplCycleCollectionUnlink(RangeBoundary&); |
55 | | |
56 | | public: |
57 | | RangeBoundaryBase(nsINode* aContainer, nsIContent* aRef) |
58 | | : mParent(aContainer) |
59 | | , mRef(aRef) |
60 | 0 | { |
61 | 0 | if (!mRef) { |
62 | 0 | mOffset = mozilla::Some(0); |
63 | 0 | } else { |
64 | 0 | NS_WARNING_ASSERTION(mRef->GetParentNode() == mParent, |
65 | 0 | "Initializing RangeBoundary with invalid value"); |
66 | 0 | mOffset.reset(); |
67 | 0 | } |
68 | 0 | } Unexecuted instantiation: mozilla::RangeBoundaryBase<nsINode*, nsIContent*>::RangeBoundaryBase(nsINode*, nsIContent*) Unexecuted instantiation: mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >::RangeBoundaryBase(nsINode*, nsIContent*) |
69 | | |
70 | | RangeBoundaryBase(nsINode* aContainer, int32_t aOffset) |
71 | | : mParent(aContainer) |
72 | | , mRef(nullptr) |
73 | | , mOffset(mozilla::Some(aOffset)) |
74 | 0 | { |
75 | 0 | if (mParent && mParent->IsContainerNode()) { |
76 | 0 | // Find a reference node |
77 | 0 | if (aOffset == static_cast<int32_t>(aContainer->GetChildCount())) { |
78 | 0 | mRef = aContainer->GetLastChild(); |
79 | 0 | } else if (aOffset != 0) { |
80 | 0 | mRef = mParent->GetChildAt_Deprecated(aOffset - 1); |
81 | 0 | } |
82 | 0 |
|
83 | 0 | NS_WARNING_ASSERTION(mRef || aOffset == 0, |
84 | 0 | "Constructing RangeBoundary with invalid value"); |
85 | 0 | } |
86 | 0 |
|
87 | 0 | NS_WARNING_ASSERTION(!mRef || mRef->GetParentNode() == mParent, |
88 | 0 | "Constructing RangeBoundary with invalid value"); |
89 | 0 | } Unexecuted instantiation: mozilla::RangeBoundaryBase<nsINode*, nsIContent*>::RangeBoundaryBase(nsINode*, int) Unexecuted instantiation: mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >::RangeBoundaryBase(nsINode*, int) |
90 | | |
91 | | RangeBoundaryBase() |
92 | | : mParent(nullptr) |
93 | | , mRef(nullptr) |
94 | 0 | { |
95 | 0 | } Unexecuted instantiation: mozilla::RangeBoundaryBase<nsINode*, nsIContent*>::RangeBoundaryBase() Unexecuted instantiation: mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >::RangeBoundaryBase() |
96 | | |
97 | | // Needed for initializing RawRangeBoundary from an existing RangeBoundary. |
98 | | template<typename PT, typename RT> |
99 | | explicit RangeBoundaryBase(const RangeBoundaryBase<PT, RT>& aOther) |
100 | | : mParent(aOther.mParent) |
101 | | , mRef(aOther.mRef) |
102 | | , mOffset(aOther.mOffset) |
103 | 0 | { |
104 | 0 | } |
105 | | |
106 | | nsIContent* |
107 | | Ref() const |
108 | 0 | { |
109 | 0 | return mRef; |
110 | 0 | } Unexecuted instantiation: mozilla::RangeBoundaryBase<nsINode*, nsIContent*>::Ref() const Unexecuted instantiation: mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >::Ref() const |
111 | | |
112 | | nsINode* |
113 | | Container() const |
114 | 0 | { |
115 | 0 | return mParent; |
116 | 0 | } Unexecuted instantiation: mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >::Container() const Unexecuted instantiation: mozilla::RangeBoundaryBase<nsINode*, nsIContent*>::Container() const |
117 | | |
118 | | nsIContent* |
119 | | GetChildAtOffset() const |
120 | 0 | { |
121 | 0 | if (!mParent || !mParent->IsContainerNode()) { |
122 | 0 | return nullptr; |
123 | 0 | } |
124 | 0 | if (!mRef) { |
125 | 0 | MOZ_ASSERT(Offset() == 0, "invalid RangeBoundary"); |
126 | 0 | return mParent->GetFirstChild(); |
127 | 0 | } |
128 | 0 | MOZ_ASSERT(mParent->GetChildAt_Deprecated(Offset()) == mRef->GetNextSibling()); |
129 | 0 | return mRef->GetNextSibling(); |
130 | 0 | } Unexecuted instantiation: mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >::GetChildAtOffset() const Unexecuted instantiation: mozilla::RangeBoundaryBase<nsINode*, nsIContent*>::GetChildAtOffset() const |
131 | | |
132 | | /** |
133 | | * GetNextSiblingOfChildOffset() returns next sibling of a child at offset. |
134 | | * If this refers after the last child or the container cannot have children, |
135 | | * this returns nullptr with warning. |
136 | | */ |
137 | | nsIContent* |
138 | | GetNextSiblingOfChildAtOffset() const |
139 | | { |
140 | | if (NS_WARN_IF(!mParent) || NS_WARN_IF(!mParent->IsContainerNode())) { |
141 | | return nullptr; |
142 | | } |
143 | | if (NS_WARN_IF(!mRef->GetNextSibling())) { |
144 | | // Already referring the end of the container. |
145 | | return nullptr; |
146 | | } |
147 | | return mRef->GetNextSibling()->GetNextSibling(); |
148 | | } |
149 | | |
150 | | /** |
151 | | * GetPreviousSiblingOfChildAtOffset() returns previous sibling of a child |
152 | | * at offset. If this refers the first child or the container cannot have |
153 | | * children, this returns nullptr with warning. |
154 | | */ |
155 | | nsIContent* |
156 | | GetPreviousSiblingOfChildAtOffset() const |
157 | 0 | { |
158 | 0 | if (NS_WARN_IF(!mParent) || NS_WARN_IF(!mParent->IsContainerNode())) { |
159 | 0 | return nullptr; |
160 | 0 | } |
161 | 0 | if (NS_WARN_IF(!mRef)) { |
162 | 0 | // Already referring the start of the container. |
163 | 0 | return nullptr; |
164 | 0 | } |
165 | 0 | return mRef; |
166 | 0 | } |
167 | | |
168 | | uint32_t |
169 | | Offset() const |
170 | 0 | { |
171 | 0 | if (mOffset.isSome()) { |
172 | 0 | return mOffset.value(); |
173 | 0 | } |
174 | 0 | |
175 | 0 | if (!mParent) { |
176 | 0 | return 0; |
177 | 0 | } |
178 | 0 | |
179 | 0 | MOZ_ASSERT(mRef); |
180 | 0 | MOZ_ASSERT(mRef->GetParentNode() == mParent); |
181 | 0 | mOffset = mozilla::Some(mParent->ComputeIndexOf(mRef) + 1); |
182 | 0 |
|
183 | 0 | return mOffset.value(); |
184 | 0 | } Unexecuted instantiation: mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >::Offset() const Unexecuted instantiation: mozilla::RangeBoundaryBase<nsINode*, nsIContent*>::Offset() const |
185 | | |
186 | | void |
187 | | InvalidateOffset() |
188 | 0 | { |
189 | 0 | MOZ_ASSERT(mParent); |
190 | 0 | MOZ_ASSERT(mParent->IsContainerNode(), "Range is positioned on a text node!"); |
191 | 0 |
|
192 | 0 | if (!mRef) { |
193 | 0 | MOZ_ASSERT(mOffset.isSome() && mOffset.value() == 0, |
194 | 0 | "Invalidating offset of invalid RangeBoundary?"); |
195 | 0 | return; |
196 | 0 | } |
197 | 0 | mOffset.reset(); |
198 | 0 | } |
199 | | |
200 | | void |
201 | | Set(nsINode* aContainer, int32_t aOffset) |
202 | 0 | { |
203 | 0 | mParent = aContainer; |
204 | 0 | if (mParent && mParent->IsContainerNode()) { |
205 | 0 | // Find a reference node |
206 | 0 | if (aOffset == static_cast<int32_t>(aContainer->GetChildCount())) { |
207 | 0 | mRef = aContainer->GetLastChild(); |
208 | 0 | } else if (aOffset == 0) { |
209 | 0 | mRef = nullptr; |
210 | 0 | } else { |
211 | 0 | mRef = mParent->GetChildAt_Deprecated(aOffset - 1); |
212 | 0 | MOZ_ASSERT(mRef); |
213 | 0 | } |
214 | 0 |
|
215 | 0 | NS_WARNING_ASSERTION(mRef || aOffset == 0, |
216 | 0 | "Setting RangeBoundary to invalid value"); |
217 | 0 | } else { |
218 | 0 | mRef = nullptr; |
219 | 0 | } |
220 | 0 |
|
221 | 0 | mOffset = mozilla::Some(aOffset); |
222 | 0 |
|
223 | 0 | NS_WARNING_ASSERTION(!mRef || mRef->GetParentNode() == mParent, |
224 | 0 | "Setting RangeBoundary to invalid value"); |
225 | 0 | } Unexecuted instantiation: mozilla::RangeBoundaryBase<nsINode*, nsIContent*>::Set(nsINode*, int) Unexecuted instantiation: mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >::Set(nsINode*, int) |
226 | | |
227 | | void |
228 | | SetAfterRef(nsINode* aParent, nsIContent* aRef) |
229 | 0 | { |
230 | 0 | mParent = aParent; |
231 | 0 | mRef = aRef; |
232 | 0 | if (!mRef) { |
233 | 0 | mOffset = mozilla::Some(0); |
234 | 0 | } else { |
235 | 0 | mOffset.reset(); |
236 | 0 | } |
237 | 0 | } Unexecuted instantiation: mozilla::RangeBoundaryBase<nsINode*, nsIContent*>::SetAfterRef(nsINode*, nsIContent*) Unexecuted instantiation: mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >::SetAfterRef(nsINode*, nsIContent*) |
238 | | |
239 | | bool |
240 | | IsSet() const |
241 | 0 | { |
242 | 0 | return mParent && (mRef || mOffset.isSome()); |
243 | 0 | } Unexecuted instantiation: mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >::IsSet() const Unexecuted instantiation: mozilla::RangeBoundaryBase<nsINode*, nsIContent*>::IsSet() const |
244 | | |
245 | | bool |
246 | | IsSetAndValid() const |
247 | 0 | { |
248 | 0 | if (!IsSet()) { |
249 | 0 | return false; |
250 | 0 | } |
251 | 0 | |
252 | 0 | if (Ref()) { |
253 | 0 | return Ref()->GetParentNode() == Container(); |
254 | 0 | } |
255 | 0 | return Offset() <= Container()->Length(); |
256 | 0 | } Unexecuted instantiation: mozilla::RangeBoundaryBase<nsINode*, nsIContent*>::IsSetAndValid() const Unexecuted instantiation: mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >::IsSetAndValid() const |
257 | | |
258 | | bool |
259 | | IsStartOfContainer() const |
260 | 0 | { |
261 | 0 | // We're at the first point in the container if we don't have a reference, |
262 | 0 | // and our offset is 0. If we don't have a Ref, we should already have an |
263 | 0 | // offset, so we can just directly fetch it. |
264 | 0 | return !Ref() && mOffset.value() == 0; |
265 | 0 | } Unexecuted instantiation: mozilla::RangeBoundaryBase<nsINode*, nsIContent*>::IsStartOfContainer() const Unexecuted instantiation: mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >::IsStartOfContainer() const |
266 | | |
267 | | bool |
268 | | IsEndOfContainer() const |
269 | | { |
270 | | // We're at the last point in the container if Ref is a pointer to the last |
271 | | // child in Container(), or our Offset() is the same as the length of our |
272 | | // container. If we don't have a Ref, then we should already have an offset, |
273 | | // so we can just directly fetch it. |
274 | | return Ref() |
275 | | ? !Ref()->GetNextSibling() |
276 | | : mOffset.value() == Container()->Length(); |
277 | | } |
278 | | |
279 | | // Convenience methods for switching between the two types |
280 | | // of RangeBoundary. |
281 | | RangeBoundaryBase<nsINode*, nsIContent*> |
282 | | AsRaw() const |
283 | 0 | { |
284 | 0 | return RangeBoundaryBase<nsINode*, nsIContent*>(*this); |
285 | 0 | } |
286 | | |
287 | | template<typename A, typename B> |
288 | | RangeBoundaryBase& operator=(const RangeBoundaryBase<A,B>& aOther) |
289 | 0 | { |
290 | 0 | // mParent and mRef can be strong pointers, so better to try to avoid any |
291 | 0 | // extra AddRef/Release calls. |
292 | 0 | if (mParent != aOther.mParent) { |
293 | 0 | mParent = aOther.mParent; |
294 | 0 | } |
295 | 0 | if (mRef != aOther.mRef) { |
296 | 0 | mRef = aOther.mRef; |
297 | 0 | } |
298 | 0 | mOffset = aOther.mOffset; |
299 | 0 | return *this; |
300 | 0 | } Unexecuted instantiation: mozilla::RangeBoundaryBase<nsINode*, nsIContent*>& mozilla::RangeBoundaryBase<nsINode*, nsIContent*>::operator=<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >(mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> > const&) Unexecuted instantiation: mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >& mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >::operator=<nsINode*, nsIContent*>(mozilla::RangeBoundaryBase<nsINode*, nsIContent*> const&) |
301 | | |
302 | | template<typename A, typename B> |
303 | | bool operator==(const RangeBoundaryBase<A, B>& aOther) const |
304 | 0 | { |
305 | 0 | return mParent == aOther.mParent && |
306 | 0 | (mRef ? mRef == aOther.mRef : mOffset == aOther.mOffset); |
307 | 0 | } Unexecuted instantiation: bool mozilla::RangeBoundaryBase<nsINode*, nsIContent*>::operator==<nsINode*, nsIContent*>(mozilla::RangeBoundaryBase<nsINode*, nsIContent*> const&) const Unexecuted instantiation: bool mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >::operator==<nsINode*, nsIContent*>(mozilla::RangeBoundaryBase<nsINode*, nsIContent*> const&) const Unexecuted instantiation: bool mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >::operator==<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >(mozilla::RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> > const&) const |
308 | | |
309 | | template<typename A, typename B> |
310 | | bool operator!=(const RangeBoundaryBase<A, B>& aOther) const |
311 | 0 | { |
312 | 0 | return !(*this == aOther); |
313 | 0 | } |
314 | | |
315 | | private: |
316 | | ParentType mParent; |
317 | | RefType mRef; |
318 | | |
319 | | mutable mozilla::Maybe<uint32_t> mOffset; |
320 | | }; |
321 | | |
322 | | inline void |
323 | | ImplCycleCollectionUnlink(RangeBoundary& aField) |
324 | 0 | { |
325 | 0 | ImplCycleCollectionUnlink(aField.mParent); |
326 | 0 | ImplCycleCollectionUnlink(aField.mRef); |
327 | 0 | } |
328 | | |
329 | | inline void |
330 | | ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, |
331 | | RangeBoundary& aField, |
332 | | const char* aName, |
333 | | uint32_t aFlags) |
334 | 0 | { |
335 | 0 | ImplCycleCollectionTraverse(aCallback, aField.mParent, "mParent", 0); |
336 | 0 | ImplCycleCollectionTraverse(aCallback, aField.mRef, "mRef", 0); |
337 | 0 | } |
338 | | |
339 | | } // namespace mozilla |
340 | | |
341 | | #endif // defined(mozilla_RangeBoundary_h) |