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