accessible/src/base/NotificationController.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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_

mercurial