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