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 "core/accessibility/AXObject.h"
30#include "core/rendering/RenderText.h"
31#include "platform/Timer.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 AbstractInlineTextBox;
40class Document;
41class HTMLAreaElement;
42class Node;
43class Page;
44class RenderObject;
45class ScrollView;
46class VisiblePosition;
47class Widget;
48
49struct TextMarkerData {
50    AXID axID;
51    Node* node;
52    int offset;
53    EAffinity affinity;
54};
55
56class AXComputedObjectAttributeCache {
57public:
58    static PassOwnPtr<AXComputedObjectAttributeCache> create() { return adoptPtr(new AXComputedObjectAttributeCache()); }
59
60    AXObjectInclusion getIgnored(AXID) const;
61    void setIgnored(AXID, AXObjectInclusion);
62
63    void clear();
64
65private:
66    AXComputedObjectAttributeCache() { }
67
68    struct CachedAXObjectAttributes {
69        CachedAXObjectAttributes() : ignored(DefaultBehavior) { }
70
71        AXObjectInclusion ignored;
72    };
73
74    HashMap<AXID, CachedAXObjectAttributes> m_idMapping;
75};
76
77enum PostType { PostSynchronously, PostAsynchronously };
78
79class AXObjectCache {
80    WTF_MAKE_NONCOPYABLE(AXObjectCache); WTF_MAKE_FAST_ALLOCATED;
81public:
82    explicit AXObjectCache(Document&);
83    ~AXObjectCache();
84
85    static AXObject* focusedUIElementForPage(const Page*);
86
87    // Returns the root object for the entire document.
88    AXObject* rootObject();
89
90    // For AX objects with elements that back them.
91    AXObject* getOrCreate(RenderObject*);
92    AXObject* getOrCreate(Widget*);
93    AXObject* getOrCreate(Node*);
94    AXObject* getOrCreate(AbstractInlineTextBox*);
95
96    // used for objects without backing elements
97    AXObject* getOrCreate(AccessibilityRole);
98
99    // will only return the AXObject if it already exists
100    AXObject* get(RenderObject*);
101    AXObject* get(Widget*);
102    AXObject* get(Node*);
103    AXObject* get(AbstractInlineTextBox*);
104
105    void remove(RenderObject*);
106    void remove(Node*);
107    void remove(Widget*);
108    void remove(AbstractInlineTextBox*);
109    void remove(AXID);
110
111    void clearWeakMembers(Visitor*);
112
113    void detachWrapper(AXObject*);
114    void attachWrapper(AXObject*);
115    void childrenChanged(Node*);
116    void childrenChanged(RenderObject*);
117    void childrenChanged(AXObject*);
118    void checkedStateChanged(Node*);
119    void selectedChildrenChanged(Node*);
120    void selectedChildrenChanged(RenderObject*);
121    void selectionChanged(Node*);
122    // Called by a node when text or a text equivalent (e.g. alt) attribute is changed.
123    void textChanged(Node*);
124    void textChanged(RenderObject*);
125    // Called when a node has just been attached, so we can make sure we have the right subclass of AXObject.
126    void updateCacheAfterNodeIsAttached(Node*);
127
128    void handleActiveDescendantChanged(Node*);
129    void handleAriaRoleChanged(Node*);
130    void handleFocusedUIElementChanged(Node* oldFocusedNode, Node* newFocusedNode);
131    void handleScrolledToAnchor(const Node* anchorNode);
132    void handleAriaExpandedChange(Node*);
133
134    // Called when scroll bars are added / removed (as the view resizes).
135    void handleScrollbarUpdate(ScrollView*);
136
137    void handleLayoutComplete(RenderObject*);
138
139    // Called when the scroll offset changes.
140    void handleScrollPositionChanged(ScrollView*);
141    void handleScrollPositionChanged(RenderObject*);
142
143    void handleAttributeChanged(const QualifiedName& attrName, Element*);
144    void recomputeIsIgnored(RenderObject* renderer);
145
146    void inlineTextBoxesUpdated(RenderObject* renderer);
147
148    static void enableAccessibility() { gAccessibilityEnabled = true; }
149    static bool accessibilityEnabled() { return gAccessibilityEnabled; }
150    static void setInlineTextBoxAccessibility(bool flag) { gInlineTextBoxAccessibility = flag; }
151    static bool inlineTextBoxAccessibility() { return gInlineTextBoxAccessibility; }
152
153    void removeAXID(AXObject*);
154    bool isIDinUse(AXID id) const { return m_idsInUse.contains(id); }
155
156    Element* rootAXEditableElement(Node*);
157    const Element* rootAXEditableElement(const Node*);
158    bool nodeIsTextControl(const Node*);
159
160    AXID platformGenerateAXID() const;
161    AXObject* objectFromAXID(AXID id) const { return m_objects.get(id); }
162
163    enum AXNotification {
164        AXActiveDescendantChanged,
165        AXAlert,
166        AXAriaAttributeChanged,
167        AXAutocorrectionOccured,
168        AXBlur,
169        AXCheckedStateChanged,
170        AXChildrenChanged,
171        AXFocusedUIElementChanged,
172        AXHide,
173        AXInvalidStatusChanged,
174        AXLayoutComplete,
175        AXLiveRegionChanged,
176        AXLoadComplete,
177        AXLocationChanged,
178        AXMenuListItemSelected,
179        AXMenuListValueChanged,
180        AXRowCollapsed,
181        AXRowCountChanged,
182        AXRowExpanded,
183        AXScrollPositionChanged,
184        AXScrolledToAnchor,
185        AXSelectedChildrenChanged,
186        AXSelectedTextChanged,
187        AXShow,
188        AXTextChanged,
189        AXTextInserted,
190        AXTextRemoved,
191        AXValueChanged
192    };
193
194    void postNotification(RenderObject*, AXNotification, bool postToElement, PostType = PostAsynchronously);
195    void postNotification(Node*, AXNotification, bool postToElement, PostType = PostAsynchronously);
196    void postNotification(AXObject*, Document*, AXNotification, bool postToElement, PostType = PostAsynchronously);
197
198    bool nodeHasRole(Node*, const AtomicString& role);
199
200    AXComputedObjectAttributeCache* computedObjectAttributeCache() { return m_computedObjectAttributeCache.get(); }
201
202protected:
203    void postPlatformNotification(AXObject*, AXNotification);
204    void textChanged(AXObject*);
205    void labelChanged(Element*);
206
207    // This is a weak reference cache for knowing if Nodes used by TextMarkers are valid.
208    void setNodeInUse(Node* n) { m_textMarkerNodes.add(n); }
209    void removeNodeForUse(Node* n) { m_textMarkerNodes.remove(n); }
210    bool isNodeInUse(Node* n) { return m_textMarkerNodes.contains(n); }
211
212private:
213    Document& m_document;
214    HashMap<AXID, RefPtr<AXObject> > m_objects;
215    HashMap<RenderObject*, AXID> m_renderObjectMapping;
216    HashMap<Widget*, AXID> m_widgetObjectMapping;
217    HashMap<Node*, AXID> m_nodeObjectMapping;
218    HashMap<AbstractInlineTextBox*, AXID> m_inlineTextBoxObjectMapping;
219    HashSet<Node*> m_textMarkerNodes;
220    OwnPtr<AXComputedObjectAttributeCache> m_computedObjectAttributeCache;
221    static bool gAccessibilityEnabled;
222    static bool gInlineTextBoxAccessibility;
223
224    HashSet<AXID> m_idsInUse;
225
226    Timer<AXObjectCache> m_notificationPostTimer;
227    Vector<pair<RefPtr<AXObject>, AXNotification> > m_notificationsToPost;
228    void notificationPostTimerFired(Timer<AXObjectCache>*);
229
230    static AXObject* focusedImageMapUIElement(HTMLAreaElement*);
231
232    AXID getAXID(AXObject*);
233};
234
235bool nodeHasRole(Node*, const String& role);
236// This will let you know if aria-hidden was explicitly set to false.
237bool isNodeAriaVisible(Node*);
238
239}
240
241#endif
242