e0b432f85478fc4cd06b68fa48e60e8f118636e8
[WebKit-https.git] / WebCore / page / AXObjectCache.cpp
1 /*
2  * Copyright (C) 2008 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "AXObjectCache.h"
31
32 #include "AccessibilityList.h"
33 #include "AccessibilityListBox.h"
34 #include "AccessibilityListBoxOption.h"
35 #include "AccessibilityImageMapLink.h"
36 #include "AccessibilityRenderObject.h"
37 #include "AccessibilityTable.h"
38 #include "AccessibilityTableCell.h"
39 #include "AccessibilityTableColumn.h"
40 #include "AccessibilityTableHeaderContainer.h"
41 #include "AccessibilityTableRow.h"
42 #include "HTMLNames.h"
43 #include "RenderObject.h"
44
45 #include <wtf/PassRefPtr.h>
46
47 namespace WebCore {
48
49 using namespace HTMLNames;
50     
51 bool AXObjectCache::gAccessibilityEnabled = false;
52 bool AXObjectCache::gAccessibilityEnhancedUserInterfaceEnabled = false;
53
54 AXObjectCache::~AXObjectCache()
55 {
56     HashMap<AXID, RefPtr<AccessibilityObject> >::iterator end = m_objects.end();
57     for (HashMap<AXID, RefPtr<AccessibilityObject> >::iterator it = m_objects.begin(); it != end; ++it) {
58         AccessibilityObject* obj = (*it).second.get();
59         detachWrapper(obj);
60         obj->detach();
61     }
62 }
63
64 AccessibilityObject* AXObjectCache::get(RenderObject* renderer)
65 {
66     if (!renderer)
67         return 0;
68     
69     RefPtr<AccessibilityObject> obj = 0;
70     AXID axID = m_renderObjectMapping.get(renderer);
71     ASSERT(!HashTraits<AXID>::isDeletedValue(axID));
72
73     if (axID)
74         obj = m_objects.get(axID).get();
75
76     Node* node = renderer->node();
77     if (!obj) {
78         if (renderer->isListBox())
79             obj = AccessibilityListBox::create(renderer);
80         else if (node && (node->hasTagName(ulTag) || node->hasTagName(olTag) || node->hasTagName(dlTag)))
81             obj = AccessibilityList::create(renderer);
82         else if (renderer->isTable())
83             obj = AccessibilityTable::create(renderer);
84         else if (renderer->isTableRow())
85             obj = AccessibilityTableRow::create(renderer);
86         else if (renderer->isTableCell())
87             obj = AccessibilityTableCell::create(renderer);
88         else
89             obj = AccessibilityRenderObject::create(renderer);
90         
91         getAXID(obj.get());
92         
93         m_renderObjectMapping.set(renderer, obj.get()->axObjectID());
94         m_objects.set(obj.get()->axObjectID(), obj);    
95         attachWrapper(obj.get());
96     }
97     
98     return obj.get();
99 }
100
101 AccessibilityObject* AXObjectCache::get(AccessibilityRole role)
102 {
103     RefPtr<AccessibilityObject> obj = 0;
104     
105     // will be filled in...
106     switch (role) {
107         case ListBoxOptionRole:
108             obj = AccessibilityListBoxOption::create();
109             break;
110         case ImageMapLinkRole:
111             obj = AccessibilityImageMapLink::create();
112             break;
113         case ColumnRole:
114             obj = AccessibilityTableColumn::create();
115             break;            
116         case TableHeaderContainerRole:
117             obj = AccessibilityTableHeaderContainer::create();
118             break;            
119         default:
120             obj = 0;
121     }
122     
123     if (obj)
124         getAXID(obj.get());
125     else
126         return 0;
127
128     m_objects.set(obj->axObjectID(), obj);    
129     attachWrapper(obj.get());
130     return obj.get();
131 }
132
133 void AXObjectCache::remove(AXID axID)
134 {
135     if (!axID)
136         return;
137     
138     // first fetch object to operate some cleanup functions on it 
139     AccessibilityObject* obj = m_objects.get(axID).get();
140     if (!obj)
141         return;
142     
143     detachWrapper(obj);
144     obj->detach();
145     removeAXID(obj);
146     
147     // finally remove the object
148     if (!m_objects.take(axID)) {
149         return;
150     }
151     
152     ASSERT(m_objects.size() >= m_idsInUse.size());    
153 }
154     
155 void AXObjectCache::remove(RenderObject* renderer)
156 {
157     if (!renderer)
158         return;
159     
160     AXID axID = m_renderObjectMapping.get(renderer);
161     remove(axID);
162     m_renderObjectMapping.remove(renderer);
163 }
164
165 AXID AXObjectCache::getAXID(AccessibilityObject* obj)
166 {
167     // check for already-assigned ID
168     AXID objID = obj->axObjectID();
169     if (objID) {
170         ASSERT(m_idsInUse.contains(objID));
171         return objID;
172     }
173     
174     // generate a new ID
175     static AXID lastUsedID = 0;
176     objID = lastUsedID;
177     do
178         ++objID;
179     while (objID == 0 || HashTraits<AXID>::isDeletedValue(objID) || m_idsInUse.contains(objID));
180     m_idsInUse.add(objID);
181     lastUsedID = objID;
182     obj->setAXObjectID(objID);
183     
184     return objID;
185 }
186
187 void AXObjectCache::removeAXID(AccessibilityObject* obj)
188 {
189     AXID objID = obj->axObjectID();
190     if (objID == 0)
191         return;
192     ASSERT(!HashTraits<AXID>::isDeletedValue(objID));
193     ASSERT(m_idsInUse.contains(objID));
194     obj->setAXObjectID(0);
195     m_idsInUse.remove(objID);
196 }
197
198 void AXObjectCache::childrenChanged(RenderObject* renderer)
199 {
200     if (!renderer)
201         return;
202  
203     AXID axID = m_renderObjectMapping.get(renderer);
204     if (!axID)
205         return;
206     
207     AccessibilityObject* obj = m_objects.get(axID).get();
208     if (obj)
209         obj->childrenChanged();
210 }
211
212 #if HAVE(ACCESSIBILITY)
213 void AXObjectCache::selectedChildrenChanged(RenderObject* renderer)
214 {
215     postNotificationToElement(renderer, "AXSelectedChildrenChanged");
216 }
217 #endif
218
219 #if HAVE(ACCESSIBILITY)
220 void AXObjectCache::handleActiveDescendantChanged(RenderObject* renderer)
221 {
222     if (!renderer)
223         return;
224     AccessibilityObject* obj = get(renderer);
225     if (obj)
226         obj->handleActiveDescendantChanged();
227 }
228
229 void AXObjectCache::handleAriaRoleChanged(RenderObject* renderer)
230 {
231     if (!renderer)
232         return;
233     AccessibilityObject* obj = get(renderer);
234     if (obj && obj->isAccessibilityRenderObject())
235         static_cast<AccessibilityRenderObject*>(obj)->setAriaRole();
236 }
237 #endif
238
239 } // namespace WebCore