b4b5c37f6a12b55b6cde564fc9cbae6cdb11f685
[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 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
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     AccessibilityObjectInclusion getIgnored(AXID) const;
58     void setIgnored(AXID, AccessibilityObjectInclusion);
59
60 private:
61     struct CachedAXObjectAttributes {
62         CachedAXObjectAttributes() : ignored(DefaultBehavior) { }
63
64         AccessibilityObjectInclusion ignored;
65     };
66
67     HashMap<AXID, CachedAXObjectAttributes> m_idMapping;
68 };
69
70 enum PostTarget { TargetElement, TargetObservableParent };
71
72 enum PostType { PostSynchronously, PostAsynchronously };
73
74 class AXObjectCache {
75     WTF_MAKE_NONCOPYABLE(AXObjectCache); WTF_MAKE_FAST_ALLOCATED;
76 public:
77     explicit AXObjectCache(Document&);
78     ~AXObjectCache();
79
80     WEBCORE_EXPORT static AccessibilityObject* focusedUIElementForPage(const Page*);
81
82     // Returns the root object for the entire document.
83     WEBCORE_EXPORT AccessibilityObject* rootObject();
84     // Returns the root object for a specific frame.
85     WEBCORE_EXPORT 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     WEBCORE_EXPORT static void enableAccessibility();
131     WEBCORE_EXPORT static void disableAccessibility();
132
133     // Enhanced user interface accessibility can be toggled by the assistive technology.
134     WEBCORE_EXPORT 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         AXNewDocumentLoadComplete,
169         AXSelectedChildrenChanged,
170         AXSelectedTextChanged,
171         AXValueChanged,
172         AXScrolledToAnchor,
173         AXLiveRegionCreated,
174         AXLiveRegionChanged,
175         AXMenuListItemSelected,
176         AXMenuListValueChanged,
177         AXMenuClosed,
178         AXMenuOpened,
179         AXRowCountChanged,
180         AXRowCollapsed,
181         AXRowExpanded,
182         AXExpandedChanged,
183         AXInvalidStatusChanged,
184         AXTextChanged,
185         AXAriaAttributeChanged,
186         AXElementBusyChanged
187     };
188
189     void postNotification(RenderObject*, AXNotification, PostTarget = TargetElement, PostType = PostAsynchronously);
190     void postNotification(Node*, AXNotification, PostTarget = TargetElement, PostType = PostAsynchronously);
191     void postNotification(AccessibilityObject*, Document*, AXNotification, PostTarget = TargetElement, PostType = PostAsynchronously);
192
193     enum AXTextChange {
194         AXTextInserted,
195         AXTextDeleted,
196     };
197
198     void nodeTextChangeNotification(Node*, AXTextChange, unsigned offset, const String&);
199
200     enum AXLoadingEvent {
201         AXLoadingStarted,
202         AXLoadingReloaded,
203         AXLoadingFailed,
204         AXLoadingFinished
205     };
206
207     void frameLoadingEventNotification(Frame*, AXLoadingEvent);
208
209     void clearTextMarkerNodesInUse(Document*);
210
211     void startCachingComputedObjectAttributesUntilTreeMutates();
212     void stopCachingComputedObjectAttributes();
213
214     AXComputedObjectAttributeCache* computedObjectAttributeCache() { return m_computedObjectAttributeCache.get(); }
215
216     Document& document() const { return m_document; }
217     
218 protected:
219     void postPlatformNotification(AccessibilityObject*, AXNotification);
220     void platformHandleFocusedUIElementChanged(Node* oldFocusedNode, Node* newFocusedNode);
221
222     void nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned offset, const String&);
223     void frameLoadingEventPlatformNotification(AccessibilityObject*, AXLoadingEvent);
224     void textChanged(AccessibilityObject*);
225     void labelChanged(Element*);
226
227     // This is a weak reference cache for knowing if Nodes used by TextMarkers are valid.
228     void setNodeInUse(Node* n) { m_textMarkerNodes.add(n); }
229     void removeNodeForUse(Node* n) { m_textMarkerNodes.remove(n); }
230     bool isNodeInUse(Node* n) { return m_textMarkerNodes.contains(n); }
231
232 private:
233     Document& m_document;
234     HashMap<AXID, RefPtr<AccessibilityObject>> m_objects;
235     HashMap<RenderObject*, AXID> m_renderObjectMapping;
236     HashMap<Widget*, AXID> m_widgetObjectMapping;
237     HashMap<Node*, AXID> m_nodeObjectMapping;
238     HashSet<Node*> m_textMarkerNodes;
239     std::unique_ptr<AXComputedObjectAttributeCache> m_computedObjectAttributeCache;
240     WEBCORE_EXPORT static bool gAccessibilityEnabled;
241     WEBCORE_EXPORT static bool gAccessibilityEnhancedUserInterfaceEnabled;
242     
243     HashSet<AXID> m_idsInUse;
244     
245     Timer m_notificationPostTimer;
246     Vector<std::pair<RefPtr<AccessibilityObject>, AXNotification>> m_notificationsToPost;
247     void notificationPostTimerFired(Timer&);
248     void handleMenuOpened(Node*);
249     void handleLiveRegionCreated(Node*);
250     void handleMenuItemSelected(Node*);
251     
252     static AccessibilityObject* focusedImageMapUIElement(HTMLAreaElement*);
253     
254     AXID getAXID(AccessibilityObject*);
255 };
256
257 class AXAttributeCacheEnabler
258 {
259 public:
260     explicit AXAttributeCacheEnabler(AXObjectCache *cache);
261     ~AXAttributeCacheEnabler();
262     
263 private:
264     AXObjectCache* m_cache;
265 };
266     
267 bool nodeHasRole(Node*, const String& role);
268 // This will let you know if aria-hidden was explicitly set to false.
269 bool isNodeAriaVisible(Node*);
270     
271 #if !HAVE(ACCESSIBILITY)
272 inline AccessibilityObjectInclusion AXComputedObjectAttributeCache::getIgnored(AXID) const { return DefaultBehavior; }
273 inline void AXComputedObjectAttributeCache::setIgnored(AXID, AccessibilityObjectInclusion) { }
274 inline AXObjectCache::AXObjectCache(Document& document) : m_document(document), m_notificationPostTimer(this, (Timer::TimerFiredFunction) nullptr) { }
275 inline AXObjectCache::~AXObjectCache() { }
276 inline AccessibilityObject* AXObjectCache::focusedUIElementForPage(const Page*) { return nullptr; }
277 inline AccessibilityObject* AXObjectCache::get(RenderObject*) { return nullptr; }
278 inline AccessibilityObject* AXObjectCache::get(Node*) { return nullptr; }
279 inline AccessibilityObject* AXObjectCache::get(Widget*) { return nullptr; }
280 inline AccessibilityObject* AXObjectCache::getOrCreate(AccessibilityRole) { return nullptr; }
281 inline AccessibilityObject* AXObjectCache::getOrCreate(RenderObject*) { return nullptr; }
282 inline AccessibilityObject* AXObjectCache::getOrCreate(Node*) { return nullptr; }
283 inline AccessibilityObject* AXObjectCache::getOrCreate(Widget*) { return nullptr; }
284 inline AccessibilityObject* AXObjectCache::rootObject() { return nullptr; }
285 inline AccessibilityObject* AXObjectCache::rootObjectForFrame(Frame*) { return nullptr; }
286 inline Element* AXObjectCache::rootAXEditableElement(Node*) { return nullptr; }
287 inline bool nodeHasRole(Node*, const String&) { return false; }
288 inline void AXObjectCache::startCachingComputedObjectAttributesUntilTreeMutates() { }
289 inline void AXObjectCache::stopCachingComputedObjectAttributes() { }
290 inline bool isNodeAriaVisible(Node*) { return true; }
291 inline const Element* AXObjectCache::rootAXEditableElement(const Node*) { return nullptr; }
292 inline void AXObjectCache::attachWrapper(AccessibilityObject*) { }
293 inline void AXObjectCache::checkedStateChanged(Node*) { }
294 inline void AXObjectCache::childrenChanged(RenderObject*, RenderObject*) { }
295 inline void AXObjectCache::childrenChanged(Node*, Node*) { }
296 inline void AXObjectCache::childrenChanged(AccessibilityObject*) { }
297 inline void AXObjectCache::textChanged(RenderObject*) { }
298 inline void AXObjectCache::textChanged(Node*) { }
299 inline void AXObjectCache::textChanged(AccessibilityObject*) { }
300 inline void AXObjectCache::updateCacheAfterNodeIsAttached(Node*) { }
301 inline void AXObjectCache::detachWrapper(AccessibilityObject*, AccessibilityDetachmentType) { }
302 inline void AXObjectCache::frameLoadingEventNotification(Frame*, AXLoadingEvent) { }
303 inline void AXObjectCache::frameLoadingEventPlatformNotification(AccessibilityObject*, AXLoadingEvent) { }
304 inline void AXObjectCache::handleActiveDescendantChanged(Node*) { }
305 inline void AXObjectCache::handleAriaExpandedChange(Node*) { }
306 inline void AXObjectCache::handleAriaRoleChanged(Node*) { }
307 inline void AXObjectCache::handleFocusedUIElementChanged(Node*, Node*) { }
308 inline void AXObjectCache::handleScrollbarUpdate(ScrollView*) { }
309 inline void AXObjectCache::handleAttributeChanged(const QualifiedName&, Element*) { }
310 inline void AXObjectCache::recomputeIsIgnored(RenderObject*) { }
311 inline void AXObjectCache::handleScrolledToAnchor(const Node*) { }
312 inline void AXObjectCache::nodeTextChangeNotification(Node*, AXTextChange, unsigned, const String&) { }
313 inline void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned, const String&) { }
314 inline void AXObjectCache::postNotification(AccessibilityObject*, Document*, AXNotification, PostTarget, PostType) { }
315 inline void AXObjectCache::postNotification(RenderObject*, AXNotification, PostTarget, PostType) { }
316 inline void AXObjectCache::postNotification(Node*, AXNotification, PostTarget, PostType) { }
317 inline void AXObjectCache::postPlatformNotification(AccessibilityObject*, AXNotification) { }
318 inline void AXObjectCache::remove(AXID) { }
319 inline void AXObjectCache::remove(RenderObject*) { }
320 inline void AXObjectCache::remove(Node*) { }
321 inline void AXObjectCache::remove(Widget*) { }
322 inline void AXObjectCache::selectedChildrenChanged(RenderObject*) { }
323 inline void AXObjectCache::selectedChildrenChanged(Node*) { }
324 #endif
325
326 }
327
328 #endif