1/* 2 * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#ifndef AXObjectCache_h 27#define AXObjectCache_h 28 29#include "AccessibilityObject.h" 30#include "Timer.h" 31#include <limits.h> 32#include <wtf/Forward.h> 33#include <wtf/HashMap.h> 34#include <wtf/HashSet.h> 35#include <wtf/RefPtr.h> 36 37namespace WebCore { 38 39class Document; 40class HTMLAreaElement; 41class Node; 42class Page; 43class RenderObject; 44class ScrollView; 45class VisiblePosition; 46class Widget; 47 48struct TextMarkerData { 49 AXID axID; 50 Node* node; 51 int offset; 52 EAffinity affinity; 53}; 54 55class AXComputedObjectAttributeCache { 56public: 57 AccessibilityObjectInclusion getIgnored(AXID) const; 58 void setIgnored(AXID, AccessibilityObjectInclusion); 59 60private: 61 struct CachedAXObjectAttributes { 62 CachedAXObjectAttributes() : ignored(DefaultBehavior) { } 63 64 AccessibilityObjectInclusion ignored; 65 }; 66 67 HashMap<AXID, CachedAXObjectAttributes> m_idMapping; 68}; 69 70enum PostTarget { TargetElement, TargetObservableParent }; 71 72enum PostType { PostSynchronously, PostAsynchronously }; 73 74class AXObjectCache { 75 WTF_MAKE_NONCOPYABLE(AXObjectCache); WTF_MAKE_FAST_ALLOCATED; 76public: 77 explicit AXObjectCache(Document&); 78 ~AXObjectCache(); 79 80 static AccessibilityObject* focusedUIElementForPage(const Page*); 81 82 // Returns the root object for the entire document. 83 AccessibilityObject* rootObject(); 84 // Returns the root object for a specific frame. 85 AccessibilityObject* rootObjectForFrame(Frame*); 86 87 // For AX objects with elements that back them. 88 AccessibilityObject* getOrCreate(RenderObject*); 89 AccessibilityObject* getOrCreate(Widget*); 90 AccessibilityObject* getOrCreate(Node*); 91 92 // used for objects without backing elements 93 AccessibilityObject* getOrCreate(AccessibilityRole); 94 95 // will only return the AccessibilityObject if it already exists 96 AccessibilityObject* get(RenderObject*); 97 AccessibilityObject* get(Widget*); 98 AccessibilityObject* get(Node*); 99 100 void remove(RenderObject*); 101 void remove(Node*); 102 void remove(Widget*); 103 void remove(AXID); 104 105 void detachWrapper(AccessibilityObject*, AccessibilityDetachmentType); 106 void attachWrapper(AccessibilityObject*); 107 void childrenChanged(Node*, Node* newChild = nullptr); 108 void childrenChanged(RenderObject*, RenderObject* newChild = nullptr); 109 void childrenChanged(AccessibilityObject*); 110 void checkedStateChanged(Node*); 111 void selectedChildrenChanged(Node*); 112 void selectedChildrenChanged(RenderObject*); 113 // Called by a node when text or a text equivalent (e.g. alt) attribute is changed. 114 void textChanged(Node*); 115 void textChanged(RenderObject*); 116 // Called when a node has just been attached, so we can make sure we have the right subclass of AccessibilityObject. 117 void updateCacheAfterNodeIsAttached(Node*); 118 119 void handleActiveDescendantChanged(Node*); 120 void handleAriaRoleChanged(Node*); 121 void handleFocusedUIElementChanged(Node* oldFocusedNode, Node* newFocusedNode); 122 void handleScrolledToAnchor(const Node* anchorNode); 123 void handleAriaExpandedChange(Node*); 124 void handleScrollbarUpdate(ScrollView*); 125 126 void handleAttributeChanged(const QualifiedName& attrName, Element*); 127 void recomputeIsIgnored(RenderObject* renderer); 128 129#if HAVE(ACCESSIBILITY) 130 static void enableAccessibility(); 131 static void disableAccessibility(); 132 133 // Enhanced user interface accessibility can be toggled by the assistive technology. 134 static void setEnhancedUserInterfaceAccessibility(bool flag); 135 136 static bool accessibilityEnabled() { return gAccessibilityEnabled; } 137 static bool accessibilityEnhancedUserInterfaceEnabled() { return gAccessibilityEnhancedUserInterfaceEnabled; } 138#else 139 static void enableAccessibility() { } 140 static void disableAccessibility() { } 141 static void setEnhancedUserInterfaceAccessibility(bool) { } 142 static bool accessibilityEnabled() { return false; } 143 static bool accessibilityEnhancedUserInterfaceEnabled() { return false; } 144#endif 145 146 void removeAXID(AccessibilityObject*); 147 bool isIDinUse(AXID id) const { return m_idsInUse.contains(id); } 148 149 Element* rootAXEditableElement(Node*); 150 const Element* rootAXEditableElement(const Node*); 151 bool nodeIsTextControl(const Node*); 152 153 AXID platformGenerateAXID() const; 154 AccessibilityObject* objectFromAXID(AXID id) const { return m_objects.get(id); } 155 156 // Text marker utilities. 157 void textMarkerDataForVisiblePosition(TextMarkerData&, const VisiblePosition&); 158 VisiblePosition visiblePositionForTextMarkerData(TextMarkerData&); 159 160 enum AXNotification { 161 AXActiveDescendantChanged, 162 AXAutocorrectionOccured, 163 AXCheckedStateChanged, 164 AXChildrenChanged, 165 AXFocusedUIElementChanged, 166 AXLayoutComplete, 167 AXLoadComplete, 168 AXSelectedChildrenChanged, 169 AXSelectedTextChanged, 170 AXValueChanged, 171 AXScrolledToAnchor, 172 AXLiveRegionCreated, 173 AXLiveRegionChanged, 174 AXMenuListItemSelected, 175 AXMenuListValueChanged, 176 AXMenuClosed, 177 AXMenuOpened, 178 AXRowCountChanged, 179 AXRowCollapsed, 180 AXRowExpanded, 181 AXExpandedChanged, 182 AXInvalidStatusChanged, 183 AXTextChanged, 184 AXAriaAttributeChanged, 185 AXElementBusyChanged 186 }; 187 188 void postNotification(RenderObject*, AXNotification, PostTarget = TargetElement, PostType = PostAsynchronously); 189 void postNotification(Node*, AXNotification, PostTarget = TargetElement, PostType = PostAsynchronously); 190 void postNotification(AccessibilityObject*, Document*, AXNotification, PostTarget = TargetElement, PostType = PostAsynchronously); 191 192 enum AXTextChange { 193 AXTextInserted, 194 AXTextDeleted, 195 }; 196 197 void nodeTextChangeNotification(Node*, AXTextChange, unsigned offset, const String&); 198 199 enum AXLoadingEvent { 200 AXLoadingStarted, 201 AXLoadingReloaded, 202 AXLoadingFailed, 203 AXLoadingFinished 204 }; 205 206 void frameLoadingEventNotification(Frame*, AXLoadingEvent); 207 208 void clearTextMarkerNodesInUse(Document*); 209 210 void startCachingComputedObjectAttributesUntilTreeMutates(); 211 void stopCachingComputedObjectAttributes(); 212 213 AXComputedObjectAttributeCache* computedObjectAttributeCache() { return m_computedObjectAttributeCache.get(); } 214 215 Document& document() const { return m_document; } 216 217protected: 218 void postPlatformNotification(AccessibilityObject*, AXNotification); 219 void platformHandleFocusedUIElementChanged(Node* oldFocusedNode, Node* newFocusedNode); 220 221 void nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned offset, const String&); 222 void frameLoadingEventPlatformNotification(AccessibilityObject*, AXLoadingEvent); 223 void textChanged(AccessibilityObject*); 224 void labelChanged(Element*); 225 226 // This is a weak reference cache for knowing if Nodes used by TextMarkers are valid. 227 void setNodeInUse(Node* n) { m_textMarkerNodes.add(n); } 228 void removeNodeForUse(Node* n) { m_textMarkerNodes.remove(n); } 229 bool isNodeInUse(Node* n) { return m_textMarkerNodes.contains(n); } 230 231private: 232 Document& m_document; 233 HashMap<AXID, RefPtr<AccessibilityObject>> m_objects; 234 HashMap<RenderObject*, AXID> m_renderObjectMapping; 235 HashMap<Widget*, AXID> m_widgetObjectMapping; 236 HashMap<Node*, AXID> m_nodeObjectMapping; 237 HashSet<Node*> m_textMarkerNodes; 238 std::unique_ptr<AXComputedObjectAttributeCache> m_computedObjectAttributeCache; 239 static bool gAccessibilityEnabled; 240 static bool gAccessibilityEnhancedUserInterfaceEnabled; 241 242 HashSet<AXID> m_idsInUse; 243 244 Timer<AXObjectCache> m_notificationPostTimer; 245 Vector<std::pair<RefPtr<AccessibilityObject>, AXNotification>> m_notificationsToPost; 246 void notificationPostTimerFired(Timer<AXObjectCache>&); 247 void handleMenuOpened(Node*); 248 void handleLiveRegionCreated(Node*); 249 void handleMenuItemSelected(Node*); 250 251 static AccessibilityObject* focusedImageMapUIElement(HTMLAreaElement*); 252 253 AXID getAXID(AccessibilityObject*); 254}; 255 256class AXAttributeCacheEnabler 257{ 258public: 259 explicit AXAttributeCacheEnabler(AXObjectCache *cache); 260 ~AXAttributeCacheEnabler(); 261 262private: 263 AXObjectCache* m_cache; 264}; 265 266bool nodeHasRole(Node*, const String& role); 267// This will let you know if aria-hidden was explicitly set to false. 268bool isNodeAriaVisible(Node*); 269 270#if !HAVE(ACCESSIBILITY) 271inline AccessibilityObjectInclusion AXComputedObjectAttributeCache::getIgnored(AXID) const { return DefaultBehavior; } 272inline void AXComputedObjectAttributeCache::setIgnored(AXID, AccessibilityObjectInclusion) { } 273inline AXObjectCache::AXObjectCache(Document& document) : m_document(document), m_notificationPostTimer(this, (Timer<AXObjectCache>::TimerFiredFunction) nullptr) { } 274inline AXObjectCache::~AXObjectCache() { } 275inline AccessibilityObject* AXObjectCache::focusedUIElementForPage(const Page*) { return 0; } 276inline AccessibilityObject* AXObjectCache::get(RenderObject*) { return 0; } 277inline AccessibilityObject* AXObjectCache::get(Node*) { return 0; } 278inline AccessibilityObject* AXObjectCache::get(Widget*) { return 0; } 279inline AccessibilityObject* AXObjectCache::getOrCreate(AccessibilityRole) { return 0; } 280inline AccessibilityObject* AXObjectCache::getOrCreate(RenderObject*) { return 0; } 281inline AccessibilityObject* AXObjectCache::getOrCreate(Node*) { return 0; } 282inline AccessibilityObject* AXObjectCache::getOrCreate(Widget*) { return 0; } 283inline AccessibilityObject* AXObjectCache::rootObject() { return 0; } 284inline AccessibilityObject* AXObjectCache::rootObjectForFrame(Frame*) { return 0; } 285inline Element* AXObjectCache::rootAXEditableElement(Node*) { return 0; } 286inline bool nodeHasRole(Node*, const String&) { return false; } 287inline void AXObjectCache::startCachingComputedObjectAttributesUntilTreeMutates() { } 288inline void AXObjectCache::stopCachingComputedObjectAttributes() { } 289inline bool isNodeAriaVisible(Node*) { return true; } 290inline const Element* AXObjectCache::rootAXEditableElement(const Node*) { return 0; } 291inline void AXObjectCache::attachWrapper(AccessibilityObject*) { } 292inline void AXObjectCache::checkedStateChanged(Node*) { } 293inline void AXObjectCache::childrenChanged(RenderObject*, RenderObject*) { } 294inline void AXObjectCache::childrenChanged(Node*, Node*) { } 295inline void AXObjectCache::childrenChanged(AccessibilityObject*) { } 296inline void AXObjectCache::textChanged(RenderObject*) { } 297inline void AXObjectCache::textChanged(Node*) { } 298inline void AXObjectCache::textChanged(AccessibilityObject*) { } 299inline void AXObjectCache::updateCacheAfterNodeIsAttached(Node*) { } 300inline void AXObjectCache::detachWrapper(AccessibilityObject*, AccessibilityDetachmentType) { } 301inline void AXObjectCache::frameLoadingEventNotification(Frame*, AXLoadingEvent) { } 302inline void AXObjectCache::frameLoadingEventPlatformNotification(AccessibilityObject*, AXLoadingEvent) { } 303inline void AXObjectCache::handleActiveDescendantChanged(Node*) { } 304inline void AXObjectCache::handleAriaExpandedChange(Node*) { } 305inline void AXObjectCache::handleAriaRoleChanged(Node*) { } 306inline void AXObjectCache::handleFocusedUIElementChanged(Node*, Node*) { } 307inline void AXObjectCache::handleScrollbarUpdate(ScrollView*) { } 308inline void AXObjectCache::handleAttributeChanged(const QualifiedName&, Element*) { } 309inline void AXObjectCache::recomputeIsIgnored(RenderObject*) { } 310inline void AXObjectCache::handleScrolledToAnchor(const Node*) { } 311inline void AXObjectCache::nodeTextChangeNotification(Node*, AXTextChange, unsigned, const String&) { } 312inline void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned, const String&) { } 313inline void AXObjectCache::postNotification(AccessibilityObject*, Document*, AXNotification, PostTarget, PostType) { } 314inline void AXObjectCache::postNotification(RenderObject*, AXNotification, PostTarget, PostType) { } 315inline void AXObjectCache::postNotification(Node*, AXNotification, PostTarget, PostType) { } 316inline void AXObjectCache::postPlatformNotification(AccessibilityObject*, AXNotification) { } 317inline void AXObjectCache::remove(AXID) { } 318inline void AXObjectCache::remove(RenderObject*) { } 319inline void AXObjectCache::remove(Node*) { } 320inline void AXObjectCache::remove(Widget*) { } 321inline void AXObjectCache::selectedChildrenChanged(RenderObject*) { } 322inline void AXObjectCache::selectedChildrenChanged(Node*) { } 323#endif 324 325} 326 327#endif 328