Home | History | Annotate | Download | only in accessibility
      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 
     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 
     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
     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 
     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 
     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 
     90 BrowserAccessibilityManager::~BrowserAccessibilityManager() {
     91   tree_.reset(NULL);
     92 }
     93 
     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
    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 
    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::GotMouseDown() {
    147   osk_state_ = OSK_ALLOWED_WITHIN_FOCUSED_OBJECT;
    148   NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, GetFromAXNode(focus_));
    149 }
    150 
    151 bool BrowserAccessibilityManager::UseRootScrollOffsetsWhenComputingBounds() {
    152   return true;
    153 }
    154 
    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 
    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 
    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 
    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 
    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 
    261 void BrowserAccessibilityManager::SetFocus(
    262     BrowserAccessibility* obj, bool notify) {
    263   if (obj->node())
    264     SetFocus(obj->node(), notify);
    265 }
    266 
    267 void BrowserAccessibilityManager::DoDefaultAction(
    268     const BrowserAccessibility& node) {
    269   if (delegate_)
    270     delegate_->AccessibilityDoDefaultAction(node.GetId());
    271 }
    272 
    273 void BrowserAccessibilityManager::ScrollToMakeVisible(
    274     const BrowserAccessibility& node, gfx::Rect subfocus) {
    275   if (delegate_) {
    276     delegate_->AccessibilityScrollToMakeVisible(node.GetId(), subfocus);
    277   }
    278 }
    279 
    280 void BrowserAccessibilityManager::ScrollToPoint(
    281     const BrowserAccessibility& node, gfx::Point point) {
    282   if (delegate_) {
    283     delegate_->AccessibilityScrollToPoint(node.GetId(), point);
    284   }
    285 }
    286 
    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 
    295 gfx::Rect BrowserAccessibilityManager::GetViewBounds() {
    296   if (delegate_)
    297     return delegate_->AccessibilityGetViewBounds();
    298   return gfx::Rect();
    299 }
    300 
    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 
    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 
    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 
    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 
    355 void BrowserAccessibilityManager::OnNodeChanged(ui::AXNode* node) {
    356   GetFromAXNode(node)->OnDataChanged();
    357 }
    358 
    359 void BrowserAccessibilityManager::OnNodeCreationFinished(ui::AXNode* node) {
    360   GetFromAXNode(node)->OnUpdateFinished();
    361 }
    362 
    363 void BrowserAccessibilityManager::OnNodeChangeFinished(ui::AXNode* node) {
    364   GetFromAXNode(node)->OnUpdateFinished();
    365 }
    366 
    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