OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "content/browser/accessibility/browser_accessibility_manager_win.h" | 5 #include "content/browser/accessibility/browser_accessibility_manager_win.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
13 #include "base/win/scoped_comptr.h" | 13 #include "base/win/scoped_comptr.h" |
14 #include "base/win/windows_version.h" | 14 #include "base/win/windows_version.h" |
15 #include "content/browser/accessibility/browser_accessibility_state_impl.h" | 15 #include "content/browser/accessibility/browser_accessibility_state_impl.h" |
16 #include "content/browser/accessibility/browser_accessibility_win.h" | 16 #include "content/browser/accessibility/browser_accessibility_win.h" |
17 #include "content/browser/renderer_host/legacy_render_widget_host_win.h" | 17 #include "content/browser/renderer_host/legacy_render_widget_host_win.h" |
18 #include "content/common/accessibility_messages.h" | 18 #include "content/common/accessibility_messages.h" |
19 #include "ui/base/win/atl_module.h" | 19 #include "ui/base/win/atl_module.h" |
20 | 20 |
21 namespace content { | 21 namespace content { |
22 | 22 |
23 // Map from unique_id_win to BrowserAccessibility | |
24 using UniqueIDWinMap = base::hash_map<LONG, BrowserAccessibility*>; | |
25 base::LazyInstance<UniqueIDWinMap> g_unique_id_map = LAZY_INSTANCE_INITIALIZER; | |
26 | |
27 // static | 23 // static |
28 BrowserAccessibilityManager* BrowserAccessibilityManager::Create( | 24 BrowserAccessibilityManager* BrowserAccessibilityManager::Create( |
29 const ui::AXTreeUpdate& initial_tree, | 25 const ui::AXTreeUpdate& initial_tree, |
30 BrowserAccessibilityDelegate* delegate, | 26 BrowserAccessibilityDelegate* delegate, |
31 BrowserAccessibilityFactory* factory) { | 27 BrowserAccessibilityFactory* factory) { |
32 return new BrowserAccessibilityManagerWin(initial_tree, delegate, factory); | 28 return new BrowserAccessibilityManagerWin(initial_tree, delegate, factory); |
33 } | 29 } |
34 | 30 |
35 BrowserAccessibilityManagerWin* | 31 BrowserAccessibilityManagerWin* |
36 BrowserAccessibilityManager::ToBrowserAccessibilityManagerWin() { | 32 BrowserAccessibilityManager::ToBrowserAccessibilityManagerWin() { |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 return; | 138 return; |
143 } | 139 } |
144 | 140 |
145 // If a focus event is needed on the root, fire that first before | 141 // If a focus event is needed on the root, fire that first before |
146 // this event. | 142 // this event. |
147 if (event == EVENT_OBJECT_FOCUS && node == GetRoot()) | 143 if (event == EVENT_OBJECT_FOCUS && node == GetRoot()) |
148 focus_event_on_root_needed_ = false; | 144 focus_event_on_root_needed_ = false; |
149 else if (focus_event_on_root_needed_) | 145 else if (focus_event_on_root_needed_) |
150 OnWindowFocused(); | 146 OnWindowFocused(); |
151 | 147 |
152 LONG child_id = node->ToBrowserAccessibilityWin()->unique_id_win(); | 148 // Pass the negation of this node's unique id in the |child_id| |
| 149 // argument to NotifyWinEvent; the AT client will then call get_accChild |
| 150 // on the HWND's accessibility object and pass it that same id, which |
| 151 // we can use to retrieve the IAccessible for this node. |
| 152 LONG child_id = -node->unique_id(); |
153 ::NotifyWinEvent(event, hwnd, OBJID_CLIENT, child_id); | 153 ::NotifyWinEvent(event, hwnd, OBJID_CLIENT, child_id); |
154 } | 154 } |
155 | 155 |
156 void BrowserAccessibilityManagerWin::OnIAccessible2Used() { | 156 void BrowserAccessibilityManagerWin::OnIAccessible2Used() { |
157 BrowserAccessibilityStateImpl::GetInstance()->OnScreenReaderDetected(); | 157 BrowserAccessibilityStateImpl::GetInstance()->OnScreenReaderDetected(); |
158 } | 158 } |
159 | 159 |
160 void BrowserAccessibilityManagerWin::OnWindowFocused() { | 160 void BrowserAccessibilityManagerWin::OnWindowFocused() { |
161 // Make sure we don't call this recursively. | 161 // Make sure we don't call this recursively. |
162 if (inside_on_window_focused_) | 162 if (inside_on_window_focused_) |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
286 } | 286 } |
287 default: | 287 default: |
288 // Not all WebKit accessibility events result in a Windows | 288 // Not all WebKit accessibility events result in a Windows |
289 // accessibility notification. | 289 // accessibility notification. |
290 break; | 290 break; |
291 } | 291 } |
292 | 292 |
293 if (!node) | 293 if (!node) |
294 return; | 294 return; |
295 | 295 |
296 if (event_id != EVENT_MIN) { | 296 if (event_id != EVENT_MIN) |
297 // Pass the node's unique id in the |child_id| argument to NotifyWinEvent; | |
298 // the AT client will then call get_accChild on the HWND's accessibility | |
299 // object and pass it that same id, which we can use to retrieve the | |
300 // IAccessible for this node. | |
301 MaybeCallNotifyWinEvent(event_id, node); | 297 MaybeCallNotifyWinEvent(event_id, node); |
302 } | 298 |
303 | 299 |
304 // If this is a layout complete notification (sent when a container scrolls) | 300 // If this is a layout complete notification (sent when a container scrolls) |
305 // and there is a descendant tracked object, send a notification on it. | 301 // and there is a descendant tracked object, send a notification on it. |
306 // TODO(dmazzoni): remove once http://crbug.com/113483 is fixed. | 302 // TODO(dmazzoni): remove once http://crbug.com/113483 is fixed. |
307 if (event_type == ui::AX_EVENT_LAYOUT_COMPLETE && | 303 if (event_type == ui::AX_EVENT_LAYOUT_COMPLETE && |
308 tracked_scroll_object_ && | 304 tracked_scroll_object_ && |
309 tracked_scroll_object_->IsDescendantOf(node)) { | 305 tracked_scroll_object_->IsDescendantOf(node)) { |
310 MaybeCallNotifyWinEvent( | 306 MaybeCallNotifyWinEvent( |
311 IA2_EVENT_VISIBLE_DATA_CHANGED, tracked_scroll_object_); | 307 IA2_EVENT_VISIBLE_DATA_CHANGED, tracked_scroll_object_); |
312 tracked_scroll_object_->Release(); | 308 tracked_scroll_object_->Release(); |
313 tracked_scroll_object_ = NULL; | 309 tracked_scroll_object_ = NULL; |
314 } | 310 } |
315 } | 311 } |
316 | 312 |
317 void BrowserAccessibilityManagerWin::OnNodeCreated(ui::AXTree* tree, | 313 void BrowserAccessibilityManagerWin::OnNodeCreated(ui::AXTree* tree, |
318 ui::AXNode* node) { | 314 ui::AXNode* node) { |
319 DCHECK(node); | 315 DCHECK(node); |
320 BrowserAccessibilityManager::OnNodeCreated(tree, node); | 316 BrowserAccessibilityManager::OnNodeCreated(tree, node); |
321 BrowserAccessibility* obj = GetFromAXNode(node); | 317 BrowserAccessibility* obj = GetFromAXNode(node); |
322 if (!obj) | 318 if (!obj) |
323 return; | 319 return; |
324 if (!obj->IsNative()) | 320 if (!obj->IsNative()) |
325 return; | 321 return; |
326 LONG unique_id_win = obj->ToBrowserAccessibilityWin()->unique_id_win(); | |
327 g_unique_id_map.Get()[unique_id_win] = obj; | |
328 } | 322 } |
329 | 323 |
330 void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXTree* tree, | 324 void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXTree* tree, |
331 ui::AXNode* node) { | 325 ui::AXNode* node) { |
332 DCHECK(node); | 326 DCHECK(node); |
333 BrowserAccessibility* obj = GetFromAXNode(node); | 327 BrowserAccessibility* obj = GetFromAXNode(node); |
334 if (obj && obj->IsNative()) { | 328 if (obj && obj->IsNative()) { |
335 g_unique_id_map.Get().erase( | |
336 obj->ToBrowserAccessibilityWin()->unique_id_win()); | |
337 if (obj == tracked_scroll_object_) { | 329 if (obj == tracked_scroll_object_) { |
338 tracked_scroll_object_->Release(); | 330 tracked_scroll_object_->Release(); |
339 tracked_scroll_object_ = NULL; | 331 tracked_scroll_object_ = NULL; |
340 } | 332 } |
341 } | 333 } |
342 | 334 |
343 // Call the inherited function at the bottom, otherwise our call to | 335 // Call the inherited function at the bottom, otherwise our call to |
344 // |GetFromAXNode|, above, will fail! | 336 // |GetFromAXNode|, above, will fail! |
345 BrowserAccessibilityManager::OnNodeWillBeDeleted(tree, node); | 337 BrowserAccessibilityManager::OnNodeWillBeDeleted(tree, node); |
346 } | 338 } |
(...skipping 13 matching lines...) Expand all Loading... |
360 | 352 |
361 // Do a sequence of Windows-specific updates on each node. Each one is | 353 // Do a sequence of Windows-specific updates on each node. Each one is |
362 // done in a single pass that must complete before the next step starts. | 354 // done in a single pass that must complete before the next step starts. |
363 // The first step moves win_attributes_ to old_win_attributes_ and then | 355 // The first step moves win_attributes_ to old_win_attributes_ and then |
364 // recomputes all of win_attributes_ other than IAccessibleText. | 356 // recomputes all of win_attributes_ other than IAccessibleText. |
365 for (size_t i = 0; i < changes.size(); ++i) { | 357 for (size_t i = 0; i < changes.size(); ++i) { |
366 const ui::AXNode* changed_node = changes[i].node; | 358 const ui::AXNode* changed_node = changes[i].node; |
367 DCHECK(changed_node); | 359 DCHECK(changed_node); |
368 BrowserAccessibility* obj = GetFromAXNode(changed_node); | 360 BrowserAccessibility* obj = GetFromAXNode(changed_node); |
369 if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf()) | 361 if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf()) |
370 obj->ToBrowserAccessibilityWin()->UpdateStep1ComputeWinAttributes(); | 362 ToBrowserAccessibilityWin(obj)->UpdateStep1ComputeWinAttributes(); |
371 } | 363 } |
372 | 364 |
373 // The next step updates the hypertext of each node, which is a | 365 // The next step updates the hypertext of each node, which is a |
374 // concatenation of all of its child text nodes, so it can't run until | 366 // concatenation of all of its child text nodes, so it can't run until |
375 // the text of all of the nodes was computed in the previous step. | 367 // the text of all of the nodes was computed in the previous step. |
376 for (size_t i = 0; i < changes.size(); ++i) { | 368 for (size_t i = 0; i < changes.size(); ++i) { |
377 const ui::AXNode* changed_node = changes[i].node; | 369 const ui::AXNode* changed_node = changes[i].node; |
378 DCHECK(changed_node); | 370 DCHECK(changed_node); |
379 BrowserAccessibility* obj = GetFromAXNode(changed_node); | 371 BrowserAccessibility* obj = GetFromAXNode(changed_node); |
380 if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf()) | 372 if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf()) |
381 obj->ToBrowserAccessibilityWin()->UpdateStep2ComputeHypertext(); | 373 ToBrowserAccessibilityWin(obj)->UpdateStep2ComputeHypertext(); |
382 } | 374 } |
383 | 375 |
384 // The third step fires events on nodes based on what's changed - like | 376 // The third step fires events on nodes based on what's changed - like |
385 // if the name, value, or description changed, or if the hypertext had | 377 // if the name, value, or description changed, or if the hypertext had |
386 // text inserted or removed. It's able to figure out exactly what changed | 378 // text inserted or removed. It's able to figure out exactly what changed |
387 // because we still have old_win_attributes_ populated. | 379 // because we still have old_win_attributes_ populated. |
388 // This step has to run after the previous two steps complete because the | 380 // This step has to run after the previous two steps complete because the |
389 // client may walk the tree when it receives any of these events. | 381 // client may walk the tree when it receives any of these events. |
390 // At the end, it deletes old_win_attributes_ since they're not needed | 382 // At the end, it deletes old_win_attributes_ since they're not needed |
391 // anymore. | 383 // anymore. |
392 for (size_t i = 0; i < changes.size(); ++i) { | 384 for (size_t i = 0; i < changes.size(); ++i) { |
393 const ui::AXNode* changed_node = changes[i].node; | 385 const ui::AXNode* changed_node = changes[i].node; |
394 DCHECK(changed_node); | 386 DCHECK(changed_node); |
395 BrowserAccessibility* obj = GetFromAXNode(changed_node); | 387 BrowserAccessibility* obj = GetFromAXNode(changed_node); |
396 if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf()) { | 388 if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf()) { |
397 obj->ToBrowserAccessibilityWin()->UpdateStep3FireEvents( | 389 ToBrowserAccessibilityWin(obj)->UpdateStep3FireEvents( |
398 changes[i].type == AXTreeDelegate::SUBTREE_CREATED); | 390 changes[i].type == AXTreeDelegate::SUBTREE_CREATED); |
399 } | 391 } |
400 } | 392 } |
401 } | 393 } |
402 | 394 |
403 void BrowserAccessibilityManagerWin::TrackScrollingObject( | 395 void BrowserAccessibilityManagerWin::TrackScrollingObject( |
404 BrowserAccessibilityWin* node) { | 396 BrowserAccessibilityWin* node) { |
405 if (tracked_scroll_object_) | 397 if (tracked_scroll_object_) |
406 tracked_scroll_object_->Release(); | 398 tracked_scroll_object_->Release(); |
407 tracked_scroll_object_ = node; | 399 tracked_scroll_object_ = node; |
408 tracked_scroll_object_->AddRef(); | 400 tracked_scroll_object_->AddRef(); |
409 } | 401 } |
410 | 402 |
411 BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFromUniqueIdWin( | |
412 LONG unique_id_win) { | |
413 auto iter = g_unique_id_map.Get().find(unique_id_win); | |
414 if (iter == g_unique_id_map.Get().end()) | |
415 return nullptr; | |
416 | |
417 return iter->second->ToBrowserAccessibilityWin(); | |
418 } | |
419 | |
420 } // namespace content | 403 } // namespace content |
OLD | NEW |