Revert 268405 "Make sure that ScratchBuffer::Allocate() always r..."
[chromium-blink-merge.git] / content / browser / accessibility / browser_accessibility_manager_win.cc
blob69c88916bd014dd5ce705e2b7fa58151919d6cb6
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
3 // found in the LICENSE file.
5 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
7 #include "base/command_line.h"
8 #include "base/win/scoped_comptr.h"
9 #include "base/win/windows_version.h"
10 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
11 #include "content/browser/accessibility/browser_accessibility_win.h"
12 #include "content/browser/renderer_host/legacy_render_widget_host_win.h"
13 #include "content/common/accessibility_messages.h"
15 namespace content {
17 // static
18 BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
19 const ui::AXTreeUpdate& initial_tree,
20 BrowserAccessibilityDelegate* delegate,
21 BrowserAccessibilityFactory* factory) {
22 return new BrowserAccessibilityManagerWin(
23 content::LegacyRenderWidgetHostHWND::Create(GetDesktopWindow()).get(),
24 NULL, initial_tree, delegate, factory);
27 BrowserAccessibilityManagerWin*
28 BrowserAccessibilityManager::ToBrowserAccessibilityManagerWin() {
29 return static_cast<BrowserAccessibilityManagerWin*>(this);
32 BrowserAccessibilityManagerWin::BrowserAccessibilityManagerWin(
33 LegacyRenderWidgetHostHWND* accessible_hwnd,
34 IAccessible* parent_iaccessible,
35 const ui::AXTreeUpdate& initial_tree,
36 BrowserAccessibilityDelegate* delegate,
37 BrowserAccessibilityFactory* factory)
38 : BrowserAccessibilityManager(initial_tree, delegate, factory),
39 parent_hwnd_(accessible_hwnd->GetParent()),
40 parent_iaccessible_(parent_iaccessible),
41 tracked_scroll_object_(NULL),
42 accessible_hwnd_(accessible_hwnd) {
43 accessible_hwnd_->set_browser_accessibility_manager(this);
46 BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() {
47 if (tracked_scroll_object_) {
48 tracked_scroll_object_->Release();
49 tracked_scroll_object_ = NULL;
51 if (accessible_hwnd_)
52 accessible_hwnd_->OnManagerDeleted();
55 // static
56 ui::AXTreeUpdate BrowserAccessibilityManagerWin::GetEmptyDocument() {
57 ui::AXNodeData empty_document;
58 empty_document.id = 0;
59 empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA;
60 empty_document.state =
61 (1 << ui::AX_STATE_ENABLED) |
62 (1 << ui::AX_STATE_READ_ONLY) |
63 (1 << ui::AX_STATE_BUSY);
65 ui::AXTreeUpdate update;
66 update.nodes.push_back(empty_document);
67 return update;
70 void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(DWORD event,
71 LONG child_id) {
72 // Don't fire events if this view isn't hooked up to its parent.
73 if (!parent_iaccessible())
74 return;
76 // If on Win 7 and complete accessibility is enabled, use the fake child HWND
77 // to use as the root of the accessibility tree. See comments above
78 // LegacyRenderWidgetHostHWND for details.
79 if (BrowserAccessibilityStateImpl::GetInstance()->IsAccessibleBrowser()) {
80 DCHECK(accessible_hwnd_);
81 parent_hwnd_ = accessible_hwnd_->hwnd();
82 parent_iaccessible_ = accessible_hwnd_->window_accessible();
84 ::NotifyWinEvent(event, parent_hwnd(), OBJID_CLIENT, child_id);
88 void BrowserAccessibilityManagerWin::OnNodeCreated(ui::AXNode* node) {
89 BrowserAccessibilityManager::OnNodeCreated(node);
90 BrowserAccessibility* obj = GetFromAXNode(node);
91 LONG unique_id_win = obj->ToBrowserAccessibilityWin()->unique_id_win();
92 unique_id_to_ax_id_map_[unique_id_win] = obj->GetId();
95 void BrowserAccessibilityManagerWin::OnNodeWillBeDeleted(ui::AXNode* node) {
96 BrowserAccessibilityManager::OnNodeWillBeDeleted(node);
97 BrowserAccessibility* obj = GetFromAXNode(node);
98 if (!obj)
99 return;
100 unique_id_to_ax_id_map_.erase(
101 obj->ToBrowserAccessibilityWin()->unique_id_win());
102 if (obj == tracked_scroll_object_) {
103 tracked_scroll_object_->Release();
104 tracked_scroll_object_ = NULL;
108 void BrowserAccessibilityManagerWin::OnWindowFocused() {
109 // Fire a focus event on the root first and then the focused node.
110 if (focus_ != tree_->GetRoot())
111 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetRoot());
112 BrowserAccessibilityManager::OnWindowFocused();
115 void BrowserAccessibilityManagerWin::OnWindowBlurred() {
116 // Fire a blur event on the focused node first and then the root.
117 BrowserAccessibilityManager::OnWindowBlurred();
118 if (focus_ != tree_->GetRoot())
119 NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, GetRoot());
122 void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
123 ui::AXEvent event_type,
124 BrowserAccessibility* node) {
125 if (node->GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX)
126 return;
128 LONG event_id = EVENT_MIN;
129 switch (event_type) {
130 case ui::AX_EVENT_ACTIVEDESCENDANTCHANGED:
131 event_id = IA2_EVENT_ACTIVE_DESCENDANT_CHANGED;
132 break;
133 case ui::AX_EVENT_ALERT:
134 event_id = EVENT_SYSTEM_ALERT;
135 break;
136 case ui::AX_EVENT_ARIA_ATTRIBUTE_CHANGED:
137 event_id = IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED;
138 break;
139 case ui::AX_EVENT_AUTOCORRECTION_OCCURED:
140 event_id = IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED;
141 break;
142 case ui::AX_EVENT_BLUR:
143 // Equivalent to focus on the root.
144 event_id = EVENT_OBJECT_FOCUS;
145 node = GetRoot();
146 break;
147 case ui::AX_EVENT_CHECKED_STATE_CHANGED:
148 event_id = EVENT_OBJECT_STATECHANGE;
149 break;
150 case ui::AX_EVENT_CHILDREN_CHANGED:
151 event_id = EVENT_OBJECT_REORDER;
152 break;
153 case ui::AX_EVENT_FOCUS:
154 event_id = EVENT_OBJECT_FOCUS;
155 break;
156 case ui::AX_EVENT_INVALID_STATUS_CHANGED:
157 event_id = EVENT_OBJECT_STATECHANGE;
158 break;
159 case ui::AX_EVENT_LIVE_REGION_CHANGED:
160 if (node->GetBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_BUSY))
161 return;
162 event_id = EVENT_OBJECT_LIVEREGIONCHANGED;
163 break;
164 case ui::AX_EVENT_LOAD_COMPLETE:
165 event_id = IA2_EVENT_DOCUMENT_LOAD_COMPLETE;
166 break;
167 case ui::AX_EVENT_MENU_LIST_ITEM_SELECTED:
168 event_id = EVENT_OBJECT_FOCUS;
169 break;
170 case ui::AX_EVENT_MENU_LIST_VALUE_CHANGED:
171 event_id = EVENT_OBJECT_VALUECHANGE;
172 break;
173 case ui::AX_EVENT_HIDE:
174 event_id = EVENT_OBJECT_HIDE;
175 break;
176 case ui::AX_EVENT_SHOW:
177 event_id = EVENT_OBJECT_SHOW;
178 break;
179 case ui::AX_EVENT_SCROLL_POSITION_CHANGED:
180 event_id = EVENT_SYSTEM_SCROLLINGEND;
181 break;
182 case ui::AX_EVENT_SCROLLED_TO_ANCHOR:
183 event_id = EVENT_SYSTEM_SCROLLINGSTART;
184 break;
185 case ui::AX_EVENT_SELECTED_CHILDREN_CHANGED:
186 event_id = EVENT_OBJECT_SELECTIONWITHIN;
187 break;
188 case ui::AX_EVENT_SELECTED_TEXT_CHANGED:
189 event_id = IA2_EVENT_TEXT_CARET_MOVED;
190 break;
191 case ui::AX_EVENT_TEXT_CHANGED:
192 event_id = EVENT_OBJECT_NAMECHANGE;
193 break;
194 case ui::AX_EVENT_TEXT_INSERTED:
195 event_id = IA2_EVENT_TEXT_INSERTED;
196 break;
197 case ui::AX_EVENT_TEXT_REMOVED:
198 event_id = IA2_EVENT_TEXT_REMOVED;
199 break;
200 case ui::AX_EVENT_VALUE_CHANGED:
201 event_id = EVENT_OBJECT_VALUECHANGE;
202 break;
203 default:
204 // Not all WebKit accessibility events result in a Windows
205 // accessibility notification.
206 break;
209 if (event_id != EVENT_MIN) {
210 // Pass the node's unique id in the |child_id| argument to NotifyWinEvent;
211 // the AT client will then call get_accChild on the HWND's accessibility
212 // object and pass it that same id, which we can use to retrieve the
213 // IAccessible for this node.
214 LONG child_id = node->ToBrowserAccessibilityWin()->unique_id_win();
215 MaybeCallNotifyWinEvent(event_id, child_id);
218 // If this is a layout complete notification (sent when a container scrolls)
219 // and there is a descendant tracked object, send a notification on it.
220 // TODO(dmazzoni): remove once http://crbug.com/113483 is fixed.
221 if (event_type == ui::AX_EVENT_LAYOUT_COMPLETE &&
222 tracked_scroll_object_ &&
223 tracked_scroll_object_->IsDescendantOf(node)) {
224 MaybeCallNotifyWinEvent(
225 IA2_EVENT_VISIBLE_DATA_CHANGED,
226 tracked_scroll_object_->ToBrowserAccessibilityWin()->unique_id_win());
227 tracked_scroll_object_->Release();
228 tracked_scroll_object_ = NULL;
232 void BrowserAccessibilityManagerWin::OnRootChanged(ui::AXNode* new_root) {
233 if (delegate_ && delegate_->AccessibilityViewHasFocus())
234 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetRoot());
237 void BrowserAccessibilityManagerWin::TrackScrollingObject(
238 BrowserAccessibilityWin* node) {
239 if (tracked_scroll_object_)
240 tracked_scroll_object_->Release();
241 tracked_scroll_object_ = node;
242 tracked_scroll_object_->AddRef();
245 BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFromUniqueIdWin(
246 LONG unique_id_win) {
247 base::hash_map<LONG, int32>::iterator iter =
248 unique_id_to_ax_id_map_.find(unique_id_win);
249 if (iter != unique_id_to_ax_id_map_.end()) {
250 BrowserAccessibility* result = GetFromID(iter->second);
251 if (result)
252 return result->ToBrowserAccessibilityWin();
254 return NULL;
257 void BrowserAccessibilityManagerWin::OnAccessibleHwndDeleted() {
258 // If the AccessibleHWND is deleted, |parent_hwnd_| and
259 // |parent_iaccessible_| are no longer valid either, since they were
260 // derived from AccessibleHWND. We don't have to restore them to
261 // previous values, though, because this should only happen
262 // during the destruct sequence for this window.
263 accessible_hwnd_ = NULL;
264 parent_hwnd_ = NULL;
265 parent_iaccessible_ = NULL;
268 } // namespace content