accessible/src/base/NotificationController.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/accessible/src/base/NotificationController.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,313 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#ifndef mozilla_a11y_NotificationController_h_
    1.10 +#define mozilla_a11y_NotificationController_h_
    1.11 +
    1.12 +#include "EventQueue.h"
    1.13 +
    1.14 +#include "nsCycleCollectionParticipant.h"
    1.15 +#include "nsRefreshDriver.h"
    1.16 +
    1.17 +#ifdef A11Y_LOG
    1.18 +#include "Logging.h"
    1.19 +#endif
    1.20 +
    1.21 +namespace mozilla {
    1.22 +namespace a11y {
    1.23 +
    1.24 +class DocAccessible;
    1.25 +
    1.26 +/**
    1.27 + * Notification interface.
    1.28 + */
    1.29 +class Notification
    1.30 +{
    1.31 +public:
    1.32 +  NS_INLINE_DECL_REFCOUNTING(Notification)
    1.33 +
    1.34 +  /**
    1.35 +   * Process notification.
    1.36 +   */
    1.37 +  virtual void Process() = 0;
    1.38 +
    1.39 +protected:
    1.40 +  Notification() { }
    1.41 +
    1.42 +  /**
    1.43 +   * Protected destructor, to discourage deletion outside of Release():
    1.44 +   */
    1.45 +  virtual ~Notification() { }
    1.46 +
    1.47 +private:
    1.48 +  Notification(const Notification&);
    1.49 +  Notification& operator = (const Notification&);
    1.50 +};
    1.51 +
    1.52 +
    1.53 +/**
    1.54 + * Template class for generic notification.
    1.55 + *
    1.56 + * @note  Instance is kept as a weak ref, the caller must guarantee it exists
    1.57 + *        longer than the document accessible owning the notification controller
    1.58 + *        that this notification is processed by.
    1.59 + */
    1.60 +template<class Class, class Arg>
    1.61 +class TNotification : public Notification
    1.62 +{
    1.63 +public:
    1.64 +  typedef void (Class::*Callback)(Arg*);
    1.65 +
    1.66 +  TNotification(Class* aInstance, Callback aCallback, Arg* aArg) :
    1.67 +    mInstance(aInstance), mCallback(aCallback), mArg(aArg) { }
    1.68 +  virtual ~TNotification() { mInstance = nullptr; }
    1.69 +
    1.70 +  virtual void Process()
    1.71 +  {
    1.72 +    (mInstance->*mCallback)(mArg);
    1.73 +
    1.74 +    mInstance = nullptr;
    1.75 +    mCallback = nullptr;
    1.76 +    mArg = nullptr;
    1.77 +  }
    1.78 +
    1.79 +private:
    1.80 +  TNotification(const TNotification&);
    1.81 +  TNotification& operator = (const TNotification&);
    1.82 +
    1.83 +  Class* mInstance;
    1.84 +  Callback mCallback;
    1.85 +  nsRefPtr<Arg> mArg;
    1.86 +};
    1.87 +
    1.88 +/**
    1.89 + * Used to process notifications from core for the document accessible.
    1.90 + */
    1.91 +class NotificationController : public EventQueue,
    1.92 +                               public nsARefreshObserver
    1.93 +{
    1.94 +public:
    1.95 +  NotificationController(DocAccessible* aDocument, nsIPresShell* aPresShell);
    1.96 +  virtual ~NotificationController();
    1.97 +
    1.98 +  NS_IMETHOD_(MozExternalRefCountType) AddRef(void);
    1.99 +  NS_IMETHOD_(MozExternalRefCountType) Release(void);
   1.100 +
   1.101 +  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(NotificationController)
   1.102 +
   1.103 +  /**
   1.104 +   * Shutdown the notification controller.
   1.105 +   */
   1.106 +  void Shutdown();
   1.107 +
   1.108 +  /**
   1.109 +   * Put an accessible event into the queue to process it later.
   1.110 +   */
   1.111 +  void QueueEvent(AccEvent* aEvent)
   1.112 +  {
   1.113 +    if (PushEvent(aEvent))
   1.114 +      ScheduleProcessing();
   1.115 +  }
   1.116 +
   1.117 +  /**
   1.118 +   * Schedule binding the child document to the tree of this document.
   1.119 +   */
   1.120 +  void ScheduleChildDocBinding(DocAccessible* aDocument);
   1.121 +
   1.122 +  /**
   1.123 +   * Schedule the accessible tree update because of rendered text changes.
   1.124 +   */
   1.125 +  inline void ScheduleTextUpdate(nsIContent* aTextNode)
   1.126 +  {
   1.127 +    if (mTextHash.PutEntry(aTextNode))
   1.128 +      ScheduleProcessing();
   1.129 +  }
   1.130 +
   1.131 +  /**
   1.132 +   * Pend accessible tree update for content insertion.
   1.133 +   */
   1.134 +  void ScheduleContentInsertion(Accessible* aContainer,
   1.135 +                                nsIContent* aStartChildNode,
   1.136 +                                nsIContent* aEndChildNode);
   1.137 +
   1.138 +  /**
   1.139 +   * Process the generic notification synchronously if there are no pending
   1.140 +   * layout changes and no notifications are pending or being processed right
   1.141 +   * now. Otherwise, queue it up to process asynchronously.
   1.142 +   *
   1.143 +   * @note  The caller must guarantee that the given instance still exists when
   1.144 +   *        the notification is processed.
   1.145 +   */
   1.146 +  template<class Class, class Arg>
   1.147 +  inline void HandleNotification(Class* aInstance,
   1.148 +                                 typename TNotification<Class, Arg>::Callback aMethod,
   1.149 +                                 Arg* aArg)
   1.150 +  {
   1.151 +    if (!IsUpdatePending()) {
   1.152 +#ifdef A11Y_LOG
   1.153 +      if (mozilla::a11y::logging::IsEnabled(mozilla::a11y::logging::eNotifications))
   1.154 +        mozilla::a11y::logging::Text("sync notification processing");
   1.155 +#endif
   1.156 +      (aInstance->*aMethod)(aArg);
   1.157 +      return;
   1.158 +    }
   1.159 +
   1.160 +    nsRefPtr<Notification> notification =
   1.161 +      new TNotification<Class, Arg>(aInstance, aMethod, aArg);
   1.162 +    if (notification && mNotifications.AppendElement(notification))
   1.163 +      ScheduleProcessing();
   1.164 +  }
   1.165 +
   1.166 +  /**
   1.167 +   * Schedule the generic notification to process asynchronously.
   1.168 +   *
   1.169 +   * @note  The caller must guarantee that the given instance still exists when
   1.170 +   *        the notification is processed.
   1.171 +   */
   1.172 +  template<class Class, class Arg>
   1.173 +  inline void ScheduleNotification(Class* aInstance,
   1.174 +                                   typename TNotification<Class, Arg>::Callback aMethod,
   1.175 +                                   Arg* aArg)
   1.176 +  {
   1.177 +    nsRefPtr<Notification> notification =
   1.178 +      new TNotification<Class, Arg>(aInstance, aMethod, aArg);
   1.179 +    if (notification && mNotifications.AppendElement(notification))
   1.180 +      ScheduleProcessing();
   1.181 +  }
   1.182 +
   1.183 +#ifdef DEBUG
   1.184 +  bool IsUpdating() const
   1.185 +    { return mObservingState == eRefreshProcessingForUpdate; }
   1.186 +#endif
   1.187 +
   1.188 +protected:
   1.189 +  nsCycleCollectingAutoRefCnt mRefCnt;
   1.190 +  NS_DECL_OWNINGTHREAD
   1.191 +
   1.192 +  /**
   1.193 +   * Start to observe refresh to make notifications and events processing after
   1.194 +   * layout.
   1.195 +   */
   1.196 +  void ScheduleProcessing();
   1.197 +
   1.198 +  /**
   1.199 +   * Return true if the accessible tree state update is pending.
   1.200 +   */
   1.201 +  bool IsUpdatePending();
   1.202 +
   1.203 +private:
   1.204 +  NotificationController(const NotificationController&);
   1.205 +  NotificationController& operator = (const NotificationController&);
   1.206 +
   1.207 +  // nsARefreshObserver
   1.208 +  virtual void WillRefresh(mozilla::TimeStamp aTime);
   1.209 +
   1.210 +private:
   1.211 +  /**
   1.212 +   * Indicates whether we're waiting on an event queue processing from our
   1.213 +   * notification controller to flush events.
   1.214 +   */
   1.215 +  enum eObservingState {
   1.216 +    eNotObservingRefresh,
   1.217 +    eRefreshObserving,
   1.218 +    eRefreshProcessing,
   1.219 +    eRefreshProcessingForUpdate
   1.220 +  };
   1.221 +  eObservingState mObservingState;
   1.222 +
   1.223 +  /**
   1.224 +   * The presshell of the document accessible.
   1.225 +   */
   1.226 +  nsIPresShell* mPresShell;
   1.227 +
   1.228 +  /**
   1.229 +   * Child documents that needs to be bound to the tree.
   1.230 +   */
   1.231 +  nsTArray<nsRefPtr<DocAccessible> > mHangingChildDocuments;
   1.232 +
   1.233 +  /**
   1.234 +   * Storage for content inserted notification information.
   1.235 +   */
   1.236 +  class ContentInsertion
   1.237 +  {
   1.238 +  public:
   1.239 +    ContentInsertion(DocAccessible* aDocument, Accessible* aContainer);
   1.240 +    virtual ~ContentInsertion() { mDocument = nullptr; }
   1.241 +
   1.242 +    NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(ContentInsertion)
   1.243 +    NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ContentInsertion)
   1.244 +
   1.245 +    bool InitChildList(nsIContent* aStartChildNode, nsIContent* aEndChildNode);
   1.246 +    void Process();
   1.247 +
   1.248 +  private:
   1.249 +    ContentInsertion();
   1.250 +    ContentInsertion(const ContentInsertion&);
   1.251 +    ContentInsertion& operator = (const ContentInsertion&);
   1.252 +
   1.253 +    // The document used to process content insertion, matched to document of
   1.254 +    // the notification controller that this notification belongs to, therefore
   1.255 +    // it's ok to keep it as weak ref.
   1.256 +    DocAccessible* mDocument;
   1.257 +
   1.258 +    // The container accessible that content insertion occurs within.
   1.259 +    nsRefPtr<Accessible> mContainer;
   1.260 +
   1.261 +    // Array of inserted contents.
   1.262 +    nsTArray<nsCOMPtr<nsIContent> > mInsertedContent;
   1.263 +  };
   1.264 +
   1.265 +  /**
   1.266 +   * A pending accessible tree update notifications for content insertions.
   1.267 +   * Don't make this an nsAutoTArray; we use SwapElements() on it.
   1.268 +   */
   1.269 +  nsTArray<nsRefPtr<ContentInsertion> > mContentInsertions;
   1.270 +
   1.271 +  template<class T>
   1.272 +  class nsCOMPtrHashKey : public PLDHashEntryHdr
   1.273 +  {
   1.274 +  public:
   1.275 +    typedef T* KeyType;
   1.276 +    typedef const T* KeyTypePointer;
   1.277 +
   1.278 +    nsCOMPtrHashKey(const T* aKey) : mKey(const_cast<T*>(aKey)) {}
   1.279 +    nsCOMPtrHashKey(const nsPtrHashKey<T> &aToCopy) : mKey(aToCopy.mKey) {}
   1.280 +    ~nsCOMPtrHashKey() { }
   1.281 +
   1.282 +    KeyType GetKey() const { return mKey; }
   1.283 +    bool KeyEquals(KeyTypePointer aKey) const { return aKey == mKey; }
   1.284 +
   1.285 +    static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
   1.286 +    static PLDHashNumber HashKey(KeyTypePointer aKey)
   1.287 +      { return NS_PTR_TO_INT32(aKey) >> 2; }
   1.288 +
   1.289 +    enum { ALLOW_MEMMOVE = true };
   1.290 +
   1.291 +   protected:
   1.292 +     nsCOMPtr<T> mKey;
   1.293 +  };
   1.294 +
   1.295 +  /**
   1.296 +   * A pending accessible tree update notifications for rendered text changes.
   1.297 +   */
   1.298 +  nsTHashtable<nsCOMPtrHashKey<nsIContent> > mTextHash;
   1.299 +
   1.300 +  /**
   1.301 +   * Update the accessible tree for pending rendered text change notifications.
   1.302 +   */
   1.303 +  static PLDHashOperator TextEnumerator(nsCOMPtrHashKey<nsIContent>* aEntry,
   1.304 +                                        void* aUserArg);
   1.305 +
   1.306 +  /**
   1.307 +   * Other notifications like DOM events. Don't make this an nsAutoTArray; we
   1.308 +   * use SwapElements() on it.
   1.309 +   */
   1.310 +  nsTArray<nsRefPtr<Notification> > mNotifications;
   1.311 +};
   1.312 +
   1.313 +} // namespace a11y
   1.314 +} // namespace mozilla
   1.315 +
   1.316 +#endif // mozilla_a11y_NotificationController_h_

mercurial