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 "ui/views/accessibility/native_view_accessibility_win.h"
      6 
      7 #include <oleacc.h>
      8 #include <UIAutomationClient.h>
      9 
     10 #include <set>
     11 #include <vector>
     12 
     13 #include "base/memory/singleton.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "base/win/scoped_comptr.h"
     16 #include "base/win/windows_version.h"
     17 #include "third_party/iaccessible2/ia2_api_all.h"
     18 #include "ui/accessibility/ax_enums.h"
     19 #include "ui/accessibility/ax_text_utils.h"
     20 #include "ui/accessibility/ax_view_state.h"
     21 #include "ui/base/win/accessibility_ids_win.h"
     22 #include "ui/base/win/accessibility_misc_utils.h"
     23 #include "ui/base/win/atl_module.h"
     24 #include "ui/views/controls/button/custom_button.h"
     25 #include "ui/views/focus/focus_manager.h"
     26 #include "ui/views/focus/view_storage.h"
     27 #include "ui/views/widget/widget.h"
     28 #include "ui/views/win/hwnd_util.h"
     29 
     30 namespace views {
     31 namespace {
     32 
     33 class AccessibleWebViewRegistry {
     34  public:
     35   static AccessibleWebViewRegistry* GetInstance();
     36 
     37   void RegisterWebView(View* web_view);
     38 
     39   void UnregisterWebView(View* web_view);
     40 
     41   // Given the view that received the request for the accessible
     42   // id in |top_view|, and the child id requested, return the native
     43   // accessible object with that child id from one of the WebViews in
     44   // |top_view|'s view hierarchy, if any.
     45   IAccessible* GetAccessibleFromWebView(View* top_view, long child_id);
     46 
     47   // The system uses IAccessible APIs for many purposes, but only
     48   // assistive technology like screen readers uses IAccessible2.
     49   // Call this method to note that the IAccessible2 interface was queried and
     50   // that WebViews should be proactively notified that this interface will be
     51   // used. If this is enabled for the first time, this will explicitly call
     52   // QueryService with an argument of IAccessible2 on all WebViews, otherwise
     53   // it will just do it from now on.
     54   void EnableIAccessible2Support();
     55 
     56  private:
     57   friend struct DefaultSingletonTraits<AccessibleWebViewRegistry>;
     58   AccessibleWebViewRegistry();
     59   ~AccessibleWebViewRegistry() {}
     60 
     61   IAccessible* AccessibleObjectFromChildId(View* web_view, long child_id);
     62 
     63   void QueryIAccessible2Interface(View* web_view);
     64 
     65   // Set of all web views. We check whether each one is contained in a
     66   // top view dynamically rather than keeping track of a map.
     67   std::set<View*> web_views_;
     68 
     69   // The most recent top view used in a call to GetAccessibleFromWebView.
     70   View* last_top_view_;
     71 
     72   // The most recent web view where an accessible object was found,
     73   // corresponding to |last_top_view_|.
     74   View* last_web_view_;
     75 
     76   // If IAccessible2 support is enabled, we query the IAccessible2 interface
     77   // of WebViews proactively when they're registered, so that they are
     78   // aware that they need to support this interface.
     79   bool iaccessible2_support_enabled_;
     80 
     81   DISALLOW_COPY_AND_ASSIGN(AccessibleWebViewRegistry);
     82 };
     83 
     84 AccessibleWebViewRegistry::AccessibleWebViewRegistry()
     85     : last_top_view_(NULL),
     86       last_web_view_(NULL),
     87       iaccessible2_support_enabled_(false) {
     88 }
     89 
     90 AccessibleWebViewRegistry* AccessibleWebViewRegistry::GetInstance() {
     91   return Singleton<AccessibleWebViewRegistry>::get();
     92 }
     93 
     94 void AccessibleWebViewRegistry::RegisterWebView(View* web_view) {
     95   DCHECK(web_views_.find(web_view) == web_views_.end());
     96   web_views_.insert(web_view);
     97 
     98   if (iaccessible2_support_enabled_)
     99     QueryIAccessible2Interface(web_view);
    100 }
    101 
    102 void AccessibleWebViewRegistry::UnregisterWebView(View* web_view) {
    103   DCHECK(web_views_.find(web_view) != web_views_.end());
    104   web_views_.erase(web_view);
    105   if (last_web_view_ == web_view) {
    106     last_top_view_ = NULL;
    107     last_web_view_ = NULL;
    108   }
    109 }
    110 
    111 IAccessible* AccessibleWebViewRegistry::GetAccessibleFromWebView(
    112     View* top_view, long child_id) {
    113   // This function gets called frequently, so try to avoid searching all
    114   // of the web views if the notification is on the same web view that
    115   // sent the last one.
    116   if (last_top_view_ == top_view) {
    117     IAccessible* accessible =
    118         AccessibleObjectFromChildId(last_web_view_, child_id);
    119     if (accessible)
    120       return accessible;
    121   }
    122 
    123   // Search all web views. For each one, first ensure it's a descendant
    124   // of this view where the event was posted - and if so, see if it owns
    125   // an accessible object with that child id. If so, save the view to speed
    126   // up the next notification.
    127   for (std::set<View*>::iterator iter = web_views_.begin();
    128        iter != web_views_.end(); ++iter) {
    129     View* web_view = *iter;
    130     if (top_view == web_view || !top_view->Contains(web_view))
    131       continue;
    132     IAccessible* accessible = AccessibleObjectFromChildId(web_view, child_id);
    133     if (accessible) {
    134       last_top_view_ = top_view;
    135       last_web_view_ = web_view;
    136       return accessible;
    137     }
    138   }
    139 
    140   return NULL;
    141 }
    142 
    143 void AccessibleWebViewRegistry::EnableIAccessible2Support() {
    144   if (iaccessible2_support_enabled_)
    145     return;
    146   iaccessible2_support_enabled_ = true;
    147   for (std::set<View*>::iterator iter = web_views_.begin();
    148        iter != web_views_.end(); ++iter) {
    149     QueryIAccessible2Interface(*iter);
    150   }
    151 }
    152 
    153 IAccessible* AccessibleWebViewRegistry::AccessibleObjectFromChildId(
    154     View* web_view,
    155     long child_id) {
    156   IAccessible* web_view_accessible = web_view->GetNativeViewAccessible();
    157   if (web_view_accessible == NULL)
    158     return NULL;
    159 
    160   VARIANT var_child;
    161   var_child.vt = VT_I4;
    162   var_child.lVal = child_id;
    163   IAccessible* result = NULL;
    164   if (S_OK == web_view_accessible->get_accChild(
    165       var_child, reinterpret_cast<IDispatch**>(&result))) {
    166     return result;
    167   }
    168 
    169   return NULL;
    170 }
    171 
    172 void AccessibleWebViewRegistry::QueryIAccessible2Interface(View* web_view) {
    173   IAccessible* web_view_accessible = web_view->GetNativeViewAccessible();
    174   if (!web_view_accessible)
    175     return;
    176 
    177   base::win::ScopedComPtr<IServiceProvider> service_provider;
    178   if (S_OK != web_view_accessible->QueryInterface(service_provider.Receive()))
    179     return;
    180   base::win::ScopedComPtr<IAccessible2> iaccessible2;
    181   service_provider->QueryService(
    182       IID_IAccessible, IID_IAccessible2,
    183       reinterpret_cast<void**>(iaccessible2.Receive()));
    184 }
    185 
    186 }  // anonymous namespace
    187 
    188 // static
    189 long NativeViewAccessibilityWin::next_unique_id_ = 1;
    190 int NativeViewAccessibilityWin::view_storage_ids_[kMaxViewStorageIds] = {0};
    191 int NativeViewAccessibilityWin::next_view_storage_id_index_ = 0;
    192 std::vector<int> NativeViewAccessibilityWin::alert_target_view_storage_ids_;
    193 
    194 // static
    195 NativeViewAccessibility* NativeViewAccessibility::Create(View* view) {
    196   // Make sure ATL is initialized in this module.
    197   ui::win::CreateATLModuleIfNeeded();
    198 
    199   CComObject<NativeViewAccessibilityWin>* instance = NULL;
    200   HRESULT hr = CComObject<NativeViewAccessibilityWin>::CreateInstance(
    201       &instance);
    202   DCHECK(SUCCEEDED(hr));
    203   instance->set_view(view);
    204   instance->AddRef();
    205   return instance;
    206 }
    207 
    208 NativeViewAccessibilityWin::NativeViewAccessibilityWin()
    209     : view_(NULL),
    210       unique_id_(next_unique_id_++) {
    211 }
    212 
    213 NativeViewAccessibilityWin::~NativeViewAccessibilityWin() {
    214   RemoveAlertTarget();
    215 }
    216 
    217 void NativeViewAccessibilityWin::NotifyAccessibilityEvent(
    218     ui::AXEvent event_type) {
    219   if (!view_)
    220     return;
    221 
    222   ViewStorage* view_storage = ViewStorage::GetInstance();
    223   HWND hwnd = HWNDForView(view_);
    224   int view_storage_id = view_storage_ids_[next_view_storage_id_index_];
    225   if (view_storage_id == 0) {
    226     view_storage_id = view_storage->CreateStorageID();
    227     view_storage_ids_[next_view_storage_id_index_] = view_storage_id;
    228   } else {
    229     view_storage->RemoveView(view_storage_id);
    230   }
    231   view_storage->StoreView(view_storage_id, view_);
    232 
    233   // Positive child ids are used for enumerating direct children,
    234   // negative child ids can be used as unique ids to refer to a specific
    235   // descendants.  Make index into view_storage_ids_ into a negative child id.
    236   int child_id =
    237       base::win::kFirstViewsAccessibilityId - next_view_storage_id_index_;
    238   ::NotifyWinEvent(MSAAEvent(event_type), hwnd, OBJID_CLIENT, child_id);
    239   next_view_storage_id_index_ =
    240       (next_view_storage_id_index_ + 1) % kMaxViewStorageIds;
    241 
    242   // Keep track of views that are a target of an alert event.
    243   if (event_type == ui::AX_EVENT_ALERT)
    244     AddAlertTarget();
    245 }
    246 
    247 gfx::NativeViewAccessible NativeViewAccessibilityWin::GetNativeObject() {
    248   return this;
    249 }
    250 
    251 void NativeViewAccessibilityWin::Destroy() {
    252   view_ = NULL;
    253   Release();
    254 }
    255 
    256 STDMETHODIMP NativeViewAccessibilityWin::accHitTest(
    257     LONG x_left, LONG y_top, VARIANT* child) {
    258   if (!child)
    259     return E_INVALIDARG;
    260 
    261   if (!view_ || !view_->GetWidget())
    262     return E_FAIL;
    263 
    264   // If this is a root view, our widget might have child widgets.
    265   // Search child widgets first, since they're on top in the z-order.
    266   if (view_->GetWidget()->GetRootView() == view_) {
    267     std::vector<Widget*> child_widgets;
    268     PopulateChildWidgetVector(&child_widgets);
    269     for (size_t i = 0; i < child_widgets.size(); ++i) {
    270       Widget* child_widget = child_widgets[i];
    271       IAccessible* child_accessible =
    272           child_widget->GetRootView()->GetNativeViewAccessible();
    273       HRESULT result = child_accessible->accHitTest(x_left, y_top, child);
    274       if (result == S_OK)
    275         return result;
    276     }
    277   }
    278 
    279   gfx::Point point(x_left, y_top);
    280   View::ConvertPointFromScreen(view_, &point);
    281 
    282   // If the point is not inside this view, return false.
    283   if (!view_->HitTestPoint(point)) {
    284     child->vt = VT_EMPTY;
    285     return S_FALSE;
    286   }
    287 
    288   // Check if the point is within any of the immediate children of this
    289   // view.
    290   View* hit_child_view = NULL;
    291   for (int i = view_->child_count() - 1; i >= 0; --i) {
    292     View* child_view = view_->child_at(i);
    293     if (!child_view->visible())
    294       continue;
    295 
    296     gfx::Point point_in_child_coords(point);
    297     view_->ConvertPointToTarget(view_, child_view, &point_in_child_coords);
    298     if (child_view->HitTestPoint(point_in_child_coords)) {
    299       hit_child_view = child_view;
    300       break;
    301     }
    302   }
    303 
    304   // If the point was within one of this view's immediate children,
    305   // call accHitTest recursively on that child's native view accessible -
    306   // which may be a recursive call to this function or it may be overridden,
    307   // for example in the case of a WebView.
    308   if (hit_child_view) {
    309     HRESULT result = hit_child_view->GetNativeViewAccessible()->accHitTest(
    310         x_left, y_top, child);
    311 
    312     // If the recursive call returned CHILDID_SELF, we have to convert that
    313     // into a VT_DISPATCH for the return value to this call.
    314     if (S_OK == result && child->vt == VT_I4 && child->lVal == CHILDID_SELF) {
    315       child->vt = VT_DISPATCH;
    316       child->pdispVal = hit_child_view->GetNativeViewAccessible();
    317       // Always increment ref when returning a reference to a COM object.
    318       child->pdispVal->AddRef();
    319     }
    320     return result;
    321   }
    322 
    323   // This object is the best match, so return CHILDID_SELF. It's tempting to
    324   // simplify the logic and use VT_DISPATCH everywhere, but the Windows
    325   // call AccessibleObjectFromPoint will keep calling accHitTest until some
    326   // object returns CHILDID_SELF.
    327   child->vt = VT_I4;
    328   child->lVal = CHILDID_SELF;
    329   return S_OK;
    330 }
    331 
    332 HRESULT NativeViewAccessibilityWin::accDoDefaultAction(VARIANT var_id) {
    333   if (!IsValidId(var_id))
    334     return E_INVALIDARG;
    335 
    336   // The object does not support the method. This value is returned for
    337   // controls that do not perform actions, such as edit fields.
    338   return DISP_E_MEMBERNOTFOUND;
    339 }
    340 
    341 STDMETHODIMP NativeViewAccessibilityWin::accLocation(
    342     LONG* x_left, LONG* y_top, LONG* width, LONG* height, VARIANT var_id) {
    343   if (!IsValidId(var_id) || !x_left || !y_top || !width || !height)
    344     return E_INVALIDARG;
    345 
    346   if (!view_)
    347     return E_FAIL;
    348 
    349   if (!view_->bounds().IsEmpty()) {
    350     *width  = view_->width();
    351     *height = view_->height();
    352     gfx::Point topleft(view_->bounds().origin());
    353     View::ConvertPointToScreen(
    354         view_->parent() ? view_->parent() : view_, &topleft);
    355     *x_left = topleft.x();
    356     *y_top  = topleft.y();
    357   } else {
    358     return E_FAIL;
    359   }
    360   return S_OK;
    361 }
    362 
    363 STDMETHODIMP NativeViewAccessibilityWin::accNavigate(
    364     LONG nav_dir, VARIANT start, VARIANT* end) {
    365   if (start.vt != VT_I4 || !end)
    366     return E_INVALIDARG;
    367 
    368   if (!view_)
    369     return E_FAIL;
    370 
    371   switch (nav_dir) {
    372     case NAVDIR_FIRSTCHILD:
    373     case NAVDIR_LASTCHILD: {
    374       if (start.lVal != CHILDID_SELF) {
    375         // Start of navigation must be on the View itself.
    376         return E_INVALIDARG;
    377       } else if (!view_->has_children()) {
    378         // No children found.
    379         return S_FALSE;
    380       }
    381 
    382       // Set child_id based on first or last child.
    383       int child_id = 0;
    384       if (nav_dir == NAVDIR_LASTCHILD)
    385         child_id = view_->child_count() - 1;
    386 
    387       View* child = view_->child_at(child_id);
    388       end->vt = VT_DISPATCH;
    389       end->pdispVal = child->GetNativeViewAccessible();
    390       end->pdispVal->AddRef();
    391       return S_OK;
    392     }
    393     case NAVDIR_LEFT:
    394     case NAVDIR_UP:
    395     case NAVDIR_PREVIOUS:
    396     case NAVDIR_RIGHT:
    397     case NAVDIR_DOWN:
    398     case NAVDIR_NEXT: {
    399       // Retrieve parent to access view index and perform bounds checking.
    400       View* parent = view_->parent();
    401       if (!parent) {
    402         return E_FAIL;
    403       }
    404 
    405       if (start.lVal == CHILDID_SELF) {
    406         int view_index = parent->GetIndexOf(view_);
    407         // Check navigation bounds, adjusting for View child indexing (MSAA
    408         // child indexing starts with 1, whereas View indexing starts with 0).
    409         if (!IsValidNav(nav_dir, view_index, -1,
    410                         parent->child_count() - 1)) {
    411           // Navigation attempted to go out-of-bounds.
    412           end->vt = VT_EMPTY;
    413           return S_FALSE;
    414         } else {
    415           if (IsNavDirNext(nav_dir)) {
    416             view_index += 1;
    417           } else {
    418             view_index -=1;
    419           }
    420         }
    421 
    422         View* child = parent->child_at(view_index);
    423         end->pdispVal = child->GetNativeViewAccessible();
    424         end->vt = VT_DISPATCH;
    425         end->pdispVal->AddRef();
    426         return S_OK;
    427       } else {
    428         // Check navigation bounds, adjusting for MSAA child indexing (MSAA
    429         // child indexing starts with 1, whereas View indexing starts with 0).
    430         if (!IsValidNav(nav_dir, start.lVal, 0, parent->child_count() + 1)) {
    431             // Navigation attempted to go out-of-bounds.
    432             end->vt = VT_EMPTY;
    433             return S_FALSE;
    434           } else {
    435             if (IsNavDirNext(nav_dir)) {
    436               start.lVal += 1;
    437             } else {
    438               start.lVal -= 1;
    439             }
    440         }
    441 
    442         HRESULT result = this->get_accChild(start, &end->pdispVal);
    443         if (result == S_FALSE) {
    444           // Child is a leaf.
    445           end->vt = VT_I4;
    446           end->lVal = start.lVal;
    447         } else if (result == E_INVALIDARG) {
    448           return E_INVALIDARG;
    449         } else {
    450           // Child is not a leaf.
    451           end->vt = VT_DISPATCH;
    452         }
    453       }
    454       break;
    455     }
    456     default:
    457       return E_INVALIDARG;
    458   }
    459   // Navigation performed correctly. Global return for this function, if no
    460   // error triggered an escape earlier.
    461   return S_OK;
    462 }
    463 
    464 STDMETHODIMP NativeViewAccessibilityWin::get_accChild(VARIANT var_child,
    465                                                       IDispatch** disp_child) {
    466   if (var_child.vt != VT_I4 || !disp_child)
    467     return E_INVALIDARG;
    468 
    469   if (!view_ || !view_->GetWidget())
    470     return E_FAIL;
    471 
    472   LONG child_id = V_I4(&var_child);
    473 
    474   if (child_id == CHILDID_SELF) {
    475     // Remain with the same dispatch.
    476     return S_OK;
    477   }
    478 
    479   // If this is a root view, our widget might have child widgets. Include
    480   std::vector<Widget*> child_widgets;
    481   if (view_->GetWidget()->GetRootView() == view_)
    482     PopulateChildWidgetVector(&child_widgets);
    483   int child_widget_count = static_cast<int>(child_widgets.size());
    484 
    485   View* child_view = NULL;
    486   if (child_id > 0) {
    487     // Positive child ids are a 1-based child index, used by clients
    488     // that want to enumerate all immediate children.
    489     int child_id_as_index = child_id - 1;
    490     if (child_id_as_index < view_->child_count()) {
    491       child_view = view_->child_at(child_id_as_index);
    492     } else if (child_id_as_index < view_->child_count() + child_widget_count) {
    493       Widget* child_widget =
    494           child_widgets[child_id_as_index - view_->child_count()];
    495       child_view = child_widget->GetRootView();
    496     }
    497   } else {
    498     // Negative child ids can be used to map to any descendant.
    499     // Check child widget first.
    500     for (int i = 0; i < child_widget_count; i++) {
    501       Widget* child_widget = child_widgets[i];
    502       IAccessible* child_accessible =
    503           child_widget->GetRootView()->GetNativeViewAccessible();
    504       HRESULT result = child_accessible->get_accChild(var_child, disp_child);
    505       if (result == S_OK)
    506         return result;
    507     }
    508 
    509     // We map child ids to a view storage id that can refer to a
    510     // specific view (if that view still exists).
    511     int view_storage_id_index =
    512         base::win::kFirstViewsAccessibilityId - child_id;
    513     if (view_storage_id_index >= 0 &&
    514         view_storage_id_index < kMaxViewStorageIds) {
    515       int view_storage_id = view_storage_ids_[view_storage_id_index];
    516       ViewStorage* view_storage = ViewStorage::GetInstance();
    517       child_view = view_storage->RetrieveView(view_storage_id);
    518     } else {
    519       *disp_child = AccessibleWebViewRegistry::GetInstance()->
    520           GetAccessibleFromWebView(view_, child_id);
    521       if (*disp_child)
    522         return S_OK;
    523     }
    524   }
    525 
    526   if (!child_view) {
    527     // No child found.
    528     *disp_child = NULL;
    529     return E_FAIL;
    530   }
    531 
    532   *disp_child = child_view->GetNativeViewAccessible();
    533   (*disp_child)->AddRef();
    534   return S_OK;
    535 }
    536 
    537 STDMETHODIMP NativeViewAccessibilityWin::get_accChildCount(LONG* child_count) {
    538   if (!child_count)
    539     return E_INVALIDARG;
    540 
    541   if (!view_ || !view_->GetWidget())
    542     return E_FAIL;
    543 
    544   *child_count = view_->child_count();
    545 
    546   // If this is a root view, our widget might have child widgets. Include
    547   // them, too.
    548   if (view_->GetWidget()->GetRootView() == view_) {
    549     std::vector<Widget*> child_widgets;
    550     PopulateChildWidgetVector(&child_widgets);
    551     *child_count += child_widgets.size();
    552   }
    553 
    554   return S_OK;
    555 }
    556 
    557 STDMETHODIMP NativeViewAccessibilityWin::get_accDefaultAction(
    558     VARIANT var_id, BSTR* def_action) {
    559   if (!IsValidId(var_id) || !def_action)
    560     return E_INVALIDARG;
    561 
    562   if (!view_)
    563     return E_FAIL;
    564 
    565   ui::AXViewState state;
    566   view_->GetAccessibleState(&state);
    567   base::string16 temp_action = state.default_action;
    568 
    569   if (!temp_action.empty()) {
    570     *def_action = SysAllocString(temp_action.c_str());
    571   } else {
    572     return S_FALSE;
    573   }
    574 
    575   return S_OK;
    576 }
    577 
    578 STDMETHODIMP NativeViewAccessibilityWin::get_accDescription(
    579     VARIANT var_id, BSTR* desc) {
    580   if (!IsValidId(var_id) || !desc)
    581     return E_INVALIDARG;
    582 
    583   if (!view_)
    584     return E_FAIL;
    585 
    586   base::string16 temp_desc;
    587 
    588   view_->GetTooltipText(gfx::Point(), &temp_desc);
    589   if (!temp_desc.empty()) {
    590     *desc = SysAllocString(temp_desc.c_str());
    591   } else {
    592     return S_FALSE;
    593   }
    594 
    595   return S_OK;
    596 }
    597 
    598 STDMETHODIMP NativeViewAccessibilityWin::get_accFocus(VARIANT* focus_child) {
    599   if (!focus_child)
    600     return E_INVALIDARG;
    601 
    602   if (!view_)
    603     return E_FAIL;
    604 
    605   FocusManager* focus_manager = view_->GetFocusManager();
    606   View* focus = focus_manager ? focus_manager->GetFocusedView() : NULL;
    607   if (focus == view_) {
    608     // This view has focus.
    609     focus_child->vt = VT_I4;
    610     focus_child->lVal = CHILDID_SELF;
    611   } else if (focus && view_->Contains(focus)) {
    612     // Return the child object that has the keyboard focus.
    613     focus_child->vt = VT_DISPATCH;
    614     focus_child->pdispVal = focus->GetNativeViewAccessible();
    615     focus_child->pdispVal->AddRef();
    616     return S_OK;
    617   } else {
    618     // Neither this object nor any of its children has the keyboard focus.
    619     focus_child->vt = VT_EMPTY;
    620   }
    621   return S_OK;
    622 }
    623 
    624 STDMETHODIMP NativeViewAccessibilityWin::get_accKeyboardShortcut(
    625     VARIANT var_id, BSTR* acc_key) {
    626   if (!IsValidId(var_id) || !acc_key)
    627     return E_INVALIDARG;
    628 
    629   if (!view_)
    630     return E_FAIL;
    631 
    632   ui::AXViewState state;
    633   view_->GetAccessibleState(&state);
    634   base::string16 temp_key = state.keyboard_shortcut;
    635 
    636   if (!temp_key.empty()) {
    637     *acc_key = SysAllocString(temp_key.c_str());
    638   } else {
    639     return S_FALSE;
    640   }
    641 
    642   return S_OK;
    643 }
    644 
    645 STDMETHODIMP NativeViewAccessibilityWin::get_accName(
    646     VARIANT var_id, BSTR* name) {
    647   if (!IsValidId(var_id) || !name)
    648     return E_INVALIDARG;
    649 
    650   if (!view_)
    651     return E_FAIL;
    652 
    653   // Retrieve the current view's name.
    654   ui::AXViewState state;
    655   view_->GetAccessibleState(&state);
    656   base::string16 temp_name = state.name;
    657   if (!temp_name.empty()) {
    658     // Return name retrieved.
    659     *name = SysAllocString(temp_name.c_str());
    660   } else {
    661     // If view has no name, return S_FALSE.
    662     return S_FALSE;
    663   }
    664 
    665   return S_OK;
    666 }
    667 
    668 STDMETHODIMP NativeViewAccessibilityWin::get_accParent(
    669     IDispatch** disp_parent) {
    670   if (!disp_parent)
    671     return E_INVALIDARG;
    672 
    673   if (!view_)
    674     return E_FAIL;
    675 
    676   *disp_parent = NULL;
    677   View* parent_view = view_->parent();
    678 
    679   if (!parent_view) {
    680     HWND hwnd = HWNDForView(view_);
    681     if (!hwnd)
    682       return S_FALSE;
    683 
    684     return ::AccessibleObjectFromWindow(
    685         hwnd, OBJID_WINDOW, IID_IAccessible,
    686         reinterpret_cast<void**>(disp_parent));
    687   }
    688 
    689   *disp_parent = parent_view->GetNativeViewAccessible();
    690   (*disp_parent)->AddRef();
    691   return S_OK;
    692 }
    693 
    694 STDMETHODIMP NativeViewAccessibilityWin::get_accRole(
    695     VARIANT var_id, VARIANT* role) {
    696   if (!IsValidId(var_id) || !role)
    697     return E_INVALIDARG;
    698 
    699   if (!view_)
    700     return E_FAIL;
    701 
    702   ui::AXViewState state;
    703   view_->GetAccessibleState(&state);
    704   role->vt = VT_I4;
    705   role->lVal = MSAARole(state.role);
    706   return S_OK;
    707 }
    708 
    709 STDMETHODIMP NativeViewAccessibilityWin::get_accState(
    710     VARIANT var_id, VARIANT* state) {
    711   // This returns MSAA states. See also the IAccessible2 interface
    712   // get_states().
    713 
    714   if (!IsValidId(var_id) || !state)
    715     return E_INVALIDARG;
    716 
    717   if (!view_)
    718     return E_FAIL;
    719 
    720   state->vt = VT_I4;
    721 
    722   // Retrieve all currently applicable states of the parent.
    723   SetState(state, view_);
    724 
    725   // Make sure that state is not empty, and has the proper type.
    726   if (state->vt == VT_EMPTY)
    727     return E_FAIL;
    728 
    729   return S_OK;
    730 }
    731 
    732 STDMETHODIMP NativeViewAccessibilityWin::get_accValue(VARIANT var_id,
    733                                                       BSTR* value) {
    734   if (!IsValidId(var_id) || !value)
    735     return E_INVALIDARG;
    736 
    737   if (!view_)
    738     return E_FAIL;
    739 
    740   // Retrieve the current view's value.
    741   ui::AXViewState state;
    742   view_->GetAccessibleState(&state);
    743   base::string16 temp_value = state.value;
    744 
    745   if (!temp_value.empty()) {
    746     // Return value retrieved.
    747     *value = SysAllocString(temp_value.c_str());
    748   } else {
    749     // If view has no value, fall back into the default implementation.
    750     *value = NULL;
    751     return E_NOTIMPL;
    752   }
    753 
    754   return S_OK;
    755 }
    756 
    757 STDMETHODIMP NativeViewAccessibilityWin::put_accValue(VARIANT var_id,
    758                                                       BSTR new_value) {
    759   if (!IsValidId(var_id) || !new_value)
    760     return E_INVALIDARG;
    761 
    762   if (!view_)
    763     return E_FAIL;
    764 
    765   // Return an error if the view can't set the value.
    766   ui::AXViewState state;
    767   view_->GetAccessibleState(&state);
    768   if (state.set_value_callback.is_null())
    769     return E_FAIL;
    770 
    771   state.set_value_callback.Run(new_value);
    772   return S_OK;
    773 }
    774 
    775 // IAccessible functions not supported.
    776 
    777 STDMETHODIMP NativeViewAccessibilityWin::get_accSelection(VARIANT* selected) {
    778   if (selected)
    779     selected->vt = VT_EMPTY;
    780   return E_NOTIMPL;
    781 }
    782 
    783 STDMETHODIMP NativeViewAccessibilityWin::accSelect(
    784     LONG flagsSelect, VARIANT var_id) {
    785   return E_NOTIMPL;
    786 }
    787 
    788 STDMETHODIMP NativeViewAccessibilityWin::get_accHelp(
    789     VARIANT var_id, BSTR* help) {
    790   base::string16 temp = base::UTF8ToUTF16(view_->GetClassName());
    791   *help = SysAllocString(temp.c_str());
    792   return S_OK;
    793 }
    794 
    795 STDMETHODIMP NativeViewAccessibilityWin::get_accHelpTopic(
    796     BSTR* help_file, VARIANT var_id, LONG* topic_id) {
    797   if (help_file) {
    798     *help_file = NULL;
    799   }
    800   if (topic_id) {
    801     *topic_id = static_cast<LONG>(-1);
    802   }
    803   return E_NOTIMPL;
    804 }
    805 
    806 STDMETHODIMP NativeViewAccessibilityWin::put_accName(
    807     VARIANT var_id, BSTR put_name) {
    808   // Deprecated.
    809   return E_NOTIMPL;
    810 }
    811 
    812 //
    813 // IAccessible2
    814 //
    815 
    816 STDMETHODIMP NativeViewAccessibilityWin::role(LONG* role) {
    817   if (!view_)
    818     return E_FAIL;
    819 
    820   if (!role)
    821     return E_INVALIDARG;
    822 
    823   ui::AXViewState state;
    824   view_->GetAccessibleState(&state);
    825   *role = MSAARole(state.role);
    826   return S_OK;
    827 }
    828 
    829 STDMETHODIMP NativeViewAccessibilityWin::get_states(AccessibleStates* states) {
    830   // This returns IAccessible2 states, which supplement MSAA states.
    831   // See also the MSAA interface get_accState.
    832 
    833   if (!view_)
    834     return E_FAIL;
    835 
    836   if (!states)
    837     return E_INVALIDARG;
    838 
    839   ui::AXViewState state;
    840   view_->GetAccessibleState(&state);
    841 
    842   // There are only a couple of states we need to support
    843   // in IAccessible2. If any more are added, we may want to
    844   // add a helper function like MSAAState.
    845   *states = IA2_STATE_OPAQUE;
    846   if (state.HasStateFlag(ui::AX_STATE_EDITABLE))
    847     *states |= IA2_STATE_EDITABLE;
    848 
    849   return S_OK;
    850 }
    851 
    852 STDMETHODIMP NativeViewAccessibilityWin::get_uniqueID(LONG* unique_id) {
    853   if (!view_)
    854     return E_FAIL;
    855 
    856   if (!unique_id)
    857     return E_INVALIDARG;
    858 
    859   *unique_id = unique_id_;
    860   return S_OK;
    861 }
    862 
    863 STDMETHODIMP NativeViewAccessibilityWin::get_windowHandle(HWND* window_handle) {
    864   if (!view_)
    865     return E_FAIL;
    866 
    867   if (!window_handle)
    868     return E_INVALIDARG;
    869 
    870   *window_handle = HWNDForView(view_);
    871   return *window_handle ? S_OK : S_FALSE;
    872 }
    873 
    874 STDMETHODIMP NativeViewAccessibilityWin::get_relationTargetsOfType(
    875     BSTR type_bstr,
    876     long max_targets,
    877     IUnknown ***targets,
    878     long *n_targets) {
    879   if (!view_)
    880     return E_FAIL;
    881 
    882   if (!targets || !n_targets)
    883     return E_INVALIDARG;
    884 
    885   *n_targets = 0;
    886   *targets = NULL;
    887 
    888   // Only respond to requests for relations of type "alerts" on the
    889   // root view.
    890   base::string16 type(type_bstr);
    891   if (type != L"alerts" || view_->parent())
    892     return S_FALSE;
    893 
    894   // Collect all of the alert views that are still valid.
    895   std::vector<View*> alert_views;
    896   ViewStorage* view_storage = ViewStorage::GetInstance();
    897   for (size_t i = 0; i < alert_target_view_storage_ids_.size(); ++i) {
    898     int view_storage_id = alert_target_view_storage_ids_[i];
    899     View* view = view_storage->RetrieveView(view_storage_id);
    900     if (!view || !view_->Contains(view))
    901       continue;
    902     alert_views.push_back(view);
    903   }
    904 
    905   long count = alert_views.size();
    906   if (count == 0)
    907     return S_FALSE;
    908 
    909   // Don't return more targets than max_targets - but note that the caller
    910   // is allowed to specify max_targets=0 to mean no limit.
    911   if (max_targets > 0 && count > max_targets)
    912     count = max_targets;
    913 
    914   // Return the number of targets.
    915   *n_targets = count;
    916 
    917   // Allocate COM memory for the result array and populate it.
    918   *targets = static_cast<IUnknown**>(
    919       CoTaskMemAlloc(count * sizeof(IUnknown*)));
    920   for (long i = 0; i < count; ++i) {
    921     (*targets)[i] = alert_views[i]->GetNativeViewAccessible();
    922     (*targets)[i]->AddRef();
    923   }
    924   return S_OK;
    925 }
    926 
    927 //
    928 // IAccessibleText
    929 //
    930 
    931 STDMETHODIMP NativeViewAccessibilityWin::get_nCharacters(LONG* n_characters) {
    932   if (!view_)
    933     return E_FAIL;
    934 
    935   if (!n_characters)
    936     return E_INVALIDARG;
    937 
    938   base::string16 text = TextForIAccessibleText();
    939   *n_characters = static_cast<LONG>(text.size());
    940   return S_OK;
    941 }
    942 
    943 STDMETHODIMP NativeViewAccessibilityWin::get_caretOffset(LONG* offset) {
    944   if (!view_)
    945     return E_FAIL;
    946 
    947   if (!offset)
    948     return E_INVALIDARG;
    949 
    950   ui::AXViewState state;
    951   view_->GetAccessibleState(&state);
    952   *offset = static_cast<LONG>(state.selection_end);
    953   return S_OK;
    954 }
    955 
    956 STDMETHODIMP NativeViewAccessibilityWin::get_nSelections(LONG* n_selections) {
    957   if (!view_)
    958     return E_FAIL;
    959 
    960   if (!n_selections)
    961     return E_INVALIDARG;
    962 
    963   ui::AXViewState state;
    964   view_->GetAccessibleState(&state);
    965   if (state.selection_start != state.selection_end)
    966     *n_selections = 1;
    967   else
    968     *n_selections = 0;
    969   return S_OK;
    970 }
    971 
    972 STDMETHODIMP NativeViewAccessibilityWin::get_selection(LONG selection_index,
    973                                                       LONG* start_offset,
    974                                                       LONG* end_offset) {
    975   if (!view_)
    976     return E_FAIL;
    977 
    978   if (!start_offset || !end_offset || selection_index != 0)
    979     return E_INVALIDARG;
    980 
    981   ui::AXViewState state;
    982   view_->GetAccessibleState(&state);
    983   *start_offset = static_cast<LONG>(state.selection_start);
    984   *end_offset = static_cast<LONG>(state.selection_end);
    985   return S_OK;
    986 }
    987 
    988 STDMETHODIMP NativeViewAccessibilityWin::get_text(LONG start_offset,
    989                                                   LONG end_offset,
    990                                                   BSTR* text) {
    991   if (!view_)
    992     return E_FAIL;
    993 
    994   ui::AXViewState state;
    995   view_->GetAccessibleState(&state);
    996   base::string16 text_str = TextForIAccessibleText();
    997   LONG len = static_cast<LONG>(text_str.size());
    998 
    999   if (start_offset == IA2_TEXT_OFFSET_LENGTH) {
   1000     start_offset = len;
   1001   } else if (start_offset == IA2_TEXT_OFFSET_CARET) {
   1002     start_offset = static_cast<LONG>(state.selection_end);
   1003   }
   1004   if (end_offset == IA2_TEXT_OFFSET_LENGTH) {
   1005     end_offset = static_cast<LONG>(text_str.size());
   1006   } else if (end_offset == IA2_TEXT_OFFSET_CARET) {
   1007     end_offset = static_cast<LONG>(state.selection_end);
   1008   }
   1009 
   1010   // The spec allows the arguments to be reversed.
   1011   if (start_offset > end_offset) {
   1012     LONG tmp = start_offset;
   1013     start_offset = end_offset;
   1014     end_offset = tmp;
   1015   }
   1016 
   1017   // The spec does not allow the start or end offsets to be out or range;
   1018   // we must return an error if so.
   1019   if (start_offset < 0)
   1020     return E_INVALIDARG;
   1021   if (end_offset > len)
   1022     return E_INVALIDARG;
   1023 
   1024   base::string16 substr =
   1025       text_str.substr(start_offset, end_offset - start_offset);
   1026   if (substr.empty())
   1027     return S_FALSE;
   1028 
   1029   *text = SysAllocString(substr.c_str());
   1030   DCHECK(*text);
   1031   return S_OK;
   1032 }
   1033 
   1034 STDMETHODIMP NativeViewAccessibilityWin::get_textAtOffset(
   1035     LONG offset,
   1036     enum IA2TextBoundaryType boundary_type,
   1037     LONG* start_offset, LONG* end_offset,
   1038     BSTR* text) {
   1039   if (!start_offset || !end_offset || !text)
   1040     return E_INVALIDARG;
   1041 
   1042   // The IAccessible2 spec says we don't have to implement the "sentence"
   1043   // boundary type, we can just let the screenreader handle it.
   1044   if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
   1045     *start_offset = 0;
   1046     *end_offset = 0;
   1047     *text = NULL;
   1048     return S_FALSE;
   1049   }
   1050 
   1051   const base::string16& text_str = TextForIAccessibleText();
   1052 
   1053   *start_offset = FindBoundary(
   1054       text_str, boundary_type, offset, ui::BACKWARDS_DIRECTION);
   1055   *end_offset = FindBoundary(
   1056       text_str, boundary_type, offset, ui::FORWARDS_DIRECTION);
   1057   return get_text(*start_offset, *end_offset, text);
   1058 }
   1059 
   1060 STDMETHODIMP NativeViewAccessibilityWin::get_textBeforeOffset(
   1061     LONG offset,
   1062     enum IA2TextBoundaryType boundary_type,
   1063     LONG* start_offset, LONG* end_offset,
   1064     BSTR* text) {
   1065   if (!start_offset || !end_offset || !text)
   1066     return E_INVALIDARG;
   1067 
   1068   // The IAccessible2 spec says we don't have to implement the "sentence"
   1069   // boundary type, we can just let the screenreader handle it.
   1070   if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
   1071     *start_offset = 0;
   1072     *end_offset = 0;
   1073     *text = NULL;
   1074     return S_FALSE;
   1075   }
   1076 
   1077   const base::string16& text_str = TextForIAccessibleText();
   1078 
   1079   *start_offset = FindBoundary(
   1080       text_str, boundary_type, offset, ui::BACKWARDS_DIRECTION);
   1081   *end_offset = offset;
   1082   return get_text(*start_offset, *end_offset, text);
   1083 }
   1084 
   1085 STDMETHODIMP NativeViewAccessibilityWin::get_textAfterOffset(
   1086     LONG offset,
   1087     enum IA2TextBoundaryType boundary_type,
   1088     LONG* start_offset, LONG* end_offset,
   1089     BSTR* text) {
   1090   if (!start_offset || !end_offset || !text)
   1091     return E_INVALIDARG;
   1092 
   1093   // The IAccessible2 spec says we don't have to implement the "sentence"
   1094   // boundary type, we can just let the screenreader handle it.
   1095   if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
   1096     *start_offset = 0;
   1097     *end_offset = 0;
   1098     *text = NULL;
   1099     return S_FALSE;
   1100   }
   1101 
   1102   const base::string16& text_str = TextForIAccessibleText();
   1103 
   1104   *start_offset = offset;
   1105   *end_offset = FindBoundary(
   1106       text_str, boundary_type, offset, ui::FORWARDS_DIRECTION);
   1107   return get_text(*start_offset, *end_offset, text);
   1108 }
   1109 
   1110 STDMETHODIMP NativeViewAccessibilityWin::get_offsetAtPoint(
   1111     LONG x, LONG y, enum IA2CoordinateType coord_type, LONG* offset) {
   1112   if (!view_)
   1113     return E_FAIL;
   1114 
   1115   if (!offset)
   1116     return E_INVALIDARG;
   1117 
   1118   // We don't support this method, but we have to return something
   1119   // rather than E_NOTIMPL or screen readers will complain.
   1120   *offset = 0;
   1121   return S_OK;
   1122 }
   1123 
   1124 //
   1125 // IServiceProvider methods.
   1126 //
   1127 
   1128 STDMETHODIMP NativeViewAccessibilityWin::QueryService(
   1129     REFGUID guidService, REFIID riid, void** object) {
   1130   if (!view_)
   1131     return E_FAIL;
   1132 
   1133   if (riid == IID_IAccessible2 || riid == IID_IAccessible2_2)
   1134     AccessibleWebViewRegistry::GetInstance()->EnableIAccessible2Support();
   1135 
   1136   if (guidService == IID_IAccessible ||
   1137       guidService == IID_IAccessible2 ||
   1138       guidService == IID_IAccessible2_2 ||
   1139       guidService == IID_IAccessibleText)  {
   1140     return QueryInterface(riid, object);
   1141   }
   1142 
   1143   // We only support the IAccessibleEx interface on Windows 8 and above. This
   1144   // is needed for the On screen Keyboard to show up in metro mode, when the
   1145   // user taps an editable region in the window.
   1146   // All methods in the IAccessibleEx interface are unimplemented.
   1147   if (riid == IID_IAccessibleEx &&
   1148       base::win::GetVersion() >= base::win::VERSION_WIN8) {
   1149     return QueryInterface(riid, object);
   1150   }
   1151 
   1152   *object = NULL;
   1153   return E_FAIL;
   1154 }
   1155 
   1156 STDMETHODIMP NativeViewAccessibilityWin::GetPatternProvider(
   1157     PATTERNID id, IUnknown** provider) {
   1158   DVLOG(1) << "In Function: "
   1159            << __FUNCTION__
   1160            << " for pattern id: "
   1161            << id;
   1162   if (id == UIA_ValuePatternId || id == UIA_TextPatternId) {
   1163     ui::AXViewState state;
   1164     view_->GetAccessibleState(&state);
   1165     long role = MSAARole(state.role);
   1166 
   1167     if (role == ROLE_SYSTEM_TEXT) {
   1168       DVLOG(1) << "Returning UIA text provider";
   1169       base::win::UIATextProvider::CreateTextProvider(
   1170           state.value, true, provider);
   1171       return S_OK;
   1172     }
   1173   }
   1174   return E_NOTIMPL;
   1175 }
   1176 
   1177 STDMETHODIMP NativeViewAccessibilityWin::GetPropertyValue(PROPERTYID id,
   1178                                                           VARIANT* ret) {
   1179   DVLOG(1) << "In Function: "
   1180            << __FUNCTION__
   1181            << " for property id: "
   1182            << id;
   1183   if (id == UIA_ControlTypePropertyId) {
   1184     ui::AXViewState state;
   1185     view_->GetAccessibleState(&state);
   1186     long role = MSAARole(state.role);
   1187     if (role == ROLE_SYSTEM_TEXT) {
   1188       V_VT(ret) = VT_I4;
   1189       ret->lVal = UIA_EditControlTypeId;
   1190       DVLOG(1) << "Returning Edit control type";
   1191     } else {
   1192       DVLOG(1) << "Returning empty control type";
   1193       V_VT(ret) = VT_EMPTY;
   1194     }
   1195   } else {
   1196     V_VT(ret) = VT_EMPTY;
   1197   }
   1198   return S_OK;
   1199 }
   1200 
   1201 //
   1202 // Static methods.
   1203 //
   1204 
   1205 void NativeViewAccessibility::RegisterWebView(View* web_view) {
   1206   AccessibleWebViewRegistry::GetInstance()->RegisterWebView(web_view);
   1207 }
   1208 
   1209 void NativeViewAccessibility::UnregisterWebView(View* web_view) {
   1210   AccessibleWebViewRegistry::GetInstance()->UnregisterWebView(web_view);
   1211 }
   1212 
   1213 int32 NativeViewAccessibilityWin::MSAAEvent(ui::AXEvent event) {
   1214   switch (event) {
   1215     case ui::AX_EVENT_ALERT:
   1216       return EVENT_SYSTEM_ALERT;
   1217     case ui::AX_EVENT_FOCUS:
   1218       return EVENT_OBJECT_FOCUS;
   1219     case ui::AX_EVENT_MENU_START:
   1220       return EVENT_SYSTEM_MENUSTART;
   1221     case ui::AX_EVENT_MENU_END:
   1222       return EVENT_SYSTEM_MENUEND;
   1223     case ui::AX_EVENT_MENU_POPUP_START:
   1224       return EVENT_SYSTEM_MENUPOPUPSTART;
   1225     case ui::AX_EVENT_MENU_POPUP_END:
   1226       return EVENT_SYSTEM_MENUPOPUPEND;
   1227     case ui::AX_EVENT_TEXT_CHANGED:
   1228       return EVENT_OBJECT_NAMECHANGE;
   1229     case ui::AX_EVENT_SELECTION_CHANGED:
   1230       return IA2_EVENT_TEXT_CARET_MOVED;
   1231     case ui::AX_EVENT_VALUE_CHANGED:
   1232       return EVENT_OBJECT_VALUECHANGE;
   1233     default:
   1234       // Not supported or invalid event.
   1235       NOTREACHED();
   1236       return -1;
   1237   }
   1238 }
   1239 
   1240 int32 NativeViewAccessibilityWin::MSAARole(ui::AXRole role) {
   1241   switch (role) {
   1242     case ui::AX_ROLE_ALERT:
   1243       return ROLE_SYSTEM_ALERT;
   1244     case ui::AX_ROLE_APPLICATION:
   1245       return ROLE_SYSTEM_APPLICATION;
   1246     case ui::AX_ROLE_BUTTON_DROP_DOWN:
   1247       return ROLE_SYSTEM_BUTTONDROPDOWN;
   1248     case ui::AX_ROLE_POP_UP_BUTTON:
   1249       return ROLE_SYSTEM_BUTTONMENU;
   1250     case ui::AX_ROLE_CHECK_BOX:
   1251       return ROLE_SYSTEM_CHECKBUTTON;
   1252     case ui::AX_ROLE_COMBO_BOX:
   1253       return ROLE_SYSTEM_COMBOBOX;
   1254     case ui::AX_ROLE_DIALOG:
   1255       return ROLE_SYSTEM_DIALOG;
   1256     case ui::AX_ROLE_GROUP:
   1257       return ROLE_SYSTEM_GROUPING;
   1258     case ui::AX_ROLE_IMAGE:
   1259       return ROLE_SYSTEM_GRAPHIC;
   1260     case ui::AX_ROLE_LINK:
   1261       return ROLE_SYSTEM_LINK;
   1262     case ui::AX_ROLE_LOCATION_BAR:
   1263       return ROLE_SYSTEM_GROUPING;
   1264     case ui::AX_ROLE_MENU_BAR:
   1265       return ROLE_SYSTEM_MENUBAR;
   1266     case ui::AX_ROLE_MENU_ITEM:
   1267       return ROLE_SYSTEM_MENUITEM;
   1268     case ui::AX_ROLE_MENU_LIST_POPUP:
   1269       return ROLE_SYSTEM_MENUPOPUP;
   1270     case ui::AX_ROLE_TREE:
   1271       return ROLE_SYSTEM_OUTLINE;
   1272     case ui::AX_ROLE_TREE_ITEM:
   1273       return ROLE_SYSTEM_OUTLINEITEM;
   1274     case ui::AX_ROLE_TAB:
   1275       return ROLE_SYSTEM_PAGETAB;
   1276     case ui::AX_ROLE_TAB_LIST:
   1277       return ROLE_SYSTEM_PAGETABLIST;
   1278     case ui::AX_ROLE_PANE:
   1279       return ROLE_SYSTEM_PANE;
   1280     case ui::AX_ROLE_PROGRESS_INDICATOR:
   1281       return ROLE_SYSTEM_PROGRESSBAR;
   1282     case ui::AX_ROLE_BUTTON:
   1283       return ROLE_SYSTEM_PUSHBUTTON;
   1284     case ui::AX_ROLE_RADIO_BUTTON:
   1285       return ROLE_SYSTEM_RADIOBUTTON;
   1286     case ui::AX_ROLE_SCROLL_BAR:
   1287       return ROLE_SYSTEM_SCROLLBAR;
   1288     case ui::AX_ROLE_SPLITTER:
   1289       return ROLE_SYSTEM_SEPARATOR;
   1290     case ui::AX_ROLE_SLIDER:
   1291       return ROLE_SYSTEM_SLIDER;
   1292     case ui::AX_ROLE_STATIC_TEXT:
   1293       return ROLE_SYSTEM_STATICTEXT;
   1294     case ui::AX_ROLE_TEXT_FIELD:
   1295       return ROLE_SYSTEM_TEXT;
   1296     case ui::AX_ROLE_TITLE_BAR:
   1297       return ROLE_SYSTEM_TITLEBAR;
   1298     case ui::AX_ROLE_TOOLBAR:
   1299       return ROLE_SYSTEM_TOOLBAR;
   1300     case ui::AX_ROLE_WINDOW:
   1301       return ROLE_SYSTEM_WINDOW;
   1302     case ui::AX_ROLE_CLIENT:
   1303     default:
   1304       // This is the default role for MSAA.
   1305       return ROLE_SYSTEM_CLIENT;
   1306   }
   1307 }
   1308 
   1309 int32 NativeViewAccessibilityWin::MSAAState(const ui::AXViewState& state) {
   1310   // This maps MSAA states for get_accState(). See also the IAccessible2
   1311   // interface get_states().
   1312 
   1313   int32 msaa_state = 0;
   1314   if (state.HasStateFlag(ui::AX_STATE_CHECKED))
   1315     msaa_state |= STATE_SYSTEM_CHECKED;
   1316   if (state.HasStateFlag(ui::AX_STATE_COLLAPSED))
   1317     msaa_state |= STATE_SYSTEM_COLLAPSED;
   1318   if (state.HasStateFlag(ui::AX_STATE_DEFAULT))
   1319     msaa_state |= STATE_SYSTEM_DEFAULT;
   1320   if (state.HasStateFlag(ui::AX_STATE_EXPANDED))
   1321     msaa_state |= STATE_SYSTEM_EXPANDED;
   1322   if (state.HasStateFlag(ui::AX_STATE_HASPOPUP))
   1323     msaa_state |= STATE_SYSTEM_HASPOPUP;
   1324   if (state.HasStateFlag(ui::AX_STATE_HOVERED))
   1325     msaa_state |= STATE_SYSTEM_HOTTRACKED;
   1326   if (state.HasStateFlag(ui::AX_STATE_INVISIBLE))
   1327     msaa_state |= STATE_SYSTEM_INVISIBLE;
   1328   if (state.HasStateFlag(ui::AX_STATE_LINKED))
   1329     msaa_state |= STATE_SYSTEM_LINKED;
   1330   if (state.HasStateFlag(ui::AX_STATE_OFFSCREEN))
   1331     msaa_state |= STATE_SYSTEM_OFFSCREEN;
   1332   if (state.HasStateFlag(ui::AX_STATE_PRESSED))
   1333     msaa_state |= STATE_SYSTEM_PRESSED;
   1334   if (state.HasStateFlag(ui::AX_STATE_PROTECTED))
   1335     msaa_state |= STATE_SYSTEM_PROTECTED;
   1336   if (state.HasStateFlag(ui::AX_STATE_READ_ONLY))
   1337     msaa_state |= STATE_SYSTEM_READONLY;
   1338   if (state.HasStateFlag(ui::AX_STATE_SELECTED))
   1339     msaa_state |= STATE_SYSTEM_SELECTED;
   1340   if (state.HasStateFlag(ui::AX_STATE_FOCUSED))
   1341     msaa_state |= STATE_SYSTEM_FOCUSED;
   1342   if (state.HasStateFlag(ui::AX_STATE_DISABLED))
   1343     msaa_state |= STATE_SYSTEM_UNAVAILABLE;
   1344   return msaa_state;
   1345 }
   1346 
   1347 //
   1348 // Private methods.
   1349 //
   1350 
   1351 bool NativeViewAccessibilityWin::IsNavDirNext(int nav_dir) const {
   1352   return (nav_dir == NAVDIR_RIGHT ||
   1353           nav_dir == NAVDIR_DOWN ||
   1354           nav_dir == NAVDIR_NEXT);
   1355 }
   1356 
   1357 bool NativeViewAccessibilityWin::IsValidNav(
   1358     int nav_dir, int start_id, int lower_bound, int upper_bound) const {
   1359   if (IsNavDirNext(nav_dir)) {
   1360     if ((start_id + 1) > upper_bound) {
   1361       return false;
   1362     }
   1363   } else {
   1364     if ((start_id - 1) <= lower_bound) {
   1365       return false;
   1366     }
   1367   }
   1368   return true;
   1369 }
   1370 
   1371 bool NativeViewAccessibilityWin::IsValidId(const VARIANT& child) const {
   1372   // View accessibility returns an IAccessible for each view so we only support
   1373   // the CHILDID_SELF id.
   1374   return (VT_I4 == child.vt) && (CHILDID_SELF == child.lVal);
   1375 }
   1376 
   1377 void NativeViewAccessibilityWin::SetState(
   1378     VARIANT* msaa_state, View* view) {
   1379   // Ensure the output param is initialized to zero.
   1380   msaa_state->lVal = 0;
   1381 
   1382   // Default state; all views can have accessibility focus.
   1383   msaa_state->lVal |= STATE_SYSTEM_FOCUSABLE;
   1384 
   1385   if (!view)
   1386     return;
   1387 
   1388   if (!view->enabled())
   1389     msaa_state->lVal |= STATE_SYSTEM_UNAVAILABLE;
   1390   if (!view->visible())
   1391     msaa_state->lVal |= STATE_SYSTEM_INVISIBLE;
   1392   if (!strcmp(view->GetClassName(), CustomButton::kViewClassName)) {
   1393     CustomButton* button = static_cast<CustomButton*>(view);
   1394     if (button->IsHotTracked())
   1395       msaa_state->lVal |= STATE_SYSTEM_HOTTRACKED;
   1396   }
   1397   if (view->HasFocus())
   1398     msaa_state->lVal |= STATE_SYSTEM_FOCUSED;
   1399 
   1400   // Add on any view-specific states.
   1401   ui::AXViewState view_state;
   1402   view->GetAccessibleState(&view_state);
   1403   msaa_state->lVal |= MSAAState(view_state);
   1404 }
   1405 
   1406 base::string16 NativeViewAccessibilityWin::TextForIAccessibleText() {
   1407   ui::AXViewState state;
   1408   view_->GetAccessibleState(&state);
   1409   if (state.role == ui::AX_ROLE_TEXT_FIELD)
   1410     return state.value;
   1411   else
   1412     return state.name;
   1413 }
   1414 
   1415 void NativeViewAccessibilityWin::HandleSpecialTextOffset(
   1416     const base::string16& text, LONG* offset) {
   1417   if (*offset == IA2_TEXT_OFFSET_LENGTH) {
   1418     *offset = static_cast<LONG>(text.size());
   1419   } else if (*offset == IA2_TEXT_OFFSET_CARET) {
   1420     get_caretOffset(offset);
   1421   }
   1422 }
   1423 
   1424 ui::TextBoundaryType NativeViewAccessibilityWin::IA2TextBoundaryToTextBoundary(
   1425     IA2TextBoundaryType ia2_boundary) {
   1426   switch(ia2_boundary) {
   1427     case IA2_TEXT_BOUNDARY_CHAR: return ui::CHAR_BOUNDARY;
   1428     case IA2_TEXT_BOUNDARY_WORD: return ui::WORD_BOUNDARY;
   1429     case IA2_TEXT_BOUNDARY_LINE: return ui::LINE_BOUNDARY;
   1430     case IA2_TEXT_BOUNDARY_SENTENCE: return ui::SENTENCE_BOUNDARY;
   1431     case IA2_TEXT_BOUNDARY_PARAGRAPH: return ui::PARAGRAPH_BOUNDARY;
   1432     case IA2_TEXT_BOUNDARY_ALL: return ui::ALL_BOUNDARY;
   1433     default:
   1434       NOTREACHED();
   1435       return ui::CHAR_BOUNDARY;
   1436   }
   1437 }
   1438 
   1439 LONG NativeViewAccessibilityWin::FindBoundary(
   1440     const base::string16& text,
   1441     IA2TextBoundaryType ia2_boundary,
   1442     LONG start_offset,
   1443     ui::TextBoundaryDirection direction) {
   1444   HandleSpecialTextOffset(text, &start_offset);
   1445   ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary);
   1446   std::vector<int32> line_breaks;
   1447   return ui::FindAccessibleTextBoundary(
   1448       text, line_breaks, boundary, start_offset, direction);
   1449 }
   1450 
   1451 void NativeViewAccessibilityWin::PopulateChildWidgetVector(
   1452     std::vector<Widget*>* result_child_widgets) {
   1453   const Widget* widget = view()->GetWidget();
   1454   if (!widget)
   1455     return;
   1456 
   1457   std::set<Widget*> child_widgets;
   1458   Widget::GetAllChildWidgets(widget->GetNativeView(), &child_widgets);
   1459   Widget::GetAllOwnedWidgets(widget->GetNativeView(), &child_widgets);
   1460   for (std::set<Widget*>::const_iterator iter = child_widgets.begin();
   1461            iter != child_widgets.end(); ++iter) {
   1462     Widget* child_widget = *iter;
   1463     if (child_widget == widget)
   1464       continue;
   1465 
   1466     if (!child_widget->IsVisible())
   1467       continue;
   1468 
   1469     if (widget->GetNativeWindowProperty(kWidgetNativeViewHostKey))
   1470       continue;
   1471 
   1472     result_child_widgets->push_back(child_widget);
   1473   }
   1474 }
   1475 
   1476 void NativeViewAccessibilityWin::AddAlertTarget() {
   1477   ViewStorage* view_storage = ViewStorage::GetInstance();
   1478   for (size_t i = 0; i < alert_target_view_storage_ids_.size(); ++i) {
   1479     int view_storage_id = alert_target_view_storage_ids_[i];
   1480     View* view = view_storage->RetrieveView(view_storage_id);
   1481     if (view == view_)
   1482       return;
   1483   }
   1484   int view_storage_id = view_storage->CreateStorageID();
   1485   view_storage->StoreView(view_storage_id, view_);
   1486   alert_target_view_storage_ids_.push_back(view_storage_id);
   1487 }
   1488 
   1489 void NativeViewAccessibilityWin::RemoveAlertTarget() {
   1490   ViewStorage* view_storage = ViewStorage::GetInstance();
   1491   size_t i = 0;
   1492   while (i < alert_target_view_storage_ids_.size()) {
   1493     int view_storage_id = alert_target_view_storage_ids_[i];
   1494     View* view = view_storage->RetrieveView(view_storage_id);
   1495     if (view == NULL || view == view_) {
   1496       alert_target_view_storage_ids_.erase(
   1497           alert_target_view_storage_ids_.begin() + i);
   1498     } else {
   1499       ++i;
   1500     }
   1501   }
   1502 }
   1503 
   1504 }  // namespace views
   1505