browser_accessibility_manager.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
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 11namespace content { 12 13ui::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 47BrowserAccessibility* 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 57BrowserAccessibilityManager* 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 65BrowserAccessibilityManager::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 76BrowserAccessibilityManager::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 89BrowserAccessibilityManager::~BrowserAccessibilityManager() { 90 tree_.reset(NULL); 91} 92 93void BrowserAccessibilityManager::Initialize( 94 const ui::AXTreeUpdate& initial_tree) { 95 if (!tree_->Unserialize(initial_tree)) { 96 if (delegate_) { 97 LOG(ERROR) << tree_->error(); 98 delegate_->FatalAccessibilityTreeError(); 99 } else { 100 LOG(FATAL) << tree_->error(); 101 } 102 } 103 104 if (!focus_) 105 SetFocus(tree_->GetRoot(), false); 106} 107 108// static 109ui::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 118BrowserAccessibility* BrowserAccessibilityManager::GetRoot() { 119 return GetFromAXNode(tree_->GetRoot()); 120} 121 122BrowserAccessibility* BrowserAccessibilityManager::GetFromAXNode( 123 ui::AXNode* node) { 124 return GetFromID(node->id()); 125} 126 127BrowserAccessibility* 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 135void BrowserAccessibilityManager::OnWindowFocused() { 136 if (focus_) 137 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_)); 138} 139 140void BrowserAccessibilityManager::OnWindowBlurred() { 141 if (focus_) 142 NotifyAccessibilityEvent(ui::AX_EVENT_BLUR, GetFromAXNode(focus_)); 143} 144 145void BrowserAccessibilityManager::GotMouseDown() { 146 osk_state_ = OSK_ALLOWED_WITHIN_FOCUSED_OBJECT; 147 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_)); 148} 149 150bool BrowserAccessibilityManager::IsOSKAllowed(const gfx::Rect& bounds) { 151 if (!delegate_ || !delegate_->HasFocus()) 152 return false; 153 154 gfx::Point touch_point = delegate_->GetLastTouchEventLocation(); 155 return bounds.Contains(touch_point); 156} 157 158bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() { 159 return true; 160} 161 162void BrowserAccessibilityManager::OnAccessibilityEvents( 163 const std::vector<AccessibilityHostMsg_EventParams>& params) { 164 bool should_send_initial_focus = false; 165 166 // Process all changes to the accessibility tree first. 167 for (uint32 index = 0; index < params.size(); index++) { 168 const AccessibilityHostMsg_EventParams& param = params[index]; 169 if (!tree_->Unserialize(param.update)) { 170 if (delegate_) { 171 LOG(ERROR) << tree_->error(); 172 delegate_->FatalAccessibilityTreeError(); 173 } else { 174 CHECK(false) << tree_->error(); 175 } 176 return; 177 } 178 179 // Set focus to the root if it's not anywhere else. 180 if (!focus_) { 181 SetFocus(tree_->GetRoot(), false); 182 should_send_initial_focus = true; 183 } 184 } 185 186 if (should_send_initial_focus && 187 (!delegate_ || delegate_->HasFocus())) { 188 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_)); 189 } 190 191 // Now iterate over the events again and fire the events. 192 for (uint32 index = 0; index < params.size(); index++) { 193 const AccessibilityHostMsg_EventParams& param = params[index]; 194 195 // Find the node corresponding to the id that's the target of the 196 // event (which may not be the root of the update tree). 197 ui::AXNode* node = tree_->GetFromId(param.id); 198 if (!node) 199 continue; 200 201 ui::AXEvent event_type = param.event_type; 202 if (event_type == ui::AX_EVENT_FOCUS || 203 event_type == ui::AX_EVENT_BLUR) { 204 SetFocus(node, false); 205 206 if (osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_HIDDEN && 207 osk_state_ != OSK_DISALLOWED_BECAUSE_TAB_JUST_APPEARED) 208 osk_state_ = OSK_ALLOWED; 209 210 // Don't send a native focus event if the window itself doesn't 211 // have focus. 212 if (delegate_ && !delegate_->HasFocus()) 213 continue; 214 } 215 216 // Send the event event to the operating system. 217 NotifyAccessibilityEvent(event_type, GetFromAXNode(node)); 218 } 219} 220 221void BrowserAccessibilityManager::OnLocationChanges( 222 const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) { 223 for (size_t i = 0; i < params.size(); ++i) { 224 BrowserAccessibility* obj = GetFromID(params[i].id); 225 if (!obj) 226 continue; 227 ui::AXNode* node = obj->node(); 228 node->SetLocation(params[i].new_location); 229 obj->OnLocationChanged(); 230 } 231} 232 233BrowserAccessibility* BrowserAccessibilityManager::GetFocus( 234 BrowserAccessibility* root) { 235 if (focus_ && (!root || focus_->IsDescendantOf(root->node()))) 236 return GetFromAXNode(focus_); 237 238 return NULL; 239} 240 241void BrowserAccessibilityManager::SetFocus(ui::AXNode* node, bool notify) { 242 if (focus_ != node) 243 focus_ = node; 244 245 if (notify && node && delegate_) 246 delegate_->SetAccessibilityFocus(node->id()); 247} 248 249void BrowserAccessibilityManager::SetFocus( 250 BrowserAccessibility* obj, bool notify) { 251 if (obj->node()) 252 SetFocus(obj->node(), notify); 253} 254 255void BrowserAccessibilityManager::DoDefaultAction( 256 const BrowserAccessibility& node) { 257 if (delegate_) 258 delegate_->AccessibilityDoDefaultAction(node.GetId()); 259} 260 261void BrowserAccessibilityManager::ScrollToMakeVisible( 262 const BrowserAccessibility& node, gfx::Rect subfocus) { 263 if (delegate_) { 264 delegate_->AccessibilityScrollToMakeVisible(node.GetId(), subfocus); 265 } 266} 267 268void BrowserAccessibilityManager::ScrollToPoint( 269 const BrowserAccessibility& node, gfx::Point point) { 270 if (delegate_) { 271 delegate_->AccessibilityScrollToPoint(node.GetId(), point); 272 } 273} 274 275void BrowserAccessibilityManager::SetTextSelection( 276 const BrowserAccessibility& node, int start_offset, int end_offset) { 277 if (delegate_) { 278 delegate_->AccessibilitySetTextSelection( 279 node.GetId(), start_offset, end_offset); 280 } 281} 282 283gfx::Rect BrowserAccessibilityManager::GetViewBounds() { 284 if (delegate_) 285 return delegate_->GetViewBounds(); 286 return gfx::Rect(); 287} 288 289BrowserAccessibility* BrowserAccessibilityManager::NextInTreeOrder( 290 BrowserAccessibility* node) { 291 if (!node) 292 return NULL; 293 294 if (node->PlatformChildCount() > 0) 295 return node->PlatformGetChild(0); 296 while (node) { 297 if (node->GetParent() && 298 node->GetIndexInParent() < 299 static_cast<int>(node->GetParent()->PlatformChildCount()) - 1) { 300 return node->GetParent()->PlatformGetChild(node->GetIndexInParent() + 1); 301 } 302 node = node->GetParent(); 303 } 304 305 return NULL; 306} 307 308BrowserAccessibility* BrowserAccessibilityManager::PreviousInTreeOrder( 309 BrowserAccessibility* node) { 310 if (!node) 311 return NULL; 312 313 if (node->GetParent() && node->GetIndexInParent() > 0) { 314 node = node->GetParent()->PlatformGetChild(node->GetIndexInParent() - 1); 315 while (node->PlatformChildCount() > 0) 316 node = node->PlatformGetChild(node->PlatformChildCount() - 1); 317 return node; 318 } 319 320 return node->GetParent(); 321} 322 323void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXNode* node) { 324 if (node == focus_ && tree_) { 325 if (node != tree_->GetRoot()) 326 SetFocus(tree_->GetRoot(), false); 327 else 328 focus_ = NULL; 329 } 330 if (id_wrapper_map_.find(node->id()) == id_wrapper_map_.end()) 331 return; 332 GetFromAXNode(node)->Destroy(); 333 id_wrapper_map_.erase(node->id()); 334} 335 336void BrowserAccessibilityManager::OnNodeCreated(ui::AXNode* node) { 337 BrowserAccessibility* wrapper = factory_->Create(); 338 wrapper->Init(this, node); 339 id_wrapper_map_[node->id()] = wrapper; 340 wrapper->OnDataChanged(); 341} 342 343void BrowserAccessibilityManager::OnNodeChanged(ui::AXNode* node) { 344 GetFromAXNode(node)->OnDataChanged(); 345} 346 347void BrowserAccessibilityManager::OnNodeCreationFinished(ui::AXNode* node) { 348 GetFromAXNode(node)->OnUpdateFinished(); 349} 350 351void BrowserAccessibilityManager::OnNodeChangeFinished(ui::AXNode* node) { 352 GetFromAXNode(node)->OnUpdateFinished(); 353} 354 355} // namespace content 356