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