Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/PlacesObservers.cpp
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
#include "PlacesObservers.h"
8
9
#include "PlacesWeakCallbackWrapper.h"
10
#include "nsIWeakReferenceUtils.h"
11
#include "mozilla/ClearOnShutdown.h"
12
13
namespace mozilla {
14
namespace dom {
15
16
template <class T>
17
struct Flagged
18
{
19
  Flagged(uint32_t aFlags, T&& aValue)
20
    : flags(aFlags)
21
    , value(std::forward<T>(aValue))
22
0
  {}
Unexecuted instantiation: mozilla::dom::Flagged<RefPtr<mozilla::dom::PlacesEventCallback> >::Flagged(unsigned int, RefPtr<mozilla::dom::PlacesEventCallback>&&)
Unexecuted instantiation: mozilla::dom::Flagged<mozilla::WeakPtr<mozilla::dom::PlacesWeakCallbackWrapper> >::Flagged(unsigned int, mozilla::WeakPtr<mozilla::dom::PlacesWeakCallbackWrapper>&&)
Unexecuted instantiation: mozilla::dom::Flagged<mozilla::WeakPtr<mozilla::places::INativePlacesEventCallback> >::Flagged(unsigned int, mozilla::WeakPtr<mozilla::places::INativePlacesEventCallback>&&)
23
  Flagged(Flagged&& aOther)
24
    : Flagged(std::move(aOther.flags), std::move(aOther.value))
25
  {}
26
0
  Flagged(const Flagged& aOther) = default;
Unexecuted instantiation: mozilla::dom::Flagged<RefPtr<mozilla::dom::PlacesEventCallback> >::Flagged(mozilla::dom::Flagged<RefPtr<mozilla::dom::PlacesEventCallback> > const&)
Unexecuted instantiation: mozilla::dom::Flagged<mozilla::WeakPtr<mozilla::dom::PlacesWeakCallbackWrapper> >::Flagged(mozilla::dom::Flagged<mozilla::WeakPtr<mozilla::dom::PlacesWeakCallbackWrapper> > const&)
Unexecuted instantiation: mozilla::dom::Flagged<mozilla::WeakPtr<mozilla::places::INativePlacesEventCallback> >::Flagged(mozilla::dom::Flagged<mozilla::WeakPtr<mozilla::places::INativePlacesEventCallback> > const&)
27
0
  ~Flagged() = default;
Unexecuted instantiation: mozilla::dom::Flagged<RefPtr<mozilla::dom::PlacesEventCallback> >::~Flagged()
Unexecuted instantiation: mozilla::dom::Flagged<mozilla::WeakPtr<mozilla::dom::PlacesWeakCallbackWrapper> >::~Flagged()
Unexecuted instantiation: mozilla::dom::Flagged<mozilla::WeakPtr<mozilla::places::INativePlacesEventCallback> >::~Flagged()
28
29
  uint32_t flags;
30
  T value;
31
};
32
33
template <class T>
34
using FlaggedArray = nsTArray<Flagged<T>>;
35
36
template <class T>
37
struct ListenerCollection
38
{
39
  static StaticAutoPtr<FlaggedArray<T>> gListeners;
40
  static StaticAutoPtr<FlaggedArray<T>> gListenersToRemove;
41
42
0
  static FlaggedArray<T>* GetListeners() {
43
0
    MOZ_ASSERT(NS_IsMainThread());
44
0
    if (!gListeners) {
45
0
      gListeners = new FlaggedArray<T>();
46
0
      ClearOnShutdown(&gListeners);
47
0
    }
48
0
    return gListeners;
49
0
  }
Unexecuted instantiation: mozilla::dom::ListenerCollection<RefPtr<mozilla::dom::PlacesEventCallback> >::GetListeners()
Unexecuted instantiation: mozilla::dom::ListenerCollection<mozilla::WeakPtr<mozilla::dom::PlacesWeakCallbackWrapper> >::GetListeners()
Unexecuted instantiation: mozilla::dom::ListenerCollection<mozilla::WeakPtr<mozilla::places::INativePlacesEventCallback> >::GetListeners()
50
51
0
  static FlaggedArray<T>* GetListenersToRemove() {
52
0
    MOZ_ASSERT(NS_IsMainThread());
53
0
    if (!gListenersToRemove) {
54
0
      gListenersToRemove = new FlaggedArray<T>();
55
0
      ClearOnShutdown(&gListenersToRemove);
56
0
    }
57
0
    return gListenersToRemove;
58
0
  }
Unexecuted instantiation: mozilla::dom::ListenerCollection<RefPtr<mozilla::dom::PlacesEventCallback> >::GetListenersToRemove()
Unexecuted instantiation: mozilla::dom::ListenerCollection<mozilla::WeakPtr<mozilla::dom::PlacesWeakCallbackWrapper> >::GetListenersToRemove()
Unexecuted instantiation: mozilla::dom::ListenerCollection<mozilla::WeakPtr<mozilla::places::INativePlacesEventCallback> >::GetListenersToRemove()
59
};
60
61
template <class T>
62
StaticAutoPtr<FlaggedArray<T>> ListenerCollection<T>::gListeners;
63
template <class T>
64
StaticAutoPtr<FlaggedArray<T>> ListenerCollection<T>::gListenersToRemove;
65
66
typedef ListenerCollection<RefPtr<PlacesEventCallback>> JSListeners;
67
typedef ListenerCollection<WeakPtr<PlacesWeakCallbackWrapper>> WeakJSListeners;
68
typedef ListenerCollection<WeakPtr<places::INativePlacesEventCallback>> WeakNativeListeners;
69
70
static bool gCallingListeners = false;
71
72
uint32_t
73
GetEventTypeFlag(PlacesEventType aEventType)
74
0
{
75
0
  if (aEventType == PlacesEventType::None) {
76
0
    return 0;
77
0
  }
78
0
  return 1 << ((uint32_t)aEventType - 1);
79
0
}
80
81
uint32_t
82
GetFlagsForEventTypes(const nsTArray<PlacesEventType>& aEventTypes)
83
0
{
84
0
  uint32_t flags = 0;
85
0
  for (PlacesEventType eventType : aEventTypes) {
86
0
    flags |= GetEventTypeFlag(eventType);
87
0
  }
88
0
  return flags;
89
0
}
90
91
uint32_t
92
GetFlagsForEvents(const nsTArray<OwningNonNull<PlacesEvent>>& aEvents)
93
0
{
94
0
  uint32_t flags = 0;
95
0
  for (const PlacesEvent& event : aEvents) {
96
0
    flags |= GetEventTypeFlag(event.Type());
97
0
  }
98
0
  return flags;
99
0
}
100
101
template <class TWrapped, class TUnwrapped>
102
void CallListeners(uint32_t aEventFlags,
103
                   FlaggedArray<TWrapped>& aListeners,
104
                   const Sequence<OwningNonNull<PlacesEvent>>& aEvents,
105
                   const std::function<TUnwrapped(TWrapped&)>& aUnwrapListener,
106
                   const std::function<void(TUnwrapped&, const Sequence<OwningNonNull<PlacesEvent>>&)>& aCallListener)
107
0
{
108
0
  for (uint32_t i = 0; i < aListeners.Length(); i++) {
109
0
    Flagged<TWrapped>& l = aListeners[i];
110
0
    TUnwrapped unwrapped = aUnwrapListener(l.value);
111
0
    if (!unwrapped) {
112
0
      aListeners.RemoveElementAt(i);
113
0
      i--;
114
0
      continue;
115
0
    }
116
0
117
0
    if ((l.flags & aEventFlags) == aEventFlags) {
118
0
      aCallListener(unwrapped, aEvents);
119
0
    } else if (l.flags & aEventFlags) {
120
0
      Sequence<OwningNonNull<PlacesEvent>> filtered;
121
0
      for (const OwningNonNull<PlacesEvent>& event : aEvents) {
122
0
        if (l.flags & GetEventTypeFlag(event->Type())) {
123
0
          bool success = !!filtered.AppendElement(event, fallible);
124
0
          MOZ_RELEASE_ASSERT(success);
125
0
        }
126
0
      }
127
0
      aCallListener(unwrapped, filtered);
128
0
    }
129
0
  }
130
0
}
Unexecuted instantiation: void mozilla::dom::CallListeners<RefPtr<mozilla::dom::PlacesEventCallback>, RefPtr<mozilla::dom::PlacesEventCallback> >(unsigned int, nsTArray<mozilla::dom::Flagged<RefPtr<mozilla::dom::PlacesEventCallback> > >&, mozilla::dom::Sequence<mozilla::OwningNonNull<mozilla::dom::PlacesEvent> > const&, std::__1::function<RefPtr<mozilla::dom::PlacesEventCallback> (RefPtr<mozilla::dom::PlacesEventCallback>&)> const&, std::__1::function<void (RefPtr<mozilla::dom::PlacesEventCallback>&, mozilla::dom::Sequence<mozilla::OwningNonNull<mozilla::dom::PlacesEvent> > const&)> const&)
Unexecuted instantiation: void mozilla::dom::CallListeners<mozilla::WeakPtr<mozilla::places::INativePlacesEventCallback>, RefPtr<mozilla::places::INativePlacesEventCallback> >(unsigned int, nsTArray<mozilla::dom::Flagged<mozilla::WeakPtr<mozilla::places::INativePlacesEventCallback> > >&, mozilla::dom::Sequence<mozilla::OwningNonNull<mozilla::dom::PlacesEvent> > const&, std::__1::function<RefPtr<mozilla::places::INativePlacesEventCallback> (mozilla::WeakPtr<mozilla::places::INativePlacesEventCallback>&)> const&, std::__1::function<void (RefPtr<mozilla::places::INativePlacesEventCallback>&, mozilla::dom::Sequence<mozilla::OwningNonNull<mozilla::dom::PlacesEvent> > const&)> const&)
Unexecuted instantiation: void mozilla::dom::CallListeners<mozilla::WeakPtr<mozilla::dom::PlacesWeakCallbackWrapper>, RefPtr<mozilla::dom::PlacesWeakCallbackWrapper> >(unsigned int, nsTArray<mozilla::dom::Flagged<mozilla::WeakPtr<mozilla::dom::PlacesWeakCallbackWrapper> > >&, mozilla::dom::Sequence<mozilla::OwningNonNull<mozilla::dom::PlacesEvent> > const&, std::__1::function<RefPtr<mozilla::dom::PlacesWeakCallbackWrapper> (mozilla::WeakPtr<mozilla::dom::PlacesWeakCallbackWrapper>&)> const&, std::__1::function<void (RefPtr<mozilla::dom::PlacesWeakCallbackWrapper>&, mozilla::dom::Sequence<mozilla::OwningNonNull<mozilla::dom::PlacesEvent> > const&)> const&)
131
132
void
133
PlacesObservers::AddListener(GlobalObject& aGlobal,
134
                             const nsTArray<PlacesEventType>& aEventTypes,
135
                             PlacesEventCallback& aCallback,
136
                             ErrorResult& rv)
137
0
{
138
0
  uint32_t flags = GetFlagsForEventTypes(aEventTypes);
139
0
140
0
  FlaggedArray<RefPtr<PlacesEventCallback>>* listeners =
141
0
    JSListeners::GetListeners();
142
0
  Flagged<RefPtr<PlacesEventCallback>> pair(flags, &aCallback);
143
0
  listeners->AppendElement(pair);
144
0
}
145
146
void
147
PlacesObservers::AddListener(GlobalObject& aGlobal,
148
                             const nsTArray<PlacesEventType>& aEventTypes,
149
                             PlacesWeakCallbackWrapper& aCallback,
150
                             ErrorResult& rv)
151
0
{
152
0
  uint32_t flags = GetFlagsForEventTypes(aEventTypes);
153
0
154
0
  FlaggedArray<WeakPtr<PlacesWeakCallbackWrapper>>* listeners =
155
0
    WeakJSListeners::GetListeners();
156
0
  WeakPtr<PlacesWeakCallbackWrapper> weakCb(&aCallback);
157
0
  MOZ_ASSERT(weakCb.get());
158
0
  Flagged<WeakPtr<PlacesWeakCallbackWrapper>> flagged(flags, std::move(weakCb));
159
0
  listeners->AppendElement(flagged);
160
0
}
161
162
void
163
PlacesObservers::AddListener(const nsTArray<PlacesEventType>& aEventTypes,
164
                             places::INativePlacesEventCallback* aCallback)
165
0
{
166
0
  uint32_t flags = GetFlagsForEventTypes(aEventTypes);
167
0
168
0
  FlaggedArray<WeakPtr<places::INativePlacesEventCallback>>* listeners =
169
0
    WeakNativeListeners::GetListeners();
170
0
  Flagged<WeakPtr<places::INativePlacesEventCallback>> pair(flags, aCallback);
171
0
  listeners->AppendElement(pair);
172
0
}
173
174
void
175
PlacesObservers::RemoveListener(GlobalObject& aGlobal,
176
                                const nsTArray<PlacesEventType>& aEventTypes,
177
                                PlacesEventCallback& aCallback,
178
                                ErrorResult& rv)
179
0
{
180
0
  uint32_t flags = GetFlagsForEventTypes(aEventTypes);
181
0
  if (gCallingListeners) {
182
0
    FlaggedArray<RefPtr<PlacesEventCallback>>* listeners =
183
0
      JSListeners::GetListenersToRemove();
184
0
    Flagged<RefPtr<PlacesEventCallback>> pair(flags, &aCallback);
185
0
    listeners->AppendElement(pair);
186
0
  } else {
187
0
    RemoveListener(flags, aCallback);
188
0
  }
189
0
}
190
191
void
192
PlacesObservers::RemoveListener(GlobalObject& aGlobal,
193
                                const nsTArray<PlacesEventType>& aEventTypes,
194
                                PlacesWeakCallbackWrapper& aCallback,
195
                                ErrorResult& rv)
196
0
{
197
0
  uint32_t flags = GetFlagsForEventTypes(aEventTypes);
198
0
  if (gCallingListeners) {
199
0
    FlaggedArray<WeakPtr<PlacesWeakCallbackWrapper>>* listeners =
200
0
      WeakJSListeners::GetListenersToRemove();
201
0
    WeakPtr<PlacesWeakCallbackWrapper> weakCb(&aCallback);
202
0
    MOZ_ASSERT(weakCb.get());
203
0
    Flagged<WeakPtr<PlacesWeakCallbackWrapper>> flagged(flags, std::move(weakCb));
204
0
    listeners->AppendElement(flagged);
205
0
  } else {
206
0
    RemoveListener(flags, aCallback);
207
0
  }
208
0
}
209
210
void
211
PlacesObservers::RemoveListener(const nsTArray<PlacesEventType>& aEventTypes,
212
                                places::INativePlacesEventCallback* aCallback)
213
0
{
214
0
  uint32_t flags = GetFlagsForEventTypes(aEventTypes);
215
0
  if (gCallingListeners) {
216
0
    FlaggedArray<WeakPtr<places::INativePlacesEventCallback>>* listeners =
217
0
      WeakNativeListeners::GetListenersToRemove();
218
0
    Flagged<WeakPtr<places::INativePlacesEventCallback>> pair(flags, aCallback);
219
0
    listeners->AppendElement(pair);
220
0
  } else {
221
0
    RemoveListener(flags, aCallback);
222
0
  }
223
0
}
224
225
void
226
PlacesObservers::RemoveListener(uint32_t aFlags,
227
                                PlacesEventCallback& aCallback)
228
0
{
229
0
  FlaggedArray<RefPtr<PlacesEventCallback>>& listeners =
230
0
    *JSListeners::GetListeners();
231
0
  for (uint32_t i = 0; i < listeners.Length(); i++) {
232
0
    Flagged<RefPtr<PlacesEventCallback>>& l = listeners[i];
233
0
    if (!(*l.value == aCallback)) {
234
0
      continue;
235
0
    }
236
0
    if (l.flags == aFlags) {
237
0
      listeners.RemoveElementAt(i);
238
0
      i--;
239
0
    } else {
240
0
      l.flags &= ~aFlags;
241
0
    }
242
0
  }
243
0
}
244
245
void
246
PlacesObservers::RemoveListener(uint32_t aFlags,
247
                                PlacesWeakCallbackWrapper& aCallback)
248
0
{
249
0
  FlaggedArray<WeakPtr<PlacesWeakCallbackWrapper>>& listeners =
250
0
    *WeakJSListeners::GetListeners();
251
0
  for (uint32_t i = 0; i < listeners.Length(); i++) {
252
0
    Flagged<WeakPtr<PlacesWeakCallbackWrapper>>& l = listeners[i];
253
0
    RefPtr<PlacesWeakCallbackWrapper> unwrapped = l.value.get();
254
0
    if (unwrapped != &aCallback) {
255
0
      continue;
256
0
    }
257
0
    if (l.flags == aFlags) {
258
0
      listeners.RemoveElementAt(i);
259
0
      i--;
260
0
    } else {
261
0
      l.flags &= ~aFlags;
262
0
    }
263
0
  }
264
0
}
265
266
void
267
PlacesObservers::RemoveListener(uint32_t aFlags,
268
                                places::INativePlacesEventCallback* aCallback)
269
0
{
270
0
  FlaggedArray<WeakPtr<places::INativePlacesEventCallback>>& listeners =
271
0
    *WeakNativeListeners::GetListeners();
272
0
  for (uint32_t i = 0; i < listeners.Length(); i++) {
273
0
    Flagged<WeakPtr<places::INativePlacesEventCallback>>& l = listeners[i];
274
0
    RefPtr<places::INativePlacesEventCallback> unwrapped = l.value.get();
275
0
    if (unwrapped != aCallback) {
276
0
      continue;
277
0
    }
278
0
    if (l.flags == aFlags) {
279
0
      listeners.RemoveElementAt(i);
280
0
      i--;
281
0
    } else {
282
0
      l.flags &= ~aFlags;
283
0
    }
284
0
  }
285
0
}
286
287
void
288
PlacesObservers::NotifyListeners(GlobalObject& aGlobal,
289
                                 const Sequence<OwningNonNull<PlacesEvent>>& aEvents,
290
                                 ErrorResult& rv)
291
0
{
292
0
  NotifyListeners(aEvents);
293
0
}
294
295
void
296
PlacesObservers::NotifyListeners(const Sequence<OwningNonNull<PlacesEvent>>& aEvents)
297
0
{
298
0
  MOZ_RELEASE_ASSERT(!gCallingListeners);
299
0
  gCallingListeners = true;
300
0
  uint32_t flags = GetFlagsForEvents(aEvents);
301
0
302
0
  CallListeners<RefPtr<PlacesEventCallback>, RefPtr<PlacesEventCallback>>(
303
0
    flags, *JSListeners::GetListeners(), aEvents,
304
0
    [](auto& cb) { return cb; },
305
0
    [&](auto& cb, const auto& events) {
306
0
      cb->Call(aEvents);
307
0
    });
308
0
309
0
  CallListeners<WeakPtr<places::INativePlacesEventCallback>,
310
0
                RefPtr<places::INativePlacesEventCallback>>(
311
0
    flags, *WeakNativeListeners::GetListeners(), aEvents,
312
0
    [](auto& cb) { return cb.get(); },
313
0
    [&](auto& cb, const Sequence<OwningNonNull<PlacesEvent>>& events) {
314
0
      cb->HandlePlacesEvent(events);
315
0
    });
316
0
317
0
  CallListeners<WeakPtr<PlacesWeakCallbackWrapper>,
318
0
                RefPtr<PlacesWeakCallbackWrapper>>(
319
0
    flags, *WeakJSListeners::GetListeners(), aEvents,
320
0
    [](auto& cb) { return cb.get(); },
321
0
    [&](auto& cb, const auto& events) {
322
0
      cb->mCallback->Call(aEvents);
323
0
    });
324
0
325
0
  auto& listenersToRemove = *JSListeners::GetListenersToRemove();
326
0
  if (listenersToRemove.Length() > 0) {
327
0
    for (auto& listener : listenersToRemove) {
328
0
      RemoveListener(listener.flags, *listener.value);
329
0
    }
330
0
  }
331
0
332
0
  auto& weakListenersToRemove = *WeakJSListeners::GetListenersToRemove();
333
0
  if (weakListenersToRemove.Length() > 0) {
334
0
    for (auto& listener : weakListenersToRemove) {
335
0
      RemoveListener(listener.flags, *listener.value.get());
336
0
    }
337
0
  }
338
0
339
0
  auto& nativeListenersToRemove = *WeakNativeListeners::GetListenersToRemove();
340
0
  if (nativeListenersToRemove.Length() > 0) {
341
0
    for (auto& listener : nativeListenersToRemove) {
342
0
      RemoveListener(listener.flags, listener.value.get());
343
0
    }
344
0
  }
345
0
346
0
  gCallingListeners = false;
347
0
}
348
349
} // namespace dom
350
} // namespace mozilla