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/DocManager.h"
10 #include "mozilla/a11y/FocusManager.h"
11 #include "mozilla/a11y/Platform.h"
12 #include "mozilla/a11y/Role.h"
13 #include "mozilla/a11y/SelectionManager.h"
14 #include "mozilla/Preferences.h"
15 
16 #include "nsIContent.h"
17 #include "nsIObserver.h"
18 #include "nsIAccessibleEvent.h"
19 #include "nsIEventListenerService.h"
20 #include "nsXULAppAPI.h"
21 #include "xpcAccessibilityService.h"
22 
23 class nsImageFrame;
24 class nsIArray;
25 class nsITreeView;
26 
27 namespace mozilla {
28 
29 class PresShell;
30 
31 namespace dom {
32 class DOMStringList;
33 class Element;
34 }  // namespace dom
35 
36 namespace a11y {
37 
38 class AccAttributes;
39 class ApplicationAccessible;
40 class xpcAccessibleApplication;
41 
42 /**
43  * Return focus manager.
44  */
45 FocusManager* FocusMgr();
46 
47 /**
48  * Return selection manager.
49  */
50 SelectionManager* SelectionMgr();
51 
52 /**
53  * Returns the application accessible.
54  */
55 ApplicationAccessible* ApplicationAcc();
56 xpcAccessibleApplication* XPCApplicationAcc();
57 
58 typedef LocalAccessible*(New_Accessible)(mozilla::dom::Element* aElement,
59                                          LocalAccessible* aContext);
60 
61 // These fields are not `nsStaticAtom* const` because MSVC doesn't like it.
62 struct MarkupAttrInfo {
63   nsStaticAtom* name;
64   nsStaticAtom* value;
65 
66   nsStaticAtom* DOMAttrName;
67   nsStaticAtom* DOMAttrValue;
68 };
69 
70 struct MarkupMapInfo {
71   const nsStaticAtom* const tag;
72   New_Accessible* new_func;
73   a11y::role role;
74   MarkupAttrInfo attrs[4];
75 };
76 
77 #ifdef MOZ_XUL
78 struct XULMarkupMapInfo {
79   const nsStaticAtom* const tag;
80   New_Accessible* new_func;
81 };
82 #endif
83 
84 /**
85  * PREF_ACCESSIBILITY_FORCE_DISABLED preference change callback.
86  */
87 void PrefChanged(const char* aPref, void* aClosure);
88 
89 /**
90  * Read and normalize PREF_ACCESSIBILITY_FORCE_DISABLED preference.
91  */
92 EPlatformDisabledState ReadPlatformDisabledState();
93 
94 }  // namespace a11y
95 }  // namespace mozilla
96 
97 class nsAccessibilityService final : public mozilla::a11y::DocManager,
98                                      public mozilla::a11y::FocusManager,
99                                      public mozilla::a11y::SelectionManager,
100                                      public nsIListenerChangeListener,
101                                      public nsIObserver {
102  public:
103   typedef mozilla::a11y::LocalAccessible LocalAccessible;
104   typedef mozilla::a11y::DocAccessible DocAccessible;
105 
106   // nsIListenerChangeListener
107   NS_IMETHOD ListenersChanged(nsIArray* aEventChanges) override;
108 
109  protected:
110   ~nsAccessibilityService();
111 
112  public:
113   NS_DECL_ISUPPORTS_INHERITED
114   NS_DECL_NSIOBSERVER
115 
116   LocalAccessible* GetRootDocumentAccessible(mozilla::PresShell* aPresShell,
117                                              bool aCanCreate);
118 
119   /**
120    * Adds/remove ATK root accessible for gtk+ native window to/from children
121    * of the application accessible.
122    */
123   LocalAccessible* AddNativeRootAccessible(void* aAtkAccessible);
124   void RemoveNativeRootAccessible(LocalAccessible* aRootAccessible);
125 
126   bool HasAccessible(nsINode* aDOMNode);
127 
128   /**
129    * Get a string equivalent for an accessible role value.
130    */
131   void GetStringRole(uint32_t aRole, nsAString& aString);
132 
133   /**
134    * Get a string equivalent for an accessible state/extra state.
135    */
136   already_AddRefed<mozilla::dom::DOMStringList> GetStringStates(
137       uint64_t aStates) const;
138   void GetStringStates(uint32_t aState, uint32_t aExtraState,
139                        nsISupports** aStringStates);
140 
141   /**
142    * Get a string equivalent for an accessible event value.
143    */
144   void GetStringEventType(uint32_t aEventType, nsAString& aString);
145 
146   /**
147    * Get a string equivalent for an accessible event value.
148    */
149   void GetStringEventType(uint32_t aEventType, nsACString& aString);
150 
151   /**
152    * Get a string equivalent for an accessible relation type.
153    */
154   void GetStringRelationType(uint32_t aRelationType, nsAString& aString);
155 
156   // nsAccesibilityService
157   /**
158    * Notification used to update the accessible tree when deck panel is
159    * switched.
160    */
161   void DeckPanelSwitched(mozilla::PresShell* aPresShell, nsIContent* aDeckNode,
162                          nsIFrame* aPrevBoxFrame, nsIFrame* aCurrentBoxFrame);
163 
164   /**
165    * Notification used to update the accessible tree when new content is
166    * inserted.
167    */
168   void ContentRangeInserted(mozilla::PresShell* aPresShell,
169                             nsIContent* aStartChild, nsIContent* aEndChild);
170 
171   /**
172    * Notification used to update the accessible tree when content is removed.
173    */
174   void ContentRemoved(mozilla::PresShell* aPresShell, nsIContent* aChild);
175 
176   /**
177    * Notification used to invalidate the isLayoutTable cache.
178    */
179   void TableLayoutGuessMaybeChanged(mozilla::PresShell* aPresShell,
180                                     nsIContent* aContent);
181 
182   void UpdateText(mozilla::PresShell* aPresShell, nsIContent* aContent);
183 
184   /**
185    * Update XUL:tree accessible tree when treeview is changed.
186    */
187   void TreeViewChanged(mozilla::PresShell* aPresShell, nsIContent* aContent,
188                        nsITreeView* aView);
189 
190   /**
191    * Notify of input@type="element" value change.
192    */
193   void RangeValueChanged(mozilla::PresShell* aPresShell, nsIContent* aContent);
194 
195   /**
196    * Update the image map.
197    */
198   void UpdateImageMap(nsImageFrame* aImageFrame);
199 
200   /**
201    * Update the label accessible tree when rendered @value is changed.
202    */
203   void UpdateLabelValue(mozilla::PresShell* aPresShell, nsIContent* aLabelElm,
204                         const nsString& aNewValue);
205 
206   /**
207    * Notify accessibility that anchor jump has been accomplished to the given
208    * target. Used by layout.
209    */
210   void NotifyOfAnchorJumpTo(nsIContent* aTarget);
211 
212   /**
213    * Notify that presshell is activated.
214    */
215   void PresShellActivated(mozilla::PresShell* aPresShell);
216 
217   /**
218    * Recreate an accessible for the given content node in the presshell.
219    */
220   void RecreateAccessible(mozilla::PresShell* aPresShell, nsIContent* aContent);
221 
222   void FireAccessibleEvent(uint32_t aEvent, LocalAccessible* aTarget);
223 
224   /**
225    * Notify accessibility that the size has become available for an image.
226    * This occurs when the size of an image is initially not known, but we've
227    * now loaded enough data to know the size.
228    * Called by layout.
229    */
230   void NotifyOfImageSizeAvailable(mozilla::PresShell* aPresShell,
231                                   nsIContent* aContent);
232 
233   // nsAccessibiltiyService
234 
235   /**
236    * Return true if accessibility service has been shutdown.
237    */
IsShutdown()238   static bool IsShutdown() { return gConsumers == 0; };
239 
240   /**
241    * Creates an accessible for the given DOM node.
242    *
243    * @param  aNode             [in] the given node
244    * @param  aContext          [in] context the accessible is created in
245    * @param  aIsSubtreeHidden  [out, optional] indicates whether the node's
246    *                             frame and its subtree is hidden
247    */
248   LocalAccessible* CreateAccessible(nsINode* aNode, LocalAccessible* aContext,
249                                     bool* aIsSubtreeHidden = nullptr);
250 
MarkupRole(const nsIContent * aContent)251   mozilla::a11y::role MarkupRole(const nsIContent* aContent) const {
252     const mozilla::a11y::MarkupMapInfo* markupMap =
253         GetMarkupMapInfoForNode(aContent);
254     return markupMap ? markupMap->role : mozilla::a11y::roles::NOTHING;
255   }
256 
257   /**
258    * Return the associated value for a given attribute if
259    * it appears in the MarkupMap. Otherwise, it returns null.
260    */
MarkupAttribute(const nsIContent * aContent,nsStaticAtom * aAtom)261   nsStaticAtom* MarkupAttribute(const nsIContent* aContent,
262                                 nsStaticAtom* aAtom) const {
263     const mozilla::a11y::MarkupMapInfo* markupMap =
264         GetMarkupMapInfoForNode(aContent);
265     if (markupMap) {
266       for (size_t i = 0; i < mozilla::ArrayLength(markupMap->attrs); i++) {
267         const mozilla::a11y::MarkupAttrInfo* info = markupMap->attrs + i;
268         if (info->name == aAtom) {
269           return info->value;
270         }
271       }
272     }
273     return nullptr;
274   }
275 
276   /**
277    * Set the object attribute defined by markup for the given element.
278    */
279   void MarkupAttributes(const nsIContent* aContent,
280                         mozilla::a11y::AccAttributes* aAttributes) const;
281 
282   /**
283    * A list of possible accessibility service consumers. Accessibility service
284    * can only be shut down when there are no remaining consumers.
285    *
286    * eXPCOM       - accessibility service is used by XPCOM.
287    *
288    * eMainProcess - accessibility service was started by main process in the
289    *                content process.
290    *
291    * ePlatformAPI - accessibility service is used by the platform api in the
292    *                main process.
293    */
294   enum ServiceConsumer {
295     eXPCOM = 1 << 0,
296     eMainProcess = 1 << 1,
297     ePlatformAPI = 1 << 2,
298   };
299 
300  private:
301   // nsAccessibilityService creation is controlled by friend
302   // GetOrCreateAccService, keep constructors private.
303   nsAccessibilityService();
304   nsAccessibilityService(const nsAccessibilityService&);
305   nsAccessibilityService& operator=(const nsAccessibilityService&);
306 
307  private:
308   /**
309    * Initialize accessibility service.
310    */
311   bool Init();
312 
313   /**
314    * Shutdowns accessibility service.
315    */
316   void Shutdown();
317 
318   /**
319    * Create an accessible whose type depends on the given frame.
320    */
321   already_AddRefed<LocalAccessible> CreateAccessibleByFrameType(
322       nsIFrame* aFrame, nsIContent* aContent, LocalAccessible* aContext);
323 
324   /**
325    * Notify observers about change of the accessibility service's consumers.
326    */
327   void NotifyOfConsumersChange();
328 
329   /**
330    * Get a JSON string representing the accessibility service consumers.
331    */
332   void GetConsumers(nsAString& aString);
333 
334   /**
335    * Set accessibility service consumers.
336    */
337   void SetConsumers(uint32_t aConsumers, bool aNotify = true);
338 
339   /**
340    * Unset accessibility service consumers.
341    */
342   void UnsetConsumers(uint32_t aConsumers);
343 
344   /**
345    * Reference for accessibility service instance.
346    */
347   static nsAccessibilityService* gAccessibilityService;
348 
349   /**
350    * Reference for application accessible instance.
351    */
352   static mozilla::a11y::ApplicationAccessible* gApplicationAccessible;
353   static mozilla::a11y::xpcAccessibleApplication* gXPCApplicationAccessible;
354 
355   /**
356    * Contains a set of accessibility service consumers.
357    */
358   static uint32_t gConsumers;
359 
360   using MarkupMap = nsTHashMap<nsPtrHashKey<const nsAtom>,
361                                const mozilla::a11y::MarkupMapInfo*>;
362   MarkupMap mHTMLMarkupMap;
363   MarkupMap mMathMLMarkupMap;
364 
GetMarkupMapInfoForNode(const nsIContent * aContent)365   const mozilla::a11y::MarkupMapInfo* GetMarkupMapInfoForNode(
366       const nsIContent* aContent) const {
367     if (aContent->IsHTMLElement()) {
368       return mHTMLMarkupMap.Get(aContent->NodeInfo()->NameAtom());
369     }
370     if (aContent->IsMathMLElement()) {
371       return mMathMLMarkupMap.Get(aContent->NodeInfo()->NameAtom());
372     }
373     // This function can be called by MarkupAttribute, etc. which might in turn
374     // be called on a XUL, SVG, etc. element. For example, this can happen
375     // with nsAccUtils::SetLiveContainerAttributes.
376     return nullptr;
377   }
378 
379 #ifdef MOZ_XUL
380   nsTHashMap<nsPtrHashKey<const nsAtom>, const mozilla::a11y::XULMarkupMapInfo*>
381       mXULMarkupMap;
382 #endif
383 
384   friend nsAccessibilityService* GetAccService();
385   friend nsAccessibilityService* GetOrCreateAccService(uint32_t);
386   friend void MaybeShutdownAccService(uint32_t);
387   friend void mozilla::a11y::PrefChanged(const char*, void*);
388   friend mozilla::a11y::FocusManager* mozilla::a11y::FocusMgr();
389   friend mozilla::a11y::SelectionManager* mozilla::a11y::SelectionMgr();
390   friend mozilla::a11y::ApplicationAccessible* mozilla::a11y::ApplicationAcc();
391   friend mozilla::a11y::xpcAccessibleApplication*
392   mozilla::a11y::XPCApplicationAcc();
393   friend class xpcAccessibilityService;
394 };
395 
396 /**
397  * Return the accessibility service instance. (Handy global function)
398  */
GetAccService()399 inline nsAccessibilityService* GetAccService() {
400   return nsAccessibilityService::gAccessibilityService;
401 }
402 
403 /**
404  * Return accessibility service instance; creating one if necessary.
405  */
406 nsAccessibilityService* GetOrCreateAccService(
407     uint32_t aNewConsumer = nsAccessibilityService::ePlatformAPI);
408 
409 /**
410  * Shutdown accessibility service if needed.
411  */
412 void MaybeShutdownAccService(uint32_t aFormerConsumer);
413 
414 /**
415  * Return true if we're in a content process and not B2G.
416  */
IPCAccessibilityActive()417 inline bool IPCAccessibilityActive() { return XRE_IsContentProcess(); }
418 
419 /**
420  * Map nsIAccessibleEvents constants to strings. Used by
421  * nsAccessibilityService::GetStringEventType() method.
422  */
423 static const char kEventTypeNames[][40] = {
424     "unknown",                           //
425     "show",                              // EVENT_SHOW
426     "hide",                              // EVENT_HIDE
427     "reorder",                           // EVENT_REORDER
428     "active decendent change",           // EVENT_ACTIVE_DECENDENT_CHANGED
429     "focus",                             // EVENT_FOCUS
430     "state change",                      // EVENT_STATE_CHANGE
431     "location change",                   // EVENT_LOCATION_CHANGE
432     "name changed",                      // EVENT_NAME_CHANGE
433     "description change",                // EVENT_DESCRIPTION_CHANGE
434     "value change",                      // EVENT_VALUE_CHANGE
435     "help change",                       // EVENT_HELP_CHANGE
436     "default action change",             // EVENT_DEFACTION_CHANGE
437     "action change",                     // EVENT_ACTION_CHANGE
438     "accelerator change",                // EVENT_ACCELERATOR_CHANGE
439     "selection",                         // EVENT_SELECTION
440     "selection add",                     // EVENT_SELECTION_ADD
441     "selection remove",                  // EVENT_SELECTION_REMOVE
442     "selection within",                  // EVENT_SELECTION_WITHIN
443     "alert",                             // EVENT_ALERT
444     "foreground",                        // EVENT_FOREGROUND
445     "menu start",                        // EVENT_MENU_START
446     "menu end",                          // EVENT_MENU_END
447     "menupopup start",                   // EVENT_MENUPOPUP_START
448     "menupopup end",                     // EVENT_MENUPOPUP_END
449     "capture start",                     // EVENT_CAPTURE_START
450     "capture end",                       // EVENT_CAPTURE_END
451     "movesize start",                    // EVENT_MOVESIZE_START
452     "movesize end",                      // EVENT_MOVESIZE_END
453     "contexthelp start",                 // EVENT_CONTEXTHELP_START
454     "contexthelp end",                   // EVENT_CONTEXTHELP_END
455     "dragdrop start",                    // EVENT_DRAGDROP_START
456     "dragdrop end",                      // EVENT_DRAGDROP_END
457     "dialog start",                      // EVENT_DIALOG_START
458     "dialog end",                        // EVENT_DIALOG_END
459     "scrolling start",                   // EVENT_SCROLLING_START
460     "scrolling end",                     // EVENT_SCROLLING_END
461     "minimize start",                    // EVENT_MINIMIZE_START
462     "minimize end",                      // EVENT_MINIMIZE_END
463     "document load complete",            // EVENT_DOCUMENT_LOAD_COMPLETE
464     "document reload",                   // EVENT_DOCUMENT_RELOAD
465     "document load stopped",             // EVENT_DOCUMENT_LOAD_STOPPED
466     "document attributes changed",       // EVENT_DOCUMENT_ATTRIBUTES_CHANGED
467     "document content changed",          // EVENT_DOCUMENT_CONTENT_CHANGED
468     "property changed",                  // EVENT_PROPERTY_CHANGED
469     "page changed",                      // EVENT_PAGE_CHANGED
470     "text attribute changed",            // EVENT_TEXT_ATTRIBUTE_CHANGED
471     "text caret moved",                  // EVENT_TEXT_CARET_MOVED
472     "text changed",                      // EVENT_TEXT_CHANGED
473     "text inserted",                     // EVENT_TEXT_INSERTED
474     "text removed",                      // EVENT_TEXT_REMOVED
475     "text updated",                      // EVENT_TEXT_UPDATED
476     "text selection changed",            // EVENT_TEXT_SELECTION_CHANGED
477     "visible data changed",              // EVENT_VISIBLE_DATA_CHANGED
478     "text column changed",               // EVENT_TEXT_COLUMN_CHANGED
479     "section changed",                   // EVENT_SECTION_CHANGED
480     "table caption changed",             // EVENT_TABLE_CAPTION_CHANGED
481     "table model changed",               // EVENT_TABLE_MODEL_CHANGED
482     "table summary changed",             // EVENT_TABLE_SUMMARY_CHANGED
483     "table row description changed",     // EVENT_TABLE_ROW_DESCRIPTION_CHANGED
484     "table row header changed",          // EVENT_TABLE_ROW_HEADER_CHANGED
485     "table row insert",                  // EVENT_TABLE_ROW_INSERT
486     "table row delete",                  // EVENT_TABLE_ROW_DELETE
487     "table row reorder",                 // EVENT_TABLE_ROW_REORDER
488     "table column description changed",  // EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED
489     "table column header changed",       // EVENT_TABLE_COLUMN_HEADER_CHANGED
490     "table column insert",               // EVENT_TABLE_COLUMN_INSERT
491     "table column delete",               // EVENT_TABLE_COLUMN_DELETE
492     "table column reorder",              // EVENT_TABLE_COLUMN_REORDER
493     "window activate",                   // EVENT_WINDOW_ACTIVATE
494     "window create",                     // EVENT_WINDOW_CREATE
495     "window deactivate",                 // EVENT_WINDOW_DEACTIVATE
496     "window destroy",                    // EVENT_WINDOW_DESTROY
497     "window maximize",                   // EVENT_WINDOW_MAXIMIZE
498     "window minimize",                   // EVENT_WINDOW_MINIMIZE
499     "window resize",                     // EVENT_WINDOW_RESIZE
500     "window restore",                    // EVENT_WINDOW_RESTORE
501     "hyperlink end index changed",       // EVENT_HYPERLINK_END_INDEX_CHANGED
502     "hyperlink number of anchors changed",  // EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED
503     "hyperlink selected link changed",  // EVENT_HYPERLINK_SELECTED_LINK_CHANGED
504     "hypertext link activated",         // EVENT_HYPERTEXT_LINK_ACTIVATED
505     "hypertext link selected",          // EVENT_HYPERTEXT_LINK_SELECTED
506     "hyperlink start index changed",    // EVENT_HYPERLINK_START_INDEX_CHANGED
507     "hypertext changed",                // EVENT_HYPERTEXT_CHANGED
508     "hypertext links count changed",    // EVENT_HYPERTEXT_NLINKS_CHANGED
509     "object attribute changed",         // EVENT_OBJECT_ATTRIBUTE_CHANGED
510     "virtual cursor changed",           // EVENT_VIRTUALCURSOR_CHANGED
511     "text value change",                // EVENT_TEXT_VALUE_CHANGE
512     "scrolling",                        // EVENT_SCROLLING
513     "announcement",                     // EVENT_ANNOUNCEMENT
514     "live region added",                // EVENT_LIVE_REGION_ADDED
515     "live region removed",              // EVENT_LIVE_REGION_REMOVED
516     "table styling changed",            // EVENT_TABLE_STYLING_CHANGED
517 };
518 
519 #endif
520