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