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
55enum PostType { PostSynchronously, PostAsynchronously };
56
57class AXObjectCache {
58    WTF_MAKE_NONCOPYABLE(AXObjectCache); WTF_MAKE_FAST_ALLOCATED;
59public:
60    AXObjectCache(const Document*);
61    ~AXObjectCache();
62
63    static AccessibilityObject* focusedUIElementForPage(const Page*);
64
65    // Returns the root object for the entire document.
66    AccessibilityObject* rootObject();
67    // Returns the root object for a specific frame.
68    AccessibilityObject* rootObjectForFrame(Frame*);
69
70    // For AX objects with elements that back them.
71    AccessibilityObject* getOrCreate(RenderObject*);
72    AccessibilityObject* getOrCreate(Widget*);
73
74    // used for objects without backing elements
75    AccessibilityObject* getOrCreate(AccessibilityRole);
76
77    // will only return the AccessibilityObject if it already exists
78    AccessibilityObject* get(RenderObject*);
79
80    void remove(RenderObject*);
81    void remove(Widget*);
82    void remove(AXID);
83
84    void detachWrapper(AccessibilityObject*);
85    void attachWrapper(AccessibilityObject*);
86    void childrenChanged(RenderObject*);
87    void selectedChildrenChanged(RenderObject*);
88    // Called by a node when text or a text equivalent (e.g. alt) attribute is changed.
89    void contentChanged(RenderObject*);
90
91    void handleActiveDescendantChanged(RenderObject*);
92    void handleAriaRoleChanged(RenderObject*);
93    void handleFocusedUIElementChanged(RenderObject* oldFocusedRenderer, RenderObject* newFocusedRenderer);
94    void handleScrolledToAnchor(const Node* anchorNode);
95    void handleAriaExpandedChange(RenderObject*);
96    void handleScrollbarUpdate(ScrollView*);
97
98    static void enableAccessibility() { gAccessibilityEnabled = true; }
99    // Enhanced user interface accessibility can be toggled by the assistive technology.
100    static void setEnhancedUserInterfaceAccessibility(bool flag) { gAccessibilityEnhancedUserInterfaceEnabled = flag; }
101
102    static bool accessibilityEnabled() { return gAccessibilityEnabled; }
103    static bool accessibilityEnhancedUserInterfaceEnabled() { return gAccessibilityEnhancedUserInterfaceEnabled; }
104
105    void removeAXID(AccessibilityObject*);
106    bool isIDinUse(AXID id) const { return m_idsInUse.contains(id); }
107    AXID platformGenerateAXID() const;
108    AccessibilityObject* objectFromAXID(AXID id) const { return m_objects.get(id).get(); }
109
110    // This is a weak reference cache for knowing if Nodes used by TextMarkers are valid.
111    void setNodeInUse(Node* n) { m_textMarkerNodes.add(n); }
112    void removeNodeForUse(Node* n) { m_textMarkerNodes.remove(n); }
113    bool isNodeInUse(Node* n) { return m_textMarkerNodes.contains(n); }
114
115    // Text marker utilities.
116    void textMarkerDataForVisiblePosition(TextMarkerData&, const VisiblePosition&);
117    VisiblePosition visiblePositionForTextMarkerData(TextMarkerData&);
118
119    enum AXNotification {
120        AXActiveDescendantChanged,
121        AXAutocorrectionOccured,
122        AXCheckedStateChanged,
123        AXChildrenChanged,
124        AXFocusedUIElementChanged,
125        AXLayoutComplete,
126        AXLoadComplete,
127        AXSelectedChildrenChanged,
128        AXSelectedTextChanged,
129        AXValueChanged,
130        AXScrolledToAnchor,
131        AXLiveRegionChanged,
132        AXMenuListValueChanged,
133        AXRowCountChanged,
134        AXRowCollapsed,
135        AXRowExpanded,
136        AXInvalidStatusChanged,
137    };
138
139    void postNotification(RenderObject*, AXNotification, bool postToElement, PostType = PostAsynchronously);
140    void postNotification(AccessibilityObject*, Document*, AXNotification, bool postToElement, PostType = PostAsynchronously);
141
142    enum AXTextChange {
143        AXTextInserted,
144        AXTextDeleted,
145    };
146
147    void nodeTextChangeNotification(RenderObject*, AXTextChange, unsigned offset, unsigned count);
148
149    bool nodeHasRole(Node*, const AtomicString& role);
150
151protected:
152    void postPlatformNotification(AccessibilityObject*, AXNotification);
153    void nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned offset, unsigned count);
154
155private:
156    Document* m_document;
157    HashMap<AXID, RefPtr<AccessibilityObject> > m_objects;
158    HashMap<RenderObject*, AXID> m_renderObjectMapping;
159    HashMap<Widget*, AXID> m_widgetObjectMapping;
160    HashSet<Node*> m_textMarkerNodes;
161    static bool gAccessibilityEnabled;
162    static bool gAccessibilityEnhancedUserInterfaceEnabled;
163
164    HashSet<AXID> m_idsInUse;
165
166    Timer<AXObjectCache> m_notificationPostTimer;
167    Vector<pair<RefPtr<AccessibilityObject>, AXNotification> > m_notificationsToPost;
168    void notificationPostTimerFired(Timer<AXObjectCache>*);
169
170    static AccessibilityObject* focusedImageMapUIElement(HTMLAreaElement*);
171
172    AXID getAXID(AccessibilityObject*);
173    AccessibilityObject* get(Widget*);
174};
175
176bool nodeHasRole(Node*, const String& role);
177
178#if !HAVE(ACCESSIBILITY)
179inline void AXObjectCache::handleActiveDescendantChanged(RenderObject*) { }
180inline void AXObjectCache::handleAriaRoleChanged(RenderObject*) { }
181inline void AXObjectCache::detachWrapper(AccessibilityObject*) { }
182inline void AXObjectCache::attachWrapper(AccessibilityObject*) { }
183inline void AXObjectCache::selectedChildrenChanged(RenderObject*) { }
184inline void AXObjectCache::postNotification(RenderObject*, AXNotification, bool postToElement, PostType) { }
185inline void AXObjectCache::postNotification(AccessibilityObject*, Document*, AXNotification, bool postToElement, PostType) { }
186inline void AXObjectCache::postPlatformNotification(AccessibilityObject*, AXNotification) { }
187inline void AXObjectCache::nodeTextChangeNotification(RenderObject*, AXTextChange, unsigned, unsigned) { }
188inline void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned, unsigned) { }
189inline void AXObjectCache::handleFocusedUIElementChanged(RenderObject*, RenderObject*) { }
190inline void AXObjectCache::handleScrolledToAnchor(const Node*) { }
191inline void AXObjectCache::contentChanged(RenderObject*) { }
192inline void AXObjectCache::handleAriaExpandedChange(RenderObject*) { }
193inline void AXObjectCache::handleScrollbarUpdate(ScrollView*) { }
194#endif
195
196}
197
198#endif
199