Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / accessibility / browser_accessibility_manager_win.cc
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.
4
5 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
6
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"
14
15 namespace content {
16
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);
25 }
26
27 BrowserAccessibilityManagerWin*
28 BrowserAccessibilityManager::ToBrowserAccessibilityManagerWin() {
29   return static_cast<BrowserAccessibilityManagerWin*>(this);
30 }
31
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);
44 }
45
46 BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() {
47   if (tracked_scroll_object_) {
48     tracked_scroll_object_->Release();
49     tracked_scroll_object_ = NULL;
50   }
51   if (accessible_hwnd_)
52     accessible_hwnd_->OnManagerDeleted();
53 }
54
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);
64
65   ui::AXTreeUpdate update;
66   update.nodes.push_back(empty_document);
67   return update;
68 }
69
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;
75
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();
83   }
84   ::NotifyWinEvent(event, parent_hwnd(), OBJID_CLIENT, child_id);
85 }
86
87
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();
93 }
94
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;
105   }
106 }
107
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();
113 }
114
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());
120 }
121
122 void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
123     ui::AXEvent event_type,
124     BrowserAccessibility* node) {
125   if (node->GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX)
126     return;
127
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;
207   }
208
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);
216   }
217
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;
229   }
230 }
231
232 void BrowserAccessibilityManagerWin::OnRootChanged(ui::AXNode* new_root) {
233   if (delegate_ && delegate_->AccessibilityViewHasFocus())
234     NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetRoot());
235 }
236
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();
243 }
244
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();
253   }
254   return NULL;
255 }
256
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;
266 }
267
268 }  // namespace content