diff options
Diffstat (limited to '')
-rw-r--r-- | accessible/base/nsAccessibilityService.h | 492 |
1 files changed, 492 insertions, 0 deletions
diff --git a/accessible/base/nsAccessibilityService.h b/accessible/base/nsAccessibilityService.h new file mode 100644 index 0000000000..0b3f172f89 --- /dev/null +++ b/accessible/base/nsAccessibilityService.h @@ -0,0 +1,492 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __nsAccessibilityService_h__ +#define __nsAccessibilityService_h__ + +#include "mozilla/a11y/DocManager.h" +#include "mozilla/a11y/FocusManager.h" +#include "mozilla/a11y/Platform.h" +#include "mozilla/a11y/Role.h" +#include "mozilla/a11y/SelectionManager.h" +#include "mozilla/Preferences.h" + +#include "nsAtomHashKeys.h" +#include "nsIContent.h" +#include "nsIObserver.h" +#include "nsIAccessibleEvent.h" +#include "nsIEventListenerService.h" +#include "nsXULAppAPI.h" +#include "xpcAccessibilityService.h" + +class nsImageFrame; +class nsIArray; +class nsITreeView; + +namespace mozilla { + +class PresShell; +class Monitor; +namespace dom { +class DOMStringList; +class Element; +} // namespace dom + +namespace a11y { + +class AccAttributes; +class Accessible; +class ApplicationAccessible; +class xpcAccessibleApplication; + +/** + * Return focus manager. + */ +FocusManager* FocusMgr(); + +/** + * Return selection manager. + */ +SelectionManager* SelectionMgr(); + +/** + * Returns the application accessible. + */ +ApplicationAccessible* ApplicationAcc(); +xpcAccessibleApplication* XPCApplicationAcc(); + +typedef LocalAccessible*(New_Accessible)(mozilla::dom::Element* aElement, + LocalAccessible* aContext); + +// These fields are not `nsStaticAtom* const` because MSVC doesn't like it. +struct MarkupAttrInfo { + nsStaticAtom* name; + nsStaticAtom* value; + + nsStaticAtom* DOMAttrName; + nsStaticAtom* DOMAttrValue; +}; + +struct MarkupMapInfo { + nsStaticAtom* const tag; + New_Accessible* new_func; + a11y::role role; + MarkupAttrInfo attrs[4]; +}; + +struct XULMarkupMapInfo { + nsStaticAtom* const tag; + New_Accessible* new_func; +}; + +/** + * PREF_ACCESSIBILITY_FORCE_DISABLED preference change callback. + */ +void PrefChanged(const char* aPref, void* aClosure); + +/** + * Read and normalize PREF_ACCESSIBILITY_FORCE_DISABLED preference. + */ +EPlatformDisabledState ReadPlatformDisabledState(); + +} // namespace a11y +} // namespace mozilla + +class nsAccessibilityService final : public mozilla::a11y::DocManager, + public mozilla::a11y::FocusManager, + public mozilla::a11y::SelectionManager, + public nsIListenerChangeListener, + public nsIObserver { + public: + typedef mozilla::a11y::LocalAccessible LocalAccessible; + typedef mozilla::a11y::DocAccessible DocAccessible; + + // nsIListenerChangeListener + NS_IMETHOD ListenersChanged(nsIArray* aEventChanges) override; + + protected: + ~nsAccessibilityService(); + + public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIOBSERVER + + LocalAccessible* GetRootDocumentAccessible(mozilla::PresShell* aPresShell, + bool aCanCreate); + + /** + * Adds/remove ATK root accessible for gtk+ native window to/from children + * of the application accessible. + */ + LocalAccessible* AddNativeRootAccessible(void* aAtkAccessible); + void RemoveNativeRootAccessible(LocalAccessible* aRootAccessible); + + bool HasAccessible(nsINode* aDOMNode); + + /** + * Get a string equivalent for an accessible role value. + */ + void GetStringRole(uint32_t aRole, nsAString& aString); + + /** + * Get a string equivalent for an accessible state/extra state. + */ + already_AddRefed<mozilla::dom::DOMStringList> GetStringStates( + uint64_t aStates) const; + void GetStringStates(uint32_t aState, uint32_t aExtraState, + nsISupports** aStringStates); + + /** + * Get a string equivalent for an accessible event value. + */ + void GetStringEventType(uint32_t aEventType, nsAString& aString); + + /** + * Get a string equivalent for an accessible event value. + */ + void GetStringEventType(uint32_t aEventType, nsACString& aString); + + /** + * Get a string equivalent for an accessible relation type. + */ + void GetStringRelationType(uint32_t aRelationType, nsAString& aString); + + // nsAccesibilityService + /** + * Notification used to update the accessible tree when new content is + * inserted. + */ + void ContentRangeInserted(mozilla::PresShell* aPresShell, + nsIContent* aStartChild, nsIContent* aEndChild); + + /** + * Triggers a re-evaluation of the a11y tree of aContent after the next + * refresh. This is important because whether we create accessibles may + * depend on the frame tree / style. + */ + void ScheduleAccessibilitySubtreeUpdate(mozilla::PresShell* aPresShell, + nsIContent* aStartChild); + + /** + * Notification used to update the accessible tree when content is removed. + */ + void ContentRemoved(mozilla::PresShell* aPresShell, nsIContent* aChild); + + /** + * Notification used to invalidate the isLayoutTable cache. + */ + void TableLayoutGuessMaybeChanged(mozilla::PresShell* aPresShell, + nsIContent* aContent); + + /** + * Notifies when a combobox <option> text or label changes. + */ + void ComboboxOptionMaybeChanged(mozilla::PresShell*, + nsIContent* aMutatingNode); + + void UpdateText(mozilla::PresShell* aPresShell, nsIContent* aContent); + + /** + * Update XUL:tree accessible tree when treeview is changed. + */ + void TreeViewChanged(mozilla::PresShell* aPresShell, nsIContent* aContent, + nsITreeView* aView); + + /** + * Notify of input@type="element" value change. + */ + void RangeValueChanged(mozilla::PresShell* aPresShell, nsIContent* aContent); + + /** + * Update the image map. + */ + void UpdateImageMap(nsImageFrame* aImageFrame); + + /** + * Update the label accessible tree when rendered @value is changed. + */ + void UpdateLabelValue(mozilla::PresShell* aPresShell, nsIContent* aLabelElm, + const nsString& aNewValue); + + /** + * Notify accessibility that anchor jump has been accomplished to the given + * target. Used by layout. + */ + void NotifyOfAnchorJumpTo(nsIContent* aTarget); + + /** + * Notify that presshell is activated. + */ + void PresShellActivated(mozilla::PresShell* aPresShell); + + /** + * Recreate an accessible for the given content node in the presshell. + */ + void RecreateAccessible(mozilla::PresShell* aPresShell, nsIContent* aContent); + + void FireAccessibleEvent(uint32_t aEvent, LocalAccessible* aTarget); + + void NotifyOfPossibleBoundsChange(mozilla::PresShell* aPresShell, + nsIContent* aContent); + + void NotifyOfComputedStyleChange(mozilla::PresShell* aPresShell, + nsIContent* aContent); + + void NotifyOfTabPanelVisibilityChange(mozilla::PresShell* aPresShell, + mozilla::dom::Element* aPanel, + bool aVisible); + + void NotifyOfResolutionChange(mozilla::PresShell* aPresShell, + float aResolution); + + void NotifyOfDevPixelRatioChange(mozilla::PresShell* aPresShell, + int32_t aAppUnitsPerDevPixel); + + // nsAccessibiltiyService + + /** + * Return true if accessibility service has been shutdown. + */ + static bool IsShutdown() { return gConsumers == 0; }; + + /** + * Return true if there should be an image accessible for the given element. + */ + static bool ShouldCreateImgAccessible(mozilla::dom::Element* aElement, + DocAccessible* aDocument); + + /** + * Creates an accessible for the given DOM node. + * + * @param aNode [in] the given node + * @param aContext [in] context the accessible is created in + * @param aIsSubtreeHidden [out, optional] indicates whether the node's + * frame and its subtree is hidden + */ + LocalAccessible* CreateAccessible(nsINode* aNode, LocalAccessible* aContext, + bool* aIsSubtreeHidden = nullptr); + + mozilla::a11y::role MarkupRole(const nsIContent* aContent) const { + const mozilla::a11y::MarkupMapInfo* markupMap = + GetMarkupMapInfoFor(aContent); + return markupMap ? markupMap->role : mozilla::a11y::roles::NOTHING; + } + + /** + * Return the associated value for a given attribute if + * it appears in the MarkupMap. Otherwise, it returns null. This can be + * called with either an nsIContent or an Accessible. + */ + template <typename T> + nsStaticAtom* MarkupAttribute(T aSource, nsStaticAtom* aAtom) const { + const mozilla::a11y::MarkupMapInfo* markupMap = + GetMarkupMapInfoFor(aSource); + if (markupMap) { + for (size_t i = 0; i < mozilla::ArrayLength(markupMap->attrs); i++) { + const mozilla::a11y::MarkupAttrInfo* info = markupMap->attrs + i; + if (info->name == aAtom) { + return info->value; + } + } + } + return nullptr; + } + + /** + * Set the object attribute defined by markup for the given element. + */ + void MarkupAttributes(mozilla::a11y::Accessible* aAcc, + mozilla::a11y::AccAttributes* aAttributes) const; + + /** + * A list of possible accessibility service consumers. Accessibility service + * can only be shut down when there are no remaining consumers. + * + * eXPCOM - accessibility service is used by XPCOM. + * + * eMainProcess - accessibility service was started by main process in the + * content process. + * + * ePlatformAPI - accessibility service is used by the platform api in the + * main process. + */ + enum ServiceConsumer { + eXPCOM = 1 << 0, + eMainProcess = 1 << 1, + ePlatformAPI = 1 << 2, + }; + +#if defined(ANDROID) + static mozilla::Monitor& GetAndroidMonitor(); +#endif + + private: + // nsAccessibilityService creation is controlled by friend + // GetOrCreateAccService, keep constructors private. + nsAccessibilityService(); + nsAccessibilityService(const nsAccessibilityService&); + nsAccessibilityService& operator=(const nsAccessibilityService&); + + private: + /** + * Initialize accessibility service. + */ + bool Init(); + + /** + * Shutdowns accessibility service. + */ + void Shutdown(); + + /** + * Create an accessible whose type depends on the given frame. + */ + already_AddRefed<LocalAccessible> CreateAccessibleByFrameType( + nsIFrame* aFrame, nsIContent* aContent, LocalAccessible* aContext); + + /** + * Notify observers about change of the accessibility service's consumers. + */ + void NotifyOfConsumersChange(); + + /** + * Get a JSON string representing the accessibility service consumers. + */ + void GetConsumers(nsAString& aString); + + /** + * Set accessibility service consumers. + */ + void SetConsumers(uint32_t aConsumers, bool aNotify = true); + + /** + * Unset accessibility service consumers. + */ + void UnsetConsumers(uint32_t aConsumers); + + /** + * Reference for accessibility service instance. + */ + static nsAccessibilityService* gAccessibilityService; + + /** + * Reference for application accessible instance. + */ + static mozilla::a11y::ApplicationAccessible* gApplicationAccessible; + static mozilla::a11y::xpcAccessibleApplication* gXPCApplicationAccessible; + + /** + * Contains a set of accessibility service consumers. + */ + static uint32_t gConsumers; + + // Can be weak because all atoms are known static + using MarkupMap = nsTHashMap<nsAtom*, const mozilla::a11y::MarkupMapInfo*>; + MarkupMap mHTMLMarkupMap; + MarkupMap mMathMLMarkupMap; + + const mozilla::a11y::MarkupMapInfo* GetMarkupMapInfoFor( + const nsIContent* aContent) const { + if (aContent->IsHTMLElement()) { + return mHTMLMarkupMap.Get(aContent->NodeInfo()->NameAtom()); + } + if (aContent->IsMathMLElement()) { + return mMathMLMarkupMap.Get(aContent->NodeInfo()->NameAtom()); + } + // This function can be called by MarkupAttribute, etc. which might in turn + // be called on a XUL, SVG, etc. element. For example, this can happen + // with nsAccUtils::SetLiveContainerAttributes. + return nullptr; + } + + const mozilla::a11y::MarkupMapInfo* GetMarkupMapInfoFor( + mozilla::a11y::Accessible* aAcc) const; + + nsTHashMap<nsAtom*, const mozilla::a11y::XULMarkupMapInfo*> mXULMarkupMap; + + friend nsAccessibilityService* GetAccService(); + friend nsAccessibilityService* GetOrCreateAccService(uint32_t); + friend void MaybeShutdownAccService(uint32_t); + friend void mozilla::a11y::PrefChanged(const char*, void*); + friend mozilla::a11y::FocusManager* mozilla::a11y::FocusMgr(); + friend mozilla::a11y::SelectionManager* mozilla::a11y::SelectionMgr(); + friend mozilla::a11y::ApplicationAccessible* mozilla::a11y::ApplicationAcc(); + friend mozilla::a11y::xpcAccessibleApplication* + mozilla::a11y::XPCApplicationAcc(); + friend class xpcAccessibilityService; +}; + +/** + * Return the accessibility service instance. (Handy global function) + */ +inline nsAccessibilityService* GetAccService() { + return nsAccessibilityService::gAccessibilityService; +} + +/** + * Return accessibility service instance; creating one if necessary. + */ +nsAccessibilityService* GetOrCreateAccService( + uint32_t aNewConsumer = nsAccessibilityService::ePlatformAPI); + +/** + * Shutdown accessibility service if needed. + */ +void MaybeShutdownAccService(uint32_t aFormerConsumer); + +/** + * Return true if we're in a content process and not B2G. + */ +inline bool IPCAccessibilityActive() { return XRE_IsContentProcess(); } + +/** + * Map nsIAccessibleEvents constants to strings. Used by + * nsAccessibilityService::GetStringEventType() method. + */ +static const char kEventTypeNames[][40] = { + "unknown", // + "show", // EVENT_SHOW + "hide", // EVENT_HIDE + "reorder", // EVENT_REORDER + "focus", // EVENT_FOCUS + "state change", // EVENT_STATE_CHANGE + "name changed", // EVENT_NAME_CHANGE + "description change", // EVENT_DESCRIPTION_CHANGE + "value change", // EVENT_VALUE_CHANGE + "selection", // EVENT_SELECTION + "selection add", // EVENT_SELECTION_ADD + "selection remove", // EVENT_SELECTION_REMOVE + "selection within", // EVENT_SELECTION_WITHIN + "alert", // EVENT_ALERT + "menu start", // EVENT_MENU_START + "menu end", // EVENT_MENU_END + "menupopup start", // EVENT_MENUPOPUP_START + "menupopup end", // EVENT_MENUPOPUP_END + "dragdrop start", // EVENT_DRAGDROP_START + "scrolling start", // EVENT_SCROLLING_START + "scrolling end", // EVENT_SCROLLING_END + "document load complete", // EVENT_DOCUMENT_LOAD_COMPLETE + "document reload", // EVENT_DOCUMENT_RELOAD + "document load stopped", // EVENT_DOCUMENT_LOAD_STOPPED + "text attribute changed", // EVENT_TEXT_ATTRIBUTE_CHANGED + "text caret moved", // EVENT_TEXT_CARET_MOVED + "text inserted", // EVENT_TEXT_INSERTED + "text removed", // EVENT_TEXT_REMOVED + "text selection changed", // EVENT_TEXT_SELECTION_CHANGED + "window activate", // EVENT_WINDOW_ACTIVATE + "window deactivate", // EVENT_WINDOW_DEACTIVATE + "window maximize", // EVENT_WINDOW_MAXIMIZE + "window minimize", // EVENT_WINDOW_MINIMIZE + "window restore", // EVENT_WINDOW_RESTORE + "object attribute changed", // EVENT_OBJECT_ATTRIBUTE_CHANGED + "text value change", // EVENT_TEXT_VALUE_CHANGE + "scrolling", // EVENT_SCROLLING + "announcement", // EVENT_ANNOUNCEMENT + "live region added", // EVENT_LIVE_REGION_ADDED + "live region removed", // EVENT_LIVE_REGION_REMOVED + "inner reorder", // EVENT_INNER_REORDER +}; + +#endif |