AX: memoize expensive computation during blocks where tree doesn't change
[WebKit-https.git] / Source / WebCore / accessibility / AXObjectCache.h
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
37 namespace WebCore {
38
39 class Document;
40 class HTMLAreaElement;
41 class Node;
42 class Page;
43 class RenderObject;
44 class ScrollView;
45 class VisiblePosition;
46 class Widget;
47
48 struct TextMarkerData {
49     AXID axID;
50     Node* node;
51     int offset;
52     EAffinity affinity;
53 };
54
55 class AXComputedObjectAttributeCache {
56 public:
57     static PassOwnPtr<AXComputedObjectAttributeCache> create() { return adoptPtr(new AXComputedObjectAttributeCache()); }
58
59     AccessibilityObjectInclusion getIgnored(AXID) const;
60     void setIgnored(AXID, AccessibilityObjectInclusion);
61
62 private:
63     AXComputedObjectAttributeCache() { }
64
65     struct CachedAXObjectAttributes {
66         CachedAXObjectAttributes() : ignored(DefaultBehavior) { }
67
68         AccessibilityObjectInclusion ignored;
69     };
70
71     HashMap<AXID, CachedAXObjectAttributes> m_idMapping;
72 };
73
74 enum PostType { PostSynchronously, PostAsynchronously };
75
76 class AXObjectCache {
77     WTF_MAKE_NONCOPYABLE(AXObjectCache); WTF_MAKE_FAST_ALLOCATED;
78 public:
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).get(); }
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
209 protected:
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
221 private:
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
243 bool nodeHasRole(Node*, const String& role);
244 // This will let you know if aria-hidden was explicitly set to false.
245 bool isNodeAriaVisible(Node*);
246     
247 #if !HAVE(ACCESSIBILITY)
248 inline AccessibilityObjectInclusion AXComputedObjectAttributeCache::getIgnored(AXID) const { return DefaultBehavior; }
249 inline void AXComputedObjectAttributeCache::setIgnored(AXID, AccessibilityObjectInclusion) { }
250 inline AXObjectCache::AXObjectCache(const Document* doc) : m_document(const_cast<Document*>(doc)), m_notificationPostTimer(this, 0) { }
251 inline AXObjectCache::~AXObjectCache() { }
252 inline AccessibilityObject* AXObjectCache::focusedUIElementForPage(const Page*) { return 0; }
253 inline AccessibilityObject* AXObjectCache::get(RenderObject*) { return 0; }
254 inline AccessibilityObject* AXObjectCache::get(Node*) { return 0; }
255 inline AccessibilityObject* AXObjectCache::get(Widget*) { return 0; }
256 inline AccessibilityObject* AXObjectCache::getOrCreate(AccessibilityRole) { return 0; }
257 inline AccessibilityObject* AXObjectCache::getOrCreate(RenderObject*) { return 0; }
258 inline AccessibilityObject* AXObjectCache::getOrCreate(Node*) { return 0; }
259 inline AccessibilityObject* AXObjectCache::getOrCreate(Widget*) { return 0; }
260 inline AccessibilityObject* AXObjectCache::rootObject() { return 0; }
261 inline AccessibilityObject* AXObjectCache::rootObjectForFrame(Frame*) { return 0; }
262 inline Element* AXObjectCache::rootAXEditableElement(Node*) { return 0; }
263 inline bool nodeHasRole(Node*, const String&) { return false; }
264 inline void startCachingComputedObjectAttributesUntilTreeMutates() { }
265 inline void stopCachingComputedObjectAttributes() { }
266 inline bool isNodeAriaVisible(Node*) { return true; }
267 inline const Element* AXObjectCache::rootAXEditableElement(const Node*) { return 0; }
268 inline void AXObjectCache::attachWrapper(AccessibilityObject*) { }
269 inline void AXObjectCache::checkedStateChanged(Node*) { }
270 inline void AXObjectCache::childrenChanged(RenderObject*) { }
271 inline void AXObjectCache::childrenChanged(Node*) { }
272 inline void AXObjectCache::childrenChanged(AccessibilityObject*) { }
273 inline void AXObjectCache::textChanged(RenderObject*) { }
274 inline void AXObjectCache::textChanged(Node*) { }
275 inline void AXObjectCache::textChanged(AccessibilityObject*) { }
276 inline void AXObjectCache::updateCacheAfterNodeIsAttached(Node*) { }
277 inline void AXObjectCache::detachWrapper(AccessibilityObject*) { }
278 inline void AXObjectCache::frameLoadingEventNotification(Frame*, AXLoadingEvent) { }
279 inline void AXObjectCache::frameLoadingEventPlatformNotification(AccessibilityObject*, AXLoadingEvent) { }
280 inline void AXObjectCache::handleActiveDescendantChanged(Node*) { }
281 inline void AXObjectCache::handleAriaExpandedChange(Node*) { }
282 inline void AXObjectCache::handleAriaRoleChanged(Node*) { }
283 inline void AXObjectCache::handleFocusedUIElementChanged(Node*, Node*) { }
284 inline void AXObjectCache::handleScrollbarUpdate(ScrollView*) { }
285 inline void AXObjectCache::handleAttributeChanged(const QualifiedName&, Element*) { }
286 inline void AXObjectCache::recomputeIsIgnored(RenderObject*) { }
287 inline void AXObjectCache::handleScrolledToAnchor(const Node*) { }
288 inline void AXObjectCache::nodeTextChangeNotification(Node*, AXTextChange, unsigned, const String&) { }
289 inline void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned, const String&) { }
290 inline void AXObjectCache::postNotification(AccessibilityObject*, Document*, AXNotification, bool, PostType) { }
291 inline void AXObjectCache::postNotification(RenderObject*, AXNotification, bool, PostType) { }
292 inline void AXObjectCache::postNotification(Node*, AXNotification, bool, PostType) { }
293 inline void AXObjectCache::postPlatformNotification(AccessibilityObject*, AXNotification) { }
294 inline void AXObjectCache::remove(AXID) { }
295 inline void AXObjectCache::remove(RenderObject*) { }
296 inline void AXObjectCache::remove(Node*) { }
297 inline void AXObjectCache::remove(Widget*) { }
298 inline void AXObjectCache::selectedChildrenChanged(RenderObject*) { }
299 inline void AXObjectCache::selectedChildrenChanged(Node*) { }
300 #endif
301
302 }
303
304 #endif