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 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, and Win. For any 55 // other platform, instantiate the base class. 56 // static 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 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 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 89 BrowserAccessibilityManager::~BrowserAccessibilityManager() { 90 tree_.reset(NULL); 91 } 92 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 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 118 BrowserAccessibility* BrowserAccessibilityManager::GetRoot() { 119 return GetFromAXNode(tree_->GetRoot()); 120 } 121 122 BrowserAccessibility* BrowserAccessibilityManager::GetFromAXNode( 123 ui::AXNode* node) { 124 return GetFromID(node->id()); 125 } 126 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 135 void BrowserAccessibilityManager::OnWindowFocused() { 136 if (focus_) 137 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_)); 138 } 139 140 void BrowserAccessibilityManager::OnWindowBlurred() { 141 if (focus_) 142 NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, GetFromAXNode(focus_)); 143 } 144 145 void BrowserAccessibilityManager::GotMouseDown() { 146 osk_state_ = OSK_ALLOWED_WITHIN_FOCUSED_OBJECT; 147 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_)); 148 } 149 150 bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() { 151 return true; 152 } 153 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 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 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 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 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 260 void BrowserAccessibilityManager::SetFocus( 261 BrowserAccessibility* obj, bool notify) { 262 if (obj->node()) 263 SetFocus(obj->node(), notify); 264 } 265 266 void BrowserAccessibilityManager::DoDefaultAction( 267 const BrowserAccessibility& node) { 268 if (delegate_) 269 delegate_->AccessibilityDoDefaultAction(node.GetId()); 270 } 271 272 void BrowserAccessibilityManager::ScrollToMakeVisible( 273 const BrowserAccessibility& node, gfx::Rect subfocus) { 274 if (delegate_) { 275 delegate_->AccessibilityScrollToMakeVisible(node.GetId(), subfocus); 276 } 277 } 278 279 void BrowserAccessibilityManager::ScrollToPoint( 280 const BrowserAccessibility& node, gfx::Point point) { 281 if (delegate_) { 282 delegate_->AccessibilityScrollToPoint(node.GetId(), point); 283 } 284 } 285 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 294 gfx::Rect BrowserAccessibilityManager::GetViewBounds() { 295 if (delegate_) 296 return delegate_->AccessibilityGetViewBounds(); 297 return gfx::Rect(); 298 } 299 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 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 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 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 354 void BrowserAccessibilityManager::OnNodeChanged(ui::AXNode* node) { 355 GetFromAXNode(node)->OnDataChanged(); 356 } 357 358 void BrowserAccessibilityManager::OnNodeCreationFinished(ui::AXNode* node) { 359 GetFromAXNode(node)->OnUpdateFinished(); 360 } 361 362 void BrowserAccessibilityManager::OnNodeChangeFinished(ui::AXNode* node) { 363 GetFromAXNode(node)->OnUpdateFinished(); 364 } 365 366 } // namespace content 367