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 COMPUTER, 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 COMPUTER, 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 static PassOwnPtr<AXComputedObjectAttributeCache> create() { return adoptPtr(new AXComputedObjectAttributeCache()); } 58 59 AccessibilityObjectInclusion getIgnored(AXID) const; 60 void setIgnored(AXID, AccessibilityObjectInclusion); 61 62private: 63 AXComputedObjectAttributeCache() { } 64 65 struct CachedAXObjectAttributes { 66 CachedAXObjectAttributes() : ignored(DefaultBehavior) { } 67 68 AccessibilityObjectInclusion ignored; 69 }; 70 71 HashMap<AXID, CachedAXObjectAttributes> m_idMapping; 72}; 73 74enum PostType { PostSynchronously, PostAsynchronously }; 75 76class AXObjectCache { 77 WTF_MAKE_NONCOPYABLE(AXObjectCache); WTF_MAKE_FAST_ALLOCATED; 78public: 79 explicit AXObjectCache(const Document*); 80 ~AXObjectCache(); 81 82 static AccessibilityObject* focusedUIElementForPage(const Page*); 83 84 // Returns the root object for the entire document. 85 AccessibilityObject* rootObject(); 86 // Returns the root object for a specific frame. 87 AccessibilityObject* rootObjectForFrame(Frame*); 88 89 // For AX objects with elements that back them. 90 AccessibilityObject* getOrCreate(RenderObject*); 91 AccessibilityObject* getOrCreate(Widget*); 92 AccessibilityObject* getOrCreate(Node*); 93 94 // used for objects without backing elements 95 AccessibilityObject* getOrCreate(AccessibilityRole); 96 97 // will only return the AccessibilityObject if it already exists 98 AccessibilityObject* get(RenderObject*); 99 AccessibilityObject* get(Widget*); 100 AccessibilityObject* get(Node*); 101 102 void remove(RenderObject*); 103 void remove(Node*); 104 void remove(Widget*); 105 void remove(AXID); 106 107 void detachWrapper(AccessibilityObject*); 108 void attachWrapper(AccessibilityObject*); 109 void childrenChanged(Node*); 110 void childrenChanged(RenderObject*); 111 void childrenChanged(AccessibilityObject*); 112 void checkedStateChanged(Node*); 113 void selectedChildrenChanged(Node*); 114 void selectedChildrenChanged(RenderObject*); 115 // Called by a node when text or a text equivalent (e.g. alt) attribute is changed. 116 void textChanged(Node*); 117 void textChanged(RenderObject*); 118 // Called when a node has just been attached, so we can make sure we have the right subclass of AccessibilityObject. 119 void updateCacheAfterNodeIsAttached(Node*); 120 121 void handleActiveDescendantChanged(Node*); 122 void handleAriaRoleChanged(Node*); 123 void handleFocusedUIElementChanged(Node* oldFocusedNode, Node* newFocusedNode); 124 void handleScrolledToAnchor(const Node* anchorNode); 125 void handleAriaExpandedChange(Node*); 126 void handleScrollbarUpdate(ScrollView*); 127 128 void handleAttributeChanged(const QualifiedName& attrName, Element*); 129 void recomputeIsIgnored(RenderObject* renderer); 130 131#if HAVE(ACCESSIBILITY) 132 static void enableAccessibility() { gAccessibilityEnabled = true; } 133 // Enhanced user interface accessibility can be toggled by the assistive technology. 134 static void setEnhancedUserInterfaceAccessibility(bool flag) { gAccessibilityEnhancedUserInterfaceEnabled = flag; } 135 136 static bool accessibilityEnabled() { return gAccessibilityEnabled; } 137 static bool accessibilityEnhancedUserInterfaceEnabled() { return gAccessibilityEnhancedUserInterfaceEnabled; } 138#else 139 static void enableAccessibility() { } 140 static void setEnhancedUserInterfaceAccessibility(bool) { } 141 static bool accessibilityEnabled() { return false; } 142 static bool accessibilityEnhancedUserInterfaceEnabled() { return false; } 143#endif 144 145 void removeAXID(AccessibilityObject*); 146 bool isIDinUse(AXID id) const { return m_idsInUse.contains(id); } 147 148 Element* rootAXEditableElement(Node*); 149 const Element* rootAXEditableElement(const Node*); 150 bool nodeIsTextControl(const Node*); 151 152 AXID platformGenerateAXID() const; 153 AccessibilityObject* objectFromAXID(AXID id) const { return m_objects.get(id); } 154 155 // Text marker utilities. 156 void textMarkerDataForVisiblePosition(TextMarkerData&, const VisiblePosition&); 157 VisiblePosition visiblePositionForTextMarkerData(TextMarkerData&); 158 159 enum AXNotification { 160 AXActiveDescendantChanged, 161 AXAutocorrectionOccured, 162 AXCheckedStateChanged, 163 AXChildrenChanged, 164 AXFocusedUIElementChanged, 165 AXLayoutComplete, 166 AXLoadComplete, 167 AXSelectedChildrenChanged, 168 AXSelectedTextChanged, 169 AXValueChanged, 170 AXScrolledToAnchor, 171 AXLiveRegionChanged, 172 AXMenuListItemSelected, 173 AXMenuListValueChanged, 174 AXRowCountChanged, 175 AXRowCollapsed, 176 AXRowExpanded, 177 AXInvalidStatusChanged, 178 AXTextChanged, 179 AXAriaAttributeChanged 180 }; 181 182 void postNotification(RenderObject*, AXNotification, bool postToElement, PostType = PostAsynchronously); 183 void postNotification(Node*, AXNotification, bool postToElement, PostType = PostAsynchronously); 184 void postNotification(AccessibilityObject*, Document*, AXNotification, bool postToElement, PostType = PostAsynchronously); 185 186 enum AXTextChange { 187 AXTextInserted, 188 AXTextDeleted, 189 }; 190 191 void nodeTextChangeNotification(Node*, AXTextChange, unsigned offset, const String&); 192 193 enum AXLoadingEvent { 194 AXLoadingStarted, 195 AXLoadingReloaded, 196 AXLoadingFailed, 197 AXLoadingFinished 198 }; 199 200 void frameLoadingEventNotification(Frame*, AXLoadingEvent); 201 202 bool nodeHasRole(Node*, const AtomicString& role); 203 204 void startCachingComputedObjectAttributesUntilTreeMutates(); 205 void stopCachingComputedObjectAttributes(); 206 207 AXComputedObjectAttributeCache* computedObjectAttributeCache() { return m_computedObjectAttributeCache.get(); } 208 209protected: 210 void postPlatformNotification(AccessibilityObject*, AXNotification); 211 void nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned offset, const String&); 212 void frameLoadingEventPlatformNotification(AccessibilityObject*, AXLoadingEvent); 213 void textChanged(AccessibilityObject*); 214 void labelChanged(Element*); 215 216 // This is a weak reference cache for knowing if Nodes used by TextMarkers are valid. 217 void setNodeInUse(Node* n) { m_textMarkerNodes.add(n); } 218 void removeNodeForUse(Node* n) { m_textMarkerNodes.remove(n); } 219 bool isNodeInUse(Node* n) { return m_textMarkerNodes.contains(n); } 220 221private: 222 Document* m_document; 223 HashMap<AXID, RefPtr<AccessibilityObject> > m_objects; 224 HashMap<RenderObject*, AXID> m_renderObjectMapping; 225 HashMap<Widget*, AXID> m_widgetObjectMapping; 226 HashMap<Node*, AXID> m_nodeObjectMapping; 227 HashSet<Node*> m_textMarkerNodes; 228 OwnPtr<AXComputedObjectAttributeCache> m_computedObjectAttributeCache; 229 static bool gAccessibilityEnabled; 230 static bool gAccessibilityEnhancedUserInterfaceEnabled; 231 232 HashSet<AXID> m_idsInUse; 233 234 Timer<AXObjectCache> m_notificationPostTimer; 235 Vector<pair<RefPtr<AccessibilityObject>, AXNotification> > m_notificationsToPost; 236 void notificationPostTimerFired(Timer<AXObjectCache>*); 237 238 static AccessibilityObject* focusedImageMapUIElement(HTMLAreaElement*); 239 240 AXID getAXID(AccessibilityObject*); 241}; 242 243class AXAttributeCacheEnabler 244{ 245public: 246 explicit AXAttributeCacheEnabler(AXObjectCache *cache); 247 ~AXAttributeCacheEnabler(); 248 249private: 250 AXObjectCache* m_cache; 251}; 252 253bool nodeHasRole(Node*, const String& role); 254// This will let you know if aria-hidden was explicitly set to false. 255bool isNodeAriaVisible(Node*); 256 257#if !HAVE(ACCESSIBILITY) 258inline AccessibilityObjectInclusion AXComputedObjectAttributeCache::getIgnored(AXID) const { return DefaultBehavior; } 259inline void AXComputedObjectAttributeCache::setIgnored(AXID, AccessibilityObjectInclusion) { } 260inline AXObjectCache::AXObjectCache(const Document* doc) : m_document(const_cast<Document*>(doc)), m_notificationPostTimer(this, 0) { } 261inline AXObjectCache::~AXObjectCache() { } 262inline AccessibilityObject* AXObjectCache::focusedUIElementForPage(const Page*) { return 0; } 263inline AccessibilityObject* AXObjectCache::get(RenderObject*) { return 0; } 264inline AccessibilityObject* AXObjectCache::get(Node*) { return 0; } 265inline AccessibilityObject* AXObjectCache::get(Widget*) { return 0; } 266inline AccessibilityObject* AXObjectCache::getOrCreate(AccessibilityRole) { return 0; } 267inline AccessibilityObject* AXObjectCache::getOrCreate(RenderObject*) { return 0; } 268inline AccessibilityObject* AXObjectCache::getOrCreate(Node*) { return 0; } 269inline AccessibilityObject* AXObjectCache::getOrCreate(Widget*) { return 0; } 270inline AccessibilityObject* AXObjectCache::rootObject() { return 0; } 271inline AccessibilityObject* AXObjectCache::rootObjectForFrame(Frame*) { return 0; } 272inline Element* AXObjectCache::rootAXEditableElement(Node*) { return 0; } 273inline bool nodeHasRole(Node*, const String&) { return false; } 274inline void AXObjectCache::startCachingComputedObjectAttributesUntilTreeMutates() { } 275inline void AXObjectCache::stopCachingComputedObjectAttributes() { } 276inline bool isNodeAriaVisible(Node*) { return true; } 277inline const Element* AXObjectCache::rootAXEditableElement(const Node*) { return 0; } 278inline void AXObjectCache::attachWrapper(AccessibilityObject*) { } 279inline void AXObjectCache::checkedStateChanged(Node*) { } 280inline void AXObjectCache::childrenChanged(RenderObject*) { } 281inline void AXObjectCache::childrenChanged(Node*) { } 282inline void AXObjectCache::childrenChanged(AccessibilityObject*) { } 283inline void AXObjectCache::textChanged(RenderObject*) { } 284inline void AXObjectCache::textChanged(Node*) { } 285inline void AXObjectCache::textChanged(AccessibilityObject*) { } 286inline void AXObjectCache::updateCacheAfterNodeIsAttached(Node*) { } 287inline void AXObjectCache::detachWrapper(AccessibilityObject*) { } 288inline void AXObjectCache::frameLoadingEventNotification(Frame*, AXLoadingEvent) { } 289inline void AXObjectCache::frameLoadingEventPlatformNotification(AccessibilityObject*, AXLoadingEvent) { } 290inline void AXObjectCache::handleActiveDescendantChanged(Node*) { } 291inline void AXObjectCache::handleAriaExpandedChange(Node*) { } 292inline void AXObjectCache::handleAriaRoleChanged(Node*) { } 293inline void AXObjectCache::handleFocusedUIElementChanged(Node*, Node*) { } 294inline void AXObjectCache::handleScrollbarUpdate(ScrollView*) { } 295inline void AXObjectCache::handleAttributeChanged(const QualifiedName&, Element*) { } 296inline void AXObjectCache::recomputeIsIgnored(RenderObject*) { } 297inline void AXObjectCache::handleScrolledToAnchor(const Node*) { } 298inline void AXObjectCache::nodeTextChangeNotification(Node*, AXTextChange, unsigned, const String&) { } 299inline void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned, const String&) { } 300inline void AXObjectCache::postNotification(AccessibilityObject*, Document*, AXNotification, bool, PostType) { } 301inline void AXObjectCache::postNotification(RenderObject*, AXNotification, bool, PostType) { } 302inline void AXObjectCache::postNotification(Node*, AXNotification, bool, PostType) { } 303inline void AXObjectCache::postPlatformNotification(AccessibilityObject*, AXNotification) { } 304inline void AXObjectCache::remove(AXID) { } 305inline void AXObjectCache::remove(RenderObject*) { } 306inline void AXObjectCache::remove(Node*) { } 307inline void AXObjectCache::remove(Widget*) { } 308inline void AXObjectCache::selectedChildrenChanged(RenderObject*) { } 309inline void AXObjectCache::selectedChildrenChanged(Node*) { } 310#endif 311 312} 313 314#endif 315