Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / browser / accessibility / browser_accessibility_manager.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.h"
6
7 #include "base/logging.h"
8 #include "content/browser/accessibility/browser_accessibility.h"
9 #include "content/common/accessibility_messages.h"
10 #include "ui/accessibility/ax_tree_serializer.h"
11
12 namespace content {
13
14 ui::AXTreeUpdate MakeAXTreeUpdate(
15     const ui::AXNodeData& node1,
16     const ui::AXNodeData& node2 /* = ui::AXNodeData() */,
17     const ui::AXNodeData& node3 /* = ui::AXNodeData() */,
18     const ui::AXNodeData& node4 /* = ui::AXNodeData() */,
19     const ui::AXNodeData& node5 /* = ui::AXNodeData() */,
20     const ui::AXNodeData& node6 /* = ui::AXNodeData() */,
21     const ui::AXNodeData& node7 /* = ui::AXNodeData() */,
22     const ui::AXNodeData& node8 /* = ui::AXNodeData() */,
23     const ui::AXNodeData& node9 /* = ui::AXNodeData() */) {
24   CR_DEFINE_STATIC_LOCAL(ui::AXNodeData, empty_data, ());
25   int32 no_id = empty_data.id;
26
27   ui::AXTreeUpdate update;
28   update.nodes.push_back(node1);
29   if (node2.id != no_id)
30     update.nodes.push_back(node2);
31   if (node3.id != no_id)
32     update.nodes.push_back(node3);
33   if (node4.id != no_id)
34     update.nodes.push_back(node4);
35   if (node5.id != no_id)
36     update.nodes.push_back(node5);
37   if (node6.id != no_id)
38     update.nodes.push_back(node6);
39   if (node7.id != no_id)
40     update.nodes.push_back(node7);
41   if (node8.id != no_id)
42     update.nodes.push_back(node8);
43   if (node9.id != no_id)
44     update.nodes.push_back(node9);
45   return update;
46 }
47
48 BrowserAccessibility* BrowserAccessibilityFactory::Create() {
49   return BrowserAccessibility::Create();
50 }
51
52 BrowserAccessibilityFindInPageInfo::BrowserAccessibilityFindInPageInfo()
53     : request_id(-1),
54       match_index(-1),
55       start_id(-1),
56       start_offset(0),
57       end_id(-1),
58       end_offset(-1),
59       active_request_id(-1) {}
60
61 #if !defined(OS_MACOSX) && \
62     !defined(OS_WIN) && \
63     !defined(OS_ANDROID) \
64 // We have subclassess of BrowserAccessibilityManager on Mac, and Win. For any
65 // other platform, instantiate the base class.
66 // static
67 BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
68     const ui::AXTreeUpdate& initial_tree,
69     BrowserAccessibilityDelegate* delegate,
70     BrowserAccessibilityFactory* factory) {
71   return new BrowserAccessibilityManager(initial_tree, delegate, factory);
72 }
73 #endif
74
75 BrowserAccessibilityManager::BrowserAccessibilityManager(
76     BrowserAccessibilityDelegate* delegate,
77     BrowserAccessibilityFactory* factory)
78     : delegate_(delegate),
79       factory_(factory),
80       tree_(new ui::AXSerializableTree()),
81       focus_(NULL),
82       osk_state_(OSK_ALLOWED) {
83   tree_->SetDelegate(this);
84 }
85
86 BrowserAccessibilityManager::BrowserAccessibilityManager(
87     const ui::AXTreeUpdate& initial_tree,
88     BrowserAccessibilityDelegate* delegate,
89     BrowserAccessibilityFactory* factory)
90     : delegate_(delegate),
91       factory_(factory),
92       tree_(new ui::AXSerializableTree()),
93       focus_(NULL),
94       osk_state_(OSK_ALLOWED) {
95   tree_->SetDelegate(this);
96   Initialize(initial_tree);
97 }
98
99 BrowserAccessibilityManager::~BrowserAccessibilityManager() {
100   tree_.reset(NULL);
101 }
102
103 void BrowserAccessibilityManager::Initialize(
104     const ui::AXTreeUpdate& initial_tree) {
105   if (!tree_->Unserialize(initial_tree)) {
106     if (delegate_) {
107       LOG(ERROR) << tree_->error();
108       delegate_->AccessibilityFatalError();
109     } else {
110       LOG(FATAL) << tree_->error();
111     }
112   }
113
114   if (!focus_)
115     SetFocus(tree_->GetRoot(), false);
116 }
117
118 // static
119 ui::AXTreeUpdate BrowserAccessibilityManager::GetEmptyDocument() {
120   ui::AXNodeData empty_document;
121   empty_document.id = 0;
122   empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA;
123   ui::AXTreeUpdate update;
124   update.nodes.push_back(empty_document);
125   return update;
126 }
127
128 BrowserAccessibility* BrowserAccessibilityManager::GetRoot() {
129   return GetFromAXNode(tree_->GetRoot());
130 }
131
132 BrowserAccessibility* BrowserAccessibilityManager::GetFromAXNode(
133     ui::AXNode* node) {
134   return GetFromID(node->id());
135 }
136
137 BrowserAccessibility* BrowserAccessibilityManager::GetFromID(int32 id) {
138   base::hash_map<int32, BrowserAccessibility*>::iterator iter =
139       id_wrapper_map_.find(id);
140   if (iter != id_wrapper_map_.end())
141     return iter->second;
142   return NULL;
143 }
144
145 void BrowserAccessibilityManager::OnWindowFocused() {
146   if (focus_)
147     NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
148 }
149
150 void BrowserAccessibilityManager::OnWindowBlurred() {
151   if (focus_)
152     NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, GetFromAXNode(focus_));
153 }
154
155 void BrowserAccessibilityManager::GotMouseDown() {
156   osk_state_ = OSK_ALLOWED_WITHIN_FOCUSED_OBJECT;
157   NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
158 }
159
160 bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() {
161   return true;
162 }
163
164 void BrowserAccessibilityManager::OnAccessibilityEvents(
165     const std::vector<AccessibilityHostMsg_EventParams>& params) {
166   bool should_send_initial_focus = false;
167
168   // Process all changes to the accessibility tree first.
169   for (uint32 index = 0; index < params.size(); index++) {
170     const AccessibilityHostMsg_EventParams& param = params[index];
171     if (!tree_->Unserialize(param.update)) {
172       if (delegate_) {
173         LOG(ERROR) << tree_->error();
174         delegate_->AccessibilityFatalError();
175       } else {
176         CHECK(false) << tree_->error();
177       }
178       return;
179     }
180
181     // Set focus to the root if it's not anywhere else.
182     if (!focus_) {
183       SetFocus(tree_->GetRoot(), false);
184       should_send_initial_focus = true;
185     }
186   }
187
188   OnTreeUpdateFinished();
189
190   if (should_send_initial_focus &&
191       (!delegate_ || delegate_->AccessibilityViewHasFocus())) {
192     NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
193   }
194
195   // Now iterate over the events again and fire the events.
196   for (uint32 index = 0; index < params.size(); index++) {
197     const AccessibilityHostMsg_EventParams& param = params[index];
198
199     // Find the node corresponding to the id that's the target of the
200     // event (which may not be the root of the update tree).
201     ui::AXNode* node = tree_->GetFromId(param.id);
202     if (!node)
203       continue;
204
205     ui::AXEvent event_type = param.event_type;
206     if (event_type == ui::AX_EVENT_FOCUS ||
207         event_type == ui::AX_EVENT_BLUR) {
208       SetFocus(node, false);
209
210       if (osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_HIDDEN &&
211           osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED)
212         osk_state_ = OSK_ALLOWED;
213
214       // Don't send a native focus event if the window itself doesn't
215       // have focus.
216       if (delegate_ && !delegate_->AccessibilityViewHasFocus())
217         continue;
218     }
219
220     // Send the event event to the operating system.
221     NotifyAccessibilityEvent(event_type, GetFromAXNode(node));
222   }
223 }
224
225 void BrowserAccessibilityManager::OnLocationChanges(
226     const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) {
227   for (size_t i = 0; i < params.size(); ++i) {
228     BrowserAccessibility* obj = GetFromID(params[i].id);
229     if (!obj)
230       continue;
231     ui::AXNode* node = obj->node();
232     node->SetLocation(params[i].new_location);
233     obj->OnLocationChanged();
234   }
235 }
236
237 void BrowserAccessibilityManager::OnFindInPageResult(
238     int request_id, int match_index, int start_id, int start_offset,
239     int end_id, int end_offset) {
240   find_in_page_info_.request_id = request_id;
241   find_in_page_info_.match_index = match_index;
242   find_in_page_info_.start_id = start_id;
243   find_in_page_info_.start_offset = start_offset;
244   find_in_page_info_.end_id = end_id;
245   find_in_page_info_.end_offset = end_offset;
246
247   if (find_in_page_info_.active_request_id == request_id)
248     ActivateFindInPageResult(request_id);
249 }
250
251 void BrowserAccessibilityManager::ActivateFindInPageResult(
252     int request_id) {
253   find_in_page_info_.active_request_id = request_id;
254   if (find_in_page_info_.request_id != request_id)
255     return;
256
257   BrowserAccessibility* node = GetFromID(find_in_page_info_.start_id);
258   if (!node)
259     return;
260
261   // If an ancestor of this node is a leaf node, fire the notification on that.
262   BrowserAccessibility* ancestor = node->GetParent();
263   while (ancestor && ancestor != GetRoot()) {
264     if (ancestor->PlatformIsLeaf())
265       node = ancestor;
266     ancestor = ancestor->GetParent();
267   }
268
269   // The "scrolled to anchor" notification is a great way to get a
270   // screen reader to jump directly to a specific location in a document.
271   NotifyAccessibilityEvent(ui::AX_EVENT_SCROLLED_TO_ANCHOR, node);
272 }
273
274 BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendantFocus(
275     BrowserAccessibility* root) {
276   BrowserAccessibility* node = BrowserAccessibilityManager::GetFocus(root);
277   if (!node)
278     return NULL;
279
280   int active_descendant_id;
281   if (node->GetIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID,
282                             &active_descendant_id)) {
283     BrowserAccessibility* active_descendant =
284         node->manager()->GetFromID(active_descendant_id);
285     if (active_descendant)
286       return active_descendant;
287   }
288   return node;
289 }
290
291 BrowserAccessibility* BrowserAccessibilityManager::GetFocus(
292     BrowserAccessibility* root) {
293   if (focus_ && (!root || focus_->IsDescendantOf(root->node())))
294     return GetFromAXNode(focus_);
295
296   return NULL;
297 }
298
299 void BrowserAccessibilityManager::SetFocus(ui::AXNode* node, bool notify) {
300   if (focus_ != node)
301     focus_ = node;
302
303   if (notify && node && delegate_)
304     delegate_->AccessibilitySetFocus(node->id());
305 }
306
307 void BrowserAccessibilityManager::SetFocus(
308     BrowserAccessibility* obj, bool notify) {
309   if (obj->node())
310     SetFocus(obj->node(), notify);
311 }
312
313 void BrowserAccessibilityManager::DoDefaultAction(
314     const BrowserAccessibility& node) {
315   if (delegate_)
316     delegate_->AccessibilityDoDefaultAction(node.GetId());
317 }
318
319 void BrowserAccessibilityManager::ScrollToMakeVisible(
320     const BrowserAccessibility& node, gfx::Rect subfocus) {
321   if (delegate_) {
322     delegate_->AccessibilityScrollToMakeVisible(node.GetId(), subfocus);
323   }
324 }
325
326 void BrowserAccessibilityManager::ScrollToPoint(
327     const BrowserAccessibility& node, gfx::Point point) {
328   if (delegate_) {
329     delegate_->AccessibilityScrollToPoint(node.GetId(), point);
330   }
331 }
332
333 void BrowserAccessibilityManager::SetValue(
334     const BrowserAccessibility& node,
335     const base::string16& value) {
336   if (delegate_)
337     delegate_->AccessibilitySetValue(node.GetId(), value);
338 }
339
340 void BrowserAccessibilityManager::SetTextSelection(
341     const BrowserAccessibility& node,
342     int start_offset,
343     int end_offset) {
344   if (delegate_) {
345     delegate_->AccessibilitySetTextSelection(
346         node.GetId(), start_offset, end_offset);
347   }
348 }
349
350 gfx::Rect BrowserAccessibilityManager::GetViewBounds() {
351   if (delegate_)
352     return delegate_->AccessibilityGetViewBounds();
353   return gfx::Rect();
354 }
355
356 BrowserAccessibility* BrowserAccessibilityManager::NextInTreeOrder(
357     BrowserAccessibility* node) {
358   if (!node)
359     return NULL;
360
361   if (node->PlatformChildCount() > 0)
362     return node->PlatformGetChild(0);
363   while (node) {
364     if (node->GetParent() &&
365         node->GetIndexInParent() <
366             static_cast<int>(node->GetParent()->PlatformChildCount()) - 1) {
367       return node->GetParent()->PlatformGetChild(node->GetIndexInParent() + 1);
368     }
369     node = node->GetParent();
370   }
371
372   return NULL;
373 }
374
375 BrowserAccessibility* BrowserAccessibilityManager::PreviousInTreeOrder(
376     BrowserAccessibility* node) {
377   if (!node)
378     return NULL;
379
380   if (node->GetParent() && node->GetIndexInParent() > 0) {
381     node = node->GetParent()->PlatformGetChild(node->GetIndexInParent() - 1);
382     while (node->PlatformChildCount() > 0)
383       node = node->PlatformGetChild(node->PlatformChildCount() - 1);
384     return node;
385   }
386
387   return node->GetParent();
388 }
389
390 void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXNode* node) {
391   if (node == focus_ && tree_) {
392     if (node != tree_->GetRoot())
393       SetFocus(tree_->GetRoot(), false);
394     else
395       focus_ = NULL;
396   }
397   if (id_wrapper_map_.find(node->id()) == id_wrapper_map_.end())
398     return;
399   GetFromAXNode(node)->Destroy();
400   id_wrapper_map_.erase(node->id());
401 }
402
403 void BrowserAccessibilityManager::OnNodeCreated(ui::AXNode* node) {
404   BrowserAccessibility* wrapper = factory_->Create();
405   wrapper->Init(this, node);
406   id_wrapper_map_[node->id()] = wrapper;
407   wrapper->OnDataChanged();
408 }
409
410 void BrowserAccessibilityManager::OnNodeChanged(ui::AXNode* node) {
411   GetFromAXNode(node)->OnDataChanged();
412 }
413
414 void BrowserAccessibilityManager::OnNodeCreationFinished(ui::AXNode* node) {
415   GetFromAXNode(node)->OnUpdateFinished();
416 }
417
418 void BrowserAccessibilityManager::OnNodeChangeFinished(ui::AXNode* node) {
419   GetFromAXNode(node)->OnUpdateFinished();
420 }
421
422 ui::AXTreeUpdate BrowserAccessibilityManager::SnapshotAXTreeForTesting() {
423   scoped_ptr<ui::AXTreeSource<const ui::AXNode*> > tree_source(
424       tree_->CreateTreeSource());
425   ui::AXTreeSerializer<const ui::AXNode*> serializer(tree_source.get());
426   ui::AXTreeUpdate update;
427   serializer.SerializeChanges(tree_->GetRoot(), &update);
428   return update;
429 }
430
431 }  // namespace content