Bug 1877642 - Disable browser_fullscreen-tab-close-race.js on apple_silicon !debug...
[gecko.git] / accessible / base / NotificationController.h
blob137963f1170927ae0262e0dc26ef721d496376f4
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef mozilla_a11y_NotificationController_h_
7 #define mozilla_a11y_NotificationController_h_
9 #include "EventQueue.h"
11 #include "nsClassHashtable.h"
12 #include "nsCycleCollectionParticipant.h"
13 #include "nsIFrame.h"
14 #include "nsRefreshObservers.h"
15 #include "nsTHashSet.h"
17 #include <utility>
19 #ifdef A11Y_LOG
20 # include "Logging.h"
21 #endif
23 namespace mozilla {
25 class PresShell;
27 namespace a11y {
29 class DocAccessible;
31 /**
32 * Notification interface.
34 class Notification {
35 public:
36 NS_INLINE_DECL_REFCOUNTING(mozilla::a11y::Notification)
38 /**
39 * Process notification.
41 virtual void Process() = 0;
43 protected:
44 Notification() {}
46 /**
47 * Protected destructor, to discourage deletion outside of Release():
49 virtual ~Notification() {}
51 private:
52 Notification(const Notification&);
53 Notification& operator=(const Notification&);
56 /**
57 * Template class for generic notification.
59 * @note Instance is kept as a weak ref, the caller must guarantee it exists
60 * longer than the document accessible owning the notification controller
61 * that this notification is processed by.
63 template <class Class, class... Args>
64 class TNotification : public Notification {
65 public:
66 typedef void (Class::*Callback)(Args*...);
68 TNotification(Class* aInstance, Callback aCallback, Args*... aArgs)
69 : mInstance(aInstance), mCallback(aCallback), mArgs(aArgs...) {}
70 virtual ~TNotification() { mInstance = nullptr; }
72 virtual void Process() override {
73 ProcessHelper(std::index_sequence_for<Args...>{});
76 private:
77 TNotification(const TNotification&);
78 TNotification& operator=(const TNotification&);
80 template <size_t... Indices>
81 void ProcessHelper(std::index_sequence<Indices...>) {
82 (mInstance->*mCallback)(std::get<Indices>(mArgs)...);
85 Class* mInstance;
86 Callback mCallback;
87 std::tuple<RefPtr<Args>...> mArgs;
90 /**
91 * Used to process notifications from core for the document accessible.
93 class NotificationController final : public EventQueue,
94 public nsARefreshObserver {
95 public:
96 NotificationController(DocAccessible* aDocument, PresShell* aPresShell);
98 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override;
99 NS_IMETHOD_(MozExternalRefCountType) Release(void) override;
101 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(NotificationController)
104 * Shutdown the notification controller.
106 void Shutdown();
109 * Add an accessible event into the queue to process it later.
111 void QueueEvent(AccEvent* aEvent) {
112 if (PushEvent(aEvent)) {
113 ScheduleProcessing();
118 * Queue a mutation event to emit if not coalesced away. Returns true if the
119 * event was queued and has not yet been coalesced.
121 bool QueueMutationEvent(AccTreeMutationEvent* aEvent);
124 * Coalesce all queued mutation events.
126 void CoalesceMutationEvents();
129 * Schedule binding the child document to the tree of this document.
131 void ScheduleChildDocBinding(DocAccessible* aDocument);
134 * Schedule the accessible tree update because of rendered text changes.
136 inline void ScheduleTextUpdate(nsIContent* aTextNode) {
137 // Make sure we are not called with a node that is not in the DOM tree or
138 // not visible.
139 MOZ_ASSERT(aTextNode->GetParentNode(), "A text node is not in DOM");
140 MOZ_ASSERT(aTextNode->GetPrimaryFrame(),
141 "A text node doesn't have a frame");
142 MOZ_ASSERT(aTextNode->GetPrimaryFrame()->StyleVisibility()->IsVisible(),
143 "A text node is not visible");
145 mTextArray.AppendElement(aTextNode);
147 ScheduleProcessing();
151 * Pend accessible tree update for content insertion.
153 void ScheduleContentInsertion(LocalAccessible* aContainer,
154 nsTArray<nsCOMPtr<nsIContent>>& aInsertions);
157 * Pend an accessible subtree relocation.
159 void ScheduleRelocation(LocalAccessible* aOwner) {
160 if (!mRelocations.Contains(aOwner)) {
161 // XXX(Bug 1631371) Check if this should use a fallible operation as it
162 // pretended earlier, or change the return type to void.
163 mRelocations.AppendElement(aOwner);
164 ScheduleProcessing();
169 * Start to observe refresh to make notifications and events processing after
170 * layout.
172 void ScheduleProcessing();
175 * Process the generic notification synchronously if there are no pending
176 * layout changes and no notifications are pending or being processed right
177 * now. Otherwise, queue it up to process asynchronously.
179 * @note The caller must guarantee that the given instance still exists when
180 * the notification is processed.
182 template <class Class, class... Args>
183 inline void HandleNotification(
184 Class* aInstance,
185 typename TNotification<Class, Args...>::Callback aMethod,
186 Args*... aArgs) {
187 if (!IsUpdatePending()) {
188 #ifdef A11Y_LOG
189 if (mozilla::a11y::logging::IsEnabled(
190 mozilla::a11y::logging::eNotifications)) {
191 mozilla::a11y::logging::Text("sync notification processing");
193 #endif
194 (aInstance->*aMethod)(aArgs...);
195 return;
198 RefPtr<Notification> notification =
199 new TNotification<Class, Args...>(aInstance, aMethod, aArgs...);
200 if (notification) {
201 // XXX(Bug 1631371) Check if this should use a fallible operation as it
202 // pretended earlier.
203 mNotifications.AppendElement(notification);
204 ScheduleProcessing();
209 * Schedule the generic notification to process asynchronously.
211 * @note The caller must guarantee that the given instance still exists when
212 * the notification is processed.
214 template <class Class>
215 inline void ScheduleNotification(
216 Class* aInstance, typename TNotification<Class>::Callback aMethod) {
217 RefPtr<Notification> notification =
218 new TNotification<Class>(aInstance, aMethod);
219 if (notification) {
220 // XXX(Bug 1631371) Check if this should use a fallible operation as it
221 // pretended earlier.
222 mNotifications.AppendElement(notification);
223 ScheduleProcessing();
227 template <class Class, class Arg>
228 inline void ScheduleNotification(
229 Class* aInstance, typename TNotification<Class, Arg>::Callback aMethod,
230 Arg* aArg) {
231 RefPtr<Notification> notification =
232 new TNotification<Class, Arg>(aInstance, aMethod, aArg);
233 if (notification) {
234 // XXX(Bug 1631371) Check if this should use a fallible operation as it
235 // pretended earlier.
236 mNotifications.AppendElement(notification);
237 ScheduleProcessing();
241 #ifdef DEBUG
242 bool IsUpdating() const {
243 return mObservingState == eRefreshProcessingForUpdate;
245 #endif
247 protected:
248 virtual ~NotificationController();
250 nsCycleCollectingAutoRefCnt mRefCnt;
251 NS_DECL_OWNINGTHREAD
254 * Return true if the accessible tree state update is pending.
256 bool IsUpdatePending();
259 * Return true if we should wait for processing from the parent before we can
260 * process our own queue.
262 bool WaitingForParent();
264 private:
265 NotificationController(const NotificationController&);
266 NotificationController& operator=(const NotificationController&);
268 // nsARefreshObserver
269 virtual void WillRefresh(mozilla::TimeStamp aTime) override;
271 private:
273 * Remove a specific hide event if it should not be propagated.
275 void CoalesceHideEvent(AccHideEvent* aHideEvent);
278 * get rid of a mutation event that is no longer necessary.
280 void DropMutationEvent(AccTreeMutationEvent* aEvent);
283 * Fire all necessary mutation events.
285 void ProcessMutationEvents();
288 * Indicates whether we're waiting on an event queue processing from our
289 * notification controller to flush events.
291 enum eObservingState {
292 eNotObservingRefresh,
293 eRefreshObserving,
294 eRefreshProcessing,
295 eRefreshProcessingForUpdate
297 eObservingState mObservingState;
300 * The presshell of the document accessible.
302 PresShell* mPresShell;
305 * Child documents that needs to be bound to the tree.
307 nsTArray<RefPtr<DocAccessible>> mHangingChildDocuments;
310 * Pending accessible tree update notifications for content insertions.
312 nsClassHashtable<nsRefPtrHashKey<LocalAccessible>,
313 nsTArray<nsCOMPtr<nsIContent>>>
314 mContentInsertions;
316 template <class T>
317 class nsCOMPtrHashKey : public PLDHashEntryHdr {
318 public:
319 typedef T* KeyType;
320 typedef const T* KeyTypePointer;
322 explicit nsCOMPtrHashKey(const T* aKey) : mKey(const_cast<T*>(aKey)) {}
323 nsCOMPtrHashKey(nsCOMPtrHashKey<T>&& aOther)
324 : PLDHashEntryHdr(std::move(aOther)), mKey(std::move(aOther.mKey)) {}
325 ~nsCOMPtrHashKey() {}
327 KeyType GetKey() const { return mKey; }
328 bool KeyEquals(KeyTypePointer aKey) const { return aKey == mKey; }
330 static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
331 static PLDHashNumber HashKey(KeyTypePointer aKey) {
332 return NS_PTR_TO_INT32(aKey) >> 2;
335 enum { ALLOW_MEMMOVE = true };
337 protected:
338 nsCOMPtr<T> mKey;
342 * Pending accessible tree update notifications for rendered text changes.
343 * When there are a lot of nearby text insertions (e.g. during a reflow), it
344 * is much more performant to process them in order because we then benefit
345 * from the layout line cursor. Therefore, we use an array here.
347 nsTArray<nsCOMPtr<nsIContent>> mTextArray;
350 * Other notifications like DOM events. Don't make this an AutoTArray; we
351 * use SwapElements() on it.
353 nsTArray<RefPtr<Notification>> mNotifications;
356 * Holds all scheduled relocations.
358 nsTArray<RefPtr<LocalAccessible>> mRelocations;
361 * A list of all mutation events we may want to emit. Ordered from the first
362 * event that should be emitted to the last one to emit.
364 RefPtr<AccTreeMutationEvent> mFirstMutationEvent;
365 RefPtr<AccTreeMutationEvent> mLastMutationEvent;
368 * A class to map an accessible and event type to an event.
370 class EventMap {
371 public:
372 enum EventType {
373 ShowEvent = 0x0,
374 HideEvent = 0x1,
375 ReorderEvent = 0x2,
378 void PutEvent(AccTreeMutationEvent* aEvent);
379 AccTreeMutationEvent* GetEvent(LocalAccessible* aTarget, EventType aType);
380 void RemoveEvent(AccTreeMutationEvent* aEvent);
381 void Clear() { mTable.Clear(); }
383 private:
384 EventType GetEventType(AccTreeMutationEvent* aEvent);
386 nsRefPtrHashtable<nsUint64HashKey, AccTreeMutationEvent> mTable;
389 EventMap mMutationMap;
390 uint32_t mEventGeneration;
393 } // namespace a11y
394 } // namespace mozilla
396 #endif // mozilla_a11y_NotificationController_h_