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 "core/accessibility/AccessibilityObject.h" 30 #include "core/platform/Timer.h" 31 #include "wtf/Forward.h" 32 #include "wtf/HashMap.h" 33 #include "wtf/HashSet.h" 34 #include "wtf/RefPtr.h" 35 36 namespace WebCore { 37 38 class Document; 39 class HTMLAreaElement; 40 class Node; 41 class Page; 42 class RenderObject; 43 class ScrollView; 44 class VisiblePosition; 45 class Widget; 46 47 struct TextMarkerData { 48 AXID axID; 49 Node* node; 50 int offset; 51 EAffinity affinity; 52 }; 53 54 class AXComputedObjectAttributeCache { 55 public: 56 static PassOwnPtr<AXComputedObjectAttributeCache> create() { return adoptPtr(new AXComputedObjectAttributeCache()); } 57 58 AccessibilityObjectInclusion getIgnored(AXID) const; 59 void setIgnored(AXID, AccessibilityObjectInclusion); 60 61 private: 62 AXComputedObjectAttributeCache() { } 63 64 struct CachedAXObjectAttributes { 65 CachedAXObjectAttributes() : ignored(DefaultBehavior) { } 66 67 AccessibilityObjectInclusion ignored; 68 }; 69 70 HashMap<AXID, CachedAXObjectAttributes> m_idMapping; 71 }; 72 73 enum PostType { PostSynchronously, PostAsynchronously }; 74 75 class AXObjectCache { 76 WTF_MAKE_NONCOPYABLE(AXObjectCache); WTF_MAKE_FAST_ALLOCATED; 77 public: 78 explicit AXObjectCache(const Document*); 79 ~AXObjectCache(); 80 81 static AccessibilityObject* focusedUIElementForPage(const Page*); 82 83 // Returns the root object for the entire document. 84 AccessibilityObject* rootObject(); 85 86 // For AX objects with elements that back them. 87 AccessibilityObject* getOrCreate(RenderObject*); 88 AccessibilityObject* getOrCreate(Widget*); 89 AccessibilityObject* getOrCreate(Node*); 90 91 // used for objects without backing elements 92 AccessibilityObject* getOrCreate(AccessibilityRole); 93 94 // will only return the AccessibilityObject if it already exists 95 AccessibilityObject* get(RenderObject*); 96 AccessibilityObject* get(Widget*); 97 AccessibilityObject* get(Node*); 98 99 void remove(RenderObject*); 100 void remove(Node*); 101 void remove(Widget*); 102 void remove(AXID); 103 104 void detachWrapper(AccessibilityObject*); 105 void attachWrapper(AccessibilityObject*); 106 void childrenChanged(Node*); 107 void childrenChanged(RenderObject*); 108 void childrenChanged(AccessibilityObject*); 109 void checkedStateChanged(Node*); 110 void selectedChildrenChanged(Node*); 111 void selectedChildrenChanged(RenderObject*); 112 void selectionChanged(Node*); 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() { gAccessibilityEnabled = true; } 131 static bool accessibilityEnabled() { return gAccessibilityEnabled; } 132 #else 133 static void enableAccessibility() { } 134 static bool accessibilityEnabled() { return false; } 135 #endif 136 137 void removeAXID(AccessibilityObject*); 138 bool isIDinUse(AXID id) const { return m_idsInUse.contains(id); } 139 140 Element* rootAXEditableElement(Node*); 141 const Element* rootAXEditableElement(const Node*); 142 bool nodeIsTextControl(const Node*); 143 144 AXID platformGenerateAXID() const; 145 AccessibilityObject* objectFromAXID(AXID id) const { return m_objects.get(id); } 146 147 // Text marker utilities. 148 void textMarkerDataForVisiblePosition(TextMarkerData&, const VisiblePosition&); 149 VisiblePosition visiblePositionForTextMarkerData(TextMarkerData&); 150 151 enum AXNotification { 152 AXActiveDescendantChanged, 153 AXAutocorrectionOccured, 154 AXCheckedStateChanged, 155 AXChildrenChanged, 156 AXFocusedUIElementChanged, 157 AXLayoutComplete, 158 AXLoadComplete, 159 AXSelectedChildrenChanged, 160 AXSelectedTextChanged, 161 AXValueChanged, 162 AXScrolledToAnchor, 163 AXLiveRegionChanged, 164 AXMenuListItemSelected, 165 AXMenuListValueChanged, 166 AXRowCountChanged, 167 AXRowCollapsed, 168 AXRowExpanded, 169 AXInvalidStatusChanged, 170 AXTextChanged, 171 AXAriaAttributeChanged 172 }; 173 174 void postNotification(RenderObject*, AXNotification, bool postToElement, PostType = PostAsynchronously); 175 void postNotification(Node*, AXNotification, bool postToElement, PostType = PostAsynchronously); 176 void postNotification(AccessibilityObject*, Document*, AXNotification, bool postToElement, PostType = PostAsynchronously); 177 178 enum AXTextChange { 179 AXTextInserted, 180 AXTextDeleted, 181 }; 182 183 void nodeTextChangeNotification(Node*, AXTextChange, unsigned offset, const String&); 184 bool nodeHasRole(Node*, const AtomicString& role); 185 186 void startCachingComputedObjectAttributesUntilTreeMutates(); 187 void stopCachingComputedObjectAttributes(); 188 189 AXComputedObjectAttributeCache* computedObjectAttributeCache() { return m_computedObjectAttributeCache.get(); } 190 191 protected: 192 void postPlatformNotification(AccessibilityObject*, AXNotification); 193 void nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned offset, const String&); 194 void textChanged(AccessibilityObject*); 195 void labelChanged(Element*); 196 197 // This is a weak reference cache for knowing if Nodes used by TextMarkers are valid. 198 void setNodeInUse(Node* n) { m_textMarkerNodes.add(n); } 199 void removeNodeForUse(Node* n) { m_textMarkerNodes.remove(n); } 200 bool isNodeInUse(Node* n) { return m_textMarkerNodes.contains(n); } 201 202 private: 203 Document* m_document; 204 HashMap<AXID, RefPtr<AccessibilityObject> > m_objects; 205 HashMap<RenderObject*, AXID> m_renderObjectMapping; 206 HashMap<Widget*, AXID> m_widgetObjectMapping; 207 HashMap<Node*, AXID> m_nodeObjectMapping; 208 HashSet<Node*> m_textMarkerNodes; 209 OwnPtr<AXComputedObjectAttributeCache> m_computedObjectAttributeCache; 210 static bool gAccessibilityEnabled; 211 212 HashSet<AXID> m_idsInUse; 213 214 Timer<AXObjectCache> m_notificationPostTimer; 215 Vector<pair<RefPtr<AccessibilityObject>, AXNotification> > m_notificationsToPost; 216 void notificationPostTimerFired(Timer<AXObjectCache>*); 217 218 static AccessibilityObject* focusedImageMapUIElement(HTMLAreaElement*); 219 220 AXID getAXID(AccessibilityObject*); 221 }; 222 223 bool nodeHasRole(Node*, const String& role); 224 // This will let you know if aria-hidden was explicitly set to false. 225 bool isNodeAriaVisible(Node*); 226 227 #if !HAVE(ACCESSIBILITY) 228 inline AccessibilityObjectInclusion AXComputedObjectAttributeCache::getIgnored(AXID) const { return DefaultBehavior; } 229 inline void AXComputedObjectAttributeCache::setIgnored(AXID, AccessibilityObjectInclusion) { } 230 inline AXObjectCache::AXObjectCache(const Document* doc) : m_document(const_cast<Document*>(doc)), m_notificationPostTimer(this, 0) { } 231 inline AXObjectCache::~AXObjectCache() { } 232 inline AccessibilityObject* AXObjectCache::focusedUIElementForPage(const Page*) { return 0; } 233 inline AccessibilityObject* AXObjectCache::get(RenderObject*) { return 0; } 234 inline AccessibilityObject* AXObjectCache::get(Node*) { return 0; } 235 inline AccessibilityObject* AXObjectCache::get(Widget*) { return 0; } 236 inline AccessibilityObject* AXObjectCache::getOrCreate(AccessibilityRole) { return 0; } 237 inline AccessibilityObject* AXObjectCache::getOrCreate(RenderObject*) { return 0; } 238 inline AccessibilityObject* AXObjectCache::getOrCreate(Node*) { return 0; } 239 inline AccessibilityObject* AXObjectCache::getOrCreate(Widget*) { return 0; } 240 inline AccessibilityObject* AXObjectCache::rootObject() { return 0; } 241 inline Element* AXObjectCache::rootAXEditableElement(Node*) { return 0; } 242 inline bool nodeHasRole(Node*, const String&) { return false; } 243 inline void AXObjectCache::startCachingComputedObjectAttributesUntilTreeMutates() { } 244 inline void AXObjectCache::stopCachingComputedObjectAttributes() { } 245 inline bool isNodeAriaVisible(Node*) { return true; } 246 inline const Element* AXObjectCache::rootAXEditableElement(const Node*) { return 0; } 247 inline void AXObjectCache::attachWrapper(AccessibilityObject*) { } 248 inline void AXObjectCache::checkedStateChanged(Node*) { } 249 inline void AXObjectCache::childrenChanged(RenderObject*) { } 250 inline void AXObjectCache::childrenChanged(Node*) { } 251 inline void AXObjectCache::childrenChanged(AccessibilityObject*) { } 252 inline void AXObjectCache::textChanged(RenderObject*) { } 253 inline void AXObjectCache::textChanged(Node*) { } 254 inline void AXObjectCache::textChanged(AccessibilityObject*) { } 255 inline void AXObjectCache::updateCacheAfterNodeIsAttached(Node*) { } 256 inline void AXObjectCache::detachWrapper(AccessibilityObject*) { } 257 inline void AXObjectCache::handleActiveDescendantChanged(Node*) { } 258 inline void AXObjectCache::handleAriaExpandedChange(Node*) { } 259 inline void AXObjectCache::handleAriaRoleChanged(Node*) { } 260 inline void AXObjectCache::handleFocusedUIElementChanged(Node*, Node*) { } 261 inline void AXObjectCache::handleScrollbarUpdate(ScrollView*) { } 262 inline void AXObjectCache::handleAttributeChanged(const QualifiedName&, Element*) { } 263 inline void AXObjectCache::recomputeIsIgnored(RenderObject*) { } 264 inline void AXObjectCache::handleScrolledToAnchor(const Node*) { } 265 inline void AXObjectCache::nodeTextChangeNotification(Node*, AXTextChange, unsigned, const String&) { } 266 inline void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned, const String&) { } 267 inline void AXObjectCache::postNotification(AccessibilityObject*, Document*, AXNotification, bool, PostType) { } 268 inline void AXObjectCache::postNotification(RenderObject*, AXNotification, bool, PostType) { } 269 inline void AXObjectCache::postNotification(Node*, AXNotification, bool, PostType) { } 270 inline void AXObjectCache::postPlatformNotification(AccessibilityObject*, AXNotification) { } 271 inline void AXObjectCache::remove(AXID) { } 272 inline void AXObjectCache::remove(RenderObject*) { } 273 inline void AXObjectCache::remove(Node*) { } 274 inline void AXObjectCache::remove(Widget*) { } 275 inline void AXObjectCache::selectedChildrenChanged(RenderObject*) { } 276 inline void AXObjectCache::selectedChildrenChanged(Node*) { } 277 #endif 278 279 } 280 281 #endif 282