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