Home | History | Annotate | Download | only in accessibility
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/browser/accessibility/browser_accessibility_win.h"
      6 
      7 #include <UIAutomationClient.h>
      8 #include <UIAutomationCoreApi.h>
      9 
     10 #include "base/strings/string_number_conversions.h"
     11 #include "base/strings/string_split.h"
     12 #include "base/strings/string_util.h"
     13 #include "base/strings/utf_string_conversions.h"
     14 #include "base/win/enum_variant.h"
     15 #include "base/win/scoped_comptr.h"
     16 #include "base/win/windows_version.h"
     17 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
     18 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
     19 #include "content/common/accessibility_messages.h"
     20 #include "content/public/common/content_client.h"
     21 #include "ui/accessibility/ax_text_utils.h"
     22 #include "ui/base/win/accessibility_ids_win.h"
     23 #include "ui/base/win/accessibility_misc_utils.h"
     24 
     25 namespace content {
     26 
     27 // These nonstandard GUIDs are taken directly from the Mozilla sources
     28 // (accessible/src/msaa/nsAccessNodeWrap.cpp); some documentation is here:
     29 // http://developer.mozilla.org/en/Accessibility/AT-APIs/ImplementationFeatures/MSAA
     30 const GUID GUID_ISimpleDOM = {
     31     0x0c539790, 0x12e4, 0x11cf,
     32     0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8};
     33 const GUID GUID_IAccessibleContentDocument = {
     34     0xa5d8e1f3, 0x3571, 0x4d8f,
     35     0x95, 0x21, 0x07, 0xed, 0x28, 0xfb, 0x07, 0x2e};
     36 
     37 const base::char16 BrowserAccessibilityWin::kEmbeddedCharacter[] = L"\xfffc";
     38 
     39 // static
     40 LONG BrowserAccessibilityWin::next_unique_id_win_ =
     41     base::win::kFirstBrowserAccessibilityManagerAccessibilityId;
     42 
     43 //
     44 // BrowserAccessibilityRelation
     45 //
     46 // A simple implementation of IAccessibleRelation, used to represent
     47 // a relationship between two accessible nodes in the tree.
     48 //
     49 
     50 class BrowserAccessibilityRelation
     51     : public CComObjectRootEx<CComMultiThreadModel>,
     52       public IAccessibleRelation {
     53   BEGIN_COM_MAP(BrowserAccessibilityRelation)
     54     COM_INTERFACE_ENTRY(IAccessibleRelation)
     55   END_COM_MAP()
     56 
     57   CONTENT_EXPORT BrowserAccessibilityRelation() {}
     58   CONTENT_EXPORT virtual ~BrowserAccessibilityRelation() {}
     59 
     60   CONTENT_EXPORT void Initialize(BrowserAccessibilityWin* owner,
     61                                  const base::string16& type);
     62   CONTENT_EXPORT void AddTarget(int target_id);
     63 
     64   // IAccessibleRelation methods.
     65   CONTENT_EXPORT STDMETHODIMP get_relationType(BSTR* relation_type);
     66   CONTENT_EXPORT STDMETHODIMP get_nTargets(long* n_targets);
     67   CONTENT_EXPORT STDMETHODIMP get_target(long target_index, IUnknown** target);
     68   CONTENT_EXPORT STDMETHODIMP get_targets(long max_targets,
     69                                           IUnknown** targets,
     70                                           long* n_targets);
     71 
     72   // IAccessibleRelation methods not implemented.
     73   CONTENT_EXPORT STDMETHODIMP get_localizedRelationType(BSTR* relation_type) {
     74     return E_NOTIMPL;
     75   }
     76 
     77  private:
     78   base::string16 type_;
     79   base::win::ScopedComPtr<BrowserAccessibilityWin> owner_;
     80   std::vector<int> target_ids_;
     81 };
     82 
     83 void BrowserAccessibilityRelation::Initialize(BrowserAccessibilityWin* owner,
     84                                               const base::string16& type) {
     85   owner_ = owner;
     86   type_ = type;
     87 }
     88 
     89 void BrowserAccessibilityRelation::AddTarget(int target_id) {
     90   target_ids_.push_back(target_id);
     91 }
     92 
     93 STDMETHODIMP BrowserAccessibilityRelation::get_relationType(
     94     BSTR* relation_type) {
     95   if (!relation_type)
     96     return E_INVALIDARG;
     97 
     98   if (!owner_->instance_active())
     99     return E_FAIL;
    100 
    101   *relation_type = SysAllocString(type_.c_str());
    102   DCHECK(*relation_type);
    103   return S_OK;
    104 }
    105 
    106 STDMETHODIMP BrowserAccessibilityRelation::get_nTargets(long* n_targets) {
    107   if (!n_targets)
    108     return E_INVALIDARG;
    109 
    110   if (!owner_->instance_active())
    111     return E_FAIL;
    112 
    113   *n_targets = static_cast<long>(target_ids_.size());
    114 
    115   BrowserAccessibilityManager* manager = owner_->manager();
    116   for (long i = *n_targets - 1; i >= 0; --i) {
    117     BrowserAccessibility* result = manager->GetFromID(target_ids_[i]);
    118     if (!result || !result->instance_active()) {
    119       *n_targets = 0;
    120       break;
    121     }
    122   }
    123   return S_OK;
    124 }
    125 
    126 STDMETHODIMP BrowserAccessibilityRelation::get_target(long target_index,
    127                                                       IUnknown** target) {
    128   if (!target)
    129     return E_INVALIDARG;
    130 
    131   if (!owner_->instance_active())
    132     return E_FAIL;
    133 
    134   if (target_index < 0 ||
    135       target_index >= static_cast<long>(target_ids_.size())) {
    136     return E_INVALIDARG;
    137   }
    138 
    139   BrowserAccessibilityManager* manager = owner_->manager();
    140   BrowserAccessibility* result =
    141       manager->GetFromID(target_ids_[target_index]);
    142   if (!result || !result->instance_active())
    143     return E_FAIL;
    144 
    145   *target = static_cast<IAccessible*>(
    146       result->ToBrowserAccessibilityWin()->NewReference());
    147   return S_OK;
    148 }
    149 
    150 STDMETHODIMP BrowserAccessibilityRelation::get_targets(long max_targets,
    151                                                        IUnknown** targets,
    152                                                        long* n_targets) {
    153   if (!targets || !n_targets)
    154     return E_INVALIDARG;
    155 
    156   if (!owner_->instance_active())
    157     return E_FAIL;
    158 
    159   long count = static_cast<long>(target_ids_.size());
    160   if (count > max_targets)
    161     count = max_targets;
    162 
    163   *n_targets = count;
    164   if (count == 0)
    165     return S_FALSE;
    166 
    167   for (long i = 0; i < count; ++i) {
    168     HRESULT result = get_target(i, &targets[i]);
    169     if (result != S_OK)
    170       return result;
    171   }
    172 
    173   return S_OK;
    174 }
    175 
    176 //
    177 // BrowserAccessibilityWin
    178 //
    179 
    180 // static
    181 BrowserAccessibility* BrowserAccessibility::Create() {
    182   CComObject<BrowserAccessibilityWin>* instance;
    183   HRESULT hr = CComObject<BrowserAccessibilityWin>::CreateInstance(&instance);
    184   DCHECK(SUCCEEDED(hr));
    185   return instance->NewReference();
    186 }
    187 
    188 BrowserAccessibilityWin* BrowserAccessibility::ToBrowserAccessibilityWin() {
    189   return static_cast<BrowserAccessibilityWin*>(this);
    190 }
    191 
    192 BrowserAccessibilityWin::BrowserAccessibilityWin()
    193     : ia_role_(0),
    194       ia_state_(0),
    195       ia2_role_(0),
    196       ia2_state_(0),
    197       first_time_(true),
    198       old_ia_state_(0),
    199       previous_scroll_x_(0),
    200       previous_scroll_y_(0) {
    201   // Start unique IDs at -1 and decrement each time, because get_accChild
    202   // uses positive IDs to enumerate children, so we use negative IDs to
    203   // clearly distinguish between indices and unique IDs.
    204   unique_id_win_ = next_unique_id_win_;
    205   if (next_unique_id_win_ ==
    206           base::win::kLastBrowserAccessibilityManagerAccessibilityId) {
    207     next_unique_id_win_ =
    208         base::win::kFirstBrowserAccessibilityManagerAccessibilityId;
    209   }
    210   next_unique_id_win_--;
    211 }
    212 
    213 BrowserAccessibilityWin::~BrowserAccessibilityWin() {
    214   for (size_t i = 0; i < relations_.size(); ++i)
    215     relations_[i]->Release();
    216 }
    217 
    218 //
    219 // IAccessible methods.
    220 //
    221 // Conventions:
    222 // * Always test for instance_active() first and return E_FAIL if it's false.
    223 // * Always check for invalid arguments first, even if they're unused.
    224 // * Return S_FALSE if the only output is a string argument and it's empty.
    225 //
    226 
    227 HRESULT BrowserAccessibilityWin::accDoDefaultAction(VARIANT var_id) {
    228   if (!instance_active())
    229     return E_FAIL;
    230 
    231   BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
    232   if (!target)
    233     return E_INVALIDARG;
    234 
    235   manager()->DoDefaultAction(*target);
    236   return S_OK;
    237 }
    238 
    239 STDMETHODIMP BrowserAccessibilityWin::accHitTest(LONG x_left,
    240                                                  LONG y_top,
    241                                                  VARIANT* child) {
    242   if (!instance_active())
    243     return E_FAIL;
    244 
    245   if (!child)
    246     return E_INVALIDARG;
    247 
    248   gfx::Point point(x_left, y_top);
    249   if (!GetGlobalBoundsRect().Contains(point)) {
    250     // Return S_FALSE and VT_EMPTY when the outside the object's boundaries.
    251     child->vt = VT_EMPTY;
    252     return S_FALSE;
    253   }
    254 
    255   BrowserAccessibility* result = BrowserAccessibilityForPoint(point);
    256   if (result == this) {
    257     // Point is within this object.
    258     child->vt = VT_I4;
    259     child->lVal = CHILDID_SELF;
    260   } else {
    261     child->vt = VT_DISPATCH;
    262     child->pdispVal = result->ToBrowserAccessibilityWin()->NewReference();
    263   }
    264   return S_OK;
    265 }
    266 
    267 STDMETHODIMP BrowserAccessibilityWin::accLocation(LONG* x_left,
    268                                                   LONG* y_top,
    269                                                   LONG* width,
    270                                                   LONG* height,
    271                                                   VARIANT var_id) {
    272   if (!instance_active())
    273     return E_FAIL;
    274 
    275   if (!x_left || !y_top || !width || !height)
    276     return E_INVALIDARG;
    277 
    278   BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
    279   if (!target)
    280     return E_INVALIDARG;
    281 
    282   gfx::Rect bounds = target->GetGlobalBoundsRect();
    283   *x_left = bounds.x();
    284   *y_top  = bounds.y();
    285   *width  = bounds.width();
    286   *height = bounds.height();
    287 
    288   return S_OK;
    289 }
    290 
    291 STDMETHODIMP BrowserAccessibilityWin::accNavigate(LONG nav_dir,
    292                                                   VARIANT start,
    293                                                   VARIANT* end) {
    294   BrowserAccessibilityWin* target = GetTargetFromChildID(start);
    295   if (!target)
    296     return E_INVALIDARG;
    297 
    298   if ((nav_dir == NAVDIR_LASTCHILD || nav_dir == NAVDIR_FIRSTCHILD) &&
    299       start.lVal != CHILDID_SELF) {
    300     // MSAA states that navigating to first/last child can only be from self.
    301     return E_INVALIDARG;
    302   }
    303 
    304   uint32 child_count = target->PlatformChildCount();
    305 
    306   BrowserAccessibility* result = NULL;
    307   switch (nav_dir) {
    308     case NAVDIR_DOWN:
    309     case NAVDIR_UP:
    310     case NAVDIR_LEFT:
    311     case NAVDIR_RIGHT:
    312       // These directions are not implemented, matching Mozilla and IE.
    313       return E_NOTIMPL;
    314     case NAVDIR_FIRSTCHILD:
    315       if (child_count > 0)
    316         result = target->PlatformGetChild(0);
    317       break;
    318     case NAVDIR_LASTCHILD:
    319       if (child_count > 0)
    320         result = target->PlatformGetChild(child_count - 1);
    321       break;
    322     case NAVDIR_NEXT:
    323       result = target->GetNextSibling();
    324       break;
    325     case NAVDIR_PREVIOUS:
    326       result = target->GetPreviousSibling();
    327       break;
    328   }
    329 
    330   if (!result) {
    331     end->vt = VT_EMPTY;
    332     return S_FALSE;
    333   }
    334 
    335   end->vt = VT_DISPATCH;
    336   end->pdispVal = result->ToBrowserAccessibilityWin()->NewReference();
    337   return S_OK;
    338 }
    339 
    340 STDMETHODIMP BrowserAccessibilityWin::get_accChild(VARIANT var_child,
    341                                                    IDispatch** disp_child) {
    342   if (!instance_active())
    343     return E_FAIL;
    344 
    345   if (!disp_child)
    346     return E_INVALIDARG;
    347 
    348   *disp_child = NULL;
    349 
    350   BrowserAccessibilityWin* target = GetTargetFromChildID(var_child);
    351   if (!target)
    352     return E_INVALIDARG;
    353 
    354   (*disp_child) = target->NewReference();
    355   return S_OK;
    356 }
    357 
    358 STDMETHODIMP BrowserAccessibilityWin::get_accChildCount(LONG* child_count) {
    359   if (!instance_active())
    360     return E_FAIL;
    361 
    362   if (!child_count)
    363     return E_INVALIDARG;
    364 
    365   *child_count = PlatformChildCount();
    366 
    367   return S_OK;
    368 }
    369 
    370 STDMETHODIMP BrowserAccessibilityWin::get_accDefaultAction(VARIANT var_id,
    371                                                            BSTR* def_action) {
    372   if (!instance_active())
    373     return E_FAIL;
    374 
    375   if (!def_action)
    376     return E_INVALIDARG;
    377 
    378   BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
    379   if (!target)
    380     return E_INVALIDARG;
    381 
    382   return target->GetStringAttributeAsBstr(
    383       ui::AX_ATTR_SHORTCUT, def_action);
    384 }
    385 
    386 STDMETHODIMP BrowserAccessibilityWin::get_accDescription(VARIANT var_id,
    387                                                          BSTR* desc) {
    388   if (!instance_active())
    389     return E_FAIL;
    390 
    391   if (!desc)
    392     return E_INVALIDARG;
    393 
    394   BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
    395   if (!target)
    396     return E_INVALIDARG;
    397 
    398   return target->GetStringAttributeAsBstr(
    399       ui::AX_ATTR_DESCRIPTION, desc);
    400 }
    401 
    402 STDMETHODIMP BrowserAccessibilityWin::get_accFocus(VARIANT* focus_child) {
    403   if (!instance_active())
    404     return E_FAIL;
    405 
    406   if (!focus_child)
    407     return E_INVALIDARG;
    408 
    409   BrowserAccessibilityWin* focus = static_cast<BrowserAccessibilityWin*>(
    410       manager()->GetFocus(this));
    411   if (focus == this) {
    412     focus_child->vt = VT_I4;
    413     focus_child->lVal = CHILDID_SELF;
    414   } else if (focus == NULL) {
    415     focus_child->vt = VT_EMPTY;
    416   } else {
    417     focus_child->vt = VT_DISPATCH;
    418     focus_child->pdispVal = focus->NewReference();
    419   }
    420 
    421   return S_OK;
    422 }
    423 
    424 STDMETHODIMP BrowserAccessibilityWin::get_accHelp(VARIANT var_id, BSTR* help) {
    425   if (!instance_active())
    426     return E_FAIL;
    427 
    428   if (!help)
    429     return E_INVALIDARG;
    430 
    431   BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
    432   if (!target)
    433     return E_INVALIDARG;
    434 
    435   return target->GetStringAttributeAsBstr(
    436       ui::AX_ATTR_HELP, help);
    437 }
    438 
    439 STDMETHODIMP BrowserAccessibilityWin::get_accKeyboardShortcut(VARIANT var_id,
    440                                                               BSTR* acc_key) {
    441   if (!instance_active())
    442     return E_FAIL;
    443 
    444   if (!acc_key)
    445     return E_INVALIDARG;
    446 
    447   BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
    448   if (!target)
    449     return E_INVALIDARG;
    450 
    451   return target->GetStringAttributeAsBstr(
    452       ui::AX_ATTR_SHORTCUT, acc_key);
    453 }
    454 
    455 STDMETHODIMP BrowserAccessibilityWin::get_accName(VARIANT var_id, BSTR* name) {
    456   if (!instance_active())
    457     return E_FAIL;
    458 
    459   if (!name)
    460     return E_INVALIDARG;
    461 
    462   BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
    463   if (!target)
    464     return E_INVALIDARG;
    465 
    466   std::string name_str = target->name();
    467 
    468   // If the name is empty, see if it's labeled by another element.
    469   if (name_str.empty()) {
    470     int title_elem_id;
    471     if (target->GetIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT,
    472                                 &title_elem_id)) {
    473       BrowserAccessibility* title_elem =
    474           manager()->GetFromID(title_elem_id);
    475       if (title_elem)
    476         name_str = title_elem->GetTextRecursive();
    477     }
    478   }
    479 
    480   if (name_str.empty())
    481     return S_FALSE;
    482 
    483   *name = SysAllocString(base::UTF8ToUTF16(name_str).c_str());
    484 
    485   DCHECK(*name);
    486   return S_OK;
    487 }
    488 
    489 STDMETHODIMP BrowserAccessibilityWin::get_accParent(IDispatch** disp_parent) {
    490   if (!instance_active())
    491     return E_FAIL;
    492 
    493   if (!disp_parent)
    494     return E_INVALIDARG;
    495 
    496   IAccessible* parent_obj = GetParent()->ToBrowserAccessibilityWin();
    497   if (parent_obj == NULL) {
    498     // This happens if we're the root of the tree;
    499     // return the IAccessible for the window.
    500     parent_obj =
    501          manager()->ToBrowserAccessibilityManagerWin()->parent_iaccessible();
    502     // |parent| can only be NULL if the manager was created before the parent
    503     // IAccessible was known and it wasn't subsequently set before a client
    504     // requested it. This has been fixed. |parent| may also be NULL during
    505     // destruction. Possible cases where this could occur include tabs being
    506     // dragged to a new window, etc.
    507     if (!parent_obj) {
    508       DVLOG(1) <<  "In Function: "
    509                << __FUNCTION__
    510                << ". Parent IAccessible interface is NULL. Returning failure";
    511       return E_FAIL;
    512     }
    513   }
    514   parent_obj->AddRef();
    515   *disp_parent = parent_obj;
    516   return S_OK;
    517 }
    518 
    519 STDMETHODIMP BrowserAccessibilityWin::get_accRole(VARIANT var_id,
    520                                                   VARIANT* role) {
    521   if (!instance_active())
    522     return E_FAIL;
    523 
    524   if (!role)
    525     return E_INVALIDARG;
    526 
    527   BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
    528   if (!target)
    529     return E_INVALIDARG;
    530 
    531   if (!target->role_name_.empty()) {
    532     role->vt = VT_BSTR;
    533     role->bstrVal = SysAllocString(target->role_name_.c_str());
    534   } else {
    535     role->vt = VT_I4;
    536     role->lVal = target->ia_role_;
    537   }
    538   return S_OK;
    539 }
    540 
    541 STDMETHODIMP BrowserAccessibilityWin::get_accState(VARIANT var_id,
    542                                                    VARIANT* state) {
    543   if (!instance_active())
    544     return E_FAIL;
    545 
    546   if (!state)
    547     return E_INVALIDARG;
    548 
    549   BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
    550   if (!target)
    551     return E_INVALIDARG;
    552 
    553   state->vt = VT_I4;
    554   state->lVal = target->ia_state_;
    555   if (manager()->GetFocus(NULL) == this)
    556     state->lVal |= STATE_SYSTEM_FOCUSED;
    557 
    558   return S_OK;
    559 }
    560 
    561 STDMETHODIMP BrowserAccessibilityWin::get_accValue(VARIANT var_id,
    562                                                    BSTR* value) {
    563   if (!instance_active())
    564     return E_FAIL;
    565 
    566   if (!value)
    567     return E_INVALIDARG;
    568 
    569   BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
    570   if (!target)
    571     return E_INVALIDARG;
    572 
    573   if (target->ia_role() == ROLE_SYSTEM_PROGRESSBAR ||
    574       target->ia_role() == ROLE_SYSTEM_SCROLLBAR ||
    575       target->ia_role() == ROLE_SYSTEM_SLIDER) {
    576     base::string16 value_text = target->GetValueText();
    577     *value = SysAllocString(value_text.c_str());
    578     DCHECK(*value);
    579     return S_OK;
    580   }
    581 
    582   // Expose color well value.
    583   if (target->ia2_role() == IA2_ROLE_COLOR_CHOOSER) {
    584     int r = target->GetIntAttribute(
    585         ui::AX_ATTR_COLOR_VALUE_RED);
    586     int g = target->GetIntAttribute(
    587         ui::AX_ATTR_COLOR_VALUE_GREEN);
    588     int b = target->GetIntAttribute(
    589         ui::AX_ATTR_COLOR_VALUE_BLUE);
    590     base::string16 value_text;
    591     value_text = base::IntToString16((r * 100) / 255) + L"% red " +
    592                  base::IntToString16((g * 100) / 255) + L"% green " +
    593                  base::IntToString16((b * 100) / 255) + L"% blue";
    594     *value = SysAllocString(value_text.c_str());
    595     DCHECK(*value);
    596     return S_OK;
    597   }
    598 
    599   *value = SysAllocString(base::UTF8ToUTF16(target->value()).c_str());
    600   DCHECK(*value);
    601   return S_OK;
    602 }
    603 
    604 STDMETHODIMP BrowserAccessibilityWin::get_accHelpTopic(BSTR* help_file,
    605                                                        VARIANT var_id,
    606                                                        LONG* topic_id) {
    607   return E_NOTIMPL;
    608 }
    609 
    610 STDMETHODIMP BrowserAccessibilityWin::get_accSelection(VARIANT* selected) {
    611   if (!instance_active())
    612     return E_FAIL;
    613 
    614   if (GetRole() != ui::AX_ROLE_LIST_BOX)
    615     return E_NOTIMPL;
    616 
    617   unsigned long selected_count = 0;
    618   for (size_t i = 0; i < InternalChildCount(); ++i) {
    619     if (InternalGetChild(i)->HasState(ui::AX_STATE_SELECTED))
    620       ++selected_count;
    621   }
    622 
    623   if (selected_count == 0) {
    624     selected->vt = VT_EMPTY;
    625     return S_OK;
    626   }
    627 
    628   if (selected_count == 1) {
    629     for (size_t i = 0; i < InternalChildCount(); ++i) {
    630       if (InternalGetChild(i)->HasState(ui::AX_STATE_SELECTED)) {
    631         selected->vt = VT_DISPATCH;
    632         selected->pdispVal =
    633             InternalGetChild(i)->ToBrowserAccessibilityWin()->NewReference();
    634         return S_OK;
    635       }
    636     }
    637   }
    638 
    639   // Multiple items are selected.
    640   base::win::EnumVariant* enum_variant =
    641       new base::win::EnumVariant(selected_count);
    642   enum_variant->AddRef();
    643   unsigned long index = 0;
    644   for (size_t i = 0; i < InternalChildCount(); ++i) {
    645     if (InternalGetChild(i)->HasState(ui::AX_STATE_SELECTED)) {
    646       enum_variant->ItemAt(index)->vt = VT_DISPATCH;
    647       enum_variant->ItemAt(index)->pdispVal =
    648         InternalGetChild(i)->ToBrowserAccessibilityWin()->NewReference();
    649       ++index;
    650     }
    651   }
    652   selected->vt = VT_UNKNOWN;
    653   selected->punkVal = static_cast<IUnknown*>(
    654       static_cast<base::win::IUnknownImpl*>(enum_variant));
    655   return S_OK;
    656 }
    657 
    658 STDMETHODIMP BrowserAccessibilityWin::accSelect(
    659     LONG flags_sel, VARIANT var_id) {
    660   if (!instance_active())
    661     return E_FAIL;
    662 
    663   if (flags_sel & SELFLAG_TAKEFOCUS) {
    664     manager()->SetFocus(this, true);
    665     return S_OK;
    666   }
    667 
    668   return S_FALSE;
    669 }
    670 
    671 //
    672 // IAccessible2 methods.
    673 //
    674 
    675 STDMETHODIMP BrowserAccessibilityWin::role(LONG* role) {
    676   if (!instance_active())
    677     return E_FAIL;
    678 
    679   if (!role)
    680     return E_INVALIDARG;
    681 
    682   *role = ia2_role_;
    683 
    684   return S_OK;
    685 }
    686 
    687 STDMETHODIMP BrowserAccessibilityWin::get_attributes(BSTR* attributes) {
    688   if (!instance_active())
    689     return E_FAIL;
    690 
    691   if (!attributes)
    692     return E_INVALIDARG;
    693 
    694   // The iaccessible2 attributes are a set of key-value pairs
    695   // separated by semicolons, with a colon between the key and the value.
    696   base::string16 str;
    697   for (unsigned int i = 0; i < ia2_attributes_.size(); ++i) {
    698     if (i != 0)
    699       str += L';';
    700     str += ia2_attributes_[i];
    701   }
    702 
    703   if (str.empty())
    704     return S_FALSE;
    705 
    706   *attributes = SysAllocString(str.c_str());
    707   DCHECK(*attributes);
    708   return S_OK;
    709 }
    710 
    711 STDMETHODIMP BrowserAccessibilityWin::get_states(AccessibleStates* states) {
    712   if (!instance_active())
    713     return E_FAIL;
    714 
    715   if (!states)
    716     return E_INVALIDARG;
    717 
    718   *states = ia2_state_;
    719 
    720   return S_OK;
    721 }
    722 
    723 STDMETHODIMP BrowserAccessibilityWin::get_uniqueID(LONG* unique_id) {
    724   if (!instance_active())
    725     return E_FAIL;
    726 
    727   if (!unique_id)
    728     return E_INVALIDARG;
    729 
    730   *unique_id = unique_id_win_;
    731   return S_OK;
    732 }
    733 
    734 STDMETHODIMP BrowserAccessibilityWin::get_windowHandle(HWND* window_handle) {
    735   if (!instance_active())
    736     return E_FAIL;
    737 
    738   if (!window_handle)
    739     return E_INVALIDARG;
    740 
    741   *window_handle = manager()->ToBrowserAccessibilityManagerWin()->parent_hwnd();
    742   if (!*window_handle)
    743     return E_FAIL;
    744 
    745   return S_OK;
    746 }
    747 
    748 STDMETHODIMP BrowserAccessibilityWin::get_indexInParent(LONG* index_in_parent) {
    749   if (!instance_active())
    750     return E_FAIL;
    751 
    752   if (!index_in_parent)
    753     return E_INVALIDARG;
    754 
    755   *index_in_parent = this->GetIndexInParent();
    756   return S_OK;
    757 }
    758 
    759 STDMETHODIMP BrowserAccessibilityWin::get_nRelations(LONG* n_relations) {
    760   if (!instance_active())
    761     return E_FAIL;
    762 
    763   if (!n_relations)
    764     return E_INVALIDARG;
    765 
    766   *n_relations = relations_.size();
    767   return S_OK;
    768 }
    769 
    770 STDMETHODIMP BrowserAccessibilityWin::get_relation(
    771     LONG relation_index,
    772     IAccessibleRelation** relation) {
    773   if (!instance_active())
    774     return E_FAIL;
    775 
    776   if (relation_index < 0 ||
    777       relation_index >= static_cast<long>(relations_.size())) {
    778     return E_INVALIDARG;
    779   }
    780 
    781   if (!relation)
    782     return E_INVALIDARG;
    783 
    784   relations_[relation_index]->AddRef();
    785   *relation = relations_[relation_index];
    786   return S_OK;
    787 }
    788 
    789 STDMETHODIMP BrowserAccessibilityWin::get_relations(
    790     LONG max_relations,
    791     IAccessibleRelation** relations,
    792     LONG* n_relations) {
    793   if (!instance_active())
    794     return E_FAIL;
    795 
    796   if (!relations || !n_relations)
    797     return E_INVALIDARG;
    798 
    799   long count = static_cast<long>(relations_.size());
    800   *n_relations = count;
    801   if (count == 0)
    802     return S_FALSE;
    803 
    804   for (long i = 0; i < count; ++i) {
    805     relations_[i]->AddRef();
    806     relations[i] = relations_[i];
    807   }
    808 
    809   return S_OK;
    810 }
    811 
    812 STDMETHODIMP BrowserAccessibilityWin::scrollTo(enum IA2ScrollType scroll_type) {
    813   if (!instance_active())
    814     return E_FAIL;
    815 
    816   gfx::Rect r = GetLocation();
    817   switch(scroll_type) {
    818     case IA2_SCROLL_TYPE_TOP_LEFT:
    819       manager()->ScrollToMakeVisible(*this, gfx::Rect(r.x(), r.y(), 0, 0));
    820       break;
    821     case IA2_SCROLL_TYPE_BOTTOM_RIGHT:
    822       manager()->ScrollToMakeVisible(
    823           *this, gfx::Rect(r.right(), r.bottom(), 0, 0));
    824       break;
    825     case IA2_SCROLL_TYPE_TOP_EDGE:
    826       manager()->ScrollToMakeVisible(
    827           *this, gfx::Rect(r.x(), r.y(), r.width(), 0));
    828       break;
    829     case IA2_SCROLL_TYPE_BOTTOM_EDGE:
    830       manager()->ScrollToMakeVisible(
    831           *this, gfx::Rect(r.x(), r.bottom(), r.width(), 0));
    832     break;
    833     case IA2_SCROLL_TYPE_LEFT_EDGE:
    834       manager()->ScrollToMakeVisible(
    835           *this, gfx::Rect(r.x(), r.y(), 0, r.height()));
    836       break;
    837     case IA2_SCROLL_TYPE_RIGHT_EDGE:
    838       manager()->ScrollToMakeVisible(
    839           *this, gfx::Rect(r.right(), r.y(), 0, r.height()));
    840       break;
    841     case IA2_SCROLL_TYPE_ANYWHERE:
    842     default:
    843       manager()->ScrollToMakeVisible(*this, r);
    844       break;
    845   }
    846 
    847   manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
    848 
    849   return S_OK;
    850 }
    851 
    852 STDMETHODIMP BrowserAccessibilityWin::scrollToPoint(
    853     enum IA2CoordinateType coordinate_type,
    854     LONG x,
    855     LONG y) {
    856   if (!instance_active())
    857     return E_FAIL;
    858 
    859   gfx::Point scroll_to(x, y);
    860 
    861   if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) {
    862     scroll_to -= manager()->GetViewBounds().OffsetFromOrigin();
    863   } else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) {
    864     if (GetParent())
    865       scroll_to += GetParent()->GetLocation().OffsetFromOrigin();
    866   } else {
    867     return E_INVALIDARG;
    868   }
    869 
    870   manager()->ScrollToPoint(*this, scroll_to);
    871   manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
    872 
    873   return S_OK;
    874 }
    875 
    876 STDMETHODIMP BrowserAccessibilityWin::get_groupPosition(
    877     LONG* group_level,
    878     LONG* similar_items_in_group,
    879     LONG* position_in_group) {
    880   if (!instance_active())
    881     return E_FAIL;
    882 
    883   if (!group_level || !similar_items_in_group || !position_in_group)
    884     return E_INVALIDARG;
    885 
    886   if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION &&
    887       GetParent() &&
    888       GetParent()->GetRole() == ui::AX_ROLE_LIST_BOX) {
    889     *group_level = 0;
    890     *similar_items_in_group = GetParent()->PlatformChildCount();
    891     *position_in_group = GetIndexInParent() + 1;
    892     return S_OK;
    893   }
    894 
    895   return E_NOTIMPL;
    896 }
    897 
    898 //
    899 // IAccessibleApplication methods.
    900 //
    901 
    902 STDMETHODIMP BrowserAccessibilityWin::get_appName(BSTR* app_name) {
    903   // No need to check |instance_active()| because this interface is
    904   // global, and doesn't depend on any local state.
    905 
    906   if (!app_name)
    907     return E_INVALIDARG;
    908 
    909   // GetProduct() returns a string like "Chrome/aa.bb.cc.dd", split out
    910   // the part before the "/".
    911   std::vector<std::string> product_components;
    912   base::SplitString(GetContentClient()->GetProduct(), '/', &product_components);
    913   DCHECK_EQ(2U, product_components.size());
    914   if (product_components.size() != 2)
    915     return E_FAIL;
    916   *app_name = SysAllocString(base::UTF8ToUTF16(product_components[0]).c_str());
    917   DCHECK(*app_name);
    918   return *app_name ? S_OK : E_FAIL;
    919 }
    920 
    921 STDMETHODIMP BrowserAccessibilityWin::get_appVersion(BSTR* app_version) {
    922   // No need to check |instance_active()| because this interface is
    923   // global, and doesn't depend on any local state.
    924 
    925   if (!app_version)
    926     return E_INVALIDARG;
    927 
    928   // GetProduct() returns a string like "Chrome/aa.bb.cc.dd", split out
    929   // the part after the "/".
    930   std::vector<std::string> product_components;
    931   base::SplitString(GetContentClient()->GetProduct(), '/', &product_components);
    932   DCHECK_EQ(2U, product_components.size());
    933   if (product_components.size() != 2)
    934     return E_FAIL;
    935   *app_version =
    936       SysAllocString(base::UTF8ToUTF16(product_components[1]).c_str());
    937   DCHECK(*app_version);
    938   return *app_version ? S_OK : E_FAIL;
    939 }
    940 
    941 STDMETHODIMP BrowserAccessibilityWin::get_toolkitName(BSTR* toolkit_name) {
    942   // No need to check |instance_active()| because this interface is
    943   // global, and doesn't depend on any local state.
    944 
    945   if (!toolkit_name)
    946     return E_INVALIDARG;
    947 
    948   // This is hard-coded; all products based on the Chromium engine
    949   // will have the same toolkit name, so that assistive technology can
    950   // detect any Chrome-based product.
    951   *toolkit_name = SysAllocString(L"Chrome");
    952   DCHECK(*toolkit_name);
    953   return *toolkit_name ? S_OK : E_FAIL;
    954 }
    955 
    956 STDMETHODIMP BrowserAccessibilityWin::get_toolkitVersion(
    957     BSTR* toolkit_version) {
    958   // No need to check |instance_active()| because this interface is
    959   // global, and doesn't depend on any local state.
    960 
    961   if (!toolkit_version)
    962     return E_INVALIDARG;
    963 
    964   std::string user_agent = GetContentClient()->GetUserAgent();
    965   *toolkit_version = SysAllocString(base::UTF8ToUTF16(user_agent).c_str());
    966   DCHECK(*toolkit_version);
    967   return *toolkit_version ? S_OK : E_FAIL;
    968 }
    969 
    970 //
    971 // IAccessibleImage methods.
    972 //
    973 
    974 STDMETHODIMP BrowserAccessibilityWin::get_description(BSTR* desc) {
    975   if (!instance_active())
    976     return E_FAIL;
    977 
    978   if (!desc)
    979     return E_INVALIDARG;
    980 
    981   return GetStringAttributeAsBstr(
    982       ui::AX_ATTR_DESCRIPTION, desc);
    983 }
    984 
    985 STDMETHODIMP BrowserAccessibilityWin::get_imagePosition(
    986     enum IA2CoordinateType coordinate_type,
    987     LONG* x,
    988     LONG* y) {
    989   if (!instance_active())
    990     return E_FAIL;
    991 
    992   if (!x || !y)
    993     return E_INVALIDARG;
    994 
    995   if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) {
    996     HWND parent_hwnd =
    997         manager()->ToBrowserAccessibilityManagerWin()->parent_hwnd();
    998     if (!parent_hwnd)
    999       return E_FAIL;
   1000     POINT top_left = {0, 0};
   1001     ::ClientToScreen(parent_hwnd, &top_left);
   1002     *x = GetLocation().x() + top_left.x;
   1003     *y = GetLocation().y() + top_left.y;
   1004   } else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) {
   1005     *x = GetLocation().x();
   1006     *y = GetLocation().y();
   1007     if (GetParent()) {
   1008       *x -= GetParent()->GetLocation().x();
   1009       *y -= GetParent()->GetLocation().y();
   1010     }
   1011   } else {
   1012     return E_INVALIDARG;
   1013   }
   1014 
   1015   return S_OK;
   1016 }
   1017 
   1018 STDMETHODIMP BrowserAccessibilityWin::get_imageSize(LONG* height, LONG* width) {
   1019   if (!instance_active())
   1020     return E_FAIL;
   1021 
   1022   if (!height || !width)
   1023     return E_INVALIDARG;
   1024 
   1025   *height = GetLocation().height();
   1026   *width = GetLocation().width();
   1027   return S_OK;
   1028 }
   1029 
   1030 //
   1031 // IAccessibleTable methods.
   1032 //
   1033 
   1034 STDMETHODIMP BrowserAccessibilityWin::get_accessibleAt(
   1035     long row,
   1036     long column,
   1037     IUnknown** accessible) {
   1038   if (!instance_active())
   1039     return E_FAIL;
   1040 
   1041   if (!accessible)
   1042     return E_INVALIDARG;
   1043 
   1044   int columns;
   1045   int rows;
   1046   if (!GetIntAttribute(
   1047           ui::AX_ATTR_TABLE_COLUMN_COUNT, &columns) ||
   1048       !GetIntAttribute(
   1049           ui::AX_ATTR_TABLE_ROW_COUNT, &rows) ||
   1050       columns <= 0 ||
   1051       rows <= 0) {
   1052     return S_FALSE;
   1053   }
   1054 
   1055   if (row < 0 || row >= rows || column < 0 || column >= columns)
   1056     return E_INVALIDARG;
   1057 
   1058   const std::vector<int32>& cell_ids = GetIntListAttribute(
   1059       ui::AX_ATTR_CELL_IDS);
   1060   DCHECK_EQ(columns * rows, static_cast<int>(cell_ids.size()));
   1061 
   1062   int cell_id = cell_ids[row * columns + column];
   1063   BrowserAccessibilityWin* cell = GetFromID(cell_id);
   1064   if (cell) {
   1065     *accessible = static_cast<IAccessible*>(cell->NewReference());
   1066     return S_OK;
   1067   }
   1068 
   1069   *accessible = NULL;
   1070   return E_INVALIDARG;
   1071 }
   1072 
   1073 STDMETHODIMP BrowserAccessibilityWin::get_caption(IUnknown** accessible) {
   1074   if (!instance_active())
   1075     return E_FAIL;
   1076 
   1077   if (!accessible)
   1078     return E_INVALIDARG;
   1079 
   1080   // TODO(dmazzoni): implement
   1081   return S_FALSE;
   1082 }
   1083 
   1084 STDMETHODIMP BrowserAccessibilityWin::get_childIndex(long row,
   1085                                                      long column,
   1086                                                      long* cell_index) {
   1087   if (!instance_active())
   1088     return E_FAIL;
   1089 
   1090   if (!cell_index)
   1091     return E_INVALIDARG;
   1092 
   1093   int columns;
   1094   int rows;
   1095   if (!GetIntAttribute(
   1096           ui::AX_ATTR_TABLE_COLUMN_COUNT, &columns) ||
   1097       !GetIntAttribute(
   1098           ui::AX_ATTR_TABLE_ROW_COUNT, &rows) ||
   1099       columns <= 0 ||
   1100       rows <= 0) {
   1101     return S_FALSE;
   1102   }
   1103 
   1104   if (row < 0 || row >= rows || column < 0 || column >= columns)
   1105     return E_INVALIDARG;
   1106 
   1107   const std::vector<int32>& cell_ids = GetIntListAttribute(
   1108       ui::AX_ATTR_CELL_IDS);
   1109   const std::vector<int32>& unique_cell_ids = GetIntListAttribute(
   1110       ui::AX_ATTR_UNIQUE_CELL_IDS);
   1111   DCHECK_EQ(columns * rows, static_cast<int>(cell_ids.size()));
   1112   int cell_id = cell_ids[row * columns + column];
   1113   for (size_t i = 0; i < unique_cell_ids.size(); ++i) {
   1114     if (unique_cell_ids[i] == cell_id) {
   1115       *cell_index = (long)i;
   1116       return S_OK;
   1117     }
   1118   }
   1119 
   1120   return S_FALSE;
   1121 }
   1122 
   1123 STDMETHODIMP BrowserAccessibilityWin::get_columnDescription(long column,
   1124                                                             BSTR* description) {
   1125   if (!instance_active())
   1126     return E_FAIL;
   1127 
   1128   if (!description)
   1129     return E_INVALIDARG;
   1130 
   1131   int columns;
   1132   int rows;
   1133   if (!GetIntAttribute(
   1134           ui::AX_ATTR_TABLE_COLUMN_COUNT, &columns) ||
   1135       !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT, &rows) ||
   1136       columns <= 0 ||
   1137       rows <= 0) {
   1138     return S_FALSE;
   1139   }
   1140 
   1141   if (column < 0 || column >= columns)
   1142     return E_INVALIDARG;
   1143 
   1144   const std::vector<int32>& cell_ids = GetIntListAttribute(
   1145       ui::AX_ATTR_CELL_IDS);
   1146   for (int i = 0; i < rows; ++i) {
   1147     int cell_id = cell_ids[i * columns + column];
   1148     BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>(
   1149         manager()->GetFromID(cell_id));
   1150     if (cell && cell->GetRole() == ui::AX_ROLE_COLUMN_HEADER) {
   1151       base::string16 cell_name = cell->GetString16Attribute(
   1152           ui::AX_ATTR_NAME);
   1153       if (cell_name.size() > 0) {
   1154         *description = SysAllocString(cell_name.c_str());
   1155         return S_OK;
   1156       }
   1157 
   1158       return cell->GetStringAttributeAsBstr(
   1159           ui::AX_ATTR_DESCRIPTION, description);
   1160     }
   1161   }
   1162 
   1163   return S_FALSE;
   1164 }
   1165 
   1166 STDMETHODIMP BrowserAccessibilityWin::get_columnExtentAt(
   1167     long row,
   1168     long column,
   1169     long* n_columns_spanned) {
   1170   if (!instance_active())
   1171     return E_FAIL;
   1172 
   1173   if (!n_columns_spanned)
   1174     return E_INVALIDARG;
   1175 
   1176   int columns;
   1177   int rows;
   1178   if (!GetIntAttribute(
   1179           ui::AX_ATTR_TABLE_COLUMN_COUNT, &columns) ||
   1180       !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT, &rows) ||
   1181       columns <= 0 ||
   1182       rows <= 0) {
   1183     return S_FALSE;
   1184   }
   1185 
   1186   if (row < 0 || row >= rows || column < 0 || column >= columns)
   1187     return E_INVALIDARG;
   1188 
   1189   const std::vector<int32>& cell_ids = GetIntListAttribute(
   1190       ui::AX_ATTR_CELL_IDS);
   1191   int cell_id = cell_ids[row * columns + column];
   1192   BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>(
   1193       manager()->GetFromID(cell_id));
   1194   int colspan;
   1195   if (cell &&
   1196       cell->GetIntAttribute(
   1197           ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN, &colspan) &&
   1198       colspan >= 1) {
   1199     *n_columns_spanned = colspan;
   1200     return S_OK;
   1201   }
   1202 
   1203   return S_FALSE;
   1204 }
   1205 
   1206 STDMETHODIMP BrowserAccessibilityWin::get_columnHeader(
   1207     IAccessibleTable** accessible_table,
   1208     long* starting_row_index) {
   1209   // TODO(dmazzoni): implement
   1210   return E_NOTIMPL;
   1211 }
   1212 
   1213 STDMETHODIMP BrowserAccessibilityWin::get_columnIndex(long cell_index,
   1214                                                       long* column_index) {
   1215   if (!instance_active())
   1216     return E_FAIL;
   1217 
   1218   if (!column_index)
   1219     return E_INVALIDARG;
   1220 
   1221   const std::vector<int32>& unique_cell_ids = GetIntListAttribute(
   1222       ui::AX_ATTR_UNIQUE_CELL_IDS);
   1223   int cell_id_count = static_cast<int>(unique_cell_ids.size());
   1224   if (cell_index < 0)
   1225     return E_INVALIDARG;
   1226   if (cell_index >= cell_id_count)
   1227     return S_FALSE;
   1228 
   1229   int cell_id = unique_cell_ids[cell_index];
   1230   BrowserAccessibilityWin* cell =
   1231       manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
   1232   int col_index;
   1233   if (cell &&
   1234       cell->GetIntAttribute(
   1235           ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX, &col_index)) {
   1236     *column_index = col_index;
   1237     return S_OK;
   1238   }
   1239 
   1240   return S_FALSE;
   1241 }
   1242 
   1243 STDMETHODIMP BrowserAccessibilityWin::get_nColumns(long* column_count) {
   1244   if (!instance_active())
   1245     return E_FAIL;
   1246 
   1247   if (!column_count)
   1248     return E_INVALIDARG;
   1249 
   1250   int columns;
   1251   if (GetIntAttribute(
   1252           ui::AX_ATTR_TABLE_COLUMN_COUNT, &columns)) {
   1253     *column_count = columns;
   1254     return S_OK;
   1255   }
   1256 
   1257   return S_FALSE;
   1258 }
   1259 
   1260 STDMETHODIMP BrowserAccessibilityWin::get_nRows(long* row_count) {
   1261   if (!instance_active())
   1262     return E_FAIL;
   1263 
   1264   if (!row_count)
   1265     return E_INVALIDARG;
   1266 
   1267   int rows;
   1268   if (GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT, &rows)) {
   1269     *row_count = rows;
   1270     return S_OK;
   1271   }
   1272 
   1273   return S_FALSE;
   1274 }
   1275 
   1276 STDMETHODIMP BrowserAccessibilityWin::get_nSelectedChildren(long* cell_count) {
   1277   if (!instance_active())
   1278     return E_FAIL;
   1279 
   1280   if (!cell_count)
   1281     return E_INVALIDARG;
   1282 
   1283   // TODO(dmazzoni): add support for selected cells/rows/columns in tables.
   1284   *cell_count = 0;
   1285   return S_OK;
   1286 }
   1287 
   1288 STDMETHODIMP BrowserAccessibilityWin::get_nSelectedColumns(long* column_count) {
   1289   if (!instance_active())
   1290     return E_FAIL;
   1291 
   1292   if (!column_count)
   1293     return E_INVALIDARG;
   1294 
   1295   *column_count = 0;
   1296   return S_OK;
   1297 }
   1298 
   1299 STDMETHODIMP BrowserAccessibilityWin::get_nSelectedRows(long* row_count) {
   1300   if (!instance_active())
   1301     return E_FAIL;
   1302 
   1303   if (!row_count)
   1304     return E_INVALIDARG;
   1305 
   1306   *row_count = 0;
   1307   return S_OK;
   1308 }
   1309 
   1310 STDMETHODIMP BrowserAccessibilityWin::get_rowDescription(long row,
   1311                                                          BSTR* description) {
   1312   if (!instance_active())
   1313     return E_FAIL;
   1314 
   1315   if (!description)
   1316     return E_INVALIDARG;
   1317 
   1318   int columns;
   1319   int rows;
   1320   if (!GetIntAttribute(
   1321           ui::AX_ATTR_TABLE_COLUMN_COUNT, &columns) ||
   1322       !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT, &rows) ||
   1323       columns <= 0 ||
   1324       rows <= 0) {
   1325     return S_FALSE;
   1326   }
   1327 
   1328   if (row < 0 || row >= rows)
   1329     return E_INVALIDARG;
   1330 
   1331   const std::vector<int32>& cell_ids = GetIntListAttribute(
   1332       ui::AX_ATTR_CELL_IDS);
   1333   for (int i = 0; i < columns; ++i) {
   1334     int cell_id = cell_ids[row * columns + i];
   1335     BrowserAccessibilityWin* cell =
   1336         manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
   1337     if (cell && cell->GetRole() == ui::AX_ROLE_ROW_HEADER) {
   1338       base::string16 cell_name = cell->GetString16Attribute(
   1339           ui::AX_ATTR_NAME);
   1340       if (cell_name.size() > 0) {
   1341         *description = SysAllocString(cell_name.c_str());
   1342         return S_OK;
   1343       }
   1344 
   1345       return cell->GetStringAttributeAsBstr(
   1346           ui::AX_ATTR_DESCRIPTION, description);
   1347     }
   1348   }
   1349 
   1350   return S_FALSE;
   1351 }
   1352 
   1353 STDMETHODIMP BrowserAccessibilityWin::get_rowExtentAt(long row,
   1354                                                       long column,
   1355                                                       long* n_rows_spanned) {
   1356   if (!instance_active())
   1357     return E_FAIL;
   1358 
   1359   if (!n_rows_spanned)
   1360     return E_INVALIDARG;
   1361 
   1362   int columns;
   1363   int rows;
   1364   if (!GetIntAttribute(
   1365           ui::AX_ATTR_TABLE_COLUMN_COUNT, &columns) ||
   1366       !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT, &rows) ||
   1367       columns <= 0 ||
   1368       rows <= 0) {
   1369     return S_FALSE;
   1370   }
   1371 
   1372   if (row < 0 || row >= rows || column < 0 || column >= columns)
   1373     return E_INVALIDARG;
   1374 
   1375   const std::vector<int32>& cell_ids = GetIntListAttribute(
   1376       ui::AX_ATTR_CELL_IDS);
   1377   int cell_id = cell_ids[row * columns + column];
   1378   BrowserAccessibilityWin* cell =
   1379       manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
   1380   int rowspan;
   1381   if (cell &&
   1382       cell->GetIntAttribute(
   1383           ui::AX_ATTR_TABLE_CELL_ROW_SPAN, &rowspan) &&
   1384       rowspan >= 1) {
   1385     *n_rows_spanned = rowspan;
   1386     return S_OK;
   1387   }
   1388 
   1389   return S_FALSE;
   1390 }
   1391 
   1392 STDMETHODIMP BrowserAccessibilityWin::get_rowHeader(
   1393     IAccessibleTable** accessible_table,
   1394     long* starting_column_index) {
   1395   // TODO(dmazzoni): implement
   1396   return E_NOTIMPL;
   1397 }
   1398 
   1399 STDMETHODIMP BrowserAccessibilityWin::get_rowIndex(long cell_index,
   1400                                                    long* row_index) {
   1401   if (!instance_active())
   1402     return E_FAIL;
   1403 
   1404   if (!row_index)
   1405     return E_INVALIDARG;
   1406 
   1407   const std::vector<int32>& unique_cell_ids = GetIntListAttribute(
   1408       ui::AX_ATTR_UNIQUE_CELL_IDS);
   1409   int cell_id_count = static_cast<int>(unique_cell_ids.size());
   1410   if (cell_index < 0)
   1411     return E_INVALIDARG;
   1412   if (cell_index >= cell_id_count)
   1413     return S_FALSE;
   1414 
   1415   int cell_id = unique_cell_ids[cell_index];
   1416   BrowserAccessibilityWin* cell =
   1417       manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
   1418   int cell_row_index;
   1419   if (cell &&
   1420       cell->GetIntAttribute(
   1421           ui::AX_ATTR_TABLE_CELL_ROW_INDEX, &cell_row_index)) {
   1422     *row_index = cell_row_index;
   1423     return S_OK;
   1424   }
   1425 
   1426   return S_FALSE;
   1427 }
   1428 
   1429 STDMETHODIMP BrowserAccessibilityWin::get_selectedChildren(long max_children,
   1430                                                            long** children,
   1431                                                            long* n_children) {
   1432   if (!instance_active())
   1433     return E_FAIL;
   1434 
   1435   if (!children || !n_children)
   1436     return E_INVALIDARG;
   1437 
   1438   // TODO(dmazzoni): Implement this.
   1439   *n_children = 0;
   1440   return S_OK;
   1441 }
   1442 
   1443 STDMETHODIMP BrowserAccessibilityWin::get_selectedColumns(long max_columns,
   1444                                                           long** columns,
   1445                                                           long* n_columns) {
   1446   if (!instance_active())
   1447     return E_FAIL;
   1448 
   1449   if (!columns || !n_columns)
   1450     return E_INVALIDARG;
   1451 
   1452   // TODO(dmazzoni): Implement this.
   1453   *n_columns = 0;
   1454   return S_OK;
   1455 }
   1456 
   1457 STDMETHODIMP BrowserAccessibilityWin::get_selectedRows(long max_rows,
   1458                                                        long** rows,
   1459                                                        long* n_rows) {
   1460   if (!instance_active())
   1461     return E_FAIL;
   1462 
   1463   if (!rows || !n_rows)
   1464     return E_INVALIDARG;
   1465 
   1466   // TODO(dmazzoni): Implement this.
   1467   *n_rows = 0;
   1468   return S_OK;
   1469 }
   1470 
   1471 STDMETHODIMP BrowserAccessibilityWin::get_summary(IUnknown** accessible) {
   1472   if (!instance_active())
   1473     return E_FAIL;
   1474 
   1475   if (!accessible)
   1476     return E_INVALIDARG;
   1477 
   1478   // TODO(dmazzoni): implement
   1479   return S_FALSE;
   1480 }
   1481 
   1482 STDMETHODIMP BrowserAccessibilityWin::get_isColumnSelected(
   1483     long column,
   1484     boolean* is_selected) {
   1485   if (!instance_active())
   1486     return E_FAIL;
   1487 
   1488   if (!is_selected)
   1489     return E_INVALIDARG;
   1490 
   1491   // TODO(dmazzoni): Implement this.
   1492   *is_selected = false;
   1493   return S_OK;
   1494 }
   1495 
   1496 STDMETHODIMP BrowserAccessibilityWin::get_isRowSelected(long row,
   1497                                                         boolean* is_selected) {
   1498   if (!instance_active())
   1499     return E_FAIL;
   1500 
   1501   if (!is_selected)
   1502     return E_INVALIDARG;
   1503 
   1504   // TODO(dmazzoni): Implement this.
   1505   *is_selected = false;
   1506   return S_OK;
   1507 }
   1508 
   1509 STDMETHODIMP BrowserAccessibilityWin::get_isSelected(long row,
   1510                                                      long column,
   1511                                                      boolean* is_selected) {
   1512   if (!instance_active())
   1513     return E_FAIL;
   1514 
   1515   if (!is_selected)
   1516     return E_INVALIDARG;
   1517 
   1518   // TODO(dmazzoni): Implement this.
   1519   *is_selected = false;
   1520   return S_OK;
   1521 }
   1522 
   1523 STDMETHODIMP BrowserAccessibilityWin::get_rowColumnExtentsAtIndex(
   1524     long index,
   1525     long* row,
   1526     long* column,
   1527     long* row_extents,
   1528     long* column_extents,
   1529     boolean* is_selected) {
   1530   if (!instance_active())
   1531     return E_FAIL;
   1532 
   1533   if (!row || !column || !row_extents || !column_extents || !is_selected)
   1534     return E_INVALIDARG;
   1535 
   1536   const std::vector<int32>& unique_cell_ids = GetIntListAttribute(
   1537       ui::AX_ATTR_UNIQUE_CELL_IDS);
   1538   int cell_id_count = static_cast<int>(unique_cell_ids.size());
   1539   if (index < 0)
   1540     return E_INVALIDARG;
   1541   if (index >= cell_id_count)
   1542     return S_FALSE;
   1543 
   1544   int cell_id = unique_cell_ids[index];
   1545   BrowserAccessibilityWin* cell =
   1546       manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
   1547   int rowspan;
   1548   int colspan;
   1549   if (cell &&
   1550       cell->GetIntAttribute(
   1551           ui::AX_ATTR_TABLE_CELL_ROW_SPAN, &rowspan) &&
   1552       cell->GetIntAttribute(
   1553           ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN, &colspan) &&
   1554       rowspan >= 1 &&
   1555       colspan >= 1) {
   1556     *row_extents = rowspan;
   1557     *column_extents = colspan;
   1558     return S_OK;
   1559   }
   1560 
   1561   return S_FALSE;
   1562 }
   1563 
   1564 //
   1565 // IAccessibleTable2 methods.
   1566 //
   1567 
   1568 STDMETHODIMP BrowserAccessibilityWin::get_cellAt(long row,
   1569                                                  long column,
   1570                                                  IUnknown** cell) {
   1571   return get_accessibleAt(row, column, cell);
   1572 }
   1573 
   1574 STDMETHODIMP BrowserAccessibilityWin::get_nSelectedCells(long* cell_count) {
   1575   return get_nSelectedChildren(cell_count);
   1576 }
   1577 
   1578 STDMETHODIMP BrowserAccessibilityWin::get_selectedCells(
   1579     IUnknown*** cells,
   1580     long* n_selected_cells) {
   1581   if (!instance_active())
   1582     return E_FAIL;
   1583 
   1584   if (!cells || !n_selected_cells)
   1585     return E_INVALIDARG;
   1586 
   1587   // TODO(dmazzoni): Implement this.
   1588   *n_selected_cells = 0;
   1589   return S_OK;
   1590 }
   1591 
   1592 STDMETHODIMP BrowserAccessibilityWin::get_selectedColumns(long** columns,
   1593                                                           long* n_columns) {
   1594   if (!instance_active())
   1595     return E_FAIL;
   1596 
   1597   if (!columns || !n_columns)
   1598     return E_INVALIDARG;
   1599 
   1600   // TODO(dmazzoni): Implement this.
   1601   *n_columns = 0;
   1602   return S_OK;
   1603 }
   1604 
   1605 STDMETHODIMP BrowserAccessibilityWin::get_selectedRows(long** rows,
   1606                                                        long* n_rows) {
   1607   if (!instance_active())
   1608     return E_FAIL;
   1609 
   1610   if (!rows || !n_rows)
   1611     return E_INVALIDARG;
   1612 
   1613   // TODO(dmazzoni): Implement this.
   1614   *n_rows = 0;
   1615   return S_OK;
   1616 }
   1617 
   1618 
   1619 //
   1620 // IAccessibleTableCell methods.
   1621 //
   1622 
   1623 STDMETHODIMP BrowserAccessibilityWin::get_columnExtent(
   1624     long* n_columns_spanned) {
   1625   if (!instance_active())
   1626     return E_FAIL;
   1627 
   1628   if (!n_columns_spanned)
   1629     return E_INVALIDARG;
   1630 
   1631   int colspan;
   1632   if (GetIntAttribute(
   1633           ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN, &colspan) &&
   1634       colspan >= 1) {
   1635     *n_columns_spanned = colspan;
   1636     return S_OK;
   1637   }
   1638 
   1639   return S_FALSE;
   1640 }
   1641 
   1642 STDMETHODIMP BrowserAccessibilityWin::get_columnHeaderCells(
   1643     IUnknown*** cell_accessibles,
   1644     long* n_column_header_cells) {
   1645   if (!instance_active())
   1646     return E_FAIL;
   1647 
   1648   if (!cell_accessibles || !n_column_header_cells)
   1649     return E_INVALIDARG;
   1650 
   1651   *n_column_header_cells = 0;
   1652 
   1653   int column;
   1654   if (!GetIntAttribute(
   1655           ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX, &column)) {
   1656     return S_FALSE;
   1657   }
   1658 
   1659   BrowserAccessibility* table = GetParent();
   1660   while (table && table->GetRole() != ui::AX_ROLE_TABLE)
   1661     table = table->GetParent();
   1662   if (!table) {
   1663     NOTREACHED();
   1664     return S_FALSE;
   1665   }
   1666 
   1667   int columns;
   1668   int rows;
   1669   if (!table->GetIntAttribute(
   1670           ui::AX_ATTR_TABLE_COLUMN_COUNT, &columns) ||
   1671       !table->GetIntAttribute(
   1672           ui::AX_ATTR_TABLE_ROW_COUNT, &rows)) {
   1673     return S_FALSE;
   1674   }
   1675   if (columns <= 0 || rows <= 0 || column < 0 || column >= columns)
   1676     return S_FALSE;
   1677 
   1678   const std::vector<int32>& cell_ids = table->GetIntListAttribute(
   1679       ui::AX_ATTR_CELL_IDS);
   1680 
   1681   for (int i = 0; i < rows; ++i) {
   1682     int cell_id = cell_ids[i * columns + column];
   1683     BrowserAccessibilityWin* cell =
   1684         manager()->GetFromID(cell_id)->ToBrowserAccessibilityWin();
   1685     if (cell && cell->GetRole() == ui::AX_ROLE_COLUMN_HEADER)
   1686       (*n_column_header_cells)++;
   1687   }
   1688 
   1689   *cell_accessibles = static_cast<IUnknown**>(CoTaskMemAlloc(
   1690       (*n_column_header_cells) * sizeof(cell_accessibles[0])));
   1691   int index = 0;
   1692   for (int i = 0; i < rows; ++i) {
   1693     int cell_id = cell_ids[i * columns + column];
   1694     BrowserAccessibility* cell = manager()->GetFromID(cell_id);
   1695     if (cell && cell->GetRole() == ui::AX_ROLE_COLUMN_HEADER) {
   1696       (*cell_accessibles)[index] = static_cast<IAccessible*>(
   1697           cell->ToBrowserAccessibilityWin()->NewReference());
   1698       ++index;
   1699     }
   1700   }
   1701 
   1702   return S_OK;
   1703 }
   1704 
   1705 STDMETHODIMP BrowserAccessibilityWin::get_columnIndex(long* column_index) {
   1706   if (!instance_active())
   1707     return E_FAIL;
   1708 
   1709   if (!column_index)
   1710     return E_INVALIDARG;
   1711 
   1712   int column;
   1713   if (GetIntAttribute(
   1714           ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX, &column)) {
   1715     *column_index = column;
   1716     return S_OK;
   1717   }
   1718 
   1719   return S_FALSE;
   1720 }
   1721 
   1722 STDMETHODIMP BrowserAccessibilityWin::get_rowExtent(long* n_rows_spanned) {
   1723   if (!instance_active())
   1724     return E_FAIL;
   1725 
   1726   if (!n_rows_spanned)
   1727     return E_INVALIDARG;
   1728 
   1729   int rowspan;
   1730   if (GetIntAttribute(
   1731           ui::AX_ATTR_TABLE_CELL_ROW_SPAN, &rowspan) &&
   1732       rowspan >= 1) {
   1733     *n_rows_spanned = rowspan;
   1734     return S_OK;
   1735   }
   1736 
   1737   return S_FALSE;
   1738 }
   1739 
   1740 STDMETHODIMP BrowserAccessibilityWin::get_rowHeaderCells(
   1741     IUnknown*** cell_accessibles,
   1742     long* n_row_header_cells) {
   1743   if (!instance_active())
   1744     return E_FAIL;
   1745 
   1746   if (!cell_accessibles || !n_row_header_cells)
   1747     return E_INVALIDARG;
   1748 
   1749   *n_row_header_cells = 0;
   1750 
   1751   int row;
   1752   if (!GetIntAttribute(
   1753           ui::AX_ATTR_TABLE_CELL_ROW_INDEX, &row)) {
   1754     return S_FALSE;
   1755   }
   1756 
   1757   BrowserAccessibility* table = GetParent();
   1758   while (table && table->GetRole() != ui::AX_ROLE_TABLE)
   1759     table = table->GetParent();
   1760   if (!table) {
   1761     NOTREACHED();
   1762     return S_FALSE;
   1763   }
   1764 
   1765   int columns;
   1766   int rows;
   1767   if (!table->GetIntAttribute(
   1768           ui::AX_ATTR_TABLE_COLUMN_COUNT, &columns) ||
   1769       !table->GetIntAttribute(
   1770           ui::AX_ATTR_TABLE_ROW_COUNT, &rows)) {
   1771     return S_FALSE;
   1772   }
   1773   if (columns <= 0 || rows <= 0 || row < 0 || row >= rows)
   1774     return S_FALSE;
   1775 
   1776   const std::vector<int32>& cell_ids = table->GetIntListAttribute(
   1777       ui::AX_ATTR_CELL_IDS);
   1778 
   1779   for (int i = 0; i < columns; ++i) {
   1780     int cell_id = cell_ids[row * columns + i];
   1781     BrowserAccessibility* cell = manager()->GetFromID(cell_id);
   1782     if (cell && cell->GetRole() == ui::AX_ROLE_ROW_HEADER)
   1783       (*n_row_header_cells)++;
   1784   }
   1785 
   1786   *cell_accessibles = static_cast<IUnknown**>(CoTaskMemAlloc(
   1787       (*n_row_header_cells) * sizeof(cell_accessibles[0])));
   1788   int index = 0;
   1789   for (int i = 0; i < columns; ++i) {
   1790     int cell_id = cell_ids[row * columns + i];
   1791     BrowserAccessibility* cell = manager()->GetFromID(cell_id);
   1792     if (cell && cell->GetRole() == ui::AX_ROLE_ROW_HEADER) {
   1793       (*cell_accessibles)[index] = static_cast<IAccessible*>(
   1794           cell->ToBrowserAccessibilityWin()->NewReference());
   1795       ++index;
   1796     }
   1797   }
   1798 
   1799   return S_OK;
   1800 }
   1801 
   1802 STDMETHODIMP BrowserAccessibilityWin::get_rowIndex(long* row_index) {
   1803   if (!instance_active())
   1804     return E_FAIL;
   1805 
   1806   if (!row_index)
   1807     return E_INVALIDARG;
   1808 
   1809   int row;
   1810   if (GetIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX, &row)) {
   1811     *row_index = row;
   1812     return S_OK;
   1813   }
   1814   return S_FALSE;
   1815 }
   1816 
   1817 STDMETHODIMP BrowserAccessibilityWin::get_isSelected(boolean* is_selected) {
   1818   if (!instance_active())
   1819     return E_FAIL;
   1820 
   1821   if (!is_selected)
   1822     return E_INVALIDARG;
   1823 
   1824   *is_selected = false;
   1825   return S_OK;
   1826 }
   1827 
   1828 STDMETHODIMP BrowserAccessibilityWin::get_rowColumnExtents(
   1829     long* row_index,
   1830     long* column_index,
   1831     long* row_extents,
   1832     long* column_extents,
   1833     boolean* is_selected) {
   1834   if (!instance_active())
   1835     return E_FAIL;
   1836 
   1837   if (!row_index ||
   1838       !column_index ||
   1839       !row_extents ||
   1840       !column_extents ||
   1841       !is_selected) {
   1842     return E_INVALIDARG;
   1843   }
   1844 
   1845   int row;
   1846   int column;
   1847   int rowspan;
   1848   int colspan;
   1849   if (GetIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX, &row) &&
   1850       GetIntAttribute(
   1851           ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX, &column) &&
   1852       GetIntAttribute(
   1853           ui::AX_ATTR_TABLE_CELL_ROW_SPAN, &rowspan) &&
   1854       GetIntAttribute(
   1855           ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN, &colspan)) {
   1856     *row_index = row;
   1857     *column_index = column;
   1858     *row_extents = rowspan;
   1859     *column_extents = colspan;
   1860     *is_selected = false;
   1861     return S_OK;
   1862   }
   1863 
   1864   return S_FALSE;
   1865 }
   1866 
   1867 STDMETHODIMP BrowserAccessibilityWin::get_table(IUnknown** table) {
   1868   if (!instance_active())
   1869     return E_FAIL;
   1870 
   1871   if (!table)
   1872     return E_INVALIDARG;
   1873 
   1874 
   1875   int row;
   1876   int column;
   1877   GetIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX, &row);
   1878   GetIntAttribute(ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX, &column);
   1879 
   1880   BrowserAccessibility* find_table = GetParent();
   1881   while (find_table && find_table->GetRole() != ui::AX_ROLE_TABLE)
   1882     find_table = find_table->GetParent();
   1883   if (!find_table) {
   1884     NOTREACHED();
   1885     return S_FALSE;
   1886   }
   1887 
   1888   *table = static_cast<IAccessibleTable*>(
   1889       find_table->ToBrowserAccessibilityWin()->NewReference());
   1890 
   1891   return S_OK;
   1892 }
   1893 
   1894 //
   1895 // IAccessibleText methods.
   1896 //
   1897 
   1898 STDMETHODIMP BrowserAccessibilityWin::get_nCharacters(LONG* n_characters) {
   1899   if (!instance_active())
   1900     return E_FAIL;
   1901 
   1902   if (!n_characters)
   1903     return E_INVALIDARG;
   1904 
   1905   *n_characters = TextForIAccessibleText().length();
   1906   return S_OK;
   1907 }
   1908 
   1909 STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) {
   1910   if (!instance_active())
   1911     return E_FAIL;
   1912 
   1913   if (!offset)
   1914     return E_INVALIDARG;
   1915 
   1916   *offset = 0;
   1917   if (GetRole() == ui::AX_ROLE_TEXT_FIELD ||
   1918       GetRole() == ui::AX_ROLE_TEXT_AREA) {
   1919     int sel_start = 0;
   1920     if (GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START,
   1921                         &sel_start))
   1922       *offset = sel_start;
   1923   }
   1924 
   1925   return S_OK;
   1926 }
   1927 
   1928 STDMETHODIMP BrowserAccessibilityWin::get_characterExtents(
   1929     LONG offset,
   1930     enum IA2CoordinateType coordinate_type,
   1931     LONG* out_x,
   1932     LONG* out_y,
   1933     LONG* out_width,
   1934     LONG* out_height) {
   1935   if (!instance_active())
   1936     return E_FAIL;
   1937 
   1938   if (!out_x || !out_y || !out_width || !out_height)
   1939     return E_INVALIDARG;
   1940 
   1941   const base::string16& text_str = TextForIAccessibleText();
   1942   HandleSpecialTextOffset(text_str, &offset);
   1943 
   1944   if (offset < 0 || offset > static_cast<LONG>(text_str.size()))
   1945     return E_INVALIDARG;
   1946 
   1947   gfx::Rect character_bounds;
   1948   if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) {
   1949     character_bounds = GetGlobalBoundsForRange(offset, 1);
   1950   } else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) {
   1951     character_bounds = GetLocalBoundsForRange(offset, 1);
   1952     character_bounds -= GetLocation().OffsetFromOrigin();
   1953   } else {
   1954     return E_INVALIDARG;
   1955   }
   1956 
   1957   *out_x = character_bounds.x();
   1958   *out_y = character_bounds.y();
   1959   *out_width = character_bounds.width();
   1960   *out_height = character_bounds.height();
   1961 
   1962   return S_OK;
   1963 }
   1964 
   1965 STDMETHODIMP BrowserAccessibilityWin::get_nSelections(LONG* n_selections) {
   1966   if (!instance_active())
   1967     return E_FAIL;
   1968 
   1969   if (!n_selections)
   1970     return E_INVALIDARG;
   1971 
   1972   *n_selections = 0;
   1973   if (GetRole() == ui::AX_ROLE_TEXT_FIELD ||
   1974       GetRole() == ui::AX_ROLE_TEXT_AREA) {
   1975     int sel_start = 0;
   1976     int sel_end = 0;
   1977     if (GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START,
   1978                         &sel_start) &&
   1979         GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END, &sel_end) &&
   1980         sel_start != sel_end)
   1981       *n_selections = 1;
   1982   }
   1983 
   1984   return S_OK;
   1985 }
   1986 
   1987 STDMETHODIMP BrowserAccessibilityWin::get_selection(LONG selection_index,
   1988                                                     LONG* start_offset,
   1989                                                     LONG* end_offset) {
   1990   if (!instance_active())
   1991     return E_FAIL;
   1992 
   1993   if (!start_offset || !end_offset || selection_index != 0)
   1994     return E_INVALIDARG;
   1995 
   1996   *start_offset = 0;
   1997   *end_offset = 0;
   1998   if (GetRole() == ui::AX_ROLE_TEXT_FIELD ||
   1999       GetRole() == ui::AX_ROLE_TEXT_AREA) {
   2000     int sel_start = 0;
   2001     int sel_end = 0;
   2002     if (GetIntAttribute(
   2003             ui::AX_ATTR_TEXT_SEL_START, &sel_start) &&
   2004         GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END, &sel_end)) {
   2005       *start_offset = sel_start;
   2006       *end_offset = sel_end;
   2007     }
   2008   }
   2009 
   2010   return S_OK;
   2011 }
   2012 
   2013 STDMETHODIMP BrowserAccessibilityWin::get_text(LONG start_offset,
   2014                                                LONG end_offset,
   2015                                                BSTR* text) {
   2016   if (!instance_active())
   2017     return E_FAIL;
   2018 
   2019   if (!text)
   2020     return E_INVALIDARG;
   2021 
   2022   const base::string16& text_str = TextForIAccessibleText();
   2023 
   2024   // Handle special text offsets.
   2025   HandleSpecialTextOffset(text_str, &start_offset);
   2026   HandleSpecialTextOffset(text_str, &end_offset);
   2027 
   2028   // The spec allows the arguments to be reversed.
   2029   if (start_offset > end_offset) {
   2030     LONG tmp = start_offset;
   2031     start_offset = end_offset;
   2032     end_offset = tmp;
   2033   }
   2034 
   2035   // The spec does not allow the start or end offsets to be out or range;
   2036   // we must return an error if so.
   2037   LONG len = text_str.length();
   2038   if (start_offset < 0)
   2039     return E_INVALIDARG;
   2040   if (end_offset > len)
   2041     return E_INVALIDARG;
   2042 
   2043   base::string16 substr = text_str.substr(start_offset,
   2044                                           end_offset - start_offset);
   2045   if (substr.empty())
   2046     return S_FALSE;
   2047 
   2048   *text = SysAllocString(substr.c_str());
   2049   DCHECK(*text);
   2050   return S_OK;
   2051 }
   2052 
   2053 STDMETHODIMP BrowserAccessibilityWin::get_textAtOffset(
   2054     LONG offset,
   2055     enum IA2TextBoundaryType boundary_type,
   2056     LONG* start_offset,
   2057     LONG* end_offset,
   2058     BSTR* text) {
   2059   if (!instance_active())
   2060     return E_FAIL;
   2061 
   2062   if (!start_offset || !end_offset || !text)
   2063     return E_INVALIDARG;
   2064 
   2065   // The IAccessible2 spec says we don't have to implement the "sentence"
   2066   // boundary type, we can just let the screenreader handle it.
   2067   if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
   2068     *start_offset = 0;
   2069     *end_offset = 0;
   2070     *text = NULL;
   2071     return S_FALSE;
   2072   }
   2073 
   2074   const base::string16& text_str = TextForIAccessibleText();
   2075 
   2076   *start_offset = FindBoundary(
   2077       text_str, boundary_type, offset, ui::BACKWARDS_DIRECTION);
   2078   *end_offset = FindBoundary(
   2079       text_str, boundary_type, offset, ui::FORWARDS_DIRECTION);
   2080   return get_text(*start_offset, *end_offset, text);
   2081 }
   2082 
   2083 STDMETHODIMP BrowserAccessibilityWin::get_textBeforeOffset(
   2084     LONG offset,
   2085     enum IA2TextBoundaryType boundary_type,
   2086     LONG* start_offset,
   2087     LONG* end_offset,
   2088     BSTR* text) {
   2089   if (!instance_active())
   2090     return E_FAIL;
   2091 
   2092   if (!start_offset || !end_offset || !text)
   2093     return E_INVALIDARG;
   2094 
   2095   // The IAccessible2 spec says we don't have to implement the "sentence"
   2096   // boundary type, we can just let the screenreader handle it.
   2097   if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
   2098     *start_offset = 0;
   2099     *end_offset = 0;
   2100     *text = NULL;
   2101     return S_FALSE;
   2102   }
   2103 
   2104   const base::string16& text_str = TextForIAccessibleText();
   2105 
   2106   *start_offset = FindBoundary(
   2107       text_str, boundary_type, offset, ui::BACKWARDS_DIRECTION);
   2108   *end_offset = offset;
   2109   return get_text(*start_offset, *end_offset, text);
   2110 }
   2111 
   2112 STDMETHODIMP BrowserAccessibilityWin::get_textAfterOffset(
   2113     LONG offset,
   2114     enum IA2TextBoundaryType boundary_type,
   2115     LONG* start_offset,
   2116     LONG* end_offset,
   2117     BSTR* text) {
   2118   if (!instance_active())
   2119     return E_FAIL;
   2120 
   2121   if (!start_offset || !end_offset || !text)
   2122     return E_INVALIDARG;
   2123 
   2124   // The IAccessible2 spec says we don't have to implement the "sentence"
   2125   // boundary type, we can just let the screenreader handle it.
   2126   if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
   2127     *start_offset = 0;
   2128     *end_offset = 0;
   2129     *text = NULL;
   2130     return S_FALSE;
   2131   }
   2132 
   2133   const base::string16& text_str = TextForIAccessibleText();
   2134 
   2135   *start_offset = offset;
   2136   *end_offset = FindBoundary(
   2137       text_str, boundary_type, offset, ui::FORWARDS_DIRECTION);
   2138   return get_text(*start_offset, *end_offset, text);
   2139 }
   2140 
   2141 STDMETHODIMP BrowserAccessibilityWin::get_newText(IA2TextSegment* new_text) {
   2142   if (!instance_active())
   2143     return E_FAIL;
   2144 
   2145   if (!new_text)
   2146     return E_INVALIDARG;
   2147 
   2148   base::string16 text = TextForIAccessibleText();
   2149 
   2150   new_text->text = SysAllocString(text.c_str());
   2151   new_text->start = 0;
   2152   new_text->end = static_cast<long>(text.size());
   2153   return S_OK;
   2154 }
   2155 
   2156 STDMETHODIMP BrowserAccessibilityWin::get_oldText(IA2TextSegment* old_text) {
   2157   if (!instance_active())
   2158     return E_FAIL;
   2159 
   2160   if (!old_text)
   2161     return E_INVALIDARG;
   2162 
   2163   old_text->text = SysAllocString(old_text_.c_str());
   2164   old_text->start = 0;
   2165   old_text->end = static_cast<long>(old_text_.size());
   2166   return S_OK;
   2167 }
   2168 
   2169 STDMETHODIMP BrowserAccessibilityWin::get_offsetAtPoint(
   2170     LONG x,
   2171     LONG y,
   2172     enum IA2CoordinateType coord_type,
   2173     LONG* offset) {
   2174   if (!instance_active())
   2175     return E_FAIL;
   2176 
   2177   if (!offset)
   2178     return E_INVALIDARG;
   2179 
   2180   // TODO(dmazzoni): implement this. We're returning S_OK for now so that
   2181   // screen readers still return partially accurate results rather than
   2182   // completely failing.
   2183   *offset = 0;
   2184   return S_OK;
   2185 }
   2186 
   2187 STDMETHODIMP BrowserAccessibilityWin::scrollSubstringTo(
   2188     LONG start_index,
   2189     LONG end_index,
   2190     enum IA2ScrollType scroll_type) {
   2191   // TODO(dmazzoni): adjust this for the start and end index, too.
   2192   return scrollTo(scroll_type);
   2193 }
   2194 
   2195 STDMETHODIMP BrowserAccessibilityWin::scrollSubstringToPoint(
   2196     LONG start_index,
   2197     LONG end_index,
   2198     enum IA2CoordinateType coordinate_type,
   2199     LONG x, LONG y) {
   2200   // TODO(dmazzoni): adjust this for the start and end index, too.
   2201   return scrollToPoint(coordinate_type, x, y);
   2202 }
   2203 
   2204 STDMETHODIMP BrowserAccessibilityWin::addSelection(LONG start_offset,
   2205                                                    LONG end_offset) {
   2206   if (!instance_active())
   2207     return E_FAIL;
   2208 
   2209   const base::string16& text_str = TextForIAccessibleText();
   2210   HandleSpecialTextOffset(text_str, &start_offset);
   2211   HandleSpecialTextOffset(text_str, &end_offset);
   2212 
   2213   manager()->SetTextSelection(*this, start_offset, end_offset);
   2214   return S_OK;
   2215 }
   2216 
   2217 STDMETHODIMP BrowserAccessibilityWin::removeSelection(LONG selection_index) {
   2218   if (!instance_active())
   2219     return E_FAIL;
   2220 
   2221   if (selection_index != 0)
   2222     return E_INVALIDARG;
   2223 
   2224   manager()->SetTextSelection(*this, 0, 0);
   2225   return S_OK;
   2226 }
   2227 
   2228 STDMETHODIMP BrowserAccessibilityWin::setCaretOffset(LONG offset) {
   2229   if (!instance_active())
   2230     return E_FAIL;
   2231 
   2232   const base::string16& text_str = TextForIAccessibleText();
   2233   HandleSpecialTextOffset(text_str, &offset);
   2234   manager()->SetTextSelection(*this, offset, offset);
   2235   return S_OK;
   2236 }
   2237 
   2238 STDMETHODIMP BrowserAccessibilityWin::setSelection(LONG selection_index,
   2239                                                    LONG start_offset,
   2240                                                    LONG end_offset) {
   2241   if (!instance_active())
   2242     return E_FAIL;
   2243 
   2244   if (selection_index != 0)
   2245     return E_INVALIDARG;
   2246 
   2247   const base::string16& text_str = TextForIAccessibleText();
   2248   HandleSpecialTextOffset(text_str, &start_offset);
   2249   HandleSpecialTextOffset(text_str, &end_offset);
   2250 
   2251   manager()->SetTextSelection(*this, start_offset, end_offset);
   2252   return S_OK;
   2253 }
   2254 
   2255 //
   2256 // IAccessibleHypertext methods.
   2257 //
   2258 
   2259 STDMETHODIMP BrowserAccessibilityWin::get_nHyperlinks(long* hyperlink_count) {
   2260   if (!instance_active())
   2261     return E_FAIL;
   2262 
   2263   if (!hyperlink_count)
   2264     return E_INVALIDARG;
   2265 
   2266   *hyperlink_count = hyperlink_offset_to_index_.size();
   2267   return S_OK;
   2268 }
   2269 
   2270 STDMETHODIMP BrowserAccessibilityWin::get_hyperlink(
   2271     long index,
   2272     IAccessibleHyperlink** hyperlink) {
   2273   if (!instance_active())
   2274     return E_FAIL;
   2275 
   2276   if (!hyperlink ||
   2277       index < 0 ||
   2278       index >= static_cast<long>(hyperlinks_.size())) {
   2279     return E_INVALIDARG;
   2280   }
   2281 
   2282   BrowserAccessibilityWin* child =
   2283       InternalGetChild(hyperlinks_[index])->ToBrowserAccessibilityWin();
   2284   *hyperlink = static_cast<IAccessibleHyperlink*>(child->NewReference());
   2285   return S_OK;
   2286 }
   2287 
   2288 STDMETHODIMP BrowserAccessibilityWin::get_hyperlinkIndex(
   2289     long char_index,
   2290     long* hyperlink_index) {
   2291   if (!instance_active())
   2292     return E_FAIL;
   2293 
   2294   if (!hyperlink_index)
   2295     return E_INVALIDARG;
   2296 
   2297   *hyperlink_index = -1;
   2298 
   2299   if (char_index < 0 || char_index >= static_cast<long>(hypertext_.size()))
   2300     return E_INVALIDARG;
   2301 
   2302   std::map<int32, int32>::iterator it =
   2303       hyperlink_offset_to_index_.find(char_index);
   2304   if (it == hyperlink_offset_to_index_.end())
   2305     return E_FAIL;
   2306 
   2307   *hyperlink_index = it->second;
   2308   return S_OK;
   2309 }
   2310 
   2311 //
   2312 // IAccessibleValue methods.
   2313 //
   2314 
   2315 STDMETHODIMP BrowserAccessibilityWin::get_currentValue(VARIANT* value) {
   2316   if (!instance_active())
   2317     return E_FAIL;
   2318 
   2319   if (!value)
   2320     return E_INVALIDARG;
   2321 
   2322   float float_val;
   2323   if (GetFloatAttribute(
   2324           ui::AX_ATTR_VALUE_FOR_RANGE, &float_val)) {
   2325     value->vt = VT_R8;
   2326     value->dblVal = float_val;
   2327     return S_OK;
   2328   }
   2329 
   2330   value->vt = VT_EMPTY;
   2331   return S_FALSE;
   2332 }
   2333 
   2334 STDMETHODIMP BrowserAccessibilityWin::get_minimumValue(VARIANT* value) {
   2335   if (!instance_active())
   2336     return E_FAIL;
   2337 
   2338   if (!value)
   2339     return E_INVALIDARG;
   2340 
   2341   float float_val;
   2342   if (GetFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE,
   2343                         &float_val)) {
   2344     value->vt = VT_R8;
   2345     value->dblVal = float_val;
   2346     return S_OK;
   2347   }
   2348 
   2349   value->vt = VT_EMPTY;
   2350   return S_FALSE;
   2351 }
   2352 
   2353 STDMETHODIMP BrowserAccessibilityWin::get_maximumValue(VARIANT* value) {
   2354   if (!instance_active())
   2355     return E_FAIL;
   2356 
   2357   if (!value)
   2358     return E_INVALIDARG;
   2359 
   2360   float float_val;
   2361   if (GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE,
   2362                         &float_val)) {
   2363     value->vt = VT_R8;
   2364     value->dblVal = float_val;
   2365     return S_OK;
   2366   }
   2367 
   2368   value->vt = VT_EMPTY;
   2369   return S_FALSE;
   2370 }
   2371 
   2372 STDMETHODIMP BrowserAccessibilityWin::setCurrentValue(VARIANT new_value) {
   2373   // TODO(dmazzoni): Implement this.
   2374   return E_NOTIMPL;
   2375 }
   2376 
   2377 //
   2378 // ISimpleDOMDocument methods.
   2379 //
   2380 
   2381 STDMETHODIMP BrowserAccessibilityWin::get_URL(BSTR* url) {
   2382   if (!instance_active())
   2383     return E_FAIL;
   2384 
   2385   if (!url)
   2386     return E_INVALIDARG;
   2387 
   2388   return GetStringAttributeAsBstr(ui::AX_ATTR_DOC_URL, url);
   2389 }
   2390 
   2391 STDMETHODIMP BrowserAccessibilityWin::get_title(BSTR* title) {
   2392   if (!instance_active())
   2393     return E_FAIL;
   2394 
   2395   if (!title)
   2396     return E_INVALIDARG;
   2397 
   2398   return GetStringAttributeAsBstr(ui::AX_ATTR_DOC_TITLE, title);
   2399 }
   2400 
   2401 STDMETHODIMP BrowserAccessibilityWin::get_mimeType(BSTR* mime_type) {
   2402   if (!instance_active())
   2403     return E_FAIL;
   2404 
   2405   if (!mime_type)
   2406     return E_INVALIDARG;
   2407 
   2408   return GetStringAttributeAsBstr(
   2409       ui::AX_ATTR_DOC_MIMETYPE, mime_type);
   2410 }
   2411 
   2412 STDMETHODIMP BrowserAccessibilityWin::get_docType(BSTR* doc_type) {
   2413   if (!instance_active())
   2414     return E_FAIL;
   2415 
   2416   if (!doc_type)
   2417     return E_INVALIDARG;
   2418 
   2419   return GetStringAttributeAsBstr(
   2420       ui::AX_ATTR_DOC_DOCTYPE, doc_type);
   2421 }
   2422 
   2423 //
   2424 // ISimpleDOMNode methods.
   2425 //
   2426 
   2427 STDMETHODIMP BrowserAccessibilityWin::get_nodeInfo(
   2428     BSTR* node_name,
   2429     short* name_space_id,
   2430     BSTR* node_value,
   2431     unsigned int* num_children,
   2432     unsigned int* unique_id,
   2433     unsigned short* node_type) {
   2434   if (!instance_active())
   2435     return E_FAIL;
   2436 
   2437   if (!node_name || !name_space_id || !node_value || !num_children ||
   2438       !unique_id || !node_type) {
   2439     return E_INVALIDARG;
   2440   }
   2441 
   2442   base::string16 tag;
   2443   if (GetString16Attribute(ui::AX_ATTR_HTML_TAG, &tag))
   2444     *node_name = SysAllocString(tag.c_str());
   2445   else
   2446     *node_name = NULL;
   2447 
   2448   *name_space_id = 0;
   2449   *node_value = SysAllocString(base::UTF8ToUTF16(value()).c_str());
   2450   *num_children = PlatformChildCount();
   2451   *unique_id = unique_id_win_;
   2452 
   2453   if (ia_role_ == ROLE_SYSTEM_DOCUMENT) {
   2454     *node_type = NODETYPE_DOCUMENT;
   2455   } else if (ia_role_ == ROLE_SYSTEM_TEXT &&
   2456              ((ia2_state_ & IA2_STATE_EDITABLE) == 0)) {
   2457     *node_type = NODETYPE_TEXT;
   2458   } else {
   2459     *node_type = NODETYPE_ELEMENT;
   2460   }
   2461 
   2462   return S_OK;
   2463 }
   2464 
   2465 STDMETHODIMP BrowserAccessibilityWin::get_attributes(
   2466     unsigned short max_attribs,
   2467     BSTR* attrib_names,
   2468     short* name_space_id,
   2469     BSTR* attrib_values,
   2470     unsigned short* num_attribs) {
   2471   if (!instance_active())
   2472     return E_FAIL;
   2473 
   2474   if (!attrib_names || !name_space_id || !attrib_values || !num_attribs)
   2475     return E_INVALIDARG;
   2476 
   2477   *num_attribs = max_attribs;
   2478   if (*num_attribs > GetHtmlAttributes().size())
   2479     *num_attribs = GetHtmlAttributes().size();
   2480 
   2481   for (unsigned short i = 0; i < *num_attribs; ++i) {
   2482     attrib_names[i] = SysAllocString(
   2483         base::UTF8ToUTF16(GetHtmlAttributes()[i].first).c_str());
   2484     name_space_id[i] = 0;
   2485     attrib_values[i] = SysAllocString(
   2486         base::UTF8ToUTF16(GetHtmlAttributes()[i].second).c_str());
   2487   }
   2488   return S_OK;
   2489 }
   2490 
   2491 STDMETHODIMP BrowserAccessibilityWin::get_attributesForNames(
   2492     unsigned short num_attribs,
   2493     BSTR* attrib_names,
   2494     short* name_space_id,
   2495     BSTR* attrib_values) {
   2496   if (!instance_active())
   2497     return E_FAIL;
   2498 
   2499   if (!attrib_names || !name_space_id || !attrib_values)
   2500     return E_INVALIDARG;
   2501 
   2502   for (unsigned short i = 0; i < num_attribs; ++i) {
   2503     name_space_id[i] = 0;
   2504     bool found = false;
   2505     std::string name = base::UTF16ToUTF8((LPCWSTR)attrib_names[i]);
   2506     for (unsigned int j = 0;  j < GetHtmlAttributes().size(); ++j) {
   2507       if (GetHtmlAttributes()[j].first == name) {
   2508         attrib_values[i] = SysAllocString(
   2509             base::UTF8ToUTF16(GetHtmlAttributes()[j].second).c_str());
   2510         found = true;
   2511         break;
   2512       }
   2513     }
   2514     if (!found) {
   2515       attrib_values[i] = NULL;
   2516     }
   2517   }
   2518   return S_OK;
   2519 }
   2520 
   2521 STDMETHODIMP BrowserAccessibilityWin::get_computedStyle(
   2522     unsigned short max_style_properties,
   2523     boolean use_alternate_view,
   2524     BSTR* style_properties,
   2525     BSTR* style_values,
   2526     unsigned short *num_style_properties)  {
   2527   if (!instance_active())
   2528     return E_FAIL;
   2529 
   2530   if (!style_properties || !style_values)
   2531     return E_INVALIDARG;
   2532 
   2533   // We only cache a single style property for now: DISPLAY
   2534 
   2535   base::string16 display;
   2536   if (max_style_properties == 0 ||
   2537       !GetString16Attribute(ui::AX_ATTR_DISPLAY, &display)) {
   2538     *num_style_properties = 0;
   2539     return S_OK;
   2540   }
   2541 
   2542   *num_style_properties = 1;
   2543   style_properties[0] = SysAllocString(L"display");
   2544   style_values[0] = SysAllocString(display.c_str());
   2545 
   2546   return S_OK;
   2547 }
   2548 
   2549 STDMETHODIMP BrowserAccessibilityWin::get_computedStyleForProperties(
   2550     unsigned short num_style_properties,
   2551     boolean use_alternate_view,
   2552     BSTR* style_properties,
   2553     BSTR* style_values) {
   2554   if (!instance_active())
   2555     return E_FAIL;
   2556 
   2557   if (!style_properties || !style_values)
   2558     return E_INVALIDARG;
   2559 
   2560   // We only cache a single style property for now: DISPLAY
   2561 
   2562   for (unsigned short i = 0; i < num_style_properties; ++i) {
   2563     base::string16 name = (LPCWSTR)style_properties[i];
   2564     StringToLowerASCII(&name);
   2565     if (name == L"display") {
   2566       base::string16 display = GetString16Attribute(
   2567           ui::AX_ATTR_DISPLAY);
   2568       style_values[i] = SysAllocString(display.c_str());
   2569     } else {
   2570       style_values[i] = NULL;
   2571     }
   2572   }
   2573 
   2574   return S_OK;
   2575 }
   2576 
   2577 STDMETHODIMP BrowserAccessibilityWin::scrollTo(boolean placeTopLeft) {
   2578   return scrollTo(placeTopLeft ?
   2579       IA2_SCROLL_TYPE_TOP_LEFT : IA2_SCROLL_TYPE_ANYWHERE);
   2580 }
   2581 
   2582 STDMETHODIMP BrowserAccessibilityWin::get_parentNode(ISimpleDOMNode** node) {
   2583   if (!instance_active())
   2584     return E_FAIL;
   2585 
   2586   if (!node)
   2587     return E_INVALIDARG;
   2588 
   2589   *node = GetParent()->ToBrowserAccessibilityWin()->NewReference();
   2590   return S_OK;
   2591 }
   2592 
   2593 STDMETHODIMP BrowserAccessibilityWin::get_firstChild(ISimpleDOMNode** node)  {
   2594   if (!instance_active())
   2595     return E_FAIL;
   2596 
   2597   if (!node)
   2598     return E_INVALIDARG;
   2599 
   2600   if (PlatformChildCount() == 0) {
   2601     *node = NULL;
   2602     return S_FALSE;
   2603   }
   2604 
   2605   *node = PlatformGetChild(0)->ToBrowserAccessibilityWin()->NewReference();
   2606   return S_OK;
   2607 }
   2608 
   2609 STDMETHODIMP BrowserAccessibilityWin::get_lastChild(ISimpleDOMNode** node) {
   2610   if (!instance_active())
   2611     return E_FAIL;
   2612 
   2613   if (!node)
   2614     return E_INVALIDARG;
   2615 
   2616   if (PlatformChildCount() == 0) {
   2617     *node = NULL;
   2618     return S_FALSE;
   2619   }
   2620 
   2621   *node = PlatformGetChild(PlatformChildCount() - 1)
   2622       ->ToBrowserAccessibilityWin()->NewReference();
   2623   return S_OK;
   2624 }
   2625 
   2626 STDMETHODIMP BrowserAccessibilityWin::get_previousSibling(
   2627     ISimpleDOMNode** node) {
   2628   if (!instance_active())
   2629     return E_FAIL;
   2630 
   2631   if (!node)
   2632     return E_INVALIDARG;
   2633 
   2634   if (!GetParent() || GetIndexInParent() <= 0) {
   2635     *node = NULL;
   2636     return S_FALSE;
   2637   }
   2638 
   2639   *node = GetParent()->InternalGetChild(GetIndexInParent() - 1)->
   2640       ToBrowserAccessibilityWin()->NewReference();
   2641   return S_OK;
   2642 }
   2643 
   2644 STDMETHODIMP BrowserAccessibilityWin::get_nextSibling(ISimpleDOMNode** node) {
   2645   if (!instance_active())
   2646     return E_FAIL;
   2647 
   2648   if (!node)
   2649     return E_INVALIDARG;
   2650 
   2651   if (!GetParent() ||
   2652       GetIndexInParent() < 0 ||
   2653       GetIndexInParent() >= static_cast<int>(
   2654           GetParent()->InternalChildCount()) - 1) {
   2655     *node = NULL;
   2656     return S_FALSE;
   2657   }
   2658 
   2659   *node = GetParent()->InternalGetChild(GetIndexInParent() + 1)->
   2660       ToBrowserAccessibilityWin()->NewReference();
   2661   return S_OK;
   2662 }
   2663 
   2664 STDMETHODIMP BrowserAccessibilityWin::get_childAt(
   2665     unsigned int child_index,
   2666     ISimpleDOMNode** node) {
   2667   if (!instance_active())
   2668     return E_FAIL;
   2669 
   2670   if (!node)
   2671     return E_INVALIDARG;
   2672 
   2673   if (child_index >= PlatformChildCount())
   2674     return E_INVALIDARG;
   2675 
   2676   BrowserAccessibility* child = PlatformGetChild(child_index);
   2677   if (!child) {
   2678     *node = NULL;
   2679     return S_FALSE;
   2680   }
   2681 
   2682   *node = child->ToBrowserAccessibilityWin()->NewReference();
   2683   return S_OK;
   2684 }
   2685 
   2686 //
   2687 // ISimpleDOMText methods.
   2688 //
   2689 
   2690 STDMETHODIMP BrowserAccessibilityWin::get_domText(BSTR* dom_text) {
   2691   if (!instance_active())
   2692     return E_FAIL;
   2693 
   2694   if (!dom_text)
   2695     return E_INVALIDARG;
   2696 
   2697   return GetStringAttributeAsBstr(
   2698       ui::AX_ATTR_NAME, dom_text);
   2699 }
   2700 
   2701 STDMETHODIMP BrowserAccessibilityWin::get_clippedSubstringBounds(
   2702     unsigned int start_index,
   2703     unsigned int end_index,
   2704     int* out_x,
   2705     int* out_y,
   2706     int* out_width,
   2707     int* out_height) {
   2708   // TODO(dmazzoni): fully support this API by intersecting the
   2709   // rect with the container's rect.
   2710   return get_unclippedSubstringBounds(
   2711       start_index, end_index, out_x, out_y, out_width, out_height);
   2712 }
   2713 
   2714 STDMETHODIMP BrowserAccessibilityWin::get_unclippedSubstringBounds(
   2715     unsigned int start_index,
   2716     unsigned int end_index,
   2717     int* out_x,
   2718     int* out_y,
   2719     int* out_width,
   2720     int* out_height) {
   2721   if (!instance_active())
   2722     return E_FAIL;
   2723 
   2724   if (!out_x || !out_y || !out_width || !out_height)
   2725     return E_INVALIDARG;
   2726 
   2727   const base::string16& text_str = TextForIAccessibleText();
   2728   if (start_index > text_str.size() ||
   2729       end_index > text_str.size() ||
   2730       start_index > end_index) {
   2731     return E_INVALIDARG;
   2732   }
   2733 
   2734   gfx::Rect bounds = GetGlobalBoundsForRange(
   2735       start_index, end_index - start_index);
   2736   *out_x = bounds.x();
   2737   *out_y = bounds.y();
   2738   *out_width = bounds.width();
   2739   *out_height = bounds.height();
   2740   return S_OK;
   2741 }
   2742 
   2743 STDMETHODIMP BrowserAccessibilityWin::scrollToSubstring(
   2744     unsigned int start_index,
   2745     unsigned int end_index) {
   2746   if (!instance_active())
   2747     return E_FAIL;
   2748 
   2749   const base::string16& text_str = TextForIAccessibleText();
   2750   if (start_index > text_str.size() ||
   2751       end_index > text_str.size() ||
   2752       start_index > end_index) {
   2753     return E_INVALIDARG;
   2754   }
   2755 
   2756   manager()->ScrollToMakeVisible(*this, GetLocalBoundsForRange(
   2757       start_index, end_index - start_index));
   2758   manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
   2759 
   2760   return S_OK;
   2761 }
   2762 
   2763 //
   2764 // IServiceProvider methods.
   2765 //
   2766 
   2767 STDMETHODIMP BrowserAccessibilityWin::QueryService(REFGUID guidService,
   2768                                                    REFIID riid,
   2769                                                    void** object) {
   2770   if (!instance_active())
   2771     return E_FAIL;
   2772 
   2773   // The system uses IAccessible APIs for many purposes, but only
   2774   // assistive technology like screen readers uses IAccessible2.
   2775   // Enable full accessibility support when IAccessible2 APIs are queried.
   2776   if (riid == IID_IAccessible2)
   2777     BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility();
   2778 
   2779   if (guidService == GUID_IAccessibleContentDocument) {
   2780     // Special Mozilla extension: return the accessible for the root document.
   2781     // Screen readers use this to distinguish between a document loaded event
   2782     // on the root document vs on an iframe.
   2783     return manager()->GetRoot()->ToBrowserAccessibilityWin()->QueryInterface(
   2784         IID_IAccessible2, object);
   2785   }
   2786 
   2787   if (guidService == IID_IAccessible ||
   2788       guidService == IID_IAccessible2 ||
   2789       guidService == IID_IAccessibleAction ||
   2790       guidService == IID_IAccessibleApplication ||
   2791       guidService == IID_IAccessibleHyperlink ||
   2792       guidService == IID_IAccessibleHypertext ||
   2793       guidService == IID_IAccessibleImage ||
   2794       guidService == IID_IAccessibleTable ||
   2795       guidService == IID_IAccessibleTable2 ||
   2796       guidService == IID_IAccessibleTableCell ||
   2797       guidService == IID_IAccessibleText ||
   2798       guidService == IID_IAccessibleValue ||
   2799       guidService == IID_ISimpleDOMDocument ||
   2800       guidService == IID_ISimpleDOMNode ||
   2801       guidService == IID_ISimpleDOMText ||
   2802       guidService == GUID_ISimpleDOM) {
   2803     return QueryInterface(riid, object);
   2804   }
   2805 
   2806   // We only support the IAccessibleEx interface on Windows 8 and above. This
   2807   // is needed for the on-screen Keyboard to show up in metro mode, when the
   2808   // user taps an editable portion on the page.
   2809   // All methods in the IAccessibleEx interface are unimplemented.
   2810   if (riid == IID_IAccessibleEx &&
   2811       base::win::GetVersion() >= base::win::VERSION_WIN8) {
   2812     return QueryInterface(riid, object);
   2813   }
   2814 
   2815   *object = NULL;
   2816   return E_FAIL;
   2817 }
   2818 
   2819 STDMETHODIMP BrowserAccessibilityWin::GetPatternProvider(PATTERNID id,
   2820                                                          IUnknown** provider) {
   2821   DVLOG(1) << "In Function: "
   2822            << __FUNCTION__
   2823            << " for pattern id: "
   2824            << id;
   2825   if (id == UIA_ValuePatternId || id == UIA_TextPatternId) {
   2826     if (IsEditableText()) {
   2827       DVLOG(1) << "Returning UIA text provider";
   2828       base::win::UIATextProvider::CreateTextProvider(
   2829           GetValueText(), true, provider);
   2830       return S_OK;
   2831     }
   2832   }
   2833   return E_NOTIMPL;
   2834 }
   2835 
   2836 STDMETHODIMP BrowserAccessibilityWin::GetPropertyValue(PROPERTYID id,
   2837                                                        VARIANT* ret) {
   2838   DVLOG(1) << "In Function: "
   2839            << __FUNCTION__
   2840            << " for property id: "
   2841            << id;
   2842   V_VT(ret) = VT_EMPTY;
   2843   if (id == UIA_ControlTypePropertyId) {
   2844     if (IsEditableText()) {
   2845       V_VT(ret) = VT_I4;
   2846       ret->lVal = UIA_EditControlTypeId;
   2847       DVLOG(1) << "Returning Edit control type";
   2848     } else {
   2849       DVLOG(1) << "Returning empty control type";
   2850     }
   2851   }
   2852   return S_OK;
   2853 }
   2854 
   2855 //
   2856 // CComObjectRootEx methods.
   2857 //
   2858 
   2859 HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface(
   2860     void* this_ptr,
   2861     const _ATL_INTMAP_ENTRY* entries,
   2862     REFIID iid,
   2863     void** object) {
   2864   if (iid == IID_IAccessibleImage) {
   2865     if (ia_role_ != ROLE_SYSTEM_GRAPHIC) {
   2866       *object = NULL;
   2867       return E_NOINTERFACE;
   2868     }
   2869   } else if (iid == IID_IAccessibleTable || iid == IID_IAccessibleTable2) {
   2870     if (ia_role_ != ROLE_SYSTEM_TABLE) {
   2871       *object = NULL;
   2872       return E_NOINTERFACE;
   2873     }
   2874   } else if (iid == IID_IAccessibleTableCell) {
   2875     if (ia_role_ != ROLE_SYSTEM_CELL) {
   2876       *object = NULL;
   2877       return E_NOINTERFACE;
   2878     }
   2879   } else if (iid == IID_IAccessibleValue) {
   2880     if (ia_role_ != ROLE_SYSTEM_PROGRESSBAR &&
   2881         ia_role_ != ROLE_SYSTEM_SCROLLBAR &&
   2882         ia_role_ != ROLE_SYSTEM_SLIDER) {
   2883       *object = NULL;
   2884       return E_NOINTERFACE;
   2885     }
   2886   } else if (iid == IID_ISimpleDOMDocument) {
   2887     if (ia_role_ != ROLE_SYSTEM_DOCUMENT) {
   2888       *object = NULL;
   2889       return E_NOINTERFACE;
   2890     }
   2891   }
   2892 
   2893   return CComObjectRootBase::InternalQueryInterface(
   2894       this_ptr, entries, iid, object);
   2895 }
   2896 
   2897 //
   2898 // Private methods.
   2899 //
   2900 
   2901 // Called every time this node's data changes.
   2902 void BrowserAccessibilityWin::OnDataChanged() {
   2903   BrowserAccessibility::OnDataChanged();
   2904 
   2905   InitRoleAndState();
   2906 
   2907   // Expose the "display" and "tag" attributes.
   2908   StringAttributeToIA2(ui::AX_ATTR_DISPLAY, "display");
   2909   StringAttributeToIA2(ui::AX_ATTR_HTML_TAG, "tag");
   2910   StringAttributeToIA2(ui::AX_ATTR_ROLE, "xml-roles");
   2911 
   2912   // Expose "level" attribute for headings, trees, etc.
   2913   IntAttributeToIA2(ui::AX_ATTR_HIERARCHICAL_LEVEL, "level");
   2914 
   2915   // Expose the set size and position in set for listbox options.
   2916   if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION &&
   2917       GetParent() &&
   2918       GetParent()->GetRole() == ui::AX_ROLE_LIST_BOX) {
   2919     ia2_attributes_.push_back(
   2920         L"setsize:" + base::IntToString16(GetParent()->PlatformChildCount()));
   2921     ia2_attributes_.push_back(
   2922         L"setsize:" + base::IntToString16(GetIndexInParent() + 1));
   2923   }
   2924 
   2925   if (ia_role_ == ROLE_SYSTEM_CHECKBUTTON ||
   2926       ia_role_ == ROLE_SYSTEM_RADIOBUTTON ||
   2927       ia2_role_ == IA2_ROLE_TOGGLE_BUTTON) {
   2928     ia2_attributes_.push_back(L"checkable:true");
   2929   }
   2930 
   2931   // Expose live region attributes.
   2932   StringAttributeToIA2(ui::AX_ATTR_LIVE_STATUS, "live");
   2933   StringAttributeToIA2(ui::AX_ATTR_LIVE_RELEVANT, "relevant");
   2934   BoolAttributeToIA2(ui::AX_ATTR_LIVE_ATOMIC, "atomic");
   2935   BoolAttributeToIA2(ui::AX_ATTR_LIVE_BUSY, "busy");
   2936 
   2937   // Expose container live region attributes.
   2938   StringAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_STATUS,
   2939                        "container-live");
   2940   StringAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_RELEVANT,
   2941                        "container-relevant");
   2942   BoolAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_ATOMIC,
   2943                      "container-atomic");
   2944   BoolAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_BUSY,
   2945                      "container-busy");
   2946 
   2947   // Expose slider value.
   2948   if (ia_role_ == ROLE_SYSTEM_PROGRESSBAR ||
   2949       ia_role_ == ROLE_SYSTEM_SCROLLBAR ||
   2950       ia_role_ == ROLE_SYSTEM_SLIDER) {
   2951     ia2_attributes_.push_back(L"valuetext:" + GetValueText());
   2952   }
   2953 
   2954   // Expose table cell index.
   2955   if (ia_role_ == ROLE_SYSTEM_CELL) {
   2956     BrowserAccessibility* table = GetParent();
   2957     while (table && table->GetRole() != ui::AX_ROLE_TABLE)
   2958       table = table->GetParent();
   2959     if (table) {
   2960       const std::vector<int32>& unique_cell_ids = table->GetIntListAttribute(
   2961           ui::AX_ATTR_UNIQUE_CELL_IDS);
   2962       for (size_t i = 0; i < unique_cell_ids.size(); ++i) {
   2963         if (unique_cell_ids[i] == GetId()) {
   2964           ia2_attributes_.push_back(
   2965               base::string16(L"table-cell-index:") + base::IntToString16(i));
   2966         }
   2967       }
   2968     }
   2969   }
   2970 
   2971   // The calculation of the accessible name of an element has been
   2972   // standardized in the HTML to Platform Accessibility APIs Implementation
   2973   // Guide (http://www.w3.org/TR/html-aapi/). In order to return the
   2974   // appropriate accessible name on Windows, we need to apply some logic
   2975   // to the fields we get from WebKit.
   2976   //
   2977   // TODO(dmazzoni): move most of this logic into WebKit.
   2978   //
   2979   // WebKit gives us:
   2980   //
   2981   //   name: the default name, e.g. inner text
   2982   //   title ui element: a reference to a <label> element on the same
   2983   //       page that labels this node.
   2984   //   description: accessible labels that override the default name:
   2985   //       aria-label or aria-labelledby or aria-describedby
   2986   //   help: the value of the "title" attribute
   2987   //
   2988   // On Windows, the logic we apply lets some fields take precedence and
   2989   // always returns the primary name in "name" and the secondary name,
   2990   // if any, in "description".
   2991 
   2992   int title_elem_id = GetIntAttribute(
   2993       ui::AX_ATTR_TITLE_UI_ELEMENT);
   2994   std::string help = GetStringAttribute(ui::AX_ATTR_HELP);
   2995   std::string description = GetStringAttribute(
   2996       ui::AX_ATTR_DESCRIPTION);
   2997 
   2998   // WebKit annoyingly puts the title in the description if there's no other
   2999   // description, which just confuses the rest of the logic. Put it back.
   3000   // Now "help" is always the value of the "title" attribute, if present.
   3001   std::string title_attr;
   3002   if (GetHtmlAttribute("title", &title_attr) &&
   3003       description == title_attr &&
   3004       help.empty()) {
   3005     help = description;
   3006     description.clear();
   3007   }
   3008 
   3009   // Now implement the main logic: the descripion should become the name if
   3010   // it's nonempty, and the help should become the description if
   3011   // there's no description - or the name if there's no name or description.
   3012   if (!description.empty()) {
   3013     set_name(description);
   3014     description.clear();
   3015   }
   3016   if (!help.empty() && description.empty()) {
   3017     description = help;
   3018     help.clear();
   3019   }
   3020   if (!description.empty() && name().empty() && !title_elem_id) {
   3021     set_name(description);
   3022     description.clear();
   3023   }
   3024 
   3025   // If it's a text field, also consider the placeholder.
   3026   std::string placeholder;
   3027   if (GetRole() == ui::AX_ROLE_TEXT_FIELD &&
   3028       HasState(ui::AX_STATE_FOCUSABLE) &&
   3029       GetHtmlAttribute("placeholder", &placeholder)) {
   3030     if (name().empty() && !title_elem_id) {
   3031       set_name(placeholder);
   3032     } else if (description.empty()) {
   3033       description = placeholder;
   3034     }
   3035   }
   3036 
   3037   SetStringAttribute(ui::AX_ATTR_DESCRIPTION, description);
   3038   SetStringAttribute(ui::AX_ATTR_HELP, help);
   3039 
   3040   // On Windows, the value of a document should be its url.
   3041   if (GetRole() == ui::AX_ROLE_ROOT_WEB_AREA ||
   3042       GetRole() == ui::AX_ROLE_WEB_AREA) {
   3043     set_value(GetStringAttribute(ui::AX_ATTR_DOC_URL));
   3044   }
   3045 
   3046   // For certain roles (listbox option, static text, and list marker)
   3047   // WebKit stores the main accessible text in the "value" - swap it so
   3048   // that it's the "name".
   3049   if (name().empty() &&
   3050       (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION ||
   3051        GetRole() == ui::AX_ROLE_STATIC_TEXT ||
   3052        GetRole() == ui::AX_ROLE_LIST_MARKER)) {
   3053     std::string tmp = value();
   3054     set_value(name());
   3055     set_name(tmp);
   3056   }
   3057 
   3058   // If this doesn't have a value and is linked then set its value to the url
   3059   // attribute. This allows screen readers to read an empty link's destination.
   3060   if (value().empty() && (ia_state_ & STATE_SYSTEM_LINKED))
   3061     set_value(GetStringAttribute(ui::AX_ATTR_URL));
   3062 
   3063   // Clear any old relationships between this node and other nodes.
   3064   for (size_t i = 0; i < relations_.size(); ++i)
   3065     relations_[i]->Release();
   3066   relations_.clear();
   3067 
   3068   // Handle title UI element.
   3069   if (title_elem_id) {
   3070     // Add a labelled by relationship.
   3071     CComObject<BrowserAccessibilityRelation>* relation;
   3072     HRESULT hr = CComObject<BrowserAccessibilityRelation>::CreateInstance(
   3073         &relation);
   3074     DCHECK(SUCCEEDED(hr));
   3075     relation->AddRef();
   3076     relation->Initialize(this, IA2_RELATION_LABELLED_BY);
   3077     relation->AddTarget(title_elem_id);
   3078     relations_.push_back(relation);
   3079   }
   3080 }
   3081 
   3082 void BrowserAccessibilityWin::OnUpdateFinished() {
   3083   // Construct the hypertext for this node.
   3084   hyperlink_offset_to_index_.clear();
   3085   hyperlinks_.clear();
   3086   hypertext_.clear();
   3087   for (unsigned int i = 0; i < PlatformChildCount(); ++i) {
   3088     BrowserAccessibility* child = PlatformGetChild(i);
   3089     if (child->GetRole() == ui::AX_ROLE_STATIC_TEXT) {
   3090       hypertext_ += base::UTF8ToUTF16(child->name());
   3091     } else {
   3092       hyperlink_offset_to_index_[hypertext_.size()] = hyperlinks_.size();
   3093       hypertext_ += kEmbeddedCharacter;
   3094       hyperlinks_.push_back(i);
   3095     }
   3096   }
   3097   DCHECK_EQ(hyperlink_offset_to_index_.size(), hyperlinks_.size());
   3098 
   3099   // Fire an event when an alert first appears.
   3100   if (GetRole() == ui::AX_ROLE_ALERT && first_time_)
   3101     manager()->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, this);
   3102 
   3103   // Fire events if text has changed.
   3104   base::string16 text = TextForIAccessibleText();
   3105   if (previous_text_ != text) {
   3106     if (!previous_text_.empty() && !text.empty()) {
   3107       manager()->NotifyAccessibilityEvent(
   3108           ui::AX_EVENT_SHOW, this);
   3109     }
   3110 
   3111     // TODO(dmazzoni): Look into HIDE events, too.
   3112 
   3113     old_text_ = previous_text_;
   3114     previous_text_ = text;
   3115   }
   3116 
   3117   BrowserAccessibilityManagerWin* manager =
   3118       this->manager()->ToBrowserAccessibilityManagerWin();
   3119 
   3120   // Fire events if the state has changed.
   3121   if (!first_time_ && ia_state_ != old_ia_state_) {
   3122     // Normally focus events are handled elsewhere, however
   3123     // focus for managed descendants is platform-specific.
   3124     // Fire a focus event if the focused descendant in a multi-select
   3125     // list box changes.
   3126     if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION &&
   3127         (ia_state_ & STATE_SYSTEM_FOCUSABLE) &&
   3128         (ia_state_ & STATE_SYSTEM_SELECTABLE) &&
   3129         (ia_state_ & STATE_SYSTEM_FOCUSED) &&
   3130         !(old_ia_state_ & STATE_SYSTEM_FOCUSED)) {
   3131       manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_FOCUS, unique_id_win());
   3132     }
   3133 
   3134     if ((ia_state_ & STATE_SYSTEM_SELECTED) &&
   3135         !(old_ia_state_ & STATE_SYSTEM_SELECTED)) {
   3136       manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONADD,
   3137                                        unique_id_win());
   3138     } else if (!(ia_state_ & STATE_SYSTEM_SELECTED) &&
   3139                (old_ia_state_ & STATE_SYSTEM_SELECTED)) {
   3140       manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONREMOVE,
   3141                                        unique_id_win());
   3142     }
   3143 
   3144     old_ia_state_ = ia_state_;
   3145   }
   3146 
   3147   // Fire an event if this container object has scrolled.
   3148   int sx = 0;
   3149   int sy = 0;
   3150   if (GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
   3151       GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
   3152     if (!first_time_ &&
   3153         (sx != previous_scroll_x_ || sy != previous_scroll_y_)) {
   3154       manager->MaybeCallNotifyWinEvent(EVENT_SYSTEM_SCROLLINGEND,
   3155                                        unique_id_win());
   3156     }
   3157     previous_scroll_x_ = sx;
   3158     previous_scroll_y_ = sy;
   3159   }
   3160 
   3161   first_time_ = false;
   3162 }
   3163 
   3164 void BrowserAccessibilityWin::NativeAddReference() {
   3165   AddRef();
   3166 }
   3167 
   3168 void BrowserAccessibilityWin::NativeReleaseReference() {
   3169   Release();
   3170 }
   3171 
   3172 bool BrowserAccessibilityWin::IsNative() const {
   3173   return true;
   3174 }
   3175 
   3176 void BrowserAccessibilityWin::OnLocationChanged() const {
   3177   manager()->ToBrowserAccessibilityManagerWin()->MaybeCallNotifyWinEvent(
   3178       EVENT_OBJECT_LOCATIONCHANGE, unique_id_win());
   3179 }
   3180 
   3181 BrowserAccessibilityWin* BrowserAccessibilityWin::NewReference() {
   3182   AddRef();
   3183   return this;
   3184 }
   3185 
   3186 BrowserAccessibilityWin* BrowserAccessibilityWin::GetTargetFromChildID(
   3187     const VARIANT& var_id) {
   3188   if (var_id.vt != VT_I4)
   3189     return NULL;
   3190 
   3191   LONG child_id = var_id.lVal;
   3192   if (child_id == CHILDID_SELF)
   3193     return this;
   3194 
   3195   if (child_id >= 1 && child_id <= static_cast<LONG>(PlatformChildCount()))
   3196     return PlatformGetChild(child_id - 1)->ToBrowserAccessibilityWin();
   3197 
   3198   return manager()->ToBrowserAccessibilityManagerWin()->
   3199       GetFromUniqueIdWin(child_id);
   3200 }
   3201 
   3202 HRESULT BrowserAccessibilityWin::GetStringAttributeAsBstr(
   3203     ui::AXStringAttribute attribute,
   3204     BSTR* value_bstr) {
   3205   base::string16 str;
   3206 
   3207   if (!GetString16Attribute(attribute, &str))
   3208     return S_FALSE;
   3209 
   3210   if (str.empty())
   3211     return S_FALSE;
   3212 
   3213   *value_bstr = SysAllocString(str.c_str());
   3214   DCHECK(*value_bstr);
   3215 
   3216   return S_OK;
   3217 }
   3218 
   3219 void BrowserAccessibilityWin::StringAttributeToIA2(
   3220     ui::AXStringAttribute attribute,
   3221     const char* ia2_attr) {
   3222   base::string16 value;
   3223   if (GetString16Attribute(attribute, &value))
   3224     ia2_attributes_.push_back(base::ASCIIToUTF16(ia2_attr) + L":" + value);
   3225 }
   3226 
   3227 void BrowserAccessibilityWin::BoolAttributeToIA2(
   3228     ui::AXBoolAttribute attribute,
   3229     const char* ia2_attr) {
   3230   bool value;
   3231   if (GetBoolAttribute(attribute, &value)) {
   3232     ia2_attributes_.push_back((base::ASCIIToUTF16(ia2_attr) + L":") +
   3233                               (value ? L"true" : L"false"));
   3234   }
   3235 }
   3236 
   3237 void BrowserAccessibilityWin::IntAttributeToIA2(
   3238     ui::AXIntAttribute attribute,
   3239     const char* ia2_attr) {
   3240   int value;
   3241   if (GetIntAttribute(attribute, &value)) {
   3242     ia2_attributes_.push_back(base::ASCIIToUTF16(ia2_attr) + L":" +
   3243                               base::IntToString16(value));
   3244   }
   3245 }
   3246 
   3247 base::string16 BrowserAccessibilityWin::GetValueText() {
   3248   float fval;
   3249   base::string16 value = base::UTF8ToUTF16(this->value());
   3250 
   3251   if (value.empty() &&
   3252       GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, &fval)) {
   3253     value = base::UTF8ToUTF16(base::DoubleToString(fval));
   3254   }
   3255   return value;
   3256 }
   3257 
   3258 base::string16 BrowserAccessibilityWin::TextForIAccessibleText() {
   3259   if (IsEditableText())
   3260     return base::UTF8ToUTF16(value());
   3261   return (GetRole() == ui::AX_ROLE_STATIC_TEXT) ?
   3262       base::UTF8ToUTF16(name()) : hypertext_;
   3263 }
   3264 
   3265 void BrowserAccessibilityWin::HandleSpecialTextOffset(
   3266     const base::string16& text,
   3267     LONG* offset) {
   3268   if (*offset == IA2_TEXT_OFFSET_LENGTH)
   3269     *offset = static_cast<LONG>(text.size());
   3270   else if (*offset == IA2_TEXT_OFFSET_CARET)
   3271     get_caretOffset(offset);
   3272 }
   3273 
   3274 ui::TextBoundaryType BrowserAccessibilityWin::IA2TextBoundaryToTextBoundary(
   3275     IA2TextBoundaryType ia2_boundary) {
   3276   switch(ia2_boundary) {
   3277     case IA2_TEXT_BOUNDARY_CHAR: return ui::CHAR_BOUNDARY;
   3278     case IA2_TEXT_BOUNDARY_WORD: return ui::WORD_BOUNDARY;
   3279     case IA2_TEXT_BOUNDARY_LINE: return ui::LINE_BOUNDARY;
   3280     case IA2_TEXT_BOUNDARY_SENTENCE: return ui::SENTENCE_BOUNDARY;
   3281     case IA2_TEXT_BOUNDARY_PARAGRAPH: return ui::PARAGRAPH_BOUNDARY;
   3282     case IA2_TEXT_BOUNDARY_ALL: return ui::ALL_BOUNDARY;
   3283     default:
   3284       NOTREACHED();
   3285       return ui::CHAR_BOUNDARY;
   3286   }
   3287 }
   3288 
   3289 LONG BrowserAccessibilityWin::FindBoundary(
   3290     const base::string16& text,
   3291     IA2TextBoundaryType ia2_boundary,
   3292     LONG start_offset,
   3293     ui::TextBoundaryDirection direction) {
   3294   HandleSpecialTextOffset(text, &start_offset);
   3295   ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary);
   3296   const std::vector<int32>& line_breaks = GetIntListAttribute(
   3297       ui::AX_ATTR_LINE_BREAKS);
   3298   return ui::FindAccessibleTextBoundary(
   3299       text, line_breaks, boundary, start_offset, direction);
   3300 }
   3301 
   3302 BrowserAccessibilityWin* BrowserAccessibilityWin::GetFromID(int32 id) {
   3303   return manager()->GetFromID(id)->ToBrowserAccessibilityWin();
   3304 }
   3305 
   3306 void BrowserAccessibilityWin::InitRoleAndState() {
   3307   ia_state_ = 0;
   3308   ia2_state_ = IA2_STATE_OPAQUE;
   3309   ia2_attributes_.clear();
   3310 
   3311   if (HasState(ui::AX_STATE_BUSY))
   3312     ia_state_ |= STATE_SYSTEM_BUSY;
   3313   if (HasState(ui::AX_STATE_CHECKED))
   3314     ia_state_ |= STATE_SYSTEM_CHECKED;
   3315   if (HasState(ui::AX_STATE_COLLAPSED))
   3316     ia_state_ |= STATE_SYSTEM_COLLAPSED;
   3317   if (HasState(ui::AX_STATE_EXPANDED))
   3318     ia_state_ |= STATE_SYSTEM_EXPANDED;
   3319   if (HasState(ui::AX_STATE_FOCUSABLE))
   3320     ia_state_ |= STATE_SYSTEM_FOCUSABLE;
   3321   if (HasState(ui::AX_STATE_HASPOPUP))
   3322     ia_state_ |= STATE_SYSTEM_HASPOPUP;
   3323   if (HasState(ui::AX_STATE_HOVERED))
   3324     ia_state_ |= STATE_SYSTEM_HOTTRACKED;
   3325   if (HasState(ui::AX_STATE_INDETERMINATE))
   3326     ia_state_ |= STATE_SYSTEM_INDETERMINATE;
   3327   if (HasState(ui::AX_STATE_INVISIBLE))
   3328     ia_state_ |= STATE_SYSTEM_INVISIBLE;
   3329   if (HasState(ui::AX_STATE_LINKED))
   3330     ia_state_ |= STATE_SYSTEM_LINKED;
   3331   if (HasState(ui::AX_STATE_MULTISELECTABLE)) {
   3332     ia_state_ |= STATE_SYSTEM_EXTSELECTABLE;
   3333     ia_state_ |= STATE_SYSTEM_MULTISELECTABLE;
   3334   }
   3335   // TODO(ctguil): Support STATE_SYSTEM_EXTSELECTABLE/accSelect.
   3336   if (HasState(ui::AX_STATE_OFFSCREEN))
   3337     ia_state_ |= STATE_SYSTEM_OFFSCREEN;
   3338   if (HasState(ui::AX_STATE_PRESSED))
   3339     ia_state_ |= STATE_SYSTEM_PRESSED;
   3340   if (HasState(ui::AX_STATE_PROTECTED))
   3341     ia_state_ |= STATE_SYSTEM_PROTECTED;
   3342   if (HasState(ui::AX_STATE_REQUIRED))
   3343     ia2_state_ |= IA2_STATE_REQUIRED;
   3344   if (HasState(ui::AX_STATE_SELECTABLE))
   3345     ia_state_ |= STATE_SYSTEM_SELECTABLE;
   3346   if (HasState(ui::AX_STATE_SELECTED))
   3347     ia_state_ |= STATE_SYSTEM_SELECTED;
   3348   if (HasState(ui::AX_STATE_VISITED))
   3349     ia_state_ |= STATE_SYSTEM_TRAVERSED;
   3350   if (!HasState(ui::AX_STATE_ENABLED))
   3351     ia_state_ |= STATE_SYSTEM_UNAVAILABLE;
   3352   if (HasState(ui::AX_STATE_VERTICAL)) {
   3353     ia2_state_ |= IA2_STATE_VERTICAL;
   3354   } else {
   3355     ia2_state_ |= IA2_STATE_HORIZONTAL;
   3356   }
   3357   if (HasState(ui::AX_STATE_VISITED))
   3358     ia_state_ |= STATE_SYSTEM_TRAVERSED;
   3359 
   3360   // WebKit marks everything as readonly unless it's editable text, so if it's
   3361   // not readonly, mark it as editable now. The final computation of the
   3362   // READONLY state for MSAA is below, after the switch.
   3363   if (!HasState(ui::AX_STATE_READ_ONLY))
   3364     ia2_state_ |= IA2_STATE_EDITABLE;
   3365 
   3366   base::string16 invalid;
   3367   if (GetHtmlAttribute("aria-invalid", &invalid))
   3368     ia2_state_ |= IA2_STATE_INVALID_ENTRY;
   3369 
   3370   if (GetBoolAttribute(ui::AX_ATTR_BUTTON_MIXED))
   3371     ia_state_ |= STATE_SYSTEM_MIXED;
   3372 
   3373   if (GetBoolAttribute(ui::AX_ATTR_CAN_SET_VALUE))
   3374     ia2_state_ |= IA2_STATE_EDITABLE;
   3375 
   3376   base::string16 html_tag = GetString16Attribute(
   3377       ui::AX_ATTR_HTML_TAG);
   3378   ia_role_ = 0;
   3379   ia2_role_ = 0;
   3380   switch (GetRole()) {
   3381     case ui::AX_ROLE_ALERT:
   3382       ia_role_ = ROLE_SYSTEM_ALERT;
   3383       break;
   3384     case ui::AX_ROLE_ALERT_DIALOG:
   3385       ia_role_ = ROLE_SYSTEM_DIALOG;
   3386       break;
   3387     case ui::AX_ROLE_APPLICATION:
   3388       ia_role_ = ROLE_SYSTEM_APPLICATION;
   3389       break;
   3390     case ui::AX_ROLE_ARTICLE:
   3391       ia_role_ = ROLE_SYSTEM_GROUPING;
   3392       ia2_role_ = IA2_ROLE_SECTION;
   3393       ia_state_ |= STATE_SYSTEM_READONLY;
   3394       break;
   3395     case ui::AX_ROLE_BUSY_INDICATOR:
   3396       ia_role_ = ROLE_SYSTEM_ANIMATION;
   3397       ia_state_ |= STATE_SYSTEM_READONLY;
   3398       break;
   3399     case ui::AX_ROLE_BUTTON:
   3400       ia_role_ = ROLE_SYSTEM_PUSHBUTTON;
   3401       bool is_aria_pressed_defined;
   3402       bool is_mixed;
   3403       if (GetAriaTristate("aria-pressed", &is_aria_pressed_defined, &is_mixed))
   3404         ia_state_ |= STATE_SYSTEM_PRESSED;
   3405       if (is_aria_pressed_defined)
   3406         ia2_role_ = IA2_ROLE_TOGGLE_BUTTON;
   3407       if (is_mixed)
   3408         ia_state_ |= STATE_SYSTEM_MIXED;
   3409       break;
   3410     case ui::AX_ROLE_CANVAS:
   3411       if (GetBoolAttribute(ui::AX_ATTR_CANVAS_HAS_FALLBACK)) {
   3412         role_name_ = L"canvas";
   3413         ia2_role_ = IA2_ROLE_CANVAS;
   3414       } else {
   3415         ia_role_ = ROLE_SYSTEM_GRAPHIC;
   3416       }
   3417       break;
   3418     case ui::AX_ROLE_CELL:
   3419       ia_role_ = ROLE_SYSTEM_CELL;
   3420       break;
   3421     case ui::AX_ROLE_CHECK_BOX:
   3422       ia_role_ = ROLE_SYSTEM_CHECKBUTTON;
   3423       break;
   3424     case ui::AX_ROLE_COLOR_WELL:
   3425       ia_role_ = ROLE_SYSTEM_CLIENT;
   3426       ia2_role_ = IA2_ROLE_COLOR_CHOOSER;
   3427       break;
   3428     case ui::AX_ROLE_COLUMN:
   3429       ia_role_ = ROLE_SYSTEM_COLUMN;
   3430       ia_state_ |= STATE_SYSTEM_READONLY;
   3431       break;
   3432     case ui::AX_ROLE_COLUMN_HEADER:
   3433       ia_role_ = ROLE_SYSTEM_COLUMNHEADER;
   3434       ia_state_ |= STATE_SYSTEM_READONLY;
   3435       break;
   3436     case ui::AX_ROLE_COMBO_BOX:
   3437       ia_role_ = ROLE_SYSTEM_COMBOBOX;
   3438       break;
   3439     case ui::AX_ROLE_DIV:
   3440       role_name_ = L"div";
   3441       ia2_role_ = IA2_ROLE_SECTION;
   3442       break;
   3443     case ui::AX_ROLE_DEFINITION:
   3444       role_name_ = html_tag;
   3445       ia2_role_ = IA2_ROLE_PARAGRAPH;
   3446       ia_state_ |= STATE_SYSTEM_READONLY;
   3447       break;
   3448     case ui::AX_ROLE_DESCRIPTION_LIST_DETAIL:
   3449       role_name_ = html_tag;
   3450       ia2_role_ = IA2_ROLE_PARAGRAPH;
   3451       ia_state_ |= STATE_SYSTEM_READONLY;
   3452       break;
   3453     case ui::AX_ROLE_DESCRIPTION_LIST_TERM:
   3454       ia_role_ = ROLE_SYSTEM_LISTITEM;
   3455       ia_state_ |= STATE_SYSTEM_READONLY;
   3456       break;
   3457     case ui::AX_ROLE_DIALOG:
   3458       ia_role_ = ROLE_SYSTEM_DIALOG;
   3459       ia_state_ |= STATE_SYSTEM_READONLY;
   3460       break;
   3461     case ui::AX_ROLE_DISCLOSURE_TRIANGLE:
   3462       ia_role_ = ROLE_SYSTEM_OUTLINEBUTTON;
   3463       ia_state_ |= STATE_SYSTEM_READONLY;
   3464       break;
   3465     case ui::AX_ROLE_DOCUMENT:
   3466     case ui::AX_ROLE_ROOT_WEB_AREA:
   3467     case ui::AX_ROLE_WEB_AREA:
   3468       ia_role_ = ROLE_SYSTEM_DOCUMENT;
   3469       ia_state_ |= STATE_SYSTEM_READONLY;
   3470       ia_state_ |= STATE_SYSTEM_FOCUSABLE;
   3471       break;
   3472     case ui::AX_ROLE_EDITABLE_TEXT:
   3473       ia_role_ = ROLE_SYSTEM_TEXT;
   3474       ia2_state_ |= IA2_STATE_SINGLE_LINE;
   3475       ia2_state_ |= IA2_STATE_EDITABLE;
   3476       break;
   3477     case ui::AX_ROLE_FORM:
   3478       role_name_ = L"form";
   3479       ia2_role_ = IA2_ROLE_FORM;
   3480       break;
   3481     case ui::AX_ROLE_FOOTER:
   3482       ia_role_ = IA2_ROLE_FOOTER;
   3483       ia_state_ |= STATE_SYSTEM_READONLY;
   3484       break;
   3485     case ui::AX_ROLE_GRID:
   3486       ia_role_ = ROLE_SYSTEM_TABLE;
   3487       ia_state_ |= STATE_SYSTEM_READONLY;
   3488       break;
   3489     case ui::AX_ROLE_GROUP: {
   3490       base::string16 aria_role = GetString16Attribute(
   3491           ui::AX_ATTR_ROLE);
   3492       if (aria_role == L"group" || html_tag == L"fieldset") {
   3493         ia_role_ = ROLE_SYSTEM_GROUPING;
   3494       } else if (html_tag == L"li") {
   3495         ia_role_ = ROLE_SYSTEM_LISTITEM;
   3496       } else {
   3497         if (html_tag.empty())
   3498           role_name_ = L"div";
   3499         else
   3500           role_name_ = html_tag;
   3501         ia2_role_ = IA2_ROLE_SECTION;
   3502       }
   3503       ia_state_ |= STATE_SYSTEM_READONLY;
   3504       break;
   3505     }
   3506     case ui::AX_ROLE_GROW_AREA:
   3507       ia_role_ = ROLE_SYSTEM_GRIP;
   3508       ia_state_ |= STATE_SYSTEM_READONLY;
   3509       break;
   3510     case ui::AX_ROLE_HEADING:
   3511       role_name_ = html_tag;
   3512       ia2_role_ = IA2_ROLE_HEADING;
   3513       ia_state_ |= STATE_SYSTEM_READONLY;
   3514       break;
   3515     case ui::AX_ROLE_HORIZONTAL_RULE:
   3516       ia_role_ = ROLE_SYSTEM_SEPARATOR;
   3517       break;
   3518     case ui::AX_ROLE_IFRAME:
   3519       ia_role_ = ROLE_SYSTEM_CLIENT;
   3520       ia2_role_ = IA2_ROLE_INTERNAL_FRAME;
   3521       break;
   3522     case ui::AX_ROLE_IMAGE:
   3523       ia_role_ = ROLE_SYSTEM_GRAPHIC;
   3524       ia_state_ |= STATE_SYSTEM_READONLY;
   3525       break;
   3526     case ui::AX_ROLE_IMAGE_MAP:
   3527       role_name_ = html_tag;
   3528       ia2_role_ = IA2_ROLE_IMAGE_MAP;
   3529       ia_state_ |= STATE_SYSTEM_READONLY;
   3530       break;
   3531     case ui::AX_ROLE_IMAGE_MAP_LINK:
   3532       ia_role_ = ROLE_SYSTEM_LINK;
   3533       ia_state_ |= STATE_SYSTEM_LINKED;
   3534       ia_state_ |= STATE_SYSTEM_READONLY;
   3535       break;
   3536     case ui::AX_ROLE_LABEL_TEXT:
   3537       ia_role_ = ROLE_SYSTEM_TEXT;
   3538       ia2_role_ = IA2_ROLE_LABEL;
   3539       break;
   3540     case ui::AX_ROLE_BANNER:
   3541     case ui::AX_ROLE_COMPLEMENTARY:
   3542     case ui::AX_ROLE_CONTENT_INFO:
   3543     case ui::AX_ROLE_MAIN:
   3544     case ui::AX_ROLE_NAVIGATION:
   3545     case ui::AX_ROLE_SEARCH:
   3546       ia_role_ = ROLE_SYSTEM_GROUPING;
   3547       ia2_role_ = IA2_ROLE_SECTION;
   3548       ia_state_ |= STATE_SYSTEM_READONLY;
   3549       break;
   3550     case ui::AX_ROLE_LINK:
   3551       ia_role_ = ROLE_SYSTEM_LINK;
   3552       ia_state_ |= STATE_SYSTEM_LINKED;
   3553       break;
   3554     case ui::AX_ROLE_LIST:
   3555       ia_role_ = ROLE_SYSTEM_LIST;
   3556       ia_state_ |= STATE_SYSTEM_READONLY;
   3557       break;
   3558     case ui::AX_ROLE_LIST_BOX:
   3559       ia_role_ = ROLE_SYSTEM_LIST;
   3560       break;
   3561     case ui::AX_ROLE_LIST_BOX_OPTION:
   3562       ia_role_ = ROLE_SYSTEM_LISTITEM;
   3563       if (ia_state_ & STATE_SYSTEM_SELECTABLE) {
   3564         ia_state_ |= STATE_SYSTEM_FOCUSABLE;
   3565         if (HasState(ui::AX_STATE_FOCUSED))
   3566           ia_state_ |= STATE_SYSTEM_FOCUSED;
   3567       }
   3568       break;
   3569     case ui::AX_ROLE_LIST_ITEM:
   3570       ia_role_ = ROLE_SYSTEM_LISTITEM;
   3571       ia_state_ |= STATE_SYSTEM_READONLY;
   3572       break;
   3573     case ui::AX_ROLE_MATH_ELEMENT:
   3574       ia_role_ = ROLE_SYSTEM_EQUATION;
   3575       ia_state_ |= STATE_SYSTEM_READONLY;
   3576       break;
   3577     case ui::AX_ROLE_MENU:
   3578     case ui::AX_ROLE_MENU_BUTTON:
   3579       ia_role_ = ROLE_SYSTEM_MENUPOPUP;
   3580       break;
   3581     case ui::AX_ROLE_MENU_BAR:
   3582       ia_role_ = ROLE_SYSTEM_MENUBAR;
   3583       break;
   3584     case ui::AX_ROLE_MENU_ITEM:
   3585       ia_role_ = ROLE_SYSTEM_MENUITEM;
   3586       break;
   3587     case ui::AX_ROLE_MENU_LIST_POPUP:
   3588       ia_role_ = ROLE_SYSTEM_CLIENT;
   3589       break;
   3590     case ui::AX_ROLE_MENU_LIST_OPTION:
   3591       ia_role_ = ROLE_SYSTEM_LISTITEM;
   3592       if (ia_state_ & STATE_SYSTEM_SELECTABLE) {
   3593         ia_state_ |= STATE_SYSTEM_FOCUSABLE;
   3594         if (HasState(ui::AX_STATE_FOCUSED))
   3595           ia_state_ |= STATE_SYSTEM_FOCUSED;
   3596       }
   3597       break;
   3598     case ui::AX_ROLE_NOTE:
   3599       ia_role_ = ROLE_SYSTEM_GROUPING;
   3600       ia2_role_ = IA2_ROLE_NOTE;
   3601       ia_state_ |= STATE_SYSTEM_READONLY;
   3602       break;
   3603     case ui::AX_ROLE_OUTLINE:
   3604       ia_role_ = ROLE_SYSTEM_OUTLINE;
   3605       ia_state_ |= STATE_SYSTEM_READONLY;
   3606       break;
   3607     case ui::AX_ROLE_PARAGRAPH:
   3608       role_name_ = L"P";
   3609       ia2_role_ = IA2_ROLE_PARAGRAPH;
   3610       break;
   3611     case ui::AX_ROLE_POP_UP_BUTTON:
   3612       if (html_tag == L"select") {
   3613         ia_role_ = ROLE_SYSTEM_COMBOBOX;
   3614       } else {
   3615         ia_role_ = ROLE_SYSTEM_BUTTONMENU;
   3616       }
   3617       break;
   3618     case ui::AX_ROLE_PROGRESS_INDICATOR:
   3619       ia_role_ = ROLE_SYSTEM_PROGRESSBAR;
   3620       ia_state_ |= STATE_SYSTEM_READONLY;
   3621       break;
   3622     case ui::AX_ROLE_RADIO_BUTTON:
   3623       ia_role_ = ROLE_SYSTEM_RADIOBUTTON;
   3624       break;
   3625     case ui::AX_ROLE_RADIO_GROUP:
   3626       ia_role_ = ROLE_SYSTEM_GROUPING;
   3627       ia2_role_ = IA2_ROLE_SECTION;
   3628       break;
   3629     case ui::AX_ROLE_REGION:
   3630       ia_role_ = ROLE_SYSTEM_GROUPING;
   3631       ia2_role_ = IA2_ROLE_SECTION;
   3632       ia_state_ |= STATE_SYSTEM_READONLY;
   3633       break;
   3634     case ui::AX_ROLE_ROW:
   3635       ia_role_ = ROLE_SYSTEM_ROW;
   3636       ia_state_ |= STATE_SYSTEM_READONLY;
   3637       break;
   3638     case ui::AX_ROLE_ROW_HEADER:
   3639       ia_role_ = ROLE_SYSTEM_ROWHEADER;
   3640       ia_state_ |= STATE_SYSTEM_READONLY;
   3641       break;
   3642     case ui::AX_ROLE_RULER:
   3643       ia_role_ = ROLE_SYSTEM_CLIENT;
   3644       ia2_role_ = IA2_ROLE_RULER;
   3645       ia_state_ |= STATE_SYSTEM_READONLY;
   3646       break;
   3647     case ui::AX_ROLE_SCROLL_AREA:
   3648       ia_role_ = ROLE_SYSTEM_CLIENT;
   3649       ia2_role_ = IA2_ROLE_SCROLL_PANE;
   3650       ia_state_ |= STATE_SYSTEM_READONLY;
   3651       ia2_state_ &= ~(IA2_STATE_EDITABLE);
   3652       break;
   3653     case ui::AX_ROLE_SCROLL_BAR:
   3654       ia_role_ = ROLE_SYSTEM_SCROLLBAR;
   3655       break;
   3656     case ui::AX_ROLE_SLIDER:
   3657       ia_role_ = ROLE_SYSTEM_SLIDER;
   3658       break;
   3659     case ui::AX_ROLE_SPIN_BUTTON:
   3660       ia_role_ = ROLE_SYSTEM_SPINBUTTON;
   3661       break;
   3662     case ui::AX_ROLE_SPIN_BUTTON_PART:
   3663       ia_role_ = ROLE_SYSTEM_PUSHBUTTON;
   3664       break;
   3665     case ui::AX_ROLE_SPLIT_GROUP:
   3666       ia_role_ = ROLE_SYSTEM_CLIENT;
   3667       ia2_role_ = IA2_ROLE_SPLIT_PANE;
   3668       ia_state_ |= STATE_SYSTEM_READONLY;
   3669       break;
   3670     case ui::AX_ROLE_ANNOTATION:
   3671     case ui::AX_ROLE_LIST_MARKER:
   3672     case ui::AX_ROLE_STATIC_TEXT:
   3673       ia_role_ = ROLE_SYSTEM_STATICTEXT;
   3674       break;
   3675     case ui::AX_ROLE_STATUS:
   3676       ia_role_ = ROLE_SYSTEM_STATUSBAR;
   3677       ia_state_ |= STATE_SYSTEM_READONLY;
   3678       break;
   3679     case ui::AX_ROLE_SPLITTER:
   3680       ia_role_ = ROLE_SYSTEM_SEPARATOR;
   3681       break;
   3682     case ui::AX_ROLE_SVG_ROOT:
   3683       ia_role_ = ROLE_SYSTEM_GRAPHIC;
   3684       break;
   3685     case ui::AX_ROLE_TAB:
   3686       ia_role_ = ROLE_SYSTEM_PAGETAB;
   3687       break;
   3688     case ui::AX_ROLE_TABLE: {
   3689       base::string16 aria_role = GetString16Attribute(
   3690           ui::AX_ATTR_ROLE);
   3691       if (aria_role == L"treegrid") {
   3692         ia_role_ = ROLE_SYSTEM_OUTLINE;
   3693       } else {
   3694         ia_role_ = ROLE_SYSTEM_TABLE;
   3695         ia_state_ |= STATE_SYSTEM_READONLY;
   3696       }
   3697       break;
   3698     }
   3699     case ui::AX_ROLE_TABLE_HEADER_CONTAINER:
   3700       ia_role_ = ROLE_SYSTEM_GROUPING;
   3701       ia2_role_ = IA2_ROLE_SECTION;
   3702       ia_state_ |= STATE_SYSTEM_READONLY;
   3703       break;
   3704     case ui::AX_ROLE_TAB_LIST:
   3705       ia_role_ = ROLE_SYSTEM_PAGETABLIST;
   3706       break;
   3707     case ui::AX_ROLE_TAB_PANEL:
   3708       ia_role_ = ROLE_SYSTEM_PROPERTYPAGE;
   3709       break;
   3710     case ui::AX_ROLE_TOGGLE_BUTTON:
   3711       ia_role_ = ROLE_SYSTEM_PUSHBUTTON;
   3712       ia2_role_ = IA2_ROLE_TOGGLE_BUTTON;
   3713       break;
   3714     case ui::AX_ROLE_TEXT_AREA:
   3715       ia_role_ = ROLE_SYSTEM_TEXT;
   3716       ia2_state_ |= IA2_STATE_MULTI_LINE;
   3717       ia2_state_ |= IA2_STATE_EDITABLE;
   3718       ia2_state_ |= IA2_STATE_SELECTABLE_TEXT;
   3719       break;
   3720     case ui::AX_ROLE_TEXT_FIELD:
   3721       ia_role_ = ROLE_SYSTEM_TEXT;
   3722       ia2_state_ |= IA2_STATE_SINGLE_LINE;
   3723       ia2_state_ |= IA2_STATE_EDITABLE;
   3724       ia2_state_ |= IA2_STATE_SELECTABLE_TEXT;
   3725       break;
   3726     case ui::AX_ROLE_TIMER:
   3727       ia_role_ = ROLE_SYSTEM_CLOCK;
   3728       ia_state_ |= STATE_SYSTEM_READONLY;
   3729       break;
   3730     case ui::AX_ROLE_TOOLBAR:
   3731       ia_role_ = ROLE_SYSTEM_TOOLBAR;
   3732       ia_state_ |= STATE_SYSTEM_READONLY;
   3733       break;
   3734     case ui::AX_ROLE_TOOLTIP:
   3735       ia_role_ = ROLE_SYSTEM_TOOLTIP;
   3736       ia_state_ |= STATE_SYSTEM_READONLY;
   3737       break;
   3738     case ui::AX_ROLE_TREE:
   3739       ia_role_ = ROLE_SYSTEM_OUTLINE;
   3740       ia_state_ |= STATE_SYSTEM_READONLY;
   3741       break;
   3742     case ui::AX_ROLE_TREE_GRID:
   3743       ia_role_ = ROLE_SYSTEM_OUTLINE;
   3744       ia_state_ |= STATE_SYSTEM_READONLY;
   3745       break;
   3746     case ui::AX_ROLE_TREE_ITEM:
   3747       ia_role_ = ROLE_SYSTEM_OUTLINEITEM;
   3748       ia_state_ |= STATE_SYSTEM_READONLY;
   3749       break;
   3750     case ui::AX_ROLE_WINDOW:
   3751       ia_role_ = ROLE_SYSTEM_WINDOW;
   3752       break;
   3753 
   3754     // TODO(dmazzoni): figure out the proper MSAA role for all of these.
   3755     case ui::AX_ROLE_BROWSER:
   3756     case ui::AX_ROLE_DIRECTORY:
   3757     case ui::AX_ROLE_DRAWER:
   3758     case ui::AX_ROLE_HELP_TAG:
   3759     case ui::AX_ROLE_IGNORED:
   3760     case ui::AX_ROLE_INCREMENTOR:
   3761     case ui::AX_ROLE_LOG:
   3762     case ui::AX_ROLE_MARQUEE:
   3763     case ui::AX_ROLE_MATTE:
   3764     case ui::AX_ROLE_PRESENTATIONAL:
   3765     case ui::AX_ROLE_RULER_MARKER:
   3766     case ui::AX_ROLE_SHEET:
   3767     case ui::AX_ROLE_SLIDER_THUMB:
   3768     case ui::AX_ROLE_SYSTEM_WIDE:
   3769     case ui::AX_ROLE_VALUE_INDICATOR:
   3770     default:
   3771       ia_role_ = ROLE_SYSTEM_CLIENT;
   3772       break;
   3773   }
   3774 
   3775   // Compute the final value of READONLY for MSAA.
   3776   //
   3777   // We always set the READONLY state for elements that have the
   3778   // aria-readonly attribute and for a few roles (in the switch above).
   3779   // We clear the READONLY state on focusable controls and on a document.
   3780   // Everything else, the majority of objects, do not have this state set.
   3781   if (HasState(ui::AX_STATE_FOCUSABLE) &&
   3782       ia_role_ != ROLE_SYSTEM_DOCUMENT) {
   3783     ia_state_ &= ~(STATE_SYSTEM_READONLY);
   3784   }
   3785   if (!HasState(ui::AX_STATE_READ_ONLY))
   3786     ia_state_ &= ~(STATE_SYSTEM_READONLY);
   3787   if (GetBoolAttribute(ui::AX_ATTR_ARIA_READONLY))
   3788     ia_state_ |= STATE_SYSTEM_READONLY;
   3789 
   3790   // The role should always be set.
   3791   DCHECK(!role_name_.empty() || ia_role_);
   3792 
   3793   // If we didn't explicitly set the IAccessible2 role, make it the same
   3794   // as the MSAA role.
   3795   if (!ia2_role_)
   3796     ia2_role_ = ia_role_;
   3797 }
   3798 
   3799 }  // namespace content
   3800