OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/accessibility/browser_accessibility_manager_win.h" | 5 #include "chrome/browser/accessibility/browser_accessibility_manager_win.h" |
6 | 6 |
7 #include "chrome/browser/accessibility/browser_accessibility_win.h" | 7 #include "chrome/browser/accessibility/browser_accessibility_win.h" |
8 #include "chrome/browser/renderer_host/render_process_host.h" | |
9 #include "chrome/browser/renderer_host/render_view_host.h" | |
10 #include "chrome/common/render_messages.h" | |
11 #include "chrome/common/render_messages_params.h" | |
12 | 8 |
13 using webkit_glue::WebAccessibility; | 9 using webkit_glue::WebAccessibility; |
14 | 10 |
15 // static | 11 // static |
16 BrowserAccessibilityManager* BrowserAccessibilityManager::Create( | 12 BrowserAccessibilityManager* BrowserAccessibilityManager::Create( |
17 gfx::NativeWindow parent_window, | 13 gfx::NativeView parent_view, |
18 const webkit_glue::WebAccessibility& src, | 14 const WebAccessibility& src, |
19 BrowserAccessibilityDelegate* delegate) { | 15 BrowserAccessibilityDelegate* delegate, |
| 16 BrowserAccessibilityFactory* factory) { |
20 return new BrowserAccessibilityManagerWin( | 17 return new BrowserAccessibilityManagerWin( |
21 parent_window, src, delegate, new BrowserAccessibilityWinFactory()); | 18 parent_view, |
| 19 src, |
| 20 delegate, |
| 21 factory); |
22 } | 22 } |
23 | 23 |
24 // Factory method to create an instance of BrowserAccessibility | 24 // Defining this here instead of in the base implementation file to address link |
25 BrowserAccessibilityWin* BrowserAccessibilityWinFactory::Create() { | 25 // errors on the linux shared library build. (linux shlib) |
26 CComObject<BrowserAccessibilityWin>* instance; | 26 BrowserAccessibility* BrowserAccessibilityFactory::Create() { |
27 HRESULT hr = CComObject<BrowserAccessibilityWin>::CreateInstance(&instance); | 27 return BrowserAccessibility::Create(); |
28 DCHECK(SUCCEEDED(hr)); | |
29 return instance->NewReference(); | |
30 } | 28 } |
31 | 29 |
32 // static | 30 BrowserAccessibilityManagerWin* |
33 // Start child IDs at -1 and decrement each time, because clients use | 31 BrowserAccessibilityManager::toBrowserAccessibilityManagerWin() { |
34 // child IDs of 1, 2, 3, ... to access the children of an object by | 32 return static_cast<BrowserAccessibilityManagerWin*>(this); |
35 // index, so we use negative IDs to clearly distinguish between indices | 33 } |
36 // and unique IDs. | |
37 LONG BrowserAccessibilityManagerWin::next_child_id_ = -1; | |
38 | 34 |
39 BrowserAccessibilityManagerWin::BrowserAccessibilityManagerWin( | 35 BrowserAccessibilityManagerWin::BrowserAccessibilityManagerWin( |
40 HWND parent_window, | 36 HWND parent_view, |
41 const webkit_glue::WebAccessibility& src, | 37 const WebAccessibility& src, |
42 BrowserAccessibilityDelegate* delegate, | 38 BrowserAccessibilityDelegate* delegate, |
43 BrowserAccessibilityWinFactory* factory) | 39 BrowserAccessibilityFactory* factory) |
44 : BrowserAccessibilityManager(parent_window), | 40 : BrowserAccessibilityManager(parent_view, src, delegate, factory) { |
45 delegate_(delegate), | |
46 factory_(factory), | |
47 focus_(NULL) { | |
48 HRESULT hr = ::CreateStdAccessibleObject( | 41 HRESULT hr = ::CreateStdAccessibleObject( |
49 parent_window, OBJID_WINDOW, IID_IAccessible, | 42 parent_view, OBJID_WINDOW, IID_IAccessible, |
50 reinterpret_cast<void **>(&window_iaccessible_)); | 43 reinterpret_cast<void **>(&window_iaccessible_)); |
51 DCHECK(SUCCEEDED(hr)); | 44 DCHECK(SUCCEEDED(hr)); |
52 root_ = CreateAccessibilityTree(NULL, GetNextChildID(), src, 0); | |
53 if (!focus_) | |
54 focus_ = root_; | |
55 } | 45 } |
56 | 46 |
57 BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() { | 47 BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() { |
58 // Clients could still hold references to some nodes of the tree, so | |
59 // calling Inactivate will make sure that as many nodes as possible are | |
60 // released now, and remaining nodes are marked as inactive so that | |
61 // calls to any methods on them will return E_FAIL; | |
62 root_->InactivateTree(); | |
63 root_->Release(); | |
64 } | |
65 | |
66 BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetRoot() { | |
67 return root_; | |
68 } | |
69 | |
70 void BrowserAccessibilityManagerWin::Remove(LONG child_id) { | |
71 child_id_map_.erase(child_id); | |
72 } | |
73 | |
74 BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFromChildID( | |
75 LONG child_id) { | |
76 base::hash_map<LONG, BrowserAccessibilityWin*>::iterator iter = | |
77 child_id_map_.find(child_id); | |
78 if (iter != child_id_map_.end()) { | |
79 return iter->second; | |
80 } else { | |
81 return NULL; | |
82 } | |
83 } | 48 } |
84 | 49 |
85 IAccessible* BrowserAccessibilityManagerWin::GetParentWindowIAccessible() { | 50 IAccessible* BrowserAccessibilityManagerWin::GetParentWindowIAccessible() { |
86 return window_iaccessible_; | 51 return window_iaccessible_; |
87 } | 52 } |
88 | 53 |
89 BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFocus( | 54 void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent( |
90 BrowserAccessibilityWin* root) { | 55 ViewHostMsg_AccessibilityNotification_Params::NotificationType n, |
91 if (focus_ && (!root || focus_->IsDescendantOf(root))) | 56 BrowserAccessibility* node) { |
92 return focus_; | 57 LONG event_id; |
93 | 58 switch (n) { |
94 return NULL; | 59 case ViewHostMsg_AccessibilityNotification_Params:: |
95 } | 60 NOTIFICATION_TYPE_CHECK_STATE_CHANGED: |
96 | 61 event_id = EVENT_OBJECT_STATECHANGE; |
97 void BrowserAccessibilityManagerWin::SetFocus( | 62 break; |
98 const BrowserAccessibilityWin& node) { | 63 case ViewHostMsg_AccessibilityNotification_Params:: |
99 if (delegate_) | 64 NOTIFICATION_TYPE_CHILDREN_CHANGED: |
100 delegate_->SetAccessibilityFocus(node.renderer_id()); | 65 event_id = EVENT_OBJECT_REORDER; |
101 } | 66 break; |
102 | 67 case ViewHostMsg_AccessibilityNotification_Params:: |
103 void BrowserAccessibilityManagerWin::DoDefaultAction( | 68 NOTIFICATION_TYPE_FOCUS_CHANGED: |
104 const BrowserAccessibilityWin& node) { | 69 event_id = EVENT_OBJECT_FOCUS; |
105 if (delegate_) | 70 break; |
106 delegate_->AccessibilityDoDefaultAction(node.renderer_id()); | 71 case ViewHostMsg_AccessibilityNotification_Params:: |
107 } | 72 NOTIFICATION_TYPE_LOAD_COMPLETE: |
108 | 73 event_id = IA2_EVENT_DOCUMENT_LOAD_COMPLETE; |
109 bool BrowserAccessibilityManagerWin::CanModifyTreeInPlace( | 74 break; |
110 BrowserAccessibilityWin* current_root, | 75 case ViewHostMsg_AccessibilityNotification_Params:: |
111 const webkit_glue::WebAccessibility& new_root) { | 76 NOTIFICATION_TYPE_VALUE_CHANGED: |
112 if (current_root->renderer_id() != new_root.id) | 77 event_id = EVENT_OBJECT_VALUECHANGE; |
113 return false; | 78 break; |
114 if (current_root->GetChildCount() != new_root.children.size()) | 79 case ViewHostMsg_AccessibilityNotification_Params:: |
115 return false; | 80 NOTIFICATION_TYPE_SELECTED_TEXT_CHANGED: |
116 for (unsigned int i = 0; i < current_root->GetChildCount(); i++) { | 81 event_id = IA2_EVENT_TEXT_CARET_MOVED; |
117 if (!CanModifyTreeInPlace(current_root->GetChild(i), | |
118 new_root.children[i])) { | |
119 return false; | |
120 } | |
121 } | |
122 return true; | |
123 } | |
124 | |
125 void BrowserAccessibilityManagerWin::ModifyTreeInPlace( | |
126 BrowserAccessibilityWin* current_root, | |
127 const webkit_glue::WebAccessibility& new_root) { | |
128 DCHECK_EQ(current_root->renderer_id(), new_root.id); | |
129 DCHECK_EQ(current_root->GetChildCount(), new_root.children.size()); | |
130 for (unsigned int i = 0; i < current_root->GetChildCount(); i++) | |
131 ModifyTreeInPlace(current_root->GetChild(i), new_root.children[i]); | |
132 current_root->Initialize( | |
133 this, | |
134 current_root->GetParent(), | |
135 current_root->child_id(), | |
136 current_root->index_in_parent(), | |
137 new_root); | |
138 } | |
139 | |
140 | |
141 BrowserAccessibilityWin* BrowserAccessibilityManagerWin::UpdateTree( | |
142 const webkit_glue::WebAccessibility& acc_obj) { | |
143 base::hash_map<int, LONG>::iterator iter = | |
144 renderer_id_to_child_id_map_.find(acc_obj.id); | |
145 if (iter == renderer_id_to_child_id_map_.end()) | |
146 return NULL; | |
147 | |
148 LONG child_id = iter->second; | |
149 BrowserAccessibilityWin* old_browser_acc = GetFromChildID(child_id); | |
150 if (!old_browser_acc) | |
151 return NULL; | |
152 | |
153 if (CanModifyTreeInPlace(old_browser_acc, acc_obj)) { | |
154 ModifyTreeInPlace(old_browser_acc, acc_obj); | |
155 return old_browser_acc; | |
156 } | 82 } |
157 | 83 |
158 BrowserAccessibilityWin* new_browser_acc = CreateAccessibilityTree( | 84 NotifyWinEvent(event_id, GetParentView(), OBJID_CLIENT, node->child_id()); |
159 old_browser_acc->GetParent(), | |
160 child_id, | |
161 acc_obj, | |
162 old_browser_acc->index_in_parent()); | |
163 | |
164 if (old_browser_acc->GetParent()) { | |
165 old_browser_acc->GetParent()->ReplaceChild( | |
166 old_browser_acc, | |
167 new_browser_acc); | |
168 } else { | |
169 DCHECK_EQ(old_browser_acc, root_); | |
170 root_ = new_browser_acc; | |
171 } | |
172 old_browser_acc->InactivateTree(); | |
173 old_browser_acc->Release(); | |
174 child_id_map_[child_id] = new_browser_acc; | |
175 | |
176 return new_browser_acc; | |
177 } | 85 } |
178 | |
179 void BrowserAccessibilityManagerWin::GotFocus() { | |
180 // TODO(ctguil): Remove when tree update logic handles focus changes. | |
181 if (!focus_) | |
182 return; | |
183 | |
184 NotifyWinEvent( | |
185 EVENT_OBJECT_FOCUS, | |
186 GetParentWindow(), | |
187 OBJID_CLIENT, | |
188 focus_->child_id()); | |
189 } | |
190 | |
191 IAccessible* BrowserAccessibilityManagerWin::GetRootAccessible() { | |
192 return root_; | |
193 } | |
194 | |
195 void BrowserAccessibilityManagerWin::OnAccessibilityObjectStateChange( | |
196 const webkit_glue::WebAccessibility& acc_obj) { | |
197 BrowserAccessibilityWin* new_browser_acc = UpdateTree(acc_obj); | |
198 if (!new_browser_acc) | |
199 return; | |
200 | |
201 LONG child_id = new_browser_acc->child_id(); | |
202 NotifyWinEvent( | |
203 EVENT_OBJECT_STATECHANGE, GetParentWindow(), OBJID_CLIENT, child_id); | |
204 } | |
205 | |
206 void BrowserAccessibilityManagerWin::OnAccessibilityObjectChildrenChange( | |
207 const webkit_glue::WebAccessibility& acc_obj) { | |
208 BrowserAccessibilityWin* new_browser_acc = UpdateTree(acc_obj); | |
209 if (!new_browser_acc) | |
210 return; | |
211 | |
212 LONG child_id; | |
213 if (root_ != new_browser_acc) { | |
214 child_id = new_browser_acc->GetParent()->child_id(); | |
215 } else { | |
216 child_id = CHILDID_SELF; | |
217 } | |
218 | |
219 NotifyWinEvent( | |
220 EVENT_OBJECT_REORDER, GetParentWindow(), OBJID_CLIENT, child_id); | |
221 } | |
222 | |
223 void BrowserAccessibilityManagerWin::OnAccessibilityObjectFocusChange( | |
224 const webkit_glue::WebAccessibility& acc_obj) { | |
225 BrowserAccessibilityWin* new_browser_acc = UpdateTree(acc_obj); | |
226 if (!new_browser_acc) | |
227 return; | |
228 | |
229 focus_ = new_browser_acc; | |
230 LONG child_id = new_browser_acc->child_id(); | |
231 if (delegate_ && delegate_->HasFocus()) | |
232 GotFocus(); | |
233 } | |
234 | |
235 void BrowserAccessibilityManagerWin::OnAccessibilityObjectLoadComplete( | |
236 const webkit_glue::WebAccessibility& acc_obj) { | |
237 root_->InactivateTree(); | |
238 root_->Release(); | |
239 focus_ = NULL; | |
240 | |
241 root_ = CreateAccessibilityTree(NULL, GetNextChildID(), acc_obj, 0); | |
242 if (!focus_) | |
243 focus_ = root_; | |
244 | |
245 NotifyWinEvent( | |
246 IA2_EVENT_DOCUMENT_LOAD_COMPLETE, | |
247 GetParentWindow(), | |
248 OBJID_CLIENT, | |
249 root_->child_id()); | |
250 if (delegate_ && delegate_->HasFocus()) | |
251 GotFocus(); | |
252 } | |
253 | |
254 void BrowserAccessibilityManagerWin::OnAccessibilityObjectValueChange( | |
255 const webkit_glue::WebAccessibility& acc_obj) { | |
256 BrowserAccessibilityWin* new_browser_acc = UpdateTree(acc_obj); | |
257 if (!new_browser_acc) | |
258 return; | |
259 | |
260 LONG child_id = new_browser_acc->child_id(); | |
261 NotifyWinEvent( | |
262 EVENT_OBJECT_VALUECHANGE, GetParentWindow(), OBJID_CLIENT, child_id); | |
263 } | |
264 | |
265 void BrowserAccessibilityManagerWin::OnAccessibilityObjectTextChange( | |
266 const webkit_glue::WebAccessibility& acc_obj) { | |
267 BrowserAccessibilityWin* new_browser_acc = UpdateTree(acc_obj); | |
268 if (!new_browser_acc) | |
269 return; | |
270 | |
271 LONG child_id = new_browser_acc->child_id(); | |
272 NotifyWinEvent( | |
273 IA2_EVENT_TEXT_CARET_MOVED, GetParentWindow(), OBJID_CLIENT, child_id); | |
274 } | |
275 | |
276 LONG BrowserAccessibilityManagerWin::GetNextChildID() { | |
277 // Get the next child ID, and wrap around when we get near the end | |
278 // of a 32-bit integer range. It's okay to wrap around; we just want | |
279 // to avoid it as long as possible because clients may cache the ID of | |
280 // an object for a while to determine if they've seen it before. | |
281 next_child_id_--; | |
282 if (next_child_id_ == -2000000000) | |
283 next_child_id_ = -1; | |
284 | |
285 return next_child_id_; | |
286 } | |
287 | |
288 BrowserAccessibilityWin* | |
289 BrowserAccessibilityManagerWin::CreateAccessibilityTree( | |
290 BrowserAccessibilityWin* parent, | |
291 int child_id, | |
292 const webkit_glue::WebAccessibility& src, | |
293 int index_in_parent) { | |
294 BrowserAccessibilityWin* instance = factory_->Create(); | |
295 | |
296 instance->Initialize(this, parent, child_id, index_in_parent, src); | |
297 child_id_map_[child_id] = instance; | |
298 renderer_id_to_child_id_map_[src.id] = child_id; | |
299 if ((src.state >> WebAccessibility::STATE_FOCUSED) & 1) | |
300 focus_ = instance; | |
301 for (int i = 0; i < static_cast<int>(src.children.size()); ++i) { | |
302 BrowserAccessibilityWin* child = CreateAccessibilityTree( | |
303 instance, GetNextChildID(), src.children[i], i); | |
304 instance->AddChild(child); | |
305 } | |
306 | |
307 return instance; | |
308 } | |
OLD | NEW |