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