| 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> |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 BrowserAccessibilityManagerWin* | 31 BrowserAccessibilityManagerWin* |
| 32 BrowserAccessibilityManager::ToBrowserAccessibilityManagerWin() { | 32 BrowserAccessibilityManager::ToBrowserAccessibilityManagerWin() { |
| 33 return static_cast<BrowserAccessibilityManagerWin*>(this); | 33 return static_cast<BrowserAccessibilityManagerWin*>(this); |
| 34 } | 34 } |
| 35 | 35 |
| 36 BrowserAccessibilityManagerWin::BrowserAccessibilityManagerWin( | 36 BrowserAccessibilityManagerWin::BrowserAccessibilityManagerWin( |
| 37 const ui::AXTreeUpdate& initial_tree, | 37 const ui::AXTreeUpdate& initial_tree, |
| 38 BrowserAccessibilityDelegate* delegate, | 38 BrowserAccessibilityDelegate* delegate, |
| 39 BrowserAccessibilityFactory* factory) | 39 BrowserAccessibilityFactory* factory) |
| 40 : BrowserAccessibilityManager(delegate, factory), | 40 : BrowserAccessibilityManager(delegate, factory), |
| 41 tracked_scroll_object_(NULL), | 41 tracked_scroll_object_(NULL) { |
| 42 focus_event_on_root_needed_(false), | |
| 43 inside_on_window_focused_(false) { | |
| 44 ui::win::CreateATLModuleIfNeeded(); | 42 ui::win::CreateATLModuleIfNeeded(); |
| 45 Initialize(initial_tree); | 43 Initialize(initial_tree); |
| 46 ui::GetIAccessible2UsageObserverList().AddObserver(this); | 44 ui::GetIAccessible2UsageObserverList().AddObserver(this); |
| 47 } | 45 } |
| 48 | 46 |
| 49 BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() { | 47 BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() { |
| 50 // Destroy the tree in the subclass, rather than in the inherited | 48 // Destroy the tree in the subclass, rather than in the inherited |
| 51 // destructor, otherwise our overrides of functions like | 49 // destructor, otherwise our overrides of functions like |
| 52 // OnNodeWillBeDeleted won't be called. | 50 // OnNodeWillBeDeleted won't be called. |
| 53 tree_.reset(NULL); | 51 tree_.reset(NULL); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 // Inline text boxes are an internal implementation detail, we don't | 110 // Inline text boxes are an internal implementation detail, we don't |
| 113 // expose them to Windows. | 111 // expose them to Windows. |
| 114 if (node->GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX) | 112 if (node->GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX) |
| 115 return; | 113 return; |
| 116 | 114 |
| 117 // It doesn't make sense to fire a REORDER event on a leaf node; that | 115 // It doesn't make sense to fire a REORDER event on a leaf node; that |
| 118 // happens when the node has internal children line inline text boxes. | 116 // happens when the node has internal children line inline text boxes. |
| 119 if (event == EVENT_OBJECT_REORDER && node->PlatformIsLeaf()) | 117 if (event == EVENT_OBJECT_REORDER && node->PlatformIsLeaf()) |
| 120 return; | 118 return; |
| 121 | 119 |
| 122 // Don't fire focus, or load complete notifications if the | |
| 123 // window isn't focused, because that can confuse screen readers into | |
| 124 // entering their "browse" mode. | |
| 125 if ((event == EVENT_OBJECT_FOCUS || | |
| 126 event == IA2_EVENT_DOCUMENT_LOAD_COMPLETE) && | |
| 127 !NativeViewHasFocus()) { | |
| 128 return; | |
| 129 } | |
| 130 | |
| 131 // NVDA gets confused if we focus the main document element when it hasn't | |
| 132 // finished loading and it has no children at all, so suppress that event. | |
| 133 if (event == EVENT_OBJECT_FOCUS && | |
| 134 node == GetRoot() && | |
| 135 node->PlatformChildCount() == 0 && | |
| 136 !node->HasState(ui::AX_STATE_BUSY) && | |
| 137 !node->manager()->GetTreeData().loaded) { | |
| 138 return; | |
| 139 } | |
| 140 | |
| 141 // If a focus event is needed on the root, fire that first before | |
| 142 // this event. | |
| 143 if (event == EVENT_OBJECT_FOCUS && node == GetRoot()) | |
| 144 focus_event_on_root_needed_ = false; | |
| 145 else if (focus_event_on_root_needed_) | |
| 146 OnWindowFocused(); | |
| 147 | |
| 148 // Pass the negation of this node's unique id in the |child_id| | 120 // 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 | 121 // 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 | 122 // on the HWND's accessibility object and pass it that same id, which |
| 151 // we can use to retrieve the IAccessible for this node. | 123 // we can use to retrieve the IAccessible for this node. |
| 152 LONG child_id = -node->unique_id(); | 124 LONG child_id = -node->unique_id(); |
| 153 ::NotifyWinEvent(event, hwnd, OBJID_CLIENT, child_id); | 125 ::NotifyWinEvent(event, hwnd, OBJID_CLIENT, child_id); |
| 154 } | 126 } |
| 155 | 127 |
| 156 void BrowserAccessibilityManagerWin::OnIAccessible2Used() { | 128 void BrowserAccessibilityManagerWin::OnIAccessible2Used() { |
| 157 BrowserAccessibilityStateImpl::GetInstance()->OnScreenReaderDetected(); | 129 BrowserAccessibilityStateImpl::GetInstance()->OnScreenReaderDetected(); |
| 158 } | 130 } |
| 159 | 131 |
| 160 void BrowserAccessibilityManagerWin::OnWindowFocused() { | |
| 161 // Make sure we don't call this recursively. | |
| 162 if (inside_on_window_focused_) | |
| 163 return; | |
| 164 inside_on_window_focused_ = true; | |
| 165 | |
| 166 // This is called either when this web frame gets focused, or when | |
| 167 // the root of the accessibility tree changes. In both cases, we need | |
| 168 // to fire a focus event on the root and then on the focused element | |
| 169 // within the page, if different. | |
| 170 | |
| 171 // Set this flag so that we'll keep trying to fire these focus events | |
| 172 // if they're not successful this time. | |
| 173 focus_event_on_root_needed_ = true; | |
| 174 | |
| 175 if (!NativeViewHasFocus()) { | |
| 176 inside_on_window_focused_ = false; | |
| 177 return; | |
| 178 } | |
| 179 | |
| 180 // Try to fire a focus event on the root first and then the focused node. | |
| 181 // This will clear focus_event_on_root_needed_ if successful. | |
| 182 if (GetFocus() != GetRoot() && GetRoot()) | |
| 183 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetRoot()); | |
| 184 BrowserAccessibilityManager::OnWindowFocused(); | |
| 185 inside_on_window_focused_ = false; | |
| 186 } | |
| 187 | |
| 188 void BrowserAccessibilityManagerWin::UserIsReloading() { | 132 void BrowserAccessibilityManagerWin::UserIsReloading() { |
| 189 if (GetRoot()) | 133 if (GetRoot()) |
| 190 MaybeCallNotifyWinEvent(IA2_EVENT_DOCUMENT_RELOAD, GetRoot()); | 134 MaybeCallNotifyWinEvent(IA2_EVENT_DOCUMENT_RELOAD, GetRoot()); |
| 191 } | 135 } |
| 192 | 136 |
| 193 void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent( | 137 void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent( |
| 194 ui::AXEvent event_type, | 138 ui::AXEvent event_type, |
| 195 BrowserAccessibility* node) { | 139 BrowserAccessibility* node) { |
| 196 BrowserAccessibilityDelegate* root_delegate = GetDelegateFromRootManager(); | 140 BrowserAccessibilityDelegate* root_delegate = GetDelegateFromRootManager(); |
| 197 if (!root_delegate || !root_delegate->AccessibilityGetAcceleratedWidget()) { | 141 if (!root_delegate || !root_delegate->AccessibilityGetAcceleratedWidget()) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 212 // Don't fire focus, blur, or load complete notifications if the | 156 // Don't fire focus, blur, or load complete notifications if the |
| 213 // window isn't focused, because that can confuse screen readers into | 157 // window isn't focused, because that can confuse screen readers into |
| 214 // entering their "browse" mode. | 158 // entering their "browse" mode. |
| 215 if ((event_type == ui::AX_EVENT_FOCUS || | 159 if ((event_type == ui::AX_EVENT_FOCUS || |
| 216 event_type == ui::AX_EVENT_BLUR || | 160 event_type == ui::AX_EVENT_BLUR || |
| 217 event_type == ui::AX_EVENT_LOAD_COMPLETE) && | 161 event_type == ui::AX_EVENT_LOAD_COMPLETE) && |
| 218 !NativeViewHasFocus()) { | 162 !NativeViewHasFocus()) { |
| 219 return; | 163 return; |
| 220 } | 164 } |
| 221 | 165 |
| 222 // NVDA gets confused if we focus the main document element when it hasn't | |
| 223 // finished loading and it has no children at all, so suppress that event. | |
| 224 if (event_type == ui::AX_EVENT_FOCUS && | |
| 225 node == GetRoot() && | |
| 226 node->PlatformChildCount() == 0 && | |
| 227 !node->HasState(ui::AX_STATE_BUSY) && | |
| 228 !node->manager()->GetTreeData().loaded) { | |
| 229 return; | |
| 230 } | |
| 231 | |
| 232 // If a focus event is needed on the root, fire that first before | |
| 233 // this event. | |
| 234 if (event_type == ui::AX_EVENT_FOCUS && node == GetRoot()) | |
| 235 focus_event_on_root_needed_ = false; | |
| 236 else if (focus_event_on_root_needed_) | |
| 237 OnWindowFocused(); | |
| 238 | |
| 239 LONG event_id = EVENT_MIN; | 166 LONG event_id = EVENT_MIN; |
| 240 switch (event_type) { | 167 switch (event_type) { |
| 241 case ui::AX_EVENT_ACTIVEDESCENDANTCHANGED: | 168 case ui::AX_EVENT_ACTIVEDESCENDANTCHANGED: |
| 242 event_id = IA2_EVENT_ACTIVE_DESCENDANT_CHANGED; | 169 event_id = IA2_EVENT_ACTIVE_DESCENDANT_CHANGED; |
| 243 break; | 170 break; |
| 244 case ui::AX_EVENT_ALERT: | 171 case ui::AX_EVENT_ALERT: |
| 245 event_id = EVENT_SYSTEM_ALERT; | 172 event_id = EVENT_SYSTEM_ALERT; |
| 246 break; | 173 break; |
| 247 case ui::AX_EVENT_AUTOCORRECTION_OCCURED: | 174 case ui::AX_EVENT_AUTOCORRECTION_OCCURED: |
| 248 event_id = IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED; | 175 event_id = IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 if (event_type == ui::AX_EVENT_LAYOUT_COMPLETE && | 230 if (event_type == ui::AX_EVENT_LAYOUT_COMPLETE && |
| 304 tracked_scroll_object_ && | 231 tracked_scroll_object_ && |
| 305 tracked_scroll_object_->IsDescendantOf(node)) { | 232 tracked_scroll_object_->IsDescendantOf(node)) { |
| 306 MaybeCallNotifyWinEvent( | 233 MaybeCallNotifyWinEvent( |
| 307 IA2_EVENT_VISIBLE_DATA_CHANGED, tracked_scroll_object_); | 234 IA2_EVENT_VISIBLE_DATA_CHANGED, tracked_scroll_object_); |
| 308 tracked_scroll_object_->Release(); | 235 tracked_scroll_object_->Release(); |
| 309 tracked_scroll_object_ = NULL; | 236 tracked_scroll_object_ = NULL; |
| 310 } | 237 } |
| 311 } | 238 } |
| 312 | 239 |
| 240 bool BrowserAccessibilityManagerWin::CanFireEvents() { |
| 241 BrowserAccessibilityDelegate* root_delegate = GetDelegateFromRootManager(); |
| 242 if (!root_delegate) |
| 243 return false; |
| 244 HWND hwnd = root_delegate->AccessibilityGetAcceleratedWidget(); |
| 245 return hwnd != nullptr; |
| 246 } |
| 247 |
| 248 void BrowserAccessibilityManagerWin::FireFocusEvent( |
| 249 BrowserAccessibility* node) { |
| 250 // On Windows, we always fire a FOCUS event on the root of a frame before |
| 251 // firing a focus event within that frame. |
| 252 if (node->manager() != last_focused_manager_ && |
| 253 node != node->manager()->GetRoot()) { |
| 254 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, node->manager()->GetRoot()); |
| 255 } |
| 256 |
| 257 BrowserAccessibilityManager::FireFocusEvent(node); |
| 258 } |
| 259 |
| 313 void BrowserAccessibilityManagerWin::OnNodeCreated(ui::AXTree* tree, | 260 void BrowserAccessibilityManagerWin::OnNodeCreated(ui::AXTree* tree, |
| 314 ui::AXNode* node) { | 261 ui::AXNode* node) { |
| 315 DCHECK(node); | 262 DCHECK(node); |
| 316 BrowserAccessibilityManager::OnNodeCreated(tree, node); | 263 BrowserAccessibilityManager::OnNodeCreated(tree, node); |
| 317 BrowserAccessibility* obj = GetFromAXNode(node); | 264 BrowserAccessibility* obj = GetFromAXNode(node); |
| 318 if (!obj) | 265 if (!obj) |
| 319 return; | 266 return; |
| 320 if (!obj->IsNative()) | 267 if (!obj->IsNative()) |
| 321 return; | 268 return; |
| 322 } | 269 } |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 | 341 |
| 395 void BrowserAccessibilityManagerWin::TrackScrollingObject( | 342 void BrowserAccessibilityManagerWin::TrackScrollingObject( |
| 396 BrowserAccessibilityWin* node) { | 343 BrowserAccessibilityWin* node) { |
| 397 if (tracked_scroll_object_) | 344 if (tracked_scroll_object_) |
| 398 tracked_scroll_object_->Release(); | 345 tracked_scroll_object_->Release(); |
| 399 tracked_scroll_object_ = node; | 346 tracked_scroll_object_ = node; |
| 400 tracked_scroll_object_->AddRef(); | 347 tracked_scroll_object_->AddRef(); |
| 401 } | 348 } |
| 402 | 349 |
| 403 } // namespace content | 350 } // namespace content |
| OLD | NEW |