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 |