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 
     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