Coverage Report

Created: 2018-09-25 14:53

/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)