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