tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsAccessibilityService.h (19755B)


      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 __nsAccessibilityService_h__
      7 #define __nsAccessibilityService_h__
      8 
      9 #include "mozilla/a11y/CacheConstants.h"
     10 #include "mozilla/a11y/DocManager.h"
     11 #include "mozilla/a11y/FocusManager.h"
     12 #include "mozilla/a11y/Platform.h"
     13 #include "mozilla/a11y/Role.h"
     14 #include "mozilla/a11y/SelectionManager.h"
     15 #include "mozilla/Preferences.h"
     16 
     17 #include "nsAtomHashKeys.h"
     18 #include "nsIContent.h"
     19 #include "nsIObserver.h"
     20 #include "nsIAccessibleEvent.h"
     21 #include "nsIEventListenerService.h"
     22 #include "nsXULAppAPI.h"
     23 #include "xpcAccessibilityService.h"
     24 
     25 class nsImageFrame;
     26 class nsIArray;
     27 class nsITreeView;
     28 
     29 namespace mozilla {
     30 
     31 class PresShell;
     32 class Monitor;
     33 namespace dom {
     34 class DOMStringList;
     35 class Element;
     36 }  // namespace dom
     37 
     38 namespace a11y {
     39 
     40 class AccAttributes;
     41 class Accessible;
     42 class ApplicationAccessible;
     43 class xpcAccessibleApplication;
     44 
     45 /**
     46 * Return focus manager.
     47 */
     48 FocusManager* FocusMgr();
     49 
     50 /**
     51 * Return selection manager.
     52 */
     53 SelectionManager* SelectionMgr();
     54 
     55 /**
     56 * Returns the application accessible.
     57 */
     58 ApplicationAccessible* ApplicationAcc();
     59 xpcAccessibleApplication* XPCApplicationAcc();
     60 
     61 typedef LocalAccessible*(New_Accessible)(mozilla::dom::Element* aElement,
     62                                         LocalAccessible* aContext);
     63 
     64 // These fields are not `nsStaticAtom* const` because MSVC doesn't like it.
     65 struct MarkupAttrInfo {
     66  nsStaticAtom* name;
     67  nsStaticAtom* value;
     68 
     69  nsStaticAtom* DOMAttrName;
     70  nsStaticAtom* DOMAttrValue;
     71 };
     72 
     73 struct MarkupMapInfo {
     74  nsStaticAtom* const tag;
     75  New_Accessible* new_func;
     76  a11y::role role;
     77  MarkupAttrInfo attrs[4];
     78 };
     79 
     80 struct XULMarkupMapInfo {
     81  nsStaticAtom* const tag;
     82  New_Accessible* new_func;
     83 };
     84 
     85 /**
     86 * PREF_ACCESSIBILITY_FORCE_DISABLED preference change callback.
     87 */
     88 void PrefChanged(const char* aPref, void* aClosure);
     89 
     90 /**
     91 * Read and normalize PREF_ACCESSIBILITY_FORCE_DISABLED preference.
     92 */
     93 EPlatformDisabledState ReadPlatformDisabledState();
     94 
     95 /**
     96 * RAII class to prevent new cache domains from being requested. This is
     97 * necessary in some cases when code for an OS accessibility API requires
     98 * information in order to fire an event. We don't necessarily know that a
     99 * client is even interested in that event, so requesting data that the client
    100 * may never query doesn't make sense.
    101 */
    102 class MOZ_RAII CacheDomainActivationBlocker {
    103 public:
    104  CacheDomainActivationBlocker();
    105  ~CacheDomainActivationBlocker();
    106 
    107 private:
    108  // Used to manage re-entry.
    109  static uint32_t sEntryCount;
    110 };
    111 
    112 }  // namespace a11y
    113 }  // namespace mozilla
    114 
    115 class nsAccessibilityService final : public mozilla::a11y::DocManager,
    116                                     public mozilla::a11y::FocusManager,
    117                                     public mozilla::a11y::SelectionManager,
    118                                     public nsIListenerChangeListener,
    119                                     public nsIObserver {
    120 public:
    121  typedef mozilla::a11y::LocalAccessible LocalAccessible;
    122  typedef mozilla::a11y::DocAccessible DocAccessible;
    123 
    124  static const uint64_t kDefaultCacheDomains =
    125      mozilla::a11y::CacheDomain::NameAndDescription |
    126      mozilla::a11y::CacheDomain::State;
    127 
    128  // nsIListenerChangeListener
    129  NS_IMETHOD ListenersChanged(nsIArray* aEventChanges) override;
    130 
    131 protected:
    132  ~nsAccessibilityService();
    133 
    134 public:
    135  NS_DECL_ISUPPORTS_INHERITED
    136  NS_DECL_NSIOBSERVER
    137 
    138  LocalAccessible* GetRootDocumentAccessible(mozilla::PresShell* aPresShell,
    139                                             bool aCanCreate);
    140 
    141  /**
    142   * Adds/remove ATK root accessible for gtk+ native window to/from children
    143   * of the application accessible.
    144   */
    145  LocalAccessible* AddNativeRootAccessible(void* aAtkAccessible);
    146  void RemoveNativeRootAccessible(LocalAccessible* aRootAccessible);
    147 
    148  bool HasAccessible(nsINode* aDOMNode);
    149 
    150  /**
    151   * Get a string equivalent for an accessible role value.
    152   */
    153  void GetStringRole(uint32_t aRole, nsAString& aString);
    154 
    155  /**
    156   * Get a string equivalent for an accessible state/extra state.
    157   */
    158  already_AddRefed<mozilla::dom::DOMStringList> GetStringStates(
    159      uint64_t aStates) const;
    160  void GetStringStates(uint32_t aState, uint32_t aExtraState,
    161                       nsISupports** aStringStates);
    162 
    163  /**
    164   * Get a string equivalent for an accessible event value.
    165   */
    166  void GetStringEventType(uint32_t aEventType, nsAString& aString);
    167 
    168  /**
    169   * Get a string equivalent for an accessible event value.
    170   */
    171  void GetStringEventType(uint32_t aEventType, nsACString& aString);
    172 
    173  /**
    174   * Get a string equivalent for an accessible relation type.
    175   */
    176  void GetStringRelationType(uint32_t aRelationType, nsAString& aString);
    177 
    178  // nsAccesibilityService
    179  /**
    180   * Notification used to update the accessible tree when new content is
    181   * inserted.
    182   */
    183  void ContentRangeInserted(mozilla::PresShell* aPresShell,
    184                            nsIContent* aStartChild, nsIContent* aEndChild);
    185 
    186  /**
    187   * Triggers a re-evaluation of the a11y tree of aContent after the next
    188   * refresh. This is important because whether we create accessibles may
    189   * depend on the frame tree / style.
    190   */
    191  void ScheduleAccessibilitySubtreeUpdate(mozilla::PresShell* aPresShell,
    192                                          nsIContent* aStartChild);
    193 
    194  /**
    195   * Notification used to update the accessible tree when content is removed.
    196   */
    197  void ContentRemoved(mozilla::PresShell* aPresShell, nsIContent* aChild);
    198 
    199  /**
    200   * Notification used to invalidate the isLayoutTable cache.
    201   */
    202  void TableLayoutGuessMaybeChanged(mozilla::PresShell* aPresShell,
    203                                    nsIContent* aContent);
    204 
    205  /**
    206   * Notifies when a combobox <option> text or label changes.
    207   */
    208  void ComboboxOptionMaybeChanged(mozilla::PresShell*,
    209                                  nsIContent* aMutatingNode);
    210 
    211  void UpdateText(mozilla::PresShell* aPresShell, nsIContent* aContent);
    212 
    213  /**
    214   * Update XUL:tree accessible tree when treeview is changed.
    215   */
    216  void TreeViewChanged(mozilla::PresShell* aPresShell, nsIContent* aContent,
    217                       nsITreeView* aView);
    218 
    219  /**
    220   * Notify of input@type="element" value change.
    221   */
    222  void RangeValueChanged(mozilla::PresShell* aPresShell, nsIContent* aContent);
    223 
    224  /**
    225   * Update the image map.
    226   */
    227  void UpdateImageMap(nsImageFrame* aImageFrame);
    228 
    229  /**
    230   * Update the label accessible tree when rendered @value is changed.
    231   */
    232  void UpdateLabelValue(mozilla::PresShell* aPresShell, nsIContent* aLabelElm,
    233                        const nsString& aNewValue);
    234 
    235  /**
    236   * Notify accessibility that anchor jump has been accomplished to the given
    237   * target. Used by layout.
    238   */
    239  void NotifyOfAnchorJumpTo(nsIContent* aTarget);
    240 
    241  /**
    242   * Notify that presshell is activated.
    243   */
    244  void PresShellActivated(mozilla::PresShell* aPresShell);
    245 
    246  /**
    247   * Recreate an accessible for the given content node in the presshell.
    248   */
    249  void RecreateAccessible(mozilla::PresShell* aPresShell, nsIContent* aContent);
    250 
    251  void FireAccessibleEvent(uint32_t aEvent, LocalAccessible* aTarget);
    252 
    253  void NotifyOfPossibleBoundsChange(mozilla::PresShell* aPresShell,
    254                                    nsIContent* aContent);
    255 
    256  void NotifyOfComputedStyleChange(mozilla::PresShell* aPresShell,
    257                                   nsIContent* aContent);
    258 
    259  void NotifyOfTabPanelVisibilityChange(mozilla::PresShell* aPresShell,
    260                                        mozilla::dom::Element* aPanel,
    261                                        bool aVisible);
    262 
    263  void NotifyOfResolutionChange(mozilla::PresShell* aPresShell,
    264                                float aResolution);
    265 
    266  void NotifyOfDevPixelRatioChange(mozilla::PresShell* aPresShell,
    267                                   int32_t aAppUnitsPerDevPixel);
    268 
    269  /**
    270   * Notify accessibility that an anchor positioned frame is
    271   * about to be removed. This gives us a chance to update cached relations
    272   * before the reflow where we will lose references to the anchor and won't be
    273   * able to refresh its accessible's cache.
    274   */
    275  void NotifyAnchorPositionedRemoved(mozilla::PresShell* aPresShell,
    276                                     nsIFrame* aFrame);
    277 
    278  /**
    279   * Notify accessibility that an anchor frame is about to be removed. This
    280   * gives us a chance to update cached relations before the reflow where the
    281   * anchor will be lost and we won't be able to refresh the accessible cache of
    282   * prior relations.
    283   */
    284  void NotifyAnchorRemoved(mozilla::PresShell* aPresShell, nsIFrame* aFrame);
    285 
    286  /**
    287   * Notify accessibility that an anchor positioned frame has
    288   * been marked for reflow because of a scroll change for one of its
    289   * anchors. A fallback anchor may be activated or deactivated.
    290   */
    291  void NotifyAnchorPositionedScrollUpdate(mozilla::PresShell* aPresShell,
    292                                          nsIFrame* aFrame);
    293 
    294  /**
    295   * Notify accessibility that an element explicitly set for an attribute is
    296   * about to change. See dom::Element::ExplicitlySetAttrElement.
    297   */
    298  void NotifyAttrElementWillChange(mozilla::dom::Element* aElement,
    299                                   nsAtom* aAttr);
    300 
    301  /**
    302   * Notify accessibility that an element explicitly set for an attribute has
    303   * changed. See dom::Element::ExplicitlySetAttrElement.
    304   */
    305  void NotifyAttrElementChanged(mozilla::dom::Element* aElement, nsAtom* aAttr);
    306 
    307  // nsAccessibiltiyService
    308 
    309  /**
    310   * Return true if accessibility service has been shutdown.
    311   */
    312  static bool IsShutdown() { return gConsumers == 0; };
    313 
    314  /**
    315   * Return true if there should be an image accessible for the given element.
    316   */
    317  static bool ShouldCreateImgAccessible(mozilla::dom::Element* aElement,
    318                                        DocAccessible* aDocument);
    319 
    320  /*
    321   * Set the currently-active cache domains.
    322   */
    323  void SetCacheDomains(uint64_t aCacheDomains);
    324 
    325  bool CacheDomainIsActive(uint64_t aCacheDomain) const {
    326    return (gCacheDomains & aCacheDomain) != mozilla::a11y::CacheDomain::None;
    327  }
    328 
    329  /**
    330   * Creates an accessible for the given DOM node.
    331   *
    332   * @param  aNode             [in] the given node
    333   * @param  aContext          [in] context the accessible is created in
    334   * @param  aIsSubtreeHidden  [out, optional] indicates whether the node's
    335   *                             frame and its subtree is hidden
    336   */
    337  LocalAccessible* CreateAccessible(nsINode* aNode, LocalAccessible* aContext,
    338                                    bool* aIsSubtreeHidden = nullptr);
    339 
    340  mozilla::a11y::role MarkupRole(const nsIContent* aContent) const {
    341    const mozilla::a11y::MarkupMapInfo* markupMap =
    342        GetMarkupMapInfoFor(aContent);
    343    return markupMap ? markupMap->role : mozilla::a11y::roles::NOTHING;
    344  }
    345 
    346  /**
    347   * Return the associated value for a given attribute if
    348   * it appears in the MarkupMap. Otherwise, it returns null. This can be
    349   * called with either an nsIContent or an Accessible.
    350   */
    351  template <typename T>
    352  nsStaticAtom* MarkupAttribute(T aSource, nsStaticAtom* aAtom) const {
    353    const mozilla::a11y::MarkupMapInfo* markupMap =
    354        GetMarkupMapInfoFor(aSource);
    355    if (markupMap) {
    356      for (size_t i = 0; i < std::size(markupMap->attrs); i++) {
    357        const mozilla::a11y::MarkupAttrInfo* info = markupMap->attrs + i;
    358        if (info->name == aAtom) {
    359          return info->value;
    360        }
    361      }
    362    }
    363    return nullptr;
    364  }
    365 
    366  /**
    367   * Set the object attribute defined by markup for the given element.
    368   */
    369  void MarkupAttributes(mozilla::a11y::Accessible* aAcc,
    370                        mozilla::a11y::AccAttributes* aAttributes) const;
    371 
    372  /**
    373   * A list of possible accessibility service consumers. Accessibility service
    374   * can only be shut down when there are no remaining consumers.
    375   *
    376   * eXPCOM       - accessibility service is used by XPCOM.
    377   *
    378   * eMainProcess - accessibility service was started by main process in the
    379   *                content process.
    380   *
    381   * ePlatformAPI - accessibility service is used by the platform api in the
    382   *                main process.
    383   */
    384  enum ServiceConsumer {
    385    eXPCOM = 1 << 0,
    386    eMainProcess = 1 << 1,
    387    ePlatformAPI = 1 << 2,
    388  };
    389 
    390  static uint64_t GetActiveCacheDomains() { return gCacheDomains; }
    391  bool ShouldAllowNewCacheDomains() { return mShouldAllowNewCacheDomains; }
    392 
    393 #if defined(ANDROID)
    394  static mozilla::Monitor& GetAndroidMonitor();
    395 #endif
    396 
    397 private:
    398  // nsAccessibilityService creation is controlled by friend
    399  // GetOrCreateAccService, keep constructors private.
    400  nsAccessibilityService();
    401  nsAccessibilityService(const nsAccessibilityService&);
    402  nsAccessibilityService& operator=(const nsAccessibilityService&);
    403 
    404 private:
    405  /**
    406   * Initialize accessibility service.
    407   */
    408  bool Init(uint64_t aCacheDomains = kDefaultCacheDomains);
    409 
    410  /**
    411   * Shutdowns accessibility service.
    412   */
    413  void Shutdown();
    414 
    415  /**
    416   * Create an accessible whose type depends on the given frame.
    417   */
    418  already_AddRefed<LocalAccessible> CreateAccessibleByFrameType(
    419      nsIFrame* aFrame, nsIContent* aContent, LocalAccessible* aContext);
    420 
    421  /**
    422   * Notify observers about change of the accessibility service's consumers.
    423   */
    424  void NotifyOfConsumersChange();
    425 
    426  /**
    427   * Get a JSON string representing the accessibility service consumers.
    428   */
    429  void GetConsumers(nsAString& aString);
    430 
    431  /**
    432   * Set accessibility service consumers.
    433   */
    434  void SetConsumers(uint32_t aConsumers, bool aNotify = true);
    435 
    436  /**
    437   * Unset accessibility service consumers.
    438   */
    439  void UnsetConsumers(uint32_t aConsumers);
    440 
    441  /**
    442   * Reference for accessibility service instance.
    443   */
    444  static nsAccessibilityService* gAccessibilityService;
    445 
    446  /**
    447   * Reference for application accessible instance.
    448   */
    449  static mozilla::a11y::ApplicationAccessible* gApplicationAccessible;
    450  static mozilla::a11y::xpcAccessibleApplication* gXPCApplicationAccessible;
    451 
    452  /**
    453   * Contains a set of accessibility service consumers.
    454   */
    455  static uint32_t gConsumers;
    456 
    457  /**
    458   * Contains the currently active cache domains.
    459   */
    460  static uint64_t gCacheDomains;
    461  // True if requesting new cache domains should be allowed, false if this
    462  // should be disallowed. This should only be changed by
    463  // CacheDomainActivationBlocker.
    464  bool mShouldAllowNewCacheDomains = true;
    465 
    466  // Can be weak because all atoms are known static
    467  using MarkupMap = nsTHashMap<nsAtom*, const mozilla::a11y::MarkupMapInfo*>;
    468  MarkupMap mHTMLMarkupMap;
    469  MarkupMap mMathMLMarkupMap;
    470 
    471  const mozilla::a11y::MarkupMapInfo* GetMarkupMapInfoFor(
    472      const nsIContent* aContent) const {
    473    if (aContent->IsHTMLElement()) {
    474      return mHTMLMarkupMap.Get(aContent->NodeInfo()->NameAtom());
    475    }
    476    if (aContent->IsMathMLElement()) {
    477      return mMathMLMarkupMap.Get(aContent->NodeInfo()->NameAtom());
    478    }
    479    // This function can be called by MarkupAttribute, etc. which might in turn
    480    // be called on a XUL, SVG, etc. element. For example, this can happen
    481    // with nsAccUtils::SetLiveContainerAttributes.
    482    return nullptr;
    483  }
    484 
    485  const mozilla::a11y::MarkupMapInfo* GetMarkupMapInfoFor(
    486      mozilla::a11y::Accessible* aAcc) const;
    487 
    488  nsTHashMap<nsAtom*, const mozilla::a11y::XULMarkupMapInfo*> mXULMarkupMap;
    489 
    490  friend nsAccessibilityService* GetAccService();
    491  friend nsAccessibilityService* GetOrCreateAccService(uint32_t, uint64_t);
    492  friend void MaybeShutdownAccService(uint32_t, bool);
    493  friend void mozilla::a11y::PrefChanged(const char*, void*);
    494  friend mozilla::a11y::FocusManager* mozilla::a11y::FocusMgr();
    495  friend mozilla::a11y::SelectionManager* mozilla::a11y::SelectionMgr();
    496  friend mozilla::a11y::ApplicationAccessible* mozilla::a11y::ApplicationAcc();
    497  friend mozilla::a11y::xpcAccessibleApplication*
    498  mozilla::a11y::XPCApplicationAcc();
    499  friend class xpcAccessibilityService;
    500  friend class mozilla::a11y::CacheDomainActivationBlocker;
    501 };
    502 
    503 /**
    504 * Return the accessibility service instance. (Handy global function)
    505 */
    506 inline nsAccessibilityService* GetAccService() {
    507  return nsAccessibilityService::gAccessibilityService;
    508 }
    509 
    510 /**
    511 * Return accessibility service instance; creating one if necessary.
    512 */
    513 nsAccessibilityService* GetOrCreateAccService(
    514    uint32_t aNewConsumer = nsAccessibilityService::ePlatformAPI,
    515    uint64_t aCacheDomains = nsAccessibilityService::GetActiveCacheDomains());
    516 
    517 /**
    518 * Shutdown accessibility service if needed.
    519 * @param aFormerConsumer The ServiceConsumer that is no longer using the
    520 *        service.
    521 * @param aAsync True to shut down the service asynchronously using a runnable.
    522 *        This should be used to avoid reentry if this is called during the
    523 *        shutdown of a document.
    524 */
    525 void MaybeShutdownAccService(uint32_t aFormerConsumer, bool aAsync = false);
    526 
    527 /**
    528 * Return true if we're in a content process and not B2G.
    529 */
    530 inline bool IPCAccessibilityActive() { return XRE_IsContentProcess(); }
    531 
    532 /**
    533 * Map nsIAccessibleEvents constants to strings. Used by
    534 * nsAccessibilityService::GetStringEventType() method.
    535 */
    536 static const char kEventTypeNames[][40] = {
    537    "unknown",                   //
    538    "show",                      // EVENT_SHOW
    539    "hide",                      // EVENT_HIDE
    540    "reorder",                   // EVENT_REORDER
    541    "focus",                     // EVENT_FOCUS
    542    "state change",              // EVENT_STATE_CHANGE
    543    "name changed",              // EVENT_NAME_CHANGE
    544    "description change",        // EVENT_DESCRIPTION_CHANGE
    545    "value change",              // EVENT_VALUE_CHANGE
    546    "selection",                 // EVENT_SELECTION
    547    "selection add",             // EVENT_SELECTION_ADD
    548    "selection remove",          // EVENT_SELECTION_REMOVE
    549    "selection within",          // EVENT_SELECTION_WITHIN
    550    "alert",                     // EVENT_ALERT
    551    "menu start",                // EVENT_MENU_START
    552    "menu end",                  // EVENT_MENU_END
    553    "menupopup start",           // EVENT_MENUPOPUP_START
    554    "menupopup end",             // EVENT_MENUPOPUP_END
    555    "dragdrop start",            // EVENT_DRAGDROP_START
    556    "scrolling start",           // EVENT_SCROLLING_START
    557    "scrolling end",             // EVENT_SCROLLING_END
    558    "document load complete",    // EVENT_DOCUMENT_LOAD_COMPLETE
    559    "document reload",           // EVENT_DOCUMENT_RELOAD
    560    "document load stopped",     // EVENT_DOCUMENT_LOAD_STOPPED
    561    "text attribute changed",    // EVENT_TEXT_ATTRIBUTE_CHANGED
    562    "text caret moved",          // EVENT_TEXT_CARET_MOVED
    563    "text inserted",             // EVENT_TEXT_INSERTED
    564    "text removed",              // EVENT_TEXT_REMOVED
    565    "text selection changed",    // EVENT_TEXT_SELECTION_CHANGED
    566    "window activate",           // EVENT_WINDOW_ACTIVATE
    567    "window deactivate",         // EVENT_WINDOW_DEACTIVATE
    568    "window maximize",           // EVENT_WINDOW_MAXIMIZE
    569    "window minimize",           // EVENT_WINDOW_MINIMIZE
    570    "window restore",            // EVENT_WINDOW_RESTORE
    571    "object attribute changed",  // EVENT_OBJECT_ATTRIBUTE_CHANGED
    572    "text value change",         // EVENT_TEXT_VALUE_CHANGE
    573    "scrolling",                 // EVENT_SCROLLING
    574    "announcement",              // EVENT_ANNOUNCEMENT
    575    "live region added",         // EVENT_LIVE_REGION_ADDED
    576    "live region removed",       // EVENT_LIVE_REGION_REMOVED
    577    "inner reorder",             // EVENT_INNER_REORDER
    578    "live region changed",       // EVENT_LIVE_REGION_CHANGED
    579    "errormessage changed",      // EVENT_ERRORMESSAGE_CHANGED
    580 };
    581 
    582 #endif