LCOV - code coverage report
Current view: top level - accessible/base - NotificationController.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 73 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 52 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       5             : 
       6             : #ifndef mozilla_a11y_NotificationController_h_
       7             : #define mozilla_a11y_NotificationController_h_
       8             : 
       9             : #include "EventQueue.h"
      10             : #include "EventTree.h"
      11             : 
      12             : #include "mozilla/IndexSequence.h"
      13             : #include "mozilla/Tuple.h"
      14             : #include "nsCycleCollectionParticipant.h"
      15             : #include "nsRefreshDriver.h"
      16             : 
      17             : #ifdef A11Y_LOG
      18             : #include "Logging.h"
      19             : #endif
      20             : 
      21             : namespace mozilla {
      22             : namespace a11y {
      23             : 
      24             : class DocAccessible;
      25             : 
      26             : /**
      27             :  * Notification interface.
      28             :  */
      29             : class Notification
      30             : {
      31             : public:
      32           0 :   NS_INLINE_DECL_REFCOUNTING(mozilla::a11y::Notification)
      33             : 
      34             :   /**
      35             :    * Process notification.
      36             :    */
      37             :   virtual void Process() = 0;
      38             : 
      39             : protected:
      40           0 :   Notification() { }
      41             : 
      42             :   /**
      43             :    * Protected destructor, to discourage deletion outside of Release():
      44             :    */
      45           0 :   virtual ~Notification() { }
      46             : 
      47             : private:
      48             :   Notification(const Notification&);
      49             :   Notification& operator = (const Notification&);
      50             : };
      51             : 
      52             : 
      53             : /**
      54             :  * Template class for generic notification.
      55             :  *
      56             :  * @note  Instance is kept as a weak ref, the caller must guarantee it exists
      57             :  *        longer than the document accessible owning the notification controller
      58             :  *        that this notification is processed by.
      59             :  */
      60             : template<class Class, class ... Args>
      61             : class TNotification : public Notification
      62             : {
      63             : public:
      64             :   typedef void (Class::*Callback)(Args* ...);
      65             : 
      66           0 :   TNotification(Class* aInstance, Callback aCallback, Args* ... aArgs) :
      67           0 :     mInstance(aInstance), mCallback(aCallback), mArgs(aArgs...) { }
      68           0 :   virtual ~TNotification() { mInstance = nullptr; }
      69             : 
      70           0 :   virtual void Process() override
      71           0 :     { ProcessHelper(typename IndexSequenceFor<Args...>::Type()); }
      72             : 
      73             : private:
      74             :   TNotification(const TNotification&);
      75             :   TNotification& operator = (const TNotification&);
      76             : 
      77             :   template <size_t... Indices>
      78           0 :     void ProcessHelper(IndexSequence<Indices...>)
      79             :   {
      80           0 :      (mInstance->*mCallback)(Get<Indices>(mArgs)...);
      81           0 :   }
      82             : 
      83             :   Class* mInstance;
      84             :   Callback mCallback;
      85             :   Tuple<RefPtr<Args> ...> mArgs;
      86             : };
      87             : 
      88             : /**
      89             :  * Used to process notifications from core for the document accessible.
      90             :  */
      91             : class NotificationController final : public EventQueue,
      92             :                                      public nsARefreshObserver
      93             : {
      94             : public:
      95             :   NotificationController(DocAccessible* aDocument, nsIPresShell* aPresShell);
      96             : 
      97             :   NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override;
      98             :   NS_IMETHOD_(MozExternalRefCountType) Release(void) override;
      99             : 
     100           0 :   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(NotificationController)
     101             : 
     102             :   /**
     103             :    * Shutdown the notification controller.
     104             :    */
     105             :   void Shutdown();
     106             : 
     107             :   /**
     108             :    * Add an accessible event into the queue to process it later.
     109             :    */
     110           0 :   void QueueEvent(AccEvent* aEvent)
     111             :   {
     112           0 :     if (PushEvent(aEvent)) {
     113           0 :       ScheduleProcessing();
     114             :     }
     115           0 :   }
     116             : 
     117             :   /**
     118             :    * Creates and adds a name change event into the queue for a container of
     119             :    * the given accessible, if the accessible is a part of name computation of
     120             :    * the container.
     121             :    */
     122           0 :   void QueueNameChange(Accessible* aChangeTarget)
     123             :   {
     124           0 :     if (PushNameChange(aChangeTarget)) {
     125           0 :       ScheduleProcessing();
     126             :     }
     127           0 :   }
     128             : 
     129             :   /**
     130             :    * Returns existing event tree for the given the accessible or creates one if
     131             :    * it doesn't exists yet.
     132             :    */
     133             :   EventTree* QueueMutation(Accessible* aContainer);
     134             : 
     135             :   class MoveGuard final {
     136             :   public:
     137           0 :     explicit MoveGuard(NotificationController* aController) :
     138           0 :       mController(aController)
     139             :     {
     140             : #ifdef DEBUG
     141           0 :       MOZ_ASSERT(!mController->mMoveGuardOnStack,
     142             :                  "Move guard is on stack already!");
     143           0 :       mController->mMoveGuardOnStack = true;
     144             : #endif
     145           0 :     }
     146           0 :     ~MoveGuard() {
     147             : #ifdef DEBUG
     148           0 :       MOZ_ASSERT(mController->mMoveGuardOnStack, "No move guard on stack!");
     149           0 :       mController->mMoveGuardOnStack = false;
     150             : #endif
     151           0 :       mController->mPrecedingEvents.Clear();
     152           0 :     }
     153             : 
     154             :   private:
     155             :     NotificationController* mController;
     156             :   };
     157             : 
     158             : #ifdef A11Y_LOG
     159           0 :   const EventTree& RootEventTree() const { return mEventTree; };
     160             : #endif
     161             : 
     162             :   /**
     163             :    * Queue a mutation event to emit if not coalesced away.  Returns true if the
     164             :    * event was queued and has not yet been coalesced.
     165             :    */
     166             :   bool QueueMutationEvent(AccTreeMutationEvent* aEvent);
     167             : 
     168             :   /**
     169             :    * Coalesce all queued mutation events.
     170             :    */
     171             :   void CoalesceMutationEvents();
     172             : 
     173             :   /**
     174             :    * Schedule binding the child document to the tree of this document.
     175             :    */
     176             :   void ScheduleChildDocBinding(DocAccessible* aDocument);
     177             : 
     178             :   /**
     179             :    * Schedule the accessible tree update because of rendered text changes.
     180             :    */
     181           0 :   inline void ScheduleTextUpdate(nsIContent* aTextNode)
     182             :   {
     183             :     // Make sure we are not called with a node that is not in the DOM tree or
     184             :     // not visible.
     185           0 :     MOZ_ASSERT(aTextNode->GetParentNode(), "A text node is not in DOM");
     186           0 :     MOZ_ASSERT(aTextNode->GetPrimaryFrame(), "A text node doesn't have a frame");
     187           0 :     MOZ_ASSERT(aTextNode->GetPrimaryFrame()->StyleVisibility()->IsVisible(),
     188             :                "A text node is not visible");
     189             : 
     190           0 :     mTextHash.PutEntry(aTextNode);
     191           0 :     ScheduleProcessing();
     192           0 :   }
     193             : 
     194             :   /**
     195             :    * Pend accessible tree update for content insertion.
     196             :    */
     197             :   void ScheduleContentInsertion(Accessible* aContainer,
     198             :                                 nsIContent* aStartChildNode,
     199             :                                 nsIContent* aEndChildNode);
     200             : 
     201             :   /**
     202             :    * Pend an accessible subtree relocation.
     203             :    */
     204           0 :   void ScheduleRelocation(Accessible* aOwner)
     205             :   {
     206           0 :     if (!mRelocations.Contains(aOwner) && mRelocations.AppendElement(aOwner)) {
     207           0 :       ScheduleProcessing();
     208             :     }
     209           0 :   }
     210             : 
     211             :   /**
     212             :    * Start to observe refresh to make notifications and events processing after
     213             :    * layout.
     214             :    */
     215             :   void ScheduleProcessing();
     216             : 
     217             :   /**
     218             :    * Process the generic notification synchronously if there are no pending
     219             :    * layout changes and no notifications are pending or being processed right
     220             :    * now. Otherwise, queue it up to process asynchronously.
     221             :    *
     222             :    * @note  The caller must guarantee that the given instance still exists when
     223             :    *        the notification is processed.
     224             :    */
     225             :   template<class Class, class Arg>
     226           0 :   inline void HandleNotification(Class* aInstance,
     227             :                                  typename TNotification<Class, Arg>::Callback aMethod,
     228             :                                  Arg* aArg)
     229             :   {
     230           0 :     if (!IsUpdatePending()) {
     231             : #ifdef A11Y_LOG
     232           0 :       if (mozilla::a11y::logging::IsEnabled(mozilla::a11y::logging::eNotifications))
     233           0 :         mozilla::a11y::logging::Text("sync notification processing");
     234             : #endif
     235           0 :       (aInstance->*aMethod)(aArg);
     236           0 :       return;
     237             :     }
     238             : 
     239             :     RefPtr<Notification> notification =
     240           0 :       new TNotification<Class, Arg>(aInstance, aMethod, aArg);
     241           0 :     if (notification && mNotifications.AppendElement(notification))
     242           0 :       ScheduleProcessing();
     243             :   }
     244             : 
     245             :   /**
     246             :    * Schedule the generic notification to process asynchronously.
     247             :    *
     248             :    * @note  The caller must guarantee that the given instance still exists when
     249             :    *        the notification is processed.
     250             :    */
     251             :   template<class Class>
     252             :   inline void ScheduleNotification(Class* aInstance,
     253             :                                    typename TNotification<Class>::Callback aMethod)
     254             :   {
     255             :     RefPtr<Notification> notification =
     256             :       new TNotification<Class>(aInstance, aMethod);
     257             :     if (notification && mNotifications.AppendElement(notification))
     258             :       ScheduleProcessing();
     259             :   }
     260             : 
     261             : #ifdef DEBUG
     262           0 :   bool IsUpdating() const
     263           0 :     { return mObservingState == eRefreshProcessingForUpdate; }
     264             : #endif
     265             : 
     266             : protected:
     267             :   virtual ~NotificationController();
     268             : 
     269             :   nsCycleCollectingAutoRefCnt mRefCnt;
     270             :   NS_DECL_OWNINGTHREAD
     271             : 
     272             :   /**
     273             :    * Return true if the accessible tree state update is pending.
     274             :    */
     275             :   bool IsUpdatePending();
     276             : 
     277             : private:
     278             :   NotificationController(const NotificationController&);
     279             :   NotificationController& operator = (const NotificationController&);
     280             : 
     281             :   // nsARefreshObserver
     282             :   virtual void WillRefresh(mozilla::TimeStamp aTime) override;
     283             : 
     284             :   /**
     285             :    * Set and returns a hide event, paired with a show event, for the move.
     286             :    */
     287           0 :   void WithdrawPrecedingEvents(nsTArray<RefPtr<AccHideEvent>>* aEvs)
     288             :   {
     289           0 :     if (mPrecedingEvents.Length() > 0) {
     290           0 :       aEvs->AppendElements(mozilla::Move(mPrecedingEvents));
     291             :     }
     292           0 :   }
     293           0 :   void StorePrecedingEvent(AccHideEvent* aEv)
     294             :   {
     295           0 :     MOZ_ASSERT(mMoveGuardOnStack, "No move guard on stack!");
     296           0 :     mPrecedingEvents.AppendElement(aEv);
     297           0 :   }
     298           0 :   void StorePrecedingEvents(nsTArray<RefPtr<AccHideEvent>>&& aEvs)
     299             :   {
     300           0 :     MOZ_ASSERT(mMoveGuardOnStack, "No move guard on stack!");
     301           0 :     mPrecedingEvents.InsertElementsAt(0, aEvs);
     302           0 :   }
     303             : 
     304             : private:
     305             :   /**
     306             :    * get rid of a mutation event that is no longer necessary.
     307             :    */
     308             :   void DropMutationEvent(AccTreeMutationEvent* aEvent);
     309             : 
     310             :   /**
     311             :    * Fire all necessary mutation events.
     312             :    */
     313             :   void ProcessMutationEvents();
     314             : 
     315             :   /**
     316             :    * Indicates whether we're waiting on an event queue processing from our
     317             :    * notification controller to flush events.
     318             :    */
     319             :   enum eObservingState {
     320             :     eNotObservingRefresh,
     321             :     eRefreshObserving,
     322             :     eRefreshProcessing,
     323             :     eRefreshProcessingForUpdate
     324             :   };
     325             :   eObservingState mObservingState;
     326             : 
     327             :   /**
     328             :    * The presshell of the document accessible.
     329             :    */
     330             :   nsIPresShell* mPresShell;
     331             : 
     332             :   /**
     333             :    * Child documents that needs to be bound to the tree.
     334             :    */
     335             :   nsTArray<RefPtr<DocAccessible> > mHangingChildDocuments;
     336             : 
     337             :   /**
     338             :    * Pending accessible tree update notifications for content insertions.
     339             :    */
     340             :   nsClassHashtable<nsRefPtrHashKey<Accessible>,
     341             :                    nsTArray<nsCOMPtr<nsIContent>>> mContentInsertions;
     342             : 
     343             :   template<class T>
     344             :   class nsCOMPtrHashKey : public PLDHashEntryHdr
     345             :   {
     346             :   public:
     347             :     typedef T* KeyType;
     348             :     typedef const T* KeyTypePointer;
     349             : 
     350           0 :     explicit nsCOMPtrHashKey(const T* aKey) : mKey(const_cast<T*>(aKey)) {}
     351             :     explicit nsCOMPtrHashKey(const nsPtrHashKey<T> &aToCopy) : mKey(aToCopy.mKey) {}
     352           0 :     ~nsCOMPtrHashKey() { }
     353             : 
     354           0 :     KeyType GetKey() const { return mKey; }
     355           0 :     bool KeyEquals(KeyTypePointer aKey) const { return aKey == mKey; }
     356             : 
     357           0 :     static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
     358           0 :     static PLDHashNumber HashKey(KeyTypePointer aKey)
     359           0 :       { return NS_PTR_TO_INT32(aKey) >> 2; }
     360             : 
     361             :     enum { ALLOW_MEMMOVE = true };
     362             : 
     363             :    protected:
     364             :      nsCOMPtr<T> mKey;
     365             :   };
     366             : 
     367             :   /**
     368             :    * Pending accessible tree update notifications for rendered text changes.
     369             :    */
     370             :   nsTHashtable<nsCOMPtrHashKey<nsIContent> > mTextHash;
     371             : 
     372             :   /**
     373             :    * Other notifications like DOM events. Don't make this an AutoTArray; we
     374             :    * use SwapElements() on it.
     375             :    */
     376             :   nsTArray<RefPtr<Notification> > mNotifications;
     377             : 
     378             :   /**
     379             :    * Holds all scheduled relocations.
     380             :    */
     381             :   nsTArray<RefPtr<Accessible> > mRelocations;
     382             : 
     383             :   /**
     384             :    * Holds all mutation events.
     385             :    */
     386             :   EventTree mEventTree;
     387             : 
     388             :   /**
     389             :    * A temporary collection of hide events that should be fired before related
     390             :    * show event. Used by EventTree.
     391             :    */
     392             :   nsTArray<RefPtr<AccHideEvent>> mPrecedingEvents;
     393             : 
     394             : #ifdef DEBUG
     395             :   bool mMoveGuardOnStack;
     396             : #endif
     397             : 
     398             :   friend class MoveGuard;
     399             :   friend class EventTree;
     400             : 
     401             :   /**
     402             :    * A list of all mutation events we may want to emit.  Ordered from the first
     403             :    * event that should be emitted to the last one to emit.
     404             :    */
     405             :   RefPtr<AccTreeMutationEvent> mFirstMutationEvent;
     406             :   RefPtr<AccTreeMutationEvent> mLastMutationEvent;
     407             : 
     408             :   /**
     409             :    * A class to map an accessible and event type to an event.
     410             :    */
     411           0 :   class EventMap
     412             :   {
     413             :   public:
     414             :     enum EventType
     415             :     {
     416             :       ShowEvent = 0x0,
     417             :       HideEvent = 0x1,
     418             :       ReorderEvent = 0x2,
     419             :     };
     420             : 
     421             :     void PutEvent(AccTreeMutationEvent* aEvent);
     422             :     AccTreeMutationEvent* GetEvent(Accessible* aTarget, EventType aType);
     423             :     void RemoveEvent(AccTreeMutationEvent* aEvent);
     424             :     void Clear() { mTable.Clear(); }
     425             : 
     426             :   private:
     427             :     EventType GetEventType(AccTreeMutationEvent* aEvent);
     428             : 
     429             :     nsRefPtrHashtable<nsUint64HashKey, AccTreeMutationEvent> mTable;
     430             :   };
     431             : 
     432             :   EventMap mMutationMap;
     433             :   uint32_t mEventGeneration;
     434             : };
     435             : 
     436             : } // namespace a11y
     437             : } // namespace mozilla
     438             : 
     439             : #endif // mozilla_a11y_NotificationController_h_

Generated by: LCOV version 1.13