• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
11 namespace content {
12 
MakeAXTreeUpdate(const ui::AXNodeData & node1,const ui::AXNodeData & node2,const ui::AXNodeData & node3,const ui::AXNodeData & node4,const ui::AXNodeData & node5,const ui::AXNodeData & node6,const ui::AXNodeData & node7,const ui::AXNodeData & node8,const ui::AXNodeData & node9)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 
Create()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, and Win. For any
55 // other platform, instantiate the base class.
56 // static
Create(const ui::AXTreeUpdate & initial_tree,BrowserAccessibilityDelegate * delegate,BrowserAccessibilityFactory * factory)57 BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
58     const ui::AXTreeUpdate& initial_tree,
59     BrowserAccessibilityDelegate* delegate,
60     BrowserAccessibilityFactory* factory) {
61   return new BrowserAccessibilityManager(initial_tree, delegate, factory);
62 }
63 #endif
64 
BrowserAccessibilityManager(BrowserAccessibilityDelegate * delegate,BrowserAccessibilityFactory * factory)65 BrowserAccessibilityManager::BrowserAccessibilityManager(
66     BrowserAccessibilityDelegate* delegate,
67     BrowserAccessibilityFactory* factory)
68     : delegate_(delegate),
69       factory_(factory),
70       tree_(new ui::AXTree()),
71       focus_(NULL),
72       osk_state_(OSK_ALLOWED) {
73   tree_->SetDelegate(this);
74 }
75 
BrowserAccessibilityManager(const ui::AXTreeUpdate & initial_tree,BrowserAccessibilityDelegate * delegate,BrowserAccessibilityFactory * factory)76 BrowserAccessibilityManager::BrowserAccessibilityManager(
77     const ui::AXTreeUpdate& initial_tree,
78     BrowserAccessibilityDelegate* delegate,
79     BrowserAccessibilityFactory* factory)
80     : delegate_(delegate),
81       factory_(factory),
82       tree_(new ui::AXTree()),
83       focus_(NULL),
84       osk_state_(OSK_ALLOWED) {
85   tree_->SetDelegate(this);
86   Initialize(initial_tree);
87 }
88 
~BrowserAccessibilityManager()89 BrowserAccessibilityManager::~BrowserAccessibilityManager() {
90   tree_.reset(NULL);
91 }
92 
Initialize(const ui::AXTreeUpdate & initial_tree)93 void BrowserAccessibilityManager::Initialize(
94     const ui::AXTreeUpdate& initial_tree) {
95   if (!tree_->Unserialize(initial_tree)) {
96     if (delegate_) {
97       LOG(ERROR) << tree_->error();
98       delegate_->AccessibilityFatalError();
99     } else {
100       LOG(FATAL) << tree_->error();
101     }
102   }
103 
104   if (!focus_)
105     SetFocus(tree_->GetRoot(), false);
106 }
107 
108 // static
GetEmptyDocument()109 ui::AXTreeUpdate BrowserAccessibilityManager::GetEmptyDocument() {
110   ui::AXNodeData empty_document;
111   empty_document.id = 0;
112   empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA;
113   ui::AXTreeUpdate update;
114   update.nodes.push_back(empty_document);
115   return update;
116 }
117 
GetRoot()118 BrowserAccessibility* BrowserAccessibilityManager::GetRoot() {
119   return GetFromAXNode(tree_->GetRoot());
120 }
121 
GetFromAXNode(ui::AXNode * node)122 BrowserAccessibility* BrowserAccessibilityManager::GetFromAXNode(
123     ui::AXNode* node) {
124   return GetFromID(node->id());
125 }
126 
GetFromID(int32 id)127 BrowserAccessibility* BrowserAccessibilityManager::GetFromID(int32 id) {
128   base::hash_map<int32, BrowserAccessibility*>::iterator iter =
129       id_wrapper_map_.find(id);
130   if (iter != id_wrapper_map_.end())
131     return iter->second;
132   return NULL;
133 }
134 
OnWindowFocused()135 void BrowserAccessibilityManager::OnWindowFocused() {
136   if (focus_)
137     NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
138 }
139 
OnWindowBlurred()140 void BrowserAccessibilityManager::OnWindowBlurred() {
141   if (focus_)
142     NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, GetFromAXNode(focus_));
143 }
144 
GotMouseDown()145 void BrowserAccessibilityManager::GotMouseDown() {
146   osk_state_ = OSK_ALLOWED_WITHIN_FOCUSED_OBJECT;
147   NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
148 }
149 
UseRootScrollOffsetsWhenComputingBounds()150 bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() {
151   return true;
152 }
153 
OnAccessibilityEvents(const std::vector<AccessibilityHostMsg_EventParams> & params)154 void BrowserAccessibilityManager::OnAccessibilityEvents(
155     const std::vector<AccessibilityHostMsg_EventParams>& params) {
156   bool should_send_initial_focus = false;
157 
158   // Process all changes to the accessibility tree first.
159   for (uint32 index = 0; index < params.size(); index++) {
160     const AccessibilityHostMsg_EventParams& param = params[index];
161     if (!tree_->Unserialize(param.update)) {
162       if (delegate_) {
163         LOG(ERROR) << tree_->error();
164         delegate_->AccessibilityFatalError();
165       } else {
166         CHECK(false) << tree_->error();
167       }
168       return;
169     }
170 
171     // Set focus to the root if it's not anywhere else.
172     if (!focus_) {
173       SetFocus(tree_->GetRoot(), false);
174       should_send_initial_focus = true;
175     }
176   }
177 
178   OnTreeUpdateFinished();
179 
180   if (should_send_initial_focus &&
181       (!delegate_ || delegate_->AccessibilityViewHasFocus())) {
182     NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
183   }
184 
185   // Now iterate over the events again and fire the events.
186   for (uint32 index = 0; index < params.size(); index++) {
187     const AccessibilityHostMsg_EventParams& param = params[index];
188 
189     // Find the node corresponding to the id that's the target of the
190     // event (which may not be the root of the update tree).
191     ui::AXNode* node = tree_->GetFromId(param.id);
192     if (!node)
193       continue;
194 
195     ui::AXEvent event_type = param.event_type;
196     if (event_type == ui::AX_EVENT_FOCUS ||
197         event_type == ui::AX_EVENT_BLUR) {
198       SetFocus(node, false);
199 
200       if (osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_HIDDEN &&
201           osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED)
202         osk_state_ = OSK_ALLOWED;
203 
204       // Don't send a native focus event if the window itself doesn't
205       // have focus.
206       if (delegate_ && !delegate_->AccessibilityViewHasFocus())
207         continue;
208     }
209 
210     // Send the event event to the operating system.
211     NotifyAccessibilityEvent(event_type, GetFromAXNode(node));
212   }
213 }
214 
OnLocationChanges(const std::vector<AccessibilityHostMsg_LocationChangeParams> & params)215 void BrowserAccessibilityManager::OnLocationChanges(
216     const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) {
217   for (size_t i = 0; i < params.size(); ++i) {
218     BrowserAccessibility* obj = GetFromID(params[i].id);
219     if (!obj)
220       continue;
221     ui::AXNode* node = obj->node();
222     node->SetLocation(params[i].new_location);
223     obj->OnLocationChanged();
224   }
225 }
226 
GetActiveDescendantFocus(BrowserAccessibility * root)227 BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendantFocus(
228     BrowserAccessibility* root) {
229   BrowserAccessibility* node = BrowserAccessibilityManager::GetFocus(root);
230   if (!node)
231     return NULL;
232 
233   int active_descendant_id;
234   if (node->GetIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID,
235                             &active_descendant_id)) {
236     BrowserAccessibility* active_descendant =
237         node->manager()->GetFromID(active_descendant_id);
238     if (active_descendant)
239       return active_descendant;
240   }
241   return node;
242 }
243 
GetFocus(BrowserAccessibility * root)244 BrowserAccessibility* BrowserAccessibilityManager::GetFocus(
245     BrowserAccessibility* root) {
246   if (focus_ && (!root || focus_->IsDescendantOf(root->node())))
247     return GetFromAXNode(focus_);
248 
249   return NULL;
250 }
251 
SetFocus(ui::AXNode * node,bool notify)252 void BrowserAccessibilityManager::SetFocus(ui::AXNode* node, bool notify) {
253   if (focus_ != node)
254     focus_ = node;
255 
256   if (notify && node && delegate_)
257     delegate_->AccessibilitySetFocus(node->id());
258 }
259 
SetFocus(BrowserAccessibility * obj,bool notify)260 void BrowserAccessibilityManager::SetFocus(
261     BrowserAccessibility* obj, bool notify) {
262   if (obj->node())
263     SetFocus(obj->node(), notify);
264 }
265 
DoDefaultAction(const BrowserAccessibility & node)266 void BrowserAccessibilityManager::DoDefaultAction(
267     const BrowserAccessibility& node) {
268   if (delegate_)
269     delegate_->AccessibilityDoDefaultAction(node.GetId());
270 }
271 
ScrollToMakeVisible(const BrowserAccessibility & node,gfx::Rect subfocus)272 void BrowserAccessibilityManager::ScrollToMakeVisible(
273     const BrowserAccessibility& node, gfx::Rect subfocus) {
274   if (delegate_) {
275     delegate_->AccessibilityScrollToMakeVisible(node.GetId(), subfocus);
276   }
277 }
278 
ScrollToPoint(const BrowserAccessibility & node,gfx::Point point)279 void BrowserAccessibilityManager::ScrollToPoint(
280     const BrowserAccessibility& node, gfx::Point point) {
281   if (delegate_) {
282     delegate_->AccessibilityScrollToPoint(node.GetId(), point);
283   }
284 }
285 
SetTextSelection(const BrowserAccessibility & node,int start_offset,int end_offset)286 void BrowserAccessibilityManager::SetTextSelection(
287     const BrowserAccessibility& node, int start_offset, int end_offset) {
288   if (delegate_) {
289     delegate_->AccessibilitySetTextSelection(
290         node.GetId(), start_offset, end_offset);
291   }
292 }
293 
GetViewBounds()294 gfx::Rect BrowserAccessibilityManager::GetViewBounds() {
295   if (delegate_)
296     return delegate_->AccessibilityGetViewBounds();
297   return gfx::Rect();
298 }
299 
NextInTreeOrder(BrowserAccessibility * node)300 BrowserAccessibility* BrowserAccessibilityManager::NextInTreeOrder(
301     BrowserAccessibility* node) {
302   if (!node)
303     return NULL;
304 
305   if (node->PlatformChildCount() > 0)
306     return node->PlatformGetChild(0);
307   while (node) {
308     if (node->GetParent() &&
309         node->GetIndexInParent() <
310             static_cast<int>(node->GetParent()->PlatformChildCount()) - 1) {
311       return node->GetParent()->PlatformGetChild(node->GetIndexInParent() + 1);
312     }
313     node = node->GetParent();
314   }
315 
316   return NULL;
317 }
318 
PreviousInTreeOrder(BrowserAccessibility * node)319 BrowserAccessibility* BrowserAccessibilityManager::PreviousInTreeOrder(
320     BrowserAccessibility* node) {
321   if (!node)
322     return NULL;
323 
324   if (node->GetParent() && node->GetIndexInParent() > 0) {
325     node = node->GetParent()->PlatformGetChild(node->GetIndexInParent() - 1);
326     while (node->PlatformChildCount() > 0)
327       node = node->PlatformGetChild(node->PlatformChildCount() - 1);
328     return node;
329   }
330 
331   return node->GetParent();
332 }
333 
OnNodeWillBeDeleted(ui::AXNode * node)334 void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXNode* node) {
335   if (node == focus_ && tree_) {
336     if (node != tree_->GetRoot())
337       SetFocus(tree_->GetRoot(), false);
338     else
339       focus_ = NULL;
340   }
341   if (id_wrapper_map_.find(node->id()) == id_wrapper_map_.end())
342     return;
343   GetFromAXNode(node)->Destroy();
344   id_wrapper_map_.erase(node->id());
345 }
346 
OnNodeCreated(ui::AXNode * node)347 void BrowserAccessibilityManager::OnNodeCreated(ui::AXNode* node) {
348   BrowserAccessibility* wrapper = factory_->Create();
349   wrapper->Init(this, node);
350   id_wrapper_map_[node->id()] = wrapper;
351   wrapper->OnDataChanged();
352 }
353 
OnNodeChanged(ui::AXNode * node)354 void BrowserAccessibilityManager::OnNodeChanged(ui::AXNode* node) {
355   GetFromAXNode(node)->OnDataChanged();
356 }
357 
OnNodeCreationFinished(ui::AXNode * node)358 void BrowserAccessibilityManager::OnNodeCreationFinished(ui::AXNode* node) {
359   GetFromAXNode(node)->OnUpdateFinished();
360 }
361 
OnNodeChangeFinished(ui::AXNode * node)362 void BrowserAccessibilityManager::OnNodeChangeFinished(ui::AXNode* node) {
363   GetFromAXNode(node)->OnUpdateFinished();
364 }
365 
366 }  // namespace content
367