Source/JavaScriptCore:
[WebKit-https.git] / Source / WebCore / accessibility / AXObjectCache.h
1 /*
2  * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010, 2011, 2015 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 "AXTextStateChangeIntent.h"
30 #include "AccessibilityObject.h"
31 #include "Timer.h"
32 #include <limits.h>
33 #include <wtf/Forward.h>
34 #include <wtf/HashMap.h>
35 #include <wtf/HashSet.h>
36 #include <wtf/ListHashSet.h>
37 #include <wtf/RefPtr.h>
38
39 namespace WebCore {
40
41 class Document;
42 class HTMLAreaElement;
43 class Node;
44 class Page;
45 class RenderObject;
46 class ScrollView;
47 class VisiblePosition;
48 class Widget;
49
50 struct TextMarkerData {
51     AXID axID;
52     Node* node;
53     int offset;
54     EAffinity affinity;
55 };
56
57 class AXComputedObjectAttributeCache {
58 public:
59     AccessibilityObjectInclusion getIgnored(AXID) const;
60     void setIgnored(AXID, AccessibilityObjectInclusion);
61
62 private:
63     struct CachedAXObjectAttributes {
64         CachedAXObjectAttributes() : ignored(DefaultBehavior) { }
65
66         AccessibilityObjectInclusion ignored;
67     };
68
69     HashMap<AXID, CachedAXObjectAttributes> m_idMapping;
70 };
71
72 #if !PLATFORM(COCOA)
73 enum AXTextChange { AXTextInserted, AXTextDeleted, AXTextAttributesChanged };
74 #endif
75
76 enum PostTarget { TargetElement, TargetObservableParent };
77
78 enum PostType { PostSynchronously, PostAsynchronously };
79
80 class AXObjectCache {
81     WTF_MAKE_NONCOPYABLE(AXObjectCache); WTF_MAKE_FAST_ALLOCATED;
82 public:
83     explicit AXObjectCache(Document&);
84     ~AXObjectCache();
85
86     WEBCORE_EXPORT static AccessibilityObject* focusedUIElementForPage(const Page*);
87
88     // Returns the root object for the entire document.
89     WEBCORE_EXPORT AccessibilityObject* rootObject();
90     // Returns the root object for a specific frame.
91     WEBCORE_EXPORT AccessibilityObject* rootObjectForFrame(Frame*);
92     
93     // For AX objects with elements that back them.
94     AccessibilityObject* getOrCreate(RenderObject*);
95     AccessibilityObject* getOrCreate(Widget*);
96     AccessibilityObject* getOrCreate(Node*);
97
98     // used for objects without backing elements
99     AccessibilityObject* getOrCreate(AccessibilityRole);
100     
101     // will only return the AccessibilityObject if it already exists
102     AccessibilityObject* get(RenderObject*);
103     AccessibilityObject* get(Widget*);
104     AccessibilityObject* get(Node*);
105     
106     void remove(RenderObject*);
107     void remove(Node*);
108     void remove(Widget*);
109     void remove(AXID);
110
111     void detachWrapper(AccessibilityObject*, AccessibilityDetachmentType);
112     void attachWrapper(AccessibilityObject*);
113     void childrenChanged(Node*, Node* newChild = nullptr);
114     void childrenChanged(RenderObject*, RenderObject* newChild = nullptr);
115     void childrenChanged(AccessibilityObject*);
116     void checkedStateChanged(Node*);
117     void selectedChildrenChanged(Node*);
118     void selectedChildrenChanged(RenderObject*);
119     // Called by a node when text or a text equivalent (e.g. alt) attribute is changed.
120     void textChanged(Node*);
121     void textChanged(RenderObject*);
122     // Called when a node has just been attached, so we can make sure we have the right subclass of AccessibilityObject.
123     void updateCacheAfterNodeIsAttached(Node*);
124
125     void handleActiveDescendantChanged(Node*);
126     void handleAriaRoleChanged(Node*);
127     void handleFocusedUIElementChanged(Node* oldFocusedNode, Node* newFocusedNode);
128     void handleScrolledToAnchor(const Node* anchorNode);
129     void handleAriaExpandedChange(Node*);
130     void handleScrollbarUpdate(ScrollView*);
131
132     void handleAttributeChanged(const QualifiedName& attrName, Element*);
133     void recomputeIsIgnored(RenderObject* renderer);
134
135 #if HAVE(ACCESSIBILITY)
136     WEBCORE_EXPORT static void enableAccessibility();
137     WEBCORE_EXPORT static void disableAccessibility();
138
139     // Enhanced user interface accessibility can be toggled by the assistive technology.
140     WEBCORE_EXPORT static void setEnhancedUserInterfaceAccessibility(bool flag);
141     
142     static bool accessibilityEnabled() { return gAccessibilityEnabled; }
143     static bool accessibilityEnhancedUserInterfaceEnabled() { return gAccessibilityEnhancedUserInterfaceEnabled; }
144 #else
145     static void enableAccessibility() { }
146     static void disableAccessibility() { }
147     static void setEnhancedUserInterfaceAccessibility(bool) { }
148     static bool accessibilityEnabled() { return false; }
149     static bool accessibilityEnhancedUserInterfaceEnabled() { return false; }
150 #endif
151
152     void removeAXID(AccessibilityObject*);
153     bool isIDinUse(AXID id) const { return m_idsInUse.contains(id); }
154
155     const Element* rootAXEditableElement(const Node*);
156     bool nodeIsTextControl(const Node*);
157
158     AXID platformGenerateAXID() const;
159     AccessibilityObject* objectFromAXID(AXID id) const { return m_objects.get(id); }
160
161     // Text marker utilities.
162     void textMarkerDataForVisiblePosition(TextMarkerData&, const VisiblePosition&);
163     VisiblePosition visiblePositionForTextMarkerData(TextMarkerData&);
164
165     enum AXNotification {
166         AXActiveDescendantChanged,
167         AXAutocorrectionOccured,
168         AXCheckedStateChanged,
169         AXChildrenChanged,
170         AXFocusedUIElementChanged,
171         AXLayoutComplete,
172         AXLoadComplete,
173         AXNewDocumentLoadComplete,
174         AXSelectedChildrenChanged,
175         AXSelectedTextChanged,
176         AXValueChanged,
177         AXScrolledToAnchor,
178         AXLiveRegionCreated,
179         AXLiveRegionChanged,
180         AXMenuListItemSelected,
181         AXMenuListValueChanged,
182         AXMenuClosed,
183         AXMenuOpened,
184         AXRowCountChanged,
185         AXRowCollapsed,
186         AXRowExpanded,
187         AXExpandedChanged,
188         AXInvalidStatusChanged,
189         AXTextChanged,
190         AXAriaAttributeChanged,
191         AXElementBusyChanged
192     };
193
194     void postNotification(RenderObject*, AXNotification, PostTarget = TargetElement, PostType = PostAsynchronously);
195     void postNotification(Node*, AXNotification, PostTarget = TargetElement, PostType = PostAsynchronously);
196     void postNotification(AccessibilityObject*, Document*, AXNotification, PostTarget = TargetElement, PostType = PostAsynchronously);
197
198 #ifndef NDEBUG
199     void showIntent(const AXTextStateChangeIntent&);
200 #endif
201
202     void setTextSelectionIntent(const AXTextStateChangeIntent&);
203     void setIsSynchronizingSelection(bool);
204
205     void postTextStateChangeNotification(Node*, AXTextEditType, const String&, const VisiblePosition&);
206     void postTextReplacementNotification(Node*, AXTextEditType deletionType, const String& deletedText, AXTextEditType insertionType, const String& insertedText, const VisiblePosition&);
207     void postTextStateChangeNotification(Node*, const AXTextStateChangeIntent&, const VisibleSelection&);
208     void postTextStateChangeNotification(const Position&, const AXTextStateChangeIntent&, const VisibleSelection&);
209
210     enum AXLoadingEvent {
211         AXLoadingStarted,
212         AXLoadingReloaded,
213         AXLoadingFailed,
214         AXLoadingFinished
215     };
216
217     void frameLoadingEventNotification(Frame*, AXLoadingEvent);
218
219     void clearTextMarkerNodesInUse(Document*);
220
221     void startCachingComputedObjectAttributesUntilTreeMutates();
222     void stopCachingComputedObjectAttributes();
223
224     AXComputedObjectAttributeCache* computedObjectAttributeCache() { return m_computedObjectAttributeCache.get(); }
225
226     Document& document() const { return m_document; }
227
228 #if PLATFORM(MAC)
229     static void setShouldRepostNotificationsForTests(bool value);
230 #endif
231
232 protected:
233     void postPlatformNotification(AccessibilityObject*, AXNotification);
234     void platformHandleFocusedUIElementChanged(Node* oldFocusedNode, Node* newFocusedNode);
235
236 #if PLATFORM(COCOA)
237     void postTextStateChangePlatformNotification(AccessibilityObject*, const AXTextStateChangeIntent&, const VisibleSelection&);
238     void postTextStateChangePlatformNotification(AccessibilityObject*, AXTextEditType, const String&, const VisiblePosition&);
239     void postTextReplacementPlatformNotification(AccessibilityObject*, AXTextEditType, const String&, AXTextEditType, const String&, const VisiblePosition&);
240 #else
241     static AXTextChange textChangeForEditType(AXTextEditType);
242     void nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned, const String&);
243 #endif
244
245     void frameLoadingEventPlatformNotification(AccessibilityObject*, AXLoadingEvent);
246     void textChanged(AccessibilityObject*);
247     void labelChanged(Element*);
248
249     // This is a weak reference cache for knowing if Nodes used by TextMarkers are valid.
250     void setNodeInUse(Node* n) { m_textMarkerNodes.add(n); }
251     void removeNodeForUse(Node* n) { m_textMarkerNodes.remove(n); }
252     bool isNodeInUse(Node* n) { return m_textMarkerNodes.contains(n); }
253
254 private:
255     AccessibilityObject* rootWebArea();
256
257     static AccessibilityObject* focusedImageMapUIElement(HTMLAreaElement*);
258
259     AXID getAXID(AccessibilityObject*);
260
261     void notificationPostTimerFired();
262
263     void postTextStateChangeNotification(AccessibilityObject*, const AXTextStateChangeIntent&, const VisibleSelection&);
264
265     bool enqueuePasswordValueChangeNotification(AccessibilityObject*);
266     void passwordNotificationPostTimerFired();
267
268     void handleMenuOpened(Node*);
269     void handleLiveRegionCreated(Node*);
270     void handleMenuItemSelected(Node*);
271
272     Document& m_document;
273     HashMap<AXID, RefPtr<AccessibilityObject>> m_objects;
274     HashMap<RenderObject*, AXID> m_renderObjectMapping;
275     HashMap<Widget*, AXID> m_widgetObjectMapping;
276     HashMap<Node*, AXID> m_nodeObjectMapping;
277     HashSet<Node*> m_textMarkerNodes;
278     std::unique_ptr<AXComputedObjectAttributeCache> m_computedObjectAttributeCache;
279     WEBCORE_EXPORT static bool gAccessibilityEnabled;
280     WEBCORE_EXPORT static bool gAccessibilityEnhancedUserInterfaceEnabled;
281
282     HashSet<AXID> m_idsInUse;
283
284     Timer m_notificationPostTimer;
285     Vector<std::pair<RefPtr<AccessibilityObject>, AXNotification>> m_notificationsToPost;
286
287     Timer m_passwordNotificationPostTimer;
288
289     ListHashSet<RefPtr<AccessibilityObject>> m_passwordNotificationsToPost;
290
291     AXTextStateChangeIntent m_textSelectionIntent;
292     bool m_isSynchronizingSelection { false };
293 };
294
295 class AXAttributeCacheEnabler
296 {
297 public:
298     explicit AXAttributeCacheEnabler(AXObjectCache *cache);
299     ~AXAttributeCacheEnabler();
300     
301 private:
302     AXObjectCache* m_cache;
303 };
304     
305 bool nodeHasRole(Node*, const String& role);
306 // This will let you know if aria-hidden was explicitly set to false.
307 bool isNodeAriaVisible(Node*);
308     
309 #if !HAVE(ACCESSIBILITY)
310 inline AccessibilityObjectInclusion AXComputedObjectAttributeCache::getIgnored(AXID) const { return DefaultBehavior; }
311 inline void AXComputedObjectAttributeCache::setIgnored(AXID, AccessibilityObjectInclusion) { }
312 inline AXObjectCache::AXObjectCache(Document& document) : m_document(document), m_notificationPostTimer(this, (Timer::TimerFiredFunction) nullptr) { }
313 inline AXObjectCache::~AXObjectCache() { }
314 inline AccessibilityObject* AXObjectCache::focusedUIElementForPage(const Page*) { return nullptr; }
315 inline AccessibilityObject* AXObjectCache::get(RenderObject*) { return nullptr; }
316 inline AccessibilityObject* AXObjectCache::get(Node*) { return nullptr; }
317 inline AccessibilityObject* AXObjectCache::get(Widget*) { return nullptr; }
318 inline AccessibilityObject* AXObjectCache::getOrCreate(AccessibilityRole) { return nullptr; }
319 inline AccessibilityObject* AXObjectCache::getOrCreate(RenderObject*) { return nullptr; }
320 inline AccessibilityObject* AXObjectCache::getOrCreate(Node*) { return nullptr; }
321 inline AccessibilityObject* AXObjectCache::getOrCreate(Widget*) { return nullptr; }
322 inline AccessibilityObject* AXObjectCache::rootObject() { return nullptr; }
323 inline AccessibilityObject* AXObjectCache::rootObjectForFrame(Frame*) { return nullptr; }
324 inline Element* AXObjectCache::rootAXEditableElement(Node*) { return nullptr; }
325 inline bool nodeHasRole(Node*, const String&) { return false; }
326 inline void AXObjectCache::startCachingComputedObjectAttributesUntilTreeMutates() { }
327 inline void AXObjectCache::stopCachingComputedObjectAttributes() { }
328 inline bool isNodeAriaVisible(Node*) { return true; }
329 inline const Element* AXObjectCache::rootAXEditableElement(const Node*) { return nullptr; }
330 inline void AXObjectCache::attachWrapper(AccessibilityObject*) { }
331 inline void AXObjectCache::checkedStateChanged(Node*) { }
332 inline void AXObjectCache::childrenChanged(RenderObject*, RenderObject*) { }
333 inline void AXObjectCache::childrenChanged(Node*, Node*) { }
334 inline void AXObjectCache::childrenChanged(AccessibilityObject*) { }
335 inline void AXObjectCache::textChanged(RenderObject*) { }
336 inline void AXObjectCache::textChanged(Node*) { }
337 inline void AXObjectCache::textChanged(AccessibilityObject*) { }
338 inline void AXObjectCache::updateCacheAfterNodeIsAttached(Node*) { }
339 inline void AXObjectCache::detachWrapper(AccessibilityObject*, AccessibilityDetachmentType) { }
340 inline void AXObjectCache::frameLoadingEventNotification(Frame*, AXLoadingEvent) { }
341 inline void AXObjectCache::frameLoadingEventPlatformNotification(AccessibilityObject*, AXLoadingEvent) { }
342 inline void AXObjectCache::handleActiveDescendantChanged(Node*) { }
343 inline void AXObjectCache::handleAriaExpandedChange(Node*) { }
344 inline void AXObjectCache::handleAriaRoleChanged(Node*) { }
345 inline void AXObjectCache::handleFocusedUIElementChanged(Node*, Node*) { }
346 inline void AXObjectCache::handleScrollbarUpdate(ScrollView*) { }
347 inline void AXObjectCache::handleAttributeChanged(const QualifiedName&, Element*) { }
348 inline void AXObjectCache::recomputeIsIgnored(RenderObject*) { }
349 inline void AXObjectCache::handleScrolledToAnchor(const Node*) { }
350 inline void AXObjectCache::postTextStateChangeNotification(Node*, const AXTextStateChangeIntent&, const VisibleSelection&) { }
351 inline void AXObjectCache::postTextStateChangeNotification(Node*, AXTextEditType, const String&, const VisiblePosition&) { }
352 inline void AXObjectCache::postTextReplacementNotification(Node*, AXTextEditType, const String&, AXTextEditType, const String&, const VisiblePosition&) { }
353 inline void AXObjectCache::postNotification(AccessibilityObject*, Document*, AXNotification, PostTarget, PostType) { }
354 inline void AXObjectCache::postNotification(RenderObject*, AXNotification, PostTarget, PostType) { }
355 inline void AXObjectCache::postNotification(Node*, AXNotification, PostTarget, PostType) { }
356 inline void AXObjectCache::postPlatformNotification(AccessibilityObject*, AXNotification) { }
357 inline void AXObjectCache::remove(AXID) { }
358 inline void AXObjectCache::remove(RenderObject*) { }
359 inline void AXObjectCache::remove(Node*) { }
360 inline void AXObjectCache::remove(Widget*) { }
361 inline void AXObjectCache::selectedChildrenChanged(RenderObject*) { }
362 inline void AXObjectCache::selectedChildrenChanged(Node*) { }
363 #if PLATFORM(COCOA)
364 inline void AXObjectCache::postTextStateChangePlatformNotification(AccessibilityObject*, const AXTextStateChangeIntent&, const VisibleSelection&) { }
365 inline void AXObjectCache::postTextStateChangePlatformNotification(AccessibilityObject*, AXTextEditType, const String&, const VisiblePosition&) { }
366 inline void AXObjectCache::postTextReplacementPlatformNotification(AccessibilityObject*, AXTextEditType, const String&, AXTextEditType, const String&, const VisiblePosition&) { }
367 #else
368 inline AXTextChange AXObjectCache::textChangeForEditType(AXTextEditType) { return AXTextInserted; }
369 inline void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned, const String&) { }
370 #endif
371 #endif
372
373 }
374
375 #endif