Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 "nsCycleCollectionParticipant.h"
12 #include "nsRefreshDriver.h"
14 #ifdef A11Y_LOG
15 #include "Logging.h"
16 #endif
18 namespace mozilla {
19 namespace a11y {
21 class DocAccessible;
23 /**
24 * Notification interface.
25 */
26 class Notification
27 {
28 public:
29 NS_INLINE_DECL_REFCOUNTING(Notification)
31 /**
32 * Process notification.
33 */
34 virtual void Process() = 0;
36 protected:
37 Notification() { }
39 /**
40 * Protected destructor, to discourage deletion outside of Release():
41 */
42 virtual ~Notification() { }
44 private:
45 Notification(const Notification&);
46 Notification& operator = (const Notification&);
47 };
50 /**
51 * Template class for generic notification.
52 *
53 * @note Instance is kept as a weak ref, the caller must guarantee it exists
54 * longer than the document accessible owning the notification controller
55 * that this notification is processed by.
56 */
57 template<class Class, class Arg>
58 class TNotification : public Notification
59 {
60 public:
61 typedef void (Class::*Callback)(Arg*);
63 TNotification(Class* aInstance, Callback aCallback, Arg* aArg) :
64 mInstance(aInstance), mCallback(aCallback), mArg(aArg) { }
65 virtual ~TNotification() { mInstance = nullptr; }
67 virtual void Process()
68 {
69 (mInstance->*mCallback)(mArg);
71 mInstance = nullptr;
72 mCallback = nullptr;
73 mArg = nullptr;
74 }
76 private:
77 TNotification(const TNotification&);
78 TNotification& operator = (const TNotification&);
80 Class* mInstance;
81 Callback mCallback;
82 nsRefPtr<Arg> mArg;
83 };
85 /**
86 * Used to process notifications from core for the document accessible.
87 */
88 class NotificationController : public EventQueue,
89 public nsARefreshObserver
90 {
91 public:
92 NotificationController(DocAccessible* aDocument, nsIPresShell* aPresShell);
93 virtual ~NotificationController();
95 NS_IMETHOD_(MozExternalRefCountType) AddRef(void);
96 NS_IMETHOD_(MozExternalRefCountType) Release(void);
98 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(NotificationController)
100 /**
101 * Shutdown the notification controller.
102 */
103 void Shutdown();
105 /**
106 * Put an accessible event into the queue to process it later.
107 */
108 void QueueEvent(AccEvent* aEvent)
109 {
110 if (PushEvent(aEvent))
111 ScheduleProcessing();
112 }
114 /**
115 * Schedule binding the child document to the tree of this document.
116 */
117 void ScheduleChildDocBinding(DocAccessible* aDocument);
119 /**
120 * Schedule the accessible tree update because of rendered text changes.
121 */
122 inline void ScheduleTextUpdate(nsIContent* aTextNode)
123 {
124 if (mTextHash.PutEntry(aTextNode))
125 ScheduleProcessing();
126 }
128 /**
129 * Pend accessible tree update for content insertion.
130 */
131 void ScheduleContentInsertion(Accessible* aContainer,
132 nsIContent* aStartChildNode,
133 nsIContent* aEndChildNode);
135 /**
136 * Process the generic notification synchronously if there are no pending
137 * layout changes and no notifications are pending or being processed right
138 * now. Otherwise, queue it up to process asynchronously.
139 *
140 * @note The caller must guarantee that the given instance still exists when
141 * the notification is processed.
142 */
143 template<class Class, class Arg>
144 inline void HandleNotification(Class* aInstance,
145 typename TNotification<Class, Arg>::Callback aMethod,
146 Arg* aArg)
147 {
148 if (!IsUpdatePending()) {
149 #ifdef A11Y_LOG
150 if (mozilla::a11y::logging::IsEnabled(mozilla::a11y::logging::eNotifications))
151 mozilla::a11y::logging::Text("sync notification processing");
152 #endif
153 (aInstance->*aMethod)(aArg);
154 return;
155 }
157 nsRefPtr<Notification> notification =
158 new TNotification<Class, Arg>(aInstance, aMethod, aArg);
159 if (notification && mNotifications.AppendElement(notification))
160 ScheduleProcessing();
161 }
163 /**
164 * Schedule the generic notification to process asynchronously.
165 *
166 * @note The caller must guarantee that the given instance still exists when
167 * the notification is processed.
168 */
169 template<class Class, class Arg>
170 inline void ScheduleNotification(Class* aInstance,
171 typename TNotification<Class, Arg>::Callback aMethod,
172 Arg* aArg)
173 {
174 nsRefPtr<Notification> notification =
175 new TNotification<Class, Arg>(aInstance, aMethod, aArg);
176 if (notification && mNotifications.AppendElement(notification))
177 ScheduleProcessing();
178 }
180 #ifdef DEBUG
181 bool IsUpdating() const
182 { return mObservingState == eRefreshProcessingForUpdate; }
183 #endif
185 protected:
186 nsCycleCollectingAutoRefCnt mRefCnt;
187 NS_DECL_OWNINGTHREAD
189 /**
190 * Start to observe refresh to make notifications and events processing after
191 * layout.
192 */
193 void ScheduleProcessing();
195 /**
196 * Return true if the accessible tree state update is pending.
197 */
198 bool IsUpdatePending();
200 private:
201 NotificationController(const NotificationController&);
202 NotificationController& operator = (const NotificationController&);
204 // nsARefreshObserver
205 virtual void WillRefresh(mozilla::TimeStamp aTime);
207 private:
208 /**
209 * Indicates whether we're waiting on an event queue processing from our
210 * notification controller to flush events.
211 */
212 enum eObservingState {
213 eNotObservingRefresh,
214 eRefreshObserving,
215 eRefreshProcessing,
216 eRefreshProcessingForUpdate
217 };
218 eObservingState mObservingState;
220 /**
221 * The presshell of the document accessible.
222 */
223 nsIPresShell* mPresShell;
225 /**
226 * Child documents that needs to be bound to the tree.
227 */
228 nsTArray<nsRefPtr<DocAccessible> > mHangingChildDocuments;
230 /**
231 * Storage for content inserted notification information.
232 */
233 class ContentInsertion
234 {
235 public:
236 ContentInsertion(DocAccessible* aDocument, Accessible* aContainer);
237 virtual ~ContentInsertion() { mDocument = nullptr; }
239 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(ContentInsertion)
240 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ContentInsertion)
242 bool InitChildList(nsIContent* aStartChildNode, nsIContent* aEndChildNode);
243 void Process();
245 private:
246 ContentInsertion();
247 ContentInsertion(const ContentInsertion&);
248 ContentInsertion& operator = (const ContentInsertion&);
250 // The document used to process content insertion, matched to document of
251 // the notification controller that this notification belongs to, therefore
252 // it's ok to keep it as weak ref.
253 DocAccessible* mDocument;
255 // The container accessible that content insertion occurs within.
256 nsRefPtr<Accessible> mContainer;
258 // Array of inserted contents.
259 nsTArray<nsCOMPtr<nsIContent> > mInsertedContent;
260 };
262 /**
263 * A pending accessible tree update notifications for content insertions.
264 * Don't make this an nsAutoTArray; we use SwapElements() on it.
265 */
266 nsTArray<nsRefPtr<ContentInsertion> > mContentInsertions;
268 template<class T>
269 class nsCOMPtrHashKey : public PLDHashEntryHdr
270 {
271 public:
272 typedef T* KeyType;
273 typedef const T* KeyTypePointer;
275 nsCOMPtrHashKey(const T* aKey) : mKey(const_cast<T*>(aKey)) {}
276 nsCOMPtrHashKey(const nsPtrHashKey<T> &aToCopy) : mKey(aToCopy.mKey) {}
277 ~nsCOMPtrHashKey() { }
279 KeyType GetKey() const { return mKey; }
280 bool KeyEquals(KeyTypePointer aKey) const { return aKey == mKey; }
282 static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
283 static PLDHashNumber HashKey(KeyTypePointer aKey)
284 { return NS_PTR_TO_INT32(aKey) >> 2; }
286 enum { ALLOW_MEMMOVE = true };
288 protected:
289 nsCOMPtr<T> mKey;
290 };
292 /**
293 * A pending accessible tree update notifications for rendered text changes.
294 */
295 nsTHashtable<nsCOMPtrHashKey<nsIContent> > mTextHash;
297 /**
298 * Update the accessible tree for pending rendered text change notifications.
299 */
300 static PLDHashOperator TextEnumerator(nsCOMPtrHashKey<nsIContent>* aEntry,
301 void* aUserArg);
303 /**
304 * Other notifications like DOM events. Don't make this an nsAutoTArray; we
305 * use SwapElements() on it.
306 */
307 nsTArray<nsRefPtr<Notification> > mNotifications;
308 };
310 } // namespace a11y
311 } // namespace mozilla
313 #endif // mozilla_a11y_NotificationController_h_