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"
18 BrowserAccessibilityManager
* BrowserAccessibilityManager::Create(
19 const ui::AXNodeData
& src
,
20 BrowserAccessibilityDelegate
* delegate
,
21 BrowserAccessibilityFactory
* factory
) {
22 return new BrowserAccessibilityManagerWin(
23 content::LegacyRenderWidgetHostHWND::Create(GetDesktopWindow()).get(),
24 NULL
, src
, 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::AXNodeData
& src
,
36 BrowserAccessibilityDelegate
* delegate
,
37 BrowserAccessibilityFactory
* factory
)
38 : BrowserAccessibilityManager(src
, 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
;
52 accessible_hwnd_
->OnManagerDeleted();
56 ui::AXNodeData
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
);
64 return empty_document
;
67 void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(DWORD event
,
69 // Don't fire events if this view isn't hooked up to its parent.
70 if (!parent_iaccessible())
73 // If on Win 7 and complete accessibility is enabled, use the fake child HWND
74 // to use as the root of the accessibility tree. See comments above
75 // LegacyRenderWidgetHostHWND for details.
76 if (BrowserAccessibilityStateImpl::GetInstance()->IsAccessibleBrowser()) {
77 DCHECK(accessible_hwnd_
);
78 parent_hwnd_
= accessible_hwnd_
->hwnd();
79 parent_iaccessible_
= accessible_hwnd_
->window_accessible();
81 ::NotifyWinEvent(event
, parent_hwnd(), OBJID_CLIENT
, child_id
);
84 void BrowserAccessibilityManagerWin::AddNodeToMap(BrowserAccessibility
* node
) {
85 BrowserAccessibilityManager::AddNodeToMap(node
);
86 LONG unique_id_win
= node
->ToBrowserAccessibilityWin()->unique_id_win();
87 unique_id_to_renderer_id_map_
[unique_id_win
] = node
->renderer_id();
90 void BrowserAccessibilityManagerWin::RemoveNode(BrowserAccessibility
* node
) {
91 unique_id_to_renderer_id_map_
.erase(
92 node
->ToBrowserAccessibilityWin()->unique_id_win());
93 BrowserAccessibilityManager::RemoveNode(node
);
94 if (node
== tracked_scroll_object_
) {
95 tracked_scroll_object_
->Release();
96 tracked_scroll_object_
= NULL
;
100 void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
101 ui::AXEvent event_type
,
102 BrowserAccessibility
* node
) {
103 if (node
->role() == ui::AX_ROLE_INLINE_TEXT_BOX
)
106 LONG event_id
= EVENT_MIN
;
107 switch (event_type
) {
108 case ui::AX_EVENT_ACTIVEDESCENDANTCHANGED
:
109 event_id
= IA2_EVENT_ACTIVE_DESCENDANT_CHANGED
;
111 case ui::AX_EVENT_ALERT
:
112 event_id
= EVENT_SYSTEM_ALERT
;
114 case ui::AX_EVENT_ARIA_ATTRIBUTE_CHANGED
:
115 event_id
= IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED
;
117 case ui::AX_EVENT_AUTOCORRECTION_OCCURED
:
118 event_id
= IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED
;
120 case ui::AX_EVENT_BLUR
:
121 // Equivalent to focus on the root.
122 event_id
= EVENT_OBJECT_FOCUS
;
125 case ui::AX_EVENT_CHECKED_STATE_CHANGED
:
126 event_id
= EVENT_OBJECT_STATECHANGE
;
128 case ui::AX_EVENT_CHILDREN_CHANGED
:
129 event_id
= EVENT_OBJECT_REORDER
;
131 case ui::AX_EVENT_FOCUS
:
132 event_id
= EVENT_OBJECT_FOCUS
;
134 case ui::AX_EVENT_INVALID_STATUS_CHANGED
:
135 event_id
= EVENT_OBJECT_STATECHANGE
;
137 case ui::AX_EVENT_LIVE_REGION_CHANGED
:
138 // TODO: try not firing a native notification at all, since
139 // on Windows, each individual item in a live region that changes
140 // already gets its own notification.
141 event_id
= EVENT_OBJECT_REORDER
;
143 case ui::AX_EVENT_LOAD_COMPLETE
:
144 event_id
= IA2_EVENT_DOCUMENT_LOAD_COMPLETE
;
146 case ui::AX_EVENT_MENU_LIST_ITEM_SELECTED
:
147 event_id
= EVENT_OBJECT_FOCUS
;
149 case ui::AX_EVENT_MENU_LIST_VALUE_CHANGED
:
150 event_id
= EVENT_OBJECT_VALUECHANGE
;
152 case ui::AX_EVENT_HIDE
:
153 event_id
= EVENT_OBJECT_HIDE
;
155 case ui::AX_EVENT_SHOW
:
156 event_id
= EVENT_OBJECT_SHOW
;
158 case ui::AX_EVENT_SCROLL_POSITION_CHANGED
:
159 event_id
= EVENT_SYSTEM_SCROLLINGEND
;
161 case ui::AX_EVENT_SCROLLED_TO_ANCHOR
:
162 event_id
= EVENT_SYSTEM_SCROLLINGSTART
;
164 case ui::AX_EVENT_SELECTED_CHILDREN_CHANGED
:
165 event_id
= EVENT_OBJECT_SELECTIONWITHIN
;
167 case ui::AX_EVENT_SELECTED_TEXT_CHANGED
:
168 event_id
= IA2_EVENT_TEXT_CARET_MOVED
;
170 case ui::AX_EVENT_TEXT_CHANGED
:
171 event_id
= EVENT_OBJECT_NAMECHANGE
;
173 case ui::AX_EVENT_TEXT_INSERTED
:
174 event_id
= IA2_EVENT_TEXT_INSERTED
;
176 case ui::AX_EVENT_TEXT_REMOVED
:
177 event_id
= IA2_EVENT_TEXT_REMOVED
;
179 case ui::AX_EVENT_VALUE_CHANGED
:
180 event_id
= EVENT_OBJECT_VALUECHANGE
;
183 // Not all WebKit accessibility events result in a Windows
184 // accessibility notification.
188 if (event_id
!= EVENT_MIN
) {
189 // Pass the node's unique id in the |child_id| argument to NotifyWinEvent;
190 // the AT client will then call get_accChild on the HWND's accessibility
191 // object and pass it that same id, which we can use to retrieve the
192 // IAccessible for this node.
193 LONG child_id
= node
->ToBrowserAccessibilityWin()->unique_id_win();
194 MaybeCallNotifyWinEvent(event_id
, child_id
);
197 // If this is a layout complete notification (sent when a container scrolls)
198 // and there is a descendant tracked object, send a notification on it.
199 // TODO(dmazzoni): remove once http://crbug.com/113483 is fixed.
200 if (event_type
== ui::AX_EVENT_LAYOUT_COMPLETE
&&
201 tracked_scroll_object_
&&
202 tracked_scroll_object_
->IsDescendantOf(node
)) {
203 MaybeCallNotifyWinEvent(
204 IA2_EVENT_VISIBLE_DATA_CHANGED
,
205 tracked_scroll_object_
->ToBrowserAccessibilityWin()->unique_id_win());
206 tracked_scroll_object_
->Release();
207 tracked_scroll_object_
= NULL
;
211 void BrowserAccessibilityManagerWin::TrackScrollingObject(
212 BrowserAccessibilityWin
* node
) {
213 if (tracked_scroll_object_
)
214 tracked_scroll_object_
->Release();
215 tracked_scroll_object_
= node
;
216 tracked_scroll_object_
->AddRef();
219 BrowserAccessibilityWin
* BrowserAccessibilityManagerWin::GetFromUniqueIdWin(
220 LONG unique_id_win
) {
221 base::hash_map
<LONG
, int32
>::iterator iter
=
222 unique_id_to_renderer_id_map_
.find(unique_id_win
);
223 if (iter
!= unique_id_to_renderer_id_map_
.end()) {
224 BrowserAccessibility
* result
= GetFromRendererID(iter
->second
);
226 return result
->ToBrowserAccessibilityWin();
231 void BrowserAccessibilityManagerWin::OnAccessibleHwndDeleted() {
232 // If the AccessibleHWND is deleted, |parent_hwnd_| and
233 // |parent_iaccessible_| are no longer valid either, since they were
234 // derived from AccessibleHWND. We don't have to restore them to
235 // previous values, though, because this should only happen
236 // during the destruct sequence for this window.
237 accessible_hwnd_
= NULL
;
239 parent_iaccessible_
= NULL
;
242 } // namespace content