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/base/accessibility/accessible_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 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->GetFromRendererID(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->GetFromRendererID(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       AccessibilityNodeData::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       AccessibilityNodeData::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       AccessibilityNodeData::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       AccessibilityNodeData::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(AccessibilityNodeData::ATTR_TITLE_UI_ELEMENT,
    472                                 &title_elem_id)) {
    473       BrowserAccessibility* title_elem =
    474           manager()->GetFromRendererID(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(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 = parent()->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 
    503     // |parent| can only be NULL if the manager was created before the parent
    504     // IAccessible was known and it wasn't subsequently set before a client
    505     // requested it. Crash hard if this happens so that we get crash reports.
    506     CHECK(parent_obj);
    507   }
    508 
    509   parent_obj->AddRef();
    510   *disp_parent = parent_obj;
    511   return S_OK;
    512 }
    513 
    514 STDMETHODIMP BrowserAccessibilityWin::get_accRole(VARIANT var_id,
    515                                                   VARIANT* role) {
    516   if (!instance_active())
    517     return E_FAIL;
    518 
    519   if (!role)
    520     return E_INVALIDARG;
    521 
    522   BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
    523   if (!target)
    524     return E_INVALIDARG;
    525 
    526   if (!target->role_name_.empty()) {
    527     role->vt = VT_BSTR;
    528     role->bstrVal = SysAllocString(target->role_name_.c_str());
    529   } else {
    530     role->vt = VT_I4;
    531     role->lVal = target->ia_role_;
    532   }
    533   return S_OK;
    534 }
    535 
    536 STDMETHODIMP BrowserAccessibilityWin::get_accState(VARIANT var_id,
    537                                                    VARIANT* state) {
    538   if (!instance_active())
    539     return E_FAIL;
    540 
    541   if (!state)
    542     return E_INVALIDARG;
    543 
    544   BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
    545   if (!target)
    546     return E_INVALIDARG;
    547 
    548   state->vt = VT_I4;
    549   state->lVal = target->ia_state_;
    550   if (manager()->GetFocus(NULL) == this)
    551     state->lVal |= STATE_SYSTEM_FOCUSED;
    552 
    553   return S_OK;
    554 }
    555 
    556 STDMETHODIMP BrowserAccessibilityWin::get_accValue(VARIANT var_id,
    557                                                    BSTR* value) {
    558   if (!instance_active())
    559     return E_FAIL;
    560 
    561   if (!value)
    562     return E_INVALIDARG;
    563 
    564   BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
    565   if (!target)
    566     return E_INVALIDARG;
    567 
    568   if (target->ia_role() == ROLE_SYSTEM_PROGRESSBAR ||
    569       target->ia_role() == ROLE_SYSTEM_SCROLLBAR ||
    570       target->ia_role() == ROLE_SYSTEM_SLIDER) {
    571     base::string16 value_text = target->GetValueText();
    572     *value = SysAllocString(value_text.c_str());
    573     DCHECK(*value);
    574     return S_OK;
    575   }
    576 
    577   // Expose color well value.
    578   if (target->ia2_role() == IA2_ROLE_COLOR_CHOOSER) {
    579     int r = target->GetIntAttribute(
    580         AccessibilityNodeData::ATTR_COLOR_VALUE_RED);
    581     int g = target->GetIntAttribute(
    582         AccessibilityNodeData::ATTR_COLOR_VALUE_GREEN);
    583     int b = target->GetIntAttribute(
    584         AccessibilityNodeData::ATTR_COLOR_VALUE_BLUE);
    585     base::string16 value_text;
    586     value_text = base::IntToString16((r * 100) / 255) + L"% red " +
    587                  base::IntToString16((g * 100) / 255) + L"% green " +
    588                  base::IntToString16((b * 100) / 255) + L"% blue";
    589     *value = SysAllocString(value_text.c_str());
    590     DCHECK(*value);
    591     return S_OK;
    592   }
    593 
    594   *value = SysAllocString(UTF8ToUTF16(target->value()).c_str());
    595   DCHECK(*value);
    596   return S_OK;
    597 }
    598 
    599 STDMETHODIMP BrowserAccessibilityWin::get_accHelpTopic(BSTR* help_file,
    600                                                        VARIANT var_id,
    601                                                        LONG* topic_id) {
    602   return E_NOTIMPL;
    603 }
    604 
    605 STDMETHODIMP BrowserAccessibilityWin::get_accSelection(VARIANT* selected) {
    606   if (!instance_active())
    607     return E_FAIL;
    608 
    609   if (blink_role() != blink::WebAXRoleListBox)
    610     return E_NOTIMPL;
    611 
    612   unsigned long selected_count = 0;
    613   for (size_t i = 0; i < children().size(); ++i) {
    614     if (children()[i]->HasState(blink::WebAXStateSelected))
    615       ++selected_count;
    616   }
    617 
    618   if (selected_count == 0) {
    619     selected->vt = VT_EMPTY;
    620     return S_OK;
    621   }
    622 
    623   if (selected_count == 1) {
    624     for (size_t i = 0; i < children().size(); ++i) {
    625       if (children()[i]->HasState(blink::WebAXStateSelected)) {
    626         selected->vt = VT_DISPATCH;
    627         selected->pdispVal =
    628             children()[i]->ToBrowserAccessibilityWin()->NewReference();
    629         return S_OK;
    630       }
    631     }
    632   }
    633 
    634   // Multiple items are selected.
    635   base::win::EnumVariant* enum_variant =
    636       new base::win::EnumVariant(selected_count);
    637   enum_variant->AddRef();
    638   unsigned long index = 0;
    639   for (size_t i = 0; i < children().size(); ++i) {
    640     if (children()[i]->HasState(blink::WebAXStateSelected)) {
    641       enum_variant->ItemAt(index)->vt = VT_DISPATCH;
    642       enum_variant->ItemAt(index)->pdispVal =
    643         children()[i]->ToBrowserAccessibilityWin()->NewReference();
    644       ++index;
    645     }
    646   }
    647   selected->vt = VT_UNKNOWN;
    648   selected->punkVal = static_cast<IUnknown*>(
    649       static_cast<base::win::IUnknownImpl*>(enum_variant));
    650   return S_OK;
    651 }
    652 
    653 STDMETHODIMP BrowserAccessibilityWin::accSelect(
    654     LONG flags_sel, VARIANT var_id) {
    655   if (!instance_active())
    656     return E_FAIL;
    657 
    658   if (flags_sel & SELFLAG_TAKEFOCUS) {
    659     manager()->SetFocus(this, true);
    660     return S_OK;
    661   }
    662 
    663   return S_FALSE;
    664 }
    665 
    666 //
    667 // IAccessible2 methods.
    668 //
    669 
    670 STDMETHODIMP BrowserAccessibilityWin::role(LONG* role) {
    671   if (!instance_active())
    672     return E_FAIL;
    673 
    674   if (!role)
    675     return E_INVALIDARG;
    676 
    677   *role = ia2_role_;
    678 
    679   return S_OK;
    680 }
    681 
    682 STDMETHODIMP BrowserAccessibilityWin::get_attributes(BSTR* attributes) {
    683   if (!instance_active())
    684     return E_FAIL;
    685 
    686   if (!attributes)
    687     return E_INVALIDARG;
    688 
    689   // The iaccessible2 attributes are a set of key-value pairs
    690   // separated by semicolons, with a colon between the key and the value.
    691   base::string16 str;
    692   for (unsigned int i = 0; i < ia2_attributes_.size(); ++i) {
    693     if (i != 0)
    694       str += L';';
    695     str += ia2_attributes_[i];
    696   }
    697 
    698   if (str.empty())
    699     return S_FALSE;
    700 
    701   *attributes = SysAllocString(str.c_str());
    702   DCHECK(*attributes);
    703   return S_OK;
    704 }
    705 
    706 STDMETHODIMP BrowserAccessibilityWin::get_states(AccessibleStates* states) {
    707   if (!instance_active())
    708     return E_FAIL;
    709 
    710   if (!states)
    711     return E_INVALIDARG;
    712 
    713   *states = ia2_state_;
    714 
    715   return S_OK;
    716 }
    717 
    718 STDMETHODIMP BrowserAccessibilityWin::get_uniqueID(LONG* unique_id) {
    719   if (!instance_active())
    720     return E_FAIL;
    721 
    722   if (!unique_id)
    723     return E_INVALIDARG;
    724 
    725   *unique_id = unique_id_win_;
    726   return S_OK;
    727 }
    728 
    729 STDMETHODIMP BrowserAccessibilityWin::get_windowHandle(HWND* window_handle) {
    730   if (!instance_active())
    731     return E_FAIL;
    732 
    733   if (!window_handle)
    734     return E_INVALIDARG;
    735 
    736   *window_handle = manager()->ToBrowserAccessibilityManagerWin()->parent_hwnd();
    737   return S_OK;
    738 }
    739 
    740 STDMETHODIMP BrowserAccessibilityWin::get_indexInParent(LONG* index_in_parent) {
    741   if (!instance_active())
    742     return E_FAIL;
    743 
    744   if (!index_in_parent)
    745     return E_INVALIDARG;
    746 
    747   *index_in_parent = this->index_in_parent();
    748   return S_OK;
    749 }
    750 
    751 STDMETHODIMP BrowserAccessibilityWin::get_nRelations(LONG* n_relations) {
    752   if (!instance_active())
    753     return E_FAIL;
    754 
    755   if (!n_relations)
    756     return E_INVALIDARG;
    757 
    758   *n_relations = relations_.size();
    759   return S_OK;
    760 }
    761 
    762 STDMETHODIMP BrowserAccessibilityWin::get_relation(
    763     LONG relation_index,
    764     IAccessibleRelation** relation) {
    765   if (!instance_active())
    766     return E_FAIL;
    767 
    768   if (relation_index < 0 ||
    769       relation_index >= static_cast<long>(relations_.size())) {
    770     return E_INVALIDARG;
    771   }
    772 
    773   if (!relation)
    774     return E_INVALIDARG;
    775 
    776   relations_[relation_index]->AddRef();
    777   *relation = relations_[relation_index];
    778   return S_OK;
    779 }
    780 
    781 STDMETHODIMP BrowserAccessibilityWin::get_relations(
    782     LONG max_relations,
    783     IAccessibleRelation** relations,
    784     LONG* n_relations) {
    785   if (!instance_active())
    786     return E_FAIL;
    787 
    788   if (!relations || !n_relations)
    789     return E_INVALIDARG;
    790 
    791   long count = static_cast<long>(relations_.size());
    792   *n_relations = count;
    793   if (count == 0)
    794     return S_FALSE;
    795 
    796   for (long i = 0; i < count; ++i) {
    797     relations_[i]->AddRef();
    798     relations[i] = relations_[i];
    799   }
    800 
    801   return S_OK;
    802 }
    803 
    804 STDMETHODIMP BrowserAccessibilityWin::scrollTo(enum IA2ScrollType scroll_type) {
    805   if (!instance_active())
    806     return E_FAIL;
    807 
    808   gfx::Rect r = location();
    809   switch(scroll_type) {
    810     case IA2_SCROLL_TYPE_TOP_LEFT:
    811       manager()->ScrollToMakeVisible(*this, gfx::Rect(r.x(), r.y(), 0, 0));
    812       break;
    813     case IA2_SCROLL_TYPE_BOTTOM_RIGHT:
    814       manager()->ScrollToMakeVisible(
    815           *this, gfx::Rect(r.right(), r.bottom(), 0, 0));
    816       break;
    817     case IA2_SCROLL_TYPE_TOP_EDGE:
    818       manager()->ScrollToMakeVisible(
    819           *this, gfx::Rect(r.x(), r.y(), r.width(), 0));
    820       break;
    821     case IA2_SCROLL_TYPE_BOTTOM_EDGE:
    822       manager()->ScrollToMakeVisible(
    823           *this, gfx::Rect(r.x(), r.bottom(), r.width(), 0));
    824     break;
    825     case IA2_SCROLL_TYPE_LEFT_EDGE:
    826       manager()->ScrollToMakeVisible(
    827           *this, gfx::Rect(r.x(), r.y(), 0, r.height()));
    828       break;
    829     case IA2_SCROLL_TYPE_RIGHT_EDGE:
    830       manager()->ScrollToMakeVisible(
    831           *this, gfx::Rect(r.right(), r.y(), 0, r.height()));
    832       break;
    833     case IA2_SCROLL_TYPE_ANYWHERE:
    834     default:
    835       manager()->ScrollToMakeVisible(*this, r);
    836       break;
    837   }
    838 
    839   manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
    840 
    841   return S_OK;
    842 }
    843 
    844 STDMETHODIMP BrowserAccessibilityWin::scrollToPoint(
    845     enum IA2CoordinateType coordinate_type,
    846     LONG x,
    847     LONG y) {
    848   if (!instance_active())
    849     return E_FAIL;
    850 
    851   gfx::Point scroll_to(x, y);
    852 
    853   if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) {
    854     scroll_to -= manager()->GetViewBounds().OffsetFromOrigin();
    855   } else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) {
    856     if (parent())
    857       scroll_to += parent()->location().OffsetFromOrigin();
    858   } else {
    859     return E_INVALIDARG;
    860   }
    861 
    862   manager()->ScrollToPoint(*this, scroll_to);
    863   manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
    864 
    865   return S_OK;
    866 }
    867 
    868 STDMETHODIMP BrowserAccessibilityWin::get_groupPosition(
    869     LONG* group_level,
    870     LONG* similar_items_in_group,
    871     LONG* position_in_group) {
    872   if (!instance_active())
    873     return E_FAIL;
    874 
    875   if (!group_level || !similar_items_in_group || !position_in_group)
    876     return E_INVALIDARG;
    877 
    878   if (blink_role() == blink::WebAXRoleListBoxOption &&
    879       parent() &&
    880       parent()->role() == blink::WebAXRoleListBox) {
    881     *group_level = 0;
    882     *similar_items_in_group = parent()->PlatformChildCount();
    883     *position_in_group = index_in_parent() + 1;
    884     return S_OK;
    885   }
    886 
    887   return E_NOTIMPL;
    888 }
    889 
    890 //
    891 // IAccessibleApplication methods.
    892 //
    893 
    894 STDMETHODIMP BrowserAccessibilityWin::get_appName(BSTR* app_name) {
    895   // No need to check |instance_active()| because this interface is
    896   // global, and doesn't depend on any local state.
    897 
    898   if (!app_name)
    899     return E_INVALIDARG;
    900 
    901   // GetProduct() returns a string like "Chrome/aa.bb.cc.dd", split out
    902   // the part before the "/".
    903   std::vector<std::string> product_components;
    904   base::SplitString(GetContentClient()->GetProduct(), '/', &product_components);
    905   DCHECK_EQ(2U, product_components.size());
    906   if (product_components.size() != 2)
    907     return E_FAIL;
    908   *app_name = SysAllocString(UTF8ToUTF16(product_components[0]).c_str());
    909   DCHECK(*app_name);
    910   return *app_name ? S_OK : E_FAIL;
    911 }
    912 
    913 STDMETHODIMP BrowserAccessibilityWin::get_appVersion(BSTR* app_version) {
    914   // No need to check |instance_active()| because this interface is
    915   // global, and doesn't depend on any local state.
    916 
    917   if (!app_version)
    918     return E_INVALIDARG;
    919 
    920   // GetProduct() returns a string like "Chrome/aa.bb.cc.dd", split out
    921   // the part after the "/".
    922   std::vector<std::string> product_components;
    923   base::SplitString(GetContentClient()->GetProduct(), '/', &product_components);
    924   DCHECK_EQ(2U, product_components.size());
    925   if (product_components.size() != 2)
    926     return E_FAIL;
    927   *app_version = SysAllocString(UTF8ToUTF16(product_components[1]).c_str());
    928   DCHECK(*app_version);
    929   return *app_version ? S_OK : E_FAIL;
    930 }
    931 
    932 STDMETHODIMP BrowserAccessibilityWin::get_toolkitName(BSTR* toolkit_name) {
    933   // No need to check |instance_active()| because this interface is
    934   // global, and doesn't depend on any local state.
    935 
    936   if (!toolkit_name)
    937     return E_INVALIDARG;
    938 
    939   // This is hard-coded; all products based on the Chromium engine
    940   // will have the same toolkit name, so that assistive technology can
    941   // detect any Chrome-based product.
    942   *toolkit_name = SysAllocString(L"Chrome");
    943   DCHECK(*toolkit_name);
    944   return *toolkit_name ? S_OK : E_FAIL;
    945 }
    946 
    947 STDMETHODIMP BrowserAccessibilityWin::get_toolkitVersion(
    948     BSTR* toolkit_version) {
    949   // No need to check |instance_active()| because this interface is
    950   // global, and doesn't depend on any local state.
    951 
    952   if (!toolkit_version)
    953     return E_INVALIDARG;
    954 
    955   std::string user_agent = GetContentClient()->GetUserAgent();
    956   *toolkit_version = SysAllocString(UTF8ToUTF16(user_agent).c_str());
    957   DCHECK(*toolkit_version);
    958   return *toolkit_version ? S_OK : E_FAIL;
    959 }
    960 
    961 //
    962 // IAccessibleImage methods.
    963 //
    964 
    965 STDMETHODIMP BrowserAccessibilityWin::get_description(BSTR* desc) {
    966   if (!instance_active())
    967     return E_FAIL;
    968 
    969   if (!desc)
    970     return E_INVALIDARG;
    971 
    972   return GetStringAttributeAsBstr(
    973       AccessibilityNodeData::ATTR_DESCRIPTION, desc);
    974 }
    975 
    976 STDMETHODIMP BrowserAccessibilityWin::get_imagePosition(
    977     enum IA2CoordinateType coordinate_type,
    978     LONG* x,
    979     LONG* y) {
    980   if (!instance_active())
    981     return E_FAIL;
    982 
    983   if (!x || !y)
    984     return E_INVALIDARG;
    985 
    986   if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) {
    987     HWND parent_hwnd =
    988         manager()->ToBrowserAccessibilityManagerWin()->parent_hwnd();
    989     POINT top_left = {0, 0};
    990     ::ClientToScreen(parent_hwnd, &top_left);
    991     *x = location().x() + top_left.x;
    992     *y = location().y() + top_left.y;
    993   } else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) {
    994     *x = location().x();
    995     *y = location().y();
    996     if (parent()) {
    997       *x -= parent()->location().x();
    998       *y -= parent()->location().y();
    999     }
   1000   } else {
   1001     return E_INVALIDARG;
   1002   }
   1003 
   1004   return S_OK;
   1005 }
   1006 
   1007 STDMETHODIMP BrowserAccessibilityWin::get_imageSize(LONG* height, LONG* width) {
   1008   if (!instance_active())
   1009     return E_FAIL;
   1010 
   1011   if (!height || !width)
   1012     return E_INVALIDARG;
   1013 
   1014   *height = location().height();
   1015   *width = location().width();
   1016   return S_OK;
   1017 }
   1018 
   1019 //
   1020 // IAccessibleTable methods.
   1021 //
   1022 
   1023 STDMETHODIMP BrowserAccessibilityWin::get_accessibleAt(
   1024     long row,
   1025     long column,
   1026     IUnknown** accessible) {
   1027   if (!instance_active())
   1028     return E_FAIL;
   1029 
   1030   if (!accessible)
   1031     return E_INVALIDARG;
   1032 
   1033   int columns;
   1034   int rows;
   1035   if (!GetIntAttribute(
   1036           AccessibilityNodeData::ATTR_TABLE_COLUMN_COUNT, &columns) ||
   1037       !GetIntAttribute(
   1038           AccessibilityNodeData::ATTR_TABLE_ROW_COUNT, &rows) ||
   1039       columns <= 0 ||
   1040       rows <= 0) {
   1041     return S_FALSE;
   1042   }
   1043 
   1044   if (row < 0 || row >= rows || column < 0 || column >= columns)
   1045     return E_INVALIDARG;
   1046 
   1047   const std::vector<int32>& cell_ids = GetIntListAttribute(
   1048       AccessibilityNodeData::ATTR_CELL_IDS);
   1049   DCHECK_EQ(columns * rows, static_cast<int>(cell_ids.size()));
   1050 
   1051   int cell_id = cell_ids[row * columns + column];
   1052   BrowserAccessibilityWin* cell = GetFromRendererID(cell_id);
   1053   if (cell) {
   1054     *accessible = static_cast<IAccessible*>(cell->NewReference());
   1055     return S_OK;
   1056   }
   1057 
   1058   *accessible = NULL;
   1059   return E_INVALIDARG;
   1060 }
   1061 
   1062 STDMETHODIMP BrowserAccessibilityWin::get_caption(IUnknown** accessible) {
   1063   if (!instance_active())
   1064     return E_FAIL;
   1065 
   1066   if (!accessible)
   1067     return E_INVALIDARG;
   1068 
   1069   // TODO(dmazzoni): implement
   1070   return S_FALSE;
   1071 }
   1072 
   1073 STDMETHODIMP BrowserAccessibilityWin::get_childIndex(long row,
   1074                                                      long column,
   1075                                                      long* cell_index) {
   1076   if (!instance_active())
   1077     return E_FAIL;
   1078 
   1079   if (!cell_index)
   1080     return E_INVALIDARG;
   1081 
   1082   int columns;
   1083   int rows;
   1084   if (!GetIntAttribute(
   1085           AccessibilityNodeData::ATTR_TABLE_COLUMN_COUNT, &columns) ||
   1086       !GetIntAttribute(
   1087           AccessibilityNodeData::ATTR_TABLE_ROW_COUNT, &rows) ||
   1088       columns <= 0 ||
   1089       rows <= 0) {
   1090     return S_FALSE;
   1091   }
   1092 
   1093   if (row < 0 || row >= rows || column < 0 || column >= columns)
   1094     return E_INVALIDARG;
   1095 
   1096   const std::vector<int32>& cell_ids = GetIntListAttribute(
   1097       AccessibilityNodeData::ATTR_CELL_IDS);
   1098   const std::vector<int32>& unique_cell_ids = GetIntListAttribute(
   1099       AccessibilityNodeData::ATTR_UNIQUE_CELL_IDS);
   1100   DCHECK_EQ(columns * rows, static_cast<int>(cell_ids.size()));
   1101   int cell_id = cell_ids[row * columns + column];
   1102   for (size_t i = 0; i < unique_cell_ids.size(); ++i) {
   1103     if (unique_cell_ids[i] == cell_id) {
   1104       *cell_index = (long)i;
   1105       return S_OK;
   1106     }
   1107   }
   1108 
   1109   return S_FALSE;
   1110 }
   1111 
   1112 STDMETHODIMP BrowserAccessibilityWin::get_columnDescription(long column,
   1113                                                             BSTR* description) {
   1114   if (!instance_active())
   1115     return E_FAIL;
   1116 
   1117   if (!description)
   1118     return E_INVALIDARG;
   1119 
   1120   int columns;
   1121   int rows;
   1122   if (!GetIntAttribute(
   1123           AccessibilityNodeData::ATTR_TABLE_COLUMN_COUNT, &columns) ||
   1124       !GetIntAttribute(AccessibilityNodeData::ATTR_TABLE_ROW_COUNT, &rows) ||
   1125       columns <= 0 ||
   1126       rows <= 0) {
   1127     return S_FALSE;
   1128   }
   1129 
   1130   if (column < 0 || column >= columns)
   1131     return E_INVALIDARG;
   1132 
   1133   const std::vector<int32>& cell_ids = GetIntListAttribute(
   1134       AccessibilityNodeData::ATTR_CELL_IDS);
   1135   for (int i = 0; i < rows; ++i) {
   1136     int cell_id = cell_ids[i * columns + column];
   1137     BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>(
   1138         manager()->GetFromRendererID(cell_id));
   1139     if (cell && cell->blink_role() == blink::WebAXRoleColumnHeader) {
   1140       base::string16 cell_name = cell->GetString16Attribute(
   1141           AccessibilityNodeData::ATTR_NAME);
   1142       if (cell_name.size() > 0) {
   1143         *description = SysAllocString(cell_name.c_str());
   1144         return S_OK;
   1145       }
   1146 
   1147       return cell->GetStringAttributeAsBstr(
   1148           AccessibilityNodeData::ATTR_DESCRIPTION, description);
   1149     }
   1150   }
   1151 
   1152   return S_FALSE;
   1153 }
   1154 
   1155 STDMETHODIMP BrowserAccessibilityWin::get_columnExtentAt(
   1156     long row,
   1157     long column,
   1158     long* n_columns_spanned) {
   1159   if (!instance_active())
   1160     return E_FAIL;
   1161 
   1162   if (!n_columns_spanned)
   1163     return E_INVALIDARG;
   1164 
   1165   int columns;
   1166   int rows;
   1167   if (!GetIntAttribute(
   1168           AccessibilityNodeData::ATTR_TABLE_COLUMN_COUNT, &columns) ||
   1169       !GetIntAttribute(AccessibilityNodeData::ATTR_TABLE_ROW_COUNT, &rows) ||
   1170       columns <= 0 ||
   1171       rows <= 0) {
   1172     return S_FALSE;
   1173   }
   1174 
   1175   if (row < 0 || row >= rows || column < 0 || column >= columns)
   1176     return E_INVALIDARG;
   1177 
   1178   const std::vector<int32>& cell_ids = GetIntListAttribute(
   1179       AccessibilityNodeData::ATTR_CELL_IDS);
   1180   int cell_id = cell_ids[row * columns + column];
   1181   BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>(
   1182       manager()->GetFromRendererID(cell_id));
   1183   int colspan;
   1184   if (cell &&
   1185       cell->GetIntAttribute(
   1186           AccessibilityNodeData::ATTR_TABLE_CELL_COLUMN_SPAN, &colspan) &&
   1187       colspan >= 1) {
   1188     *n_columns_spanned = colspan;
   1189     return S_OK;
   1190   }
   1191 
   1192   return S_FALSE;
   1193 }
   1194 
   1195 STDMETHODIMP BrowserAccessibilityWin::get_columnHeader(
   1196     IAccessibleTable** accessible_table,
   1197     long* starting_row_index) {
   1198   // TODO(dmazzoni): implement
   1199   return E_NOTIMPL;
   1200 }
   1201 
   1202 STDMETHODIMP BrowserAccessibilityWin::get_columnIndex(long cell_index,
   1203                                                       long* column_index) {
   1204   if (!instance_active())
   1205     return E_FAIL;
   1206 
   1207   if (!column_index)
   1208     return E_INVALIDARG;
   1209 
   1210   const std::vector<int32>& unique_cell_ids = GetIntListAttribute(
   1211       AccessibilityNodeData::ATTR_UNIQUE_CELL_IDS);
   1212   int cell_id_count = static_cast<int>(unique_cell_ids.size());
   1213   if (cell_index < 0)
   1214     return E_INVALIDARG;
   1215   if (cell_index >= cell_id_count)
   1216     return S_FALSE;
   1217 
   1218   int cell_id = unique_cell_ids[cell_index];
   1219   BrowserAccessibilityWin* cell =
   1220       manager()->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin();
   1221   int col_index;
   1222   if (cell &&
   1223       cell->GetIntAttribute(
   1224           AccessibilityNodeData::ATTR_TABLE_CELL_COLUMN_INDEX, &col_index)) {
   1225     *column_index = col_index;
   1226     return S_OK;
   1227   }
   1228 
   1229   return S_FALSE;
   1230 }
   1231 
   1232 STDMETHODIMP BrowserAccessibilityWin::get_nColumns(long* column_count) {
   1233   if (!instance_active())
   1234     return E_FAIL;
   1235 
   1236   if (!column_count)
   1237     return E_INVALIDARG;
   1238 
   1239   int columns;
   1240   if (GetIntAttribute(
   1241           AccessibilityNodeData::ATTR_TABLE_COLUMN_COUNT, &columns)) {
   1242     *column_count = columns;
   1243     return S_OK;
   1244   }
   1245 
   1246   return S_FALSE;
   1247 }
   1248 
   1249 STDMETHODIMP BrowserAccessibilityWin::get_nRows(long* row_count) {
   1250   if (!instance_active())
   1251     return E_FAIL;
   1252 
   1253   if (!row_count)
   1254     return E_INVALIDARG;
   1255 
   1256   int rows;
   1257   if (GetIntAttribute(AccessibilityNodeData::ATTR_TABLE_ROW_COUNT, &rows)) {
   1258     *row_count = rows;
   1259     return S_OK;
   1260   }
   1261 
   1262   return S_FALSE;
   1263 }
   1264 
   1265 STDMETHODIMP BrowserAccessibilityWin::get_nSelectedChildren(long* cell_count) {
   1266   if (!instance_active())
   1267     return E_FAIL;
   1268 
   1269   if (!cell_count)
   1270     return E_INVALIDARG;
   1271 
   1272   // TODO(dmazzoni): add support for selected cells/rows/columns in tables.
   1273   *cell_count = 0;
   1274   return S_OK;
   1275 }
   1276 
   1277 STDMETHODIMP BrowserAccessibilityWin::get_nSelectedColumns(long* column_count) {
   1278   if (!instance_active())
   1279     return E_FAIL;
   1280 
   1281   if (!column_count)
   1282     return E_INVALIDARG;
   1283 
   1284   *column_count = 0;
   1285   return S_OK;
   1286 }
   1287 
   1288 STDMETHODIMP BrowserAccessibilityWin::get_nSelectedRows(long* row_count) {
   1289   if (!instance_active())
   1290     return E_FAIL;
   1291 
   1292   if (!row_count)
   1293     return E_INVALIDARG;
   1294 
   1295   *row_count = 0;
   1296   return S_OK;
   1297 }
   1298 
   1299 STDMETHODIMP BrowserAccessibilityWin::get_rowDescription(long row,
   1300                                                          BSTR* description) {
   1301   if (!instance_active())
   1302     return E_FAIL;
   1303 
   1304   if (!description)
   1305     return E_INVALIDARG;
   1306 
   1307   int columns;
   1308   int rows;
   1309   if (!GetIntAttribute(
   1310           AccessibilityNodeData::ATTR_TABLE_COLUMN_COUNT, &columns) ||
   1311       !GetIntAttribute(AccessibilityNodeData::ATTR_TABLE_ROW_COUNT, &rows) ||
   1312       columns <= 0 ||
   1313       rows <= 0) {
   1314     return S_FALSE;
   1315   }
   1316 
   1317   if (row < 0 || row >= rows)
   1318     return E_INVALIDARG;
   1319 
   1320   const std::vector<int32>& cell_ids = GetIntListAttribute(
   1321       AccessibilityNodeData::ATTR_CELL_IDS);
   1322   for (int i = 0; i < columns; ++i) {
   1323     int cell_id = cell_ids[row * columns + i];
   1324     BrowserAccessibilityWin* cell =
   1325         manager()->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin();
   1326     if (cell && cell->blink_role() == blink::WebAXRoleRowHeader) {
   1327       base::string16 cell_name = cell->GetString16Attribute(
   1328           AccessibilityNodeData::ATTR_NAME);
   1329       if (cell_name.size() > 0) {
   1330         *description = SysAllocString(cell_name.c_str());
   1331         return S_OK;
   1332       }
   1333 
   1334       return cell->GetStringAttributeAsBstr(
   1335           AccessibilityNodeData::ATTR_DESCRIPTION, description);
   1336     }
   1337   }
   1338 
   1339   return S_FALSE;
   1340 }
   1341 
   1342 STDMETHODIMP BrowserAccessibilityWin::get_rowExtentAt(long row,
   1343                                                       long column,
   1344                                                       long* n_rows_spanned) {
   1345   if (!instance_active())
   1346     return E_FAIL;
   1347 
   1348   if (!n_rows_spanned)
   1349     return E_INVALIDARG;
   1350 
   1351   int columns;
   1352   int rows;
   1353   if (!GetIntAttribute(
   1354           AccessibilityNodeData::ATTR_TABLE_COLUMN_COUNT, &columns) ||
   1355       !GetIntAttribute(AccessibilityNodeData::ATTR_TABLE_ROW_COUNT, &rows) ||
   1356       columns <= 0 ||
   1357       rows <= 0) {
   1358     return S_FALSE;
   1359   }
   1360 
   1361   if (row < 0 || row >= rows || column < 0 || column >= columns)
   1362     return E_INVALIDARG;
   1363 
   1364   const std::vector<int32>& cell_ids = GetIntListAttribute(
   1365       AccessibilityNodeData::ATTR_CELL_IDS);
   1366   int cell_id = cell_ids[row * columns + column];
   1367   BrowserAccessibilityWin* cell =
   1368       manager()->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin();
   1369   int rowspan;
   1370   if (cell &&
   1371       cell->GetIntAttribute(
   1372           AccessibilityNodeData::ATTR_TABLE_CELL_ROW_SPAN, &rowspan) &&
   1373       rowspan >= 1) {
   1374     *n_rows_spanned = rowspan;
   1375     return S_OK;
   1376   }
   1377 
   1378   return S_FALSE;
   1379 }
   1380 
   1381 STDMETHODIMP BrowserAccessibilityWin::get_rowHeader(
   1382     IAccessibleTable** accessible_table,
   1383     long* starting_column_index) {
   1384   // TODO(dmazzoni): implement
   1385   return E_NOTIMPL;
   1386 }
   1387 
   1388 STDMETHODIMP BrowserAccessibilityWin::get_rowIndex(long cell_index,
   1389                                                    long* row_index) {
   1390   if (!instance_active())
   1391     return E_FAIL;
   1392 
   1393   if (!row_index)
   1394     return E_INVALIDARG;
   1395 
   1396   const std::vector<int32>& unique_cell_ids = GetIntListAttribute(
   1397       AccessibilityNodeData::ATTR_UNIQUE_CELL_IDS);
   1398   int cell_id_count = static_cast<int>(unique_cell_ids.size());
   1399   if (cell_index < 0)
   1400     return E_INVALIDARG;
   1401   if (cell_index >= cell_id_count)
   1402     return S_FALSE;
   1403 
   1404   int cell_id = unique_cell_ids[cell_index];
   1405   BrowserAccessibilityWin* cell =
   1406       manager()->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin();
   1407   int cell_row_index;
   1408   if (cell &&
   1409       cell->GetIntAttribute(
   1410           AccessibilityNodeData::ATTR_TABLE_CELL_ROW_INDEX, &cell_row_index)) {
   1411     *row_index = cell_row_index;
   1412     return S_OK;
   1413   }
   1414 
   1415   return S_FALSE;
   1416 }
   1417 
   1418 STDMETHODIMP BrowserAccessibilityWin::get_selectedChildren(long max_children,
   1419                                                            long** children,
   1420                                                            long* n_children) {
   1421   if (!instance_active())
   1422     return E_FAIL;
   1423 
   1424   if (!children || !n_children)
   1425     return E_INVALIDARG;
   1426 
   1427   // TODO(dmazzoni): Implement this.
   1428   *n_children = 0;
   1429   return S_OK;
   1430 }
   1431 
   1432 STDMETHODIMP BrowserAccessibilityWin::get_selectedColumns(long max_columns,
   1433                                                           long** columns,
   1434                                                           long* n_columns) {
   1435   if (!instance_active())
   1436     return E_FAIL;
   1437 
   1438   if (!columns || !n_columns)
   1439     return E_INVALIDARG;
   1440 
   1441   // TODO(dmazzoni): Implement this.
   1442   *n_columns = 0;
   1443   return S_OK;
   1444 }
   1445 
   1446 STDMETHODIMP BrowserAccessibilityWin::get_selectedRows(long max_rows,
   1447                                                        long** rows,
   1448                                                        long* n_rows) {
   1449   if (!instance_active())
   1450     return E_FAIL;
   1451 
   1452   if (!rows || !n_rows)
   1453     return E_INVALIDARG;
   1454 
   1455   // TODO(dmazzoni): Implement this.
   1456   *n_rows = 0;
   1457   return S_OK;
   1458 }
   1459 
   1460 STDMETHODIMP BrowserAccessibilityWin::get_summary(IUnknown** accessible) {
   1461   if (!instance_active())
   1462     return E_FAIL;
   1463 
   1464   if (!accessible)
   1465     return E_INVALIDARG;
   1466 
   1467   // TODO(dmazzoni): implement
   1468   return S_FALSE;
   1469 }
   1470 
   1471 STDMETHODIMP BrowserAccessibilityWin::get_isColumnSelected(
   1472     long column,
   1473     boolean* is_selected) {
   1474   if (!instance_active())
   1475     return E_FAIL;
   1476 
   1477   if (!is_selected)
   1478     return E_INVALIDARG;
   1479 
   1480   // TODO(dmazzoni): Implement this.
   1481   *is_selected = false;
   1482   return S_OK;
   1483 }
   1484 
   1485 STDMETHODIMP BrowserAccessibilityWin::get_isRowSelected(long row,
   1486                                                         boolean* is_selected) {
   1487   if (!instance_active())
   1488     return E_FAIL;
   1489 
   1490   if (!is_selected)
   1491     return E_INVALIDARG;
   1492 
   1493   // TODO(dmazzoni): Implement this.
   1494   *is_selected = false;
   1495   return S_OK;
   1496 }
   1497 
   1498 STDMETHODIMP BrowserAccessibilityWin::get_isSelected(long row,
   1499                                                      long column,
   1500                                                      boolean* is_selected) {
   1501   if (!instance_active())
   1502     return E_FAIL;
   1503 
   1504   if (!is_selected)
   1505     return E_INVALIDARG;
   1506 
   1507   // TODO(dmazzoni): Implement this.
   1508   *is_selected = false;
   1509   return S_OK;
   1510 }
   1511 
   1512 STDMETHODIMP BrowserAccessibilityWin::get_rowColumnExtentsAtIndex(
   1513     long index,
   1514     long* row,
   1515     long* column,
   1516     long* row_extents,
   1517     long* column_extents,
   1518     boolean* is_selected) {
   1519   if (!instance_active())
   1520     return E_FAIL;
   1521 
   1522   if (!row || !column || !row_extents || !column_extents || !is_selected)
   1523     return E_INVALIDARG;
   1524 
   1525   const std::vector<int32>& unique_cell_ids = GetIntListAttribute(
   1526       AccessibilityNodeData::ATTR_UNIQUE_CELL_IDS);
   1527   int cell_id_count = static_cast<int>(unique_cell_ids.size());
   1528   if (index < 0)
   1529     return E_INVALIDARG;
   1530   if (index >= cell_id_count)
   1531     return S_FALSE;
   1532 
   1533   int cell_id = unique_cell_ids[index];
   1534   BrowserAccessibilityWin* cell =
   1535       manager()->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin();
   1536   int rowspan;
   1537   int colspan;
   1538   if (cell &&
   1539       cell->GetIntAttribute(
   1540           AccessibilityNodeData::ATTR_TABLE_CELL_ROW_SPAN, &rowspan) &&
   1541       cell->GetIntAttribute(
   1542           AccessibilityNodeData::ATTR_TABLE_CELL_COLUMN_SPAN, &colspan) &&
   1543       rowspan >= 1 &&
   1544       colspan >= 1) {
   1545     *row_extents = rowspan;
   1546     *column_extents = colspan;
   1547     return S_OK;
   1548   }
   1549 
   1550   return S_FALSE;
   1551 }
   1552 
   1553 //
   1554 // IAccessibleTable2 methods.
   1555 //
   1556 
   1557 STDMETHODIMP BrowserAccessibilityWin::get_cellAt(long row,
   1558                                                  long column,
   1559                                                  IUnknown** cell) {
   1560   return get_accessibleAt(row, column, cell);
   1561 }
   1562 
   1563 STDMETHODIMP BrowserAccessibilityWin::get_nSelectedCells(long* cell_count) {
   1564   return get_nSelectedChildren(cell_count);
   1565 }
   1566 
   1567 STDMETHODIMP BrowserAccessibilityWin::get_selectedCells(
   1568     IUnknown*** cells,
   1569     long* n_selected_cells) {
   1570   if (!instance_active())
   1571     return E_FAIL;
   1572 
   1573   if (!cells || !n_selected_cells)
   1574     return E_INVALIDARG;
   1575 
   1576   // TODO(dmazzoni): Implement this.
   1577   *n_selected_cells = 0;
   1578   return S_OK;
   1579 }
   1580 
   1581 STDMETHODIMP BrowserAccessibilityWin::get_selectedColumns(long** columns,
   1582                                                           long* n_columns) {
   1583   if (!instance_active())
   1584     return E_FAIL;
   1585 
   1586   if (!columns || !n_columns)
   1587     return E_INVALIDARG;
   1588 
   1589   // TODO(dmazzoni): Implement this.
   1590   *n_columns = 0;
   1591   return S_OK;
   1592 }
   1593 
   1594 STDMETHODIMP BrowserAccessibilityWin::get_selectedRows(long** rows,
   1595                                                        long* n_rows) {
   1596   if (!instance_active())
   1597     return E_FAIL;
   1598 
   1599   if (!rows || !n_rows)
   1600     return E_INVALIDARG;
   1601 
   1602   // TODO(dmazzoni): Implement this.
   1603   *n_rows = 0;
   1604   return S_OK;
   1605 }
   1606 
   1607 
   1608 //
   1609 // IAccessibleTableCell methods.
   1610 //
   1611 
   1612 STDMETHODIMP BrowserAccessibilityWin::get_columnExtent(
   1613     long* n_columns_spanned) {
   1614   if (!instance_active())
   1615     return E_FAIL;
   1616 
   1617   if (!n_columns_spanned)
   1618     return E_INVALIDARG;
   1619 
   1620   int colspan;
   1621   if (GetIntAttribute(
   1622           AccessibilityNodeData::ATTR_TABLE_CELL_COLUMN_SPAN, &colspan) &&
   1623       colspan >= 1) {
   1624     *n_columns_spanned = colspan;
   1625     return S_OK;
   1626   }
   1627 
   1628   return S_FALSE;
   1629 }
   1630 
   1631 STDMETHODIMP BrowserAccessibilityWin::get_columnHeaderCells(
   1632     IUnknown*** cell_accessibles,
   1633     long* n_column_header_cells) {
   1634   if (!instance_active())
   1635     return E_FAIL;
   1636 
   1637   if (!cell_accessibles || !n_column_header_cells)
   1638     return E_INVALIDARG;
   1639 
   1640   *n_column_header_cells = 0;
   1641 
   1642   int column;
   1643   if (!GetIntAttribute(
   1644           AccessibilityNodeData::ATTR_TABLE_CELL_COLUMN_INDEX, &column)) {
   1645     return S_FALSE;
   1646   }
   1647 
   1648   BrowserAccessibility* table = parent();
   1649   while (table && table->role() != blink::WebAXRoleTable)
   1650     table = table->parent();
   1651   if (!table) {
   1652     NOTREACHED();
   1653     return S_FALSE;
   1654   }
   1655 
   1656   int columns;
   1657   int rows;
   1658   if (!table->GetIntAttribute(
   1659           AccessibilityNodeData::ATTR_TABLE_COLUMN_COUNT, &columns) ||
   1660       !table->GetIntAttribute(
   1661           AccessibilityNodeData::ATTR_TABLE_ROW_COUNT, &rows)) {
   1662     return S_FALSE;
   1663   }
   1664   if (columns <= 0 || rows <= 0 || column < 0 || column >= columns)
   1665     return S_FALSE;
   1666 
   1667   const std::vector<int32>& cell_ids = table->GetIntListAttribute(
   1668       AccessibilityNodeData::ATTR_CELL_IDS);
   1669 
   1670   for (int i = 0; i < rows; ++i) {
   1671     int cell_id = cell_ids[i * columns + column];
   1672     BrowserAccessibilityWin* cell =
   1673         manager()->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin();
   1674     if (cell && cell->blink_role() == blink::WebAXRoleColumnHeader)
   1675       (*n_column_header_cells)++;
   1676   }
   1677 
   1678   *cell_accessibles = static_cast<IUnknown**>(CoTaskMemAlloc(
   1679       (*n_column_header_cells) * sizeof(cell_accessibles[0])));
   1680   int index = 0;
   1681   for (int i = 0; i < rows; ++i) {
   1682     int cell_id = cell_ids[i * columns + column];
   1683     BrowserAccessibility* cell = manager()->GetFromRendererID(cell_id);
   1684     if (cell && cell->role() == blink::WebAXRoleColumnHeader) {
   1685       (*cell_accessibles)[index] = static_cast<IAccessible*>(
   1686           cell->ToBrowserAccessibilityWin()->NewReference());
   1687       ++index;
   1688     }
   1689   }
   1690 
   1691   return S_OK;
   1692 }
   1693 
   1694 STDMETHODIMP BrowserAccessibilityWin::get_columnIndex(long* column_index) {
   1695   if (!instance_active())
   1696     return E_FAIL;
   1697 
   1698   if (!column_index)
   1699     return E_INVALIDARG;
   1700 
   1701   int column;
   1702   if (GetIntAttribute(
   1703           AccessibilityNodeData::ATTR_TABLE_CELL_COLUMN_INDEX, &column)) {
   1704     *column_index = column;
   1705     return S_OK;
   1706   }
   1707 
   1708   return S_FALSE;
   1709 }
   1710 
   1711 STDMETHODIMP BrowserAccessibilityWin::get_rowExtent(long* n_rows_spanned) {
   1712   if (!instance_active())
   1713     return E_FAIL;
   1714 
   1715   if (!n_rows_spanned)
   1716     return E_INVALIDARG;
   1717 
   1718   int rowspan;
   1719   if (GetIntAttribute(
   1720           AccessibilityNodeData::ATTR_TABLE_CELL_ROW_SPAN, &rowspan) &&
   1721       rowspan >= 1) {
   1722     *n_rows_spanned = rowspan;
   1723     return S_OK;
   1724   }
   1725 
   1726   return S_FALSE;
   1727 }
   1728 
   1729 STDMETHODIMP BrowserAccessibilityWin::get_rowHeaderCells(
   1730     IUnknown*** cell_accessibles,
   1731     long* n_row_header_cells) {
   1732   if (!instance_active())
   1733     return E_FAIL;
   1734 
   1735   if (!cell_accessibles || !n_row_header_cells)
   1736     return E_INVALIDARG;
   1737 
   1738   *n_row_header_cells = 0;
   1739 
   1740   int row;
   1741   if (!GetIntAttribute(
   1742           AccessibilityNodeData::ATTR_TABLE_CELL_ROW_INDEX, &row)) {
   1743     return S_FALSE;
   1744   }
   1745 
   1746   BrowserAccessibility* table = parent();
   1747   while (table && table->role() != blink::WebAXRoleTable)
   1748     table = table->parent();
   1749   if (!table) {
   1750     NOTREACHED();
   1751     return S_FALSE;
   1752   }
   1753 
   1754   int columns;
   1755   int rows;
   1756   if (!table->GetIntAttribute(
   1757           AccessibilityNodeData::ATTR_TABLE_COLUMN_COUNT, &columns) ||
   1758       !table->GetIntAttribute(
   1759           AccessibilityNodeData::ATTR_TABLE_ROW_COUNT, &rows)) {
   1760     return S_FALSE;
   1761   }
   1762   if (columns <= 0 || rows <= 0 || row < 0 || row >= rows)
   1763     return S_FALSE;
   1764 
   1765   const std::vector<int32>& cell_ids = table->GetIntListAttribute(
   1766       AccessibilityNodeData::ATTR_CELL_IDS);
   1767 
   1768   for (int i = 0; i < columns; ++i) {
   1769     int cell_id = cell_ids[row * columns + i];
   1770     BrowserAccessibility* cell = manager()->GetFromRendererID(cell_id);
   1771     if (cell && cell->role() == blink::WebAXRoleRowHeader)
   1772       (*n_row_header_cells)++;
   1773   }
   1774 
   1775   *cell_accessibles = static_cast<IUnknown**>(CoTaskMemAlloc(
   1776       (*n_row_header_cells) * sizeof(cell_accessibles[0])));
   1777   int index = 0;
   1778   for (int i = 0; i < columns; ++i) {
   1779     int cell_id = cell_ids[row * columns + i];
   1780     BrowserAccessibility* cell = manager()->GetFromRendererID(cell_id);
   1781     if (cell && cell->role() == blink::WebAXRoleRowHeader) {
   1782       (*cell_accessibles)[index] = static_cast<IAccessible*>(
   1783           cell->ToBrowserAccessibilityWin()->NewReference());
   1784       ++index;
   1785     }
   1786   }
   1787 
   1788   return S_OK;
   1789 }
   1790 
   1791 STDMETHODIMP BrowserAccessibilityWin::get_rowIndex(long* row_index) {
   1792   if (!instance_active())
   1793     return E_FAIL;
   1794 
   1795   if (!row_index)
   1796     return E_INVALIDARG;
   1797 
   1798   int row;
   1799   if (GetIntAttribute(AccessibilityNodeData::ATTR_TABLE_CELL_ROW_INDEX, &row)) {
   1800     *row_index = row;
   1801     return S_OK;
   1802   }
   1803   return S_FALSE;
   1804 }
   1805 
   1806 STDMETHODIMP BrowserAccessibilityWin::get_isSelected(boolean* is_selected) {
   1807   if (!instance_active())
   1808     return E_FAIL;
   1809 
   1810   if (!is_selected)
   1811     return E_INVALIDARG;
   1812 
   1813   *is_selected = false;
   1814   return S_OK;
   1815 }
   1816 
   1817 STDMETHODIMP BrowserAccessibilityWin::get_rowColumnExtents(
   1818     long* row_index,
   1819     long* column_index,
   1820     long* row_extents,
   1821     long* column_extents,
   1822     boolean* is_selected) {
   1823   if (!instance_active())
   1824     return E_FAIL;
   1825 
   1826   if (!row_index ||
   1827       !column_index ||
   1828       !row_extents ||
   1829       !column_extents ||
   1830       !is_selected) {
   1831     return E_INVALIDARG;
   1832   }
   1833 
   1834   int row;
   1835   int column;
   1836   int rowspan;
   1837   int colspan;
   1838   if (GetIntAttribute(AccessibilityNodeData::ATTR_TABLE_CELL_ROW_INDEX, &row) &&
   1839       GetIntAttribute(
   1840           AccessibilityNodeData::ATTR_TABLE_CELL_COLUMN_INDEX, &column) &&
   1841       GetIntAttribute(
   1842           AccessibilityNodeData::ATTR_TABLE_CELL_ROW_SPAN, &rowspan) &&
   1843       GetIntAttribute(
   1844           AccessibilityNodeData::ATTR_TABLE_CELL_COLUMN_SPAN, &colspan)) {
   1845     *row_index = row;
   1846     *column_index = column;
   1847     *row_extents = rowspan;
   1848     *column_extents = colspan;
   1849     *is_selected = false;
   1850     return S_OK;
   1851   }
   1852 
   1853   return S_FALSE;
   1854 }
   1855 
   1856 STDMETHODIMP BrowserAccessibilityWin::get_table(IUnknown** table) {
   1857   if (!instance_active())
   1858     return E_FAIL;
   1859 
   1860   if (!table)
   1861     return E_INVALIDARG;
   1862 
   1863 
   1864   int row;
   1865   int column;
   1866   GetIntAttribute(AccessibilityNodeData::ATTR_TABLE_CELL_ROW_INDEX, &row);
   1867   GetIntAttribute(AccessibilityNodeData::ATTR_TABLE_CELL_COLUMN_INDEX, &column);
   1868 
   1869   BrowserAccessibility* find_table = parent();
   1870   while (find_table && find_table->role() != blink::WebAXRoleTable)
   1871     find_table = find_table->parent();
   1872   if (!find_table) {
   1873     NOTREACHED();
   1874     return S_FALSE;
   1875   }
   1876 
   1877   *table = static_cast<IAccessibleTable*>(
   1878       find_table->ToBrowserAccessibilityWin()->NewReference());
   1879 
   1880   return S_OK;
   1881 }
   1882 
   1883 //
   1884 // IAccessibleText methods.
   1885 //
   1886 
   1887 STDMETHODIMP BrowserAccessibilityWin::get_nCharacters(LONG* n_characters) {
   1888   if (!instance_active())
   1889     return E_FAIL;
   1890 
   1891   if (!n_characters)
   1892     return E_INVALIDARG;
   1893 
   1894   *n_characters = TextForIAccessibleText().length();
   1895   return S_OK;
   1896 }
   1897 
   1898 STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) {
   1899   if (!instance_active())
   1900     return E_FAIL;
   1901 
   1902   if (!offset)
   1903     return E_INVALIDARG;
   1904 
   1905   *offset = 0;
   1906   if (blink_role() == blink::WebAXRoleTextField ||
   1907       blink_role() == blink::WebAXRoleTextArea) {
   1908     int sel_start = 0;
   1909     if (GetIntAttribute(AccessibilityNodeData::ATTR_TEXT_SEL_START,
   1910                         &sel_start))
   1911       *offset = sel_start;
   1912   }
   1913 
   1914   return S_OK;
   1915 }
   1916 
   1917 STDMETHODIMP BrowserAccessibilityWin::get_characterExtents(
   1918     LONG offset,
   1919     enum IA2CoordinateType coordinate_type,
   1920     LONG* out_x,
   1921     LONG* out_y,
   1922     LONG* out_width,
   1923     LONG* out_height) {
   1924   if (!instance_active())
   1925     return E_FAIL;
   1926 
   1927   if (!out_x || !out_y || !out_width || !out_height)
   1928     return E_INVALIDARG;
   1929 
   1930   const base::string16& text_str = TextForIAccessibleText();
   1931   HandleSpecialTextOffset(text_str, &offset);
   1932 
   1933   if (offset < 0 || offset > static_cast<LONG>(text_str.size()))
   1934     return E_INVALIDARG;
   1935 
   1936   if (blink_role() != blink::WebAXRoleStaticText)
   1937     return E_FAIL;
   1938 
   1939   gfx::Rect character_bounds;
   1940   if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) {
   1941     character_bounds = GetGlobalBoundsForRange(offset, 1);
   1942   } else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) {
   1943     character_bounds = GetLocalBoundsForRange(offset, 1);
   1944     character_bounds -= location().OffsetFromOrigin();
   1945   } else {
   1946     return E_INVALIDARG;
   1947   }
   1948 
   1949   *out_x = character_bounds.x();
   1950   *out_y = character_bounds.y();
   1951   *out_width = character_bounds.width();
   1952   *out_height = character_bounds.height();
   1953 
   1954   return S_OK;
   1955 }
   1956 
   1957 STDMETHODIMP BrowserAccessibilityWin::get_nSelections(LONG* n_selections) {
   1958   if (!instance_active())
   1959     return E_FAIL;
   1960 
   1961   if (!n_selections)
   1962     return E_INVALIDARG;
   1963 
   1964   *n_selections = 0;
   1965   if (blink_role() == blink::WebAXRoleTextField ||
   1966       blink_role() == blink::WebAXRoleTextArea) {
   1967     int sel_start = 0;
   1968     int sel_end = 0;
   1969     if (GetIntAttribute(AccessibilityNodeData::ATTR_TEXT_SEL_START,
   1970                         &sel_start) &&
   1971         GetIntAttribute(AccessibilityNodeData::ATTR_TEXT_SEL_END, &sel_end) &&
   1972         sel_start != sel_end)
   1973       *n_selections = 1;
   1974   }
   1975 
   1976   return S_OK;
   1977 }
   1978 
   1979 STDMETHODIMP BrowserAccessibilityWin::get_selection(LONG selection_index,
   1980                                                     LONG* start_offset,
   1981                                                     LONG* end_offset) {
   1982   if (!instance_active())
   1983     return E_FAIL;
   1984 
   1985   if (!start_offset || !end_offset || selection_index != 0)
   1986     return E_INVALIDARG;
   1987 
   1988   *start_offset = 0;
   1989   *end_offset = 0;
   1990   if (blink_role() == blink::WebAXRoleTextField ||
   1991       blink_role() == blink::WebAXRoleTextArea) {
   1992     int sel_start = 0;
   1993     int sel_end = 0;
   1994     if (GetIntAttribute(
   1995             AccessibilityNodeData::ATTR_TEXT_SEL_START, &sel_start) &&
   1996         GetIntAttribute(AccessibilityNodeData::ATTR_TEXT_SEL_END, &sel_end)) {
   1997       *start_offset = sel_start;
   1998       *end_offset = sel_end;
   1999     }
   2000   }
   2001 
   2002   return S_OK;
   2003 }
   2004 
   2005 STDMETHODIMP BrowserAccessibilityWin::get_text(LONG start_offset,
   2006                                                LONG end_offset,
   2007                                                BSTR* text) {
   2008   if (!instance_active())
   2009     return E_FAIL;
   2010 
   2011   if (!text)
   2012     return E_INVALIDARG;
   2013 
   2014   const base::string16& text_str = TextForIAccessibleText();
   2015 
   2016   // Handle special text offsets.
   2017   HandleSpecialTextOffset(text_str, &start_offset);
   2018   HandleSpecialTextOffset(text_str, &end_offset);
   2019 
   2020   // The spec allows the arguments to be reversed.
   2021   if (start_offset > end_offset) {
   2022     LONG tmp = start_offset;
   2023     start_offset = end_offset;
   2024     end_offset = tmp;
   2025   }
   2026 
   2027   // The spec does not allow the start or end offsets to be out or range;
   2028   // we must return an error if so.
   2029   LONG len = text_str.length();
   2030   if (start_offset < 0)
   2031     return E_INVALIDARG;
   2032   if (end_offset > len)
   2033     return E_INVALIDARG;
   2034 
   2035   base::string16 substr = text_str.substr(start_offset,
   2036                                           end_offset - start_offset);
   2037   if (substr.empty())
   2038     return S_FALSE;
   2039 
   2040   *text = SysAllocString(substr.c_str());
   2041   DCHECK(*text);
   2042   return S_OK;
   2043 }
   2044 
   2045 STDMETHODIMP BrowserAccessibilityWin::get_textAtOffset(
   2046     LONG offset,
   2047     enum IA2TextBoundaryType boundary_type,
   2048     LONG* start_offset,
   2049     LONG* end_offset,
   2050     BSTR* text) {
   2051   if (!instance_active())
   2052     return E_FAIL;
   2053 
   2054   if (!start_offset || !end_offset || !text)
   2055     return E_INVALIDARG;
   2056 
   2057   // The IAccessible2 spec says we don't have to implement the "sentence"
   2058   // boundary type, we can just let the screenreader handle it.
   2059   if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
   2060     *start_offset = 0;
   2061     *end_offset = 0;
   2062     *text = NULL;
   2063     return S_FALSE;
   2064   }
   2065 
   2066   const base::string16& text_str = TextForIAccessibleText();
   2067 
   2068   *start_offset = FindBoundary(
   2069       text_str, boundary_type, offset, ui::BACKWARDS_DIRECTION);
   2070   *end_offset = FindBoundary(
   2071       text_str, boundary_type, offset, ui::FORWARDS_DIRECTION);
   2072   return get_text(*start_offset, *end_offset, text);
   2073 }
   2074 
   2075 STDMETHODIMP BrowserAccessibilityWin::get_textBeforeOffset(
   2076     LONG offset,
   2077     enum IA2TextBoundaryType boundary_type,
   2078     LONG* start_offset,
   2079     LONG* end_offset,
   2080     BSTR* text) {
   2081   if (!instance_active())
   2082     return E_FAIL;
   2083 
   2084   if (!start_offset || !end_offset || !text)
   2085     return E_INVALIDARG;
   2086 
   2087   // The IAccessible2 spec says we don't have to implement the "sentence"
   2088   // boundary type, we can just let the screenreader handle it.
   2089   if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
   2090     *start_offset = 0;
   2091     *end_offset = 0;
   2092     *text = NULL;
   2093     return S_FALSE;
   2094   }
   2095 
   2096   const base::string16& text_str = TextForIAccessibleText();
   2097 
   2098   *start_offset = FindBoundary(
   2099       text_str, boundary_type, offset, ui::BACKWARDS_DIRECTION);
   2100   *end_offset = offset;
   2101   return get_text(*start_offset, *end_offset, text);
   2102 }
   2103 
   2104 STDMETHODIMP BrowserAccessibilityWin::get_textAfterOffset(
   2105     LONG offset,
   2106     enum IA2TextBoundaryType boundary_type,
   2107     LONG* start_offset,
   2108     LONG* end_offset,
   2109     BSTR* text) {
   2110   if (!instance_active())
   2111     return E_FAIL;
   2112 
   2113   if (!start_offset || !end_offset || !text)
   2114     return E_INVALIDARG;
   2115 
   2116   // The IAccessible2 spec says we don't have to implement the "sentence"
   2117   // boundary type, we can just let the screenreader handle it.
   2118   if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
   2119     *start_offset = 0;
   2120     *end_offset = 0;
   2121     *text = NULL;
   2122     return S_FALSE;
   2123   }
   2124 
   2125   const base::string16& text_str = TextForIAccessibleText();
   2126 
   2127   *start_offset = offset;
   2128   *end_offset = FindBoundary(
   2129       text_str, boundary_type, offset, ui::FORWARDS_DIRECTION);
   2130   return get_text(*start_offset, *end_offset, text);
   2131 }
   2132 
   2133 STDMETHODIMP BrowserAccessibilityWin::get_newText(IA2TextSegment* new_text) {
   2134   if (!instance_active())
   2135     return E_FAIL;
   2136 
   2137   if (!new_text)
   2138     return E_INVALIDARG;
   2139 
   2140   base::string16 text = TextForIAccessibleText();
   2141 
   2142   new_text->text = SysAllocString(text.c_str());
   2143   new_text->start = 0;
   2144   new_text->end = static_cast<long>(text.size());
   2145   return S_OK;
   2146 }
   2147 
   2148 STDMETHODIMP BrowserAccessibilityWin::get_oldText(IA2TextSegment* old_text) {
   2149   if (!instance_active())
   2150     return E_FAIL;
   2151 
   2152   if (!old_text)
   2153     return E_INVALIDARG;
   2154 
   2155   old_text->text = SysAllocString(old_text_.c_str());
   2156   old_text->start = 0;
   2157   old_text->end = static_cast<long>(old_text_.size());
   2158   return S_OK;
   2159 }
   2160 
   2161 STDMETHODIMP BrowserAccessibilityWin::get_offsetAtPoint(
   2162     LONG x,
   2163     LONG y,
   2164     enum IA2CoordinateType coord_type,
   2165     LONG* offset) {
   2166   if (!instance_active())
   2167     return E_FAIL;
   2168 
   2169   if (!offset)
   2170     return E_INVALIDARG;
   2171 
   2172   // TODO(dmazzoni): implement this. We're returning S_OK for now so that
   2173   // screen readers still return partially accurate results rather than
   2174   // completely failing.
   2175   *offset = 0;
   2176   return S_OK;
   2177 }
   2178 
   2179 STDMETHODIMP BrowserAccessibilityWin::scrollSubstringTo(
   2180     LONG start_index,
   2181     LONG end_index,
   2182     enum IA2ScrollType scroll_type) {
   2183   // TODO(dmazzoni): adjust this for the start and end index, too.
   2184   return scrollTo(scroll_type);
   2185 }
   2186 
   2187 STDMETHODIMP BrowserAccessibilityWin::scrollSubstringToPoint(
   2188     LONG start_index,
   2189     LONG end_index,
   2190     enum IA2CoordinateType coordinate_type,
   2191     LONG x, LONG y) {
   2192   // TODO(dmazzoni): adjust this for the start and end index, too.
   2193   return scrollToPoint(coordinate_type, x, y);
   2194 }
   2195 
   2196 STDMETHODIMP BrowserAccessibilityWin::addSelection(LONG start_offset,
   2197                                                    LONG end_offset) {
   2198   if (!instance_active())
   2199     return E_FAIL;
   2200 
   2201   const base::string16& text_str = TextForIAccessibleText();
   2202   HandleSpecialTextOffset(text_str, &start_offset);
   2203   HandleSpecialTextOffset(text_str, &end_offset);
   2204 
   2205   manager()->SetTextSelection(*this, start_offset, end_offset);
   2206   return S_OK;
   2207 }
   2208 
   2209 STDMETHODIMP BrowserAccessibilityWin::removeSelection(LONG selection_index) {
   2210   if (!instance_active())
   2211     return E_FAIL;
   2212 
   2213   if (selection_index != 0)
   2214     return E_INVALIDARG;
   2215 
   2216   manager()->SetTextSelection(*this, 0, 0);
   2217   return S_OK;
   2218 }
   2219 
   2220 STDMETHODIMP BrowserAccessibilityWin::setCaretOffset(LONG offset) {
   2221   if (!instance_active())
   2222     return E_FAIL;
   2223 
   2224   const base::string16& text_str = TextForIAccessibleText();
   2225   HandleSpecialTextOffset(text_str, &offset);
   2226   manager()->SetTextSelection(*this, offset, offset);
   2227   return S_OK;
   2228 }
   2229 
   2230 STDMETHODIMP BrowserAccessibilityWin::setSelection(LONG selection_index,
   2231                                                    LONG start_offset,
   2232                                                    LONG end_offset) {
   2233   if (!instance_active())
   2234     return E_FAIL;
   2235 
   2236   if (selection_index != 0)
   2237     return E_INVALIDARG;
   2238 
   2239   const base::string16& text_str = TextForIAccessibleText();
   2240   HandleSpecialTextOffset(text_str, &start_offset);
   2241   HandleSpecialTextOffset(text_str, &end_offset);
   2242 
   2243   manager()->SetTextSelection(*this, start_offset, end_offset);
   2244   return S_OK;
   2245 }
   2246 
   2247 //
   2248 // IAccessibleHypertext methods.
   2249 //
   2250 
   2251 STDMETHODIMP BrowserAccessibilityWin::get_nHyperlinks(long* hyperlink_count) {
   2252   if (!instance_active())
   2253     return E_FAIL;
   2254 
   2255   if (!hyperlink_count)
   2256     return E_INVALIDARG;
   2257 
   2258   *hyperlink_count = hyperlink_offset_to_index_.size();
   2259   return S_OK;
   2260 }
   2261 
   2262 STDMETHODIMP BrowserAccessibilityWin::get_hyperlink(
   2263     long index,
   2264     IAccessibleHyperlink** hyperlink) {
   2265   if (!instance_active())
   2266     return E_FAIL;
   2267 
   2268   if (!hyperlink ||
   2269       index < 0 ||
   2270       index >= static_cast<long>(hyperlinks_.size())) {
   2271     return E_INVALIDARG;
   2272   }
   2273 
   2274   BrowserAccessibilityWin* child =
   2275       children()[hyperlinks_[index]]->ToBrowserAccessibilityWin();
   2276   *hyperlink = static_cast<IAccessibleHyperlink*>(child->NewReference());
   2277   return S_OK;
   2278 }
   2279 
   2280 STDMETHODIMP BrowserAccessibilityWin::get_hyperlinkIndex(
   2281     long char_index,
   2282     long* hyperlink_index) {
   2283   if (!instance_active())
   2284     return E_FAIL;
   2285 
   2286   if (!hyperlink_index)
   2287     return E_INVALIDARG;
   2288 
   2289   *hyperlink_index = -1;
   2290 
   2291   if (char_index < 0 || char_index >= static_cast<long>(hypertext_.size()))
   2292     return E_INVALIDARG;
   2293 
   2294   std::map<int32, int32>::iterator it =
   2295       hyperlink_offset_to_index_.find(char_index);
   2296   if (it == hyperlink_offset_to_index_.end())
   2297     return E_FAIL;
   2298 
   2299   *hyperlink_index = it->second;
   2300   return S_OK;
   2301 }
   2302 
   2303 //
   2304 // IAccessibleValue methods.
   2305 //
   2306 
   2307 STDMETHODIMP BrowserAccessibilityWin::get_currentValue(VARIANT* value) {
   2308   if (!instance_active())
   2309     return E_FAIL;
   2310 
   2311   if (!value)
   2312     return E_INVALIDARG;
   2313 
   2314   float float_val;
   2315   if (GetFloatAttribute(
   2316           AccessibilityNodeData::ATTR_VALUE_FOR_RANGE, &float_val)) {
   2317     value->vt = VT_R8;
   2318     value->dblVal = float_val;
   2319     return S_OK;
   2320   }
   2321 
   2322   value->vt = VT_EMPTY;
   2323   return S_FALSE;
   2324 }
   2325 
   2326 STDMETHODIMP BrowserAccessibilityWin::get_minimumValue(VARIANT* value) {
   2327   if (!instance_active())
   2328     return E_FAIL;
   2329 
   2330   if (!value)
   2331     return E_INVALIDARG;
   2332 
   2333   float float_val;
   2334   if (GetFloatAttribute(AccessibilityNodeData::ATTR_MIN_VALUE_FOR_RANGE,
   2335                         &float_val)) {
   2336     value->vt = VT_R8;
   2337     value->dblVal = float_val;
   2338     return S_OK;
   2339   }
   2340 
   2341   value->vt = VT_EMPTY;
   2342   return S_FALSE;
   2343 }
   2344 
   2345 STDMETHODIMP BrowserAccessibilityWin::get_maximumValue(VARIANT* value) {
   2346   if (!instance_active())
   2347     return E_FAIL;
   2348 
   2349   if (!value)
   2350     return E_INVALIDARG;
   2351 
   2352   float float_val;
   2353   if (GetFloatAttribute(AccessibilityNodeData::ATTR_MAX_VALUE_FOR_RANGE,
   2354                         &float_val)) {
   2355     value->vt = VT_R8;
   2356     value->dblVal = float_val;
   2357     return S_OK;
   2358   }
   2359 
   2360   value->vt = VT_EMPTY;
   2361   return S_FALSE;
   2362 }
   2363 
   2364 STDMETHODIMP BrowserAccessibilityWin::setCurrentValue(VARIANT new_value) {
   2365   // TODO(dmazzoni): Implement this.
   2366   return E_NOTIMPL;
   2367 }
   2368 
   2369 //
   2370 // ISimpleDOMDocument methods.
   2371 //
   2372 
   2373 STDMETHODIMP BrowserAccessibilityWin::get_URL(BSTR* url) {
   2374   if (!instance_active())
   2375     return E_FAIL;
   2376 
   2377   if (!url)
   2378     return E_INVALIDARG;
   2379 
   2380   return GetStringAttributeAsBstr(AccessibilityNodeData::ATTR_DOC_URL, url);
   2381 }
   2382 
   2383 STDMETHODIMP BrowserAccessibilityWin::get_title(BSTR* title) {
   2384   if (!instance_active())
   2385     return E_FAIL;
   2386 
   2387   if (!title)
   2388     return E_INVALIDARG;
   2389 
   2390   return GetStringAttributeAsBstr(AccessibilityNodeData::ATTR_DOC_TITLE, title);
   2391 }
   2392 
   2393 STDMETHODIMP BrowserAccessibilityWin::get_mimeType(BSTR* mime_type) {
   2394   if (!instance_active())
   2395     return E_FAIL;
   2396 
   2397   if (!mime_type)
   2398     return E_INVALIDARG;
   2399 
   2400   return GetStringAttributeAsBstr(
   2401       AccessibilityNodeData::ATTR_DOC_MIMETYPE, mime_type);
   2402 }
   2403 
   2404 STDMETHODIMP BrowserAccessibilityWin::get_docType(BSTR* doc_type) {
   2405   if (!instance_active())
   2406     return E_FAIL;
   2407 
   2408   if (!doc_type)
   2409     return E_INVALIDARG;
   2410 
   2411   return GetStringAttributeAsBstr(
   2412       AccessibilityNodeData::ATTR_DOC_DOCTYPE, doc_type);
   2413 }
   2414 
   2415 //
   2416 // ISimpleDOMNode methods.
   2417 //
   2418 
   2419 STDMETHODIMP BrowserAccessibilityWin::get_nodeInfo(
   2420     BSTR* node_name,
   2421     short* name_space_id,
   2422     BSTR* node_value,
   2423     unsigned int* num_children,
   2424     unsigned int* unique_id,
   2425     unsigned short* node_type) {
   2426   if (!instance_active())
   2427     return E_FAIL;
   2428 
   2429   if (!node_name || !name_space_id || !node_value || !num_children ||
   2430       !unique_id || !node_type) {
   2431     return E_INVALIDARG;
   2432   }
   2433 
   2434   base::string16 tag;
   2435   if (GetString16Attribute(AccessibilityNodeData::ATTR_HTML_TAG, &tag))
   2436     *node_name = SysAllocString(tag.c_str());
   2437   else
   2438     *node_name = NULL;
   2439 
   2440   *name_space_id = 0;
   2441   *node_value = SysAllocString(UTF8ToUTF16(value()).c_str());
   2442   *num_children = PlatformChildCount();
   2443   *unique_id = unique_id_win_;
   2444 
   2445   if (ia_role_ == ROLE_SYSTEM_DOCUMENT) {
   2446     *node_type = NODETYPE_DOCUMENT;
   2447   } else if (ia_role_ == ROLE_SYSTEM_TEXT &&
   2448              ((ia2_state_ & IA2_STATE_EDITABLE) == 0)) {
   2449     *node_type = NODETYPE_TEXT;
   2450   } else {
   2451     *node_type = NODETYPE_ELEMENT;
   2452   }
   2453 
   2454   return S_OK;
   2455 }
   2456 
   2457 STDMETHODIMP BrowserAccessibilityWin::get_attributes(
   2458     unsigned short max_attribs,
   2459     BSTR* attrib_names,
   2460     short* name_space_id,
   2461     BSTR* attrib_values,
   2462     unsigned short* num_attribs) {
   2463   if (!instance_active())
   2464     return E_FAIL;
   2465 
   2466   if (!attrib_names || !name_space_id || !attrib_values || !num_attribs)
   2467     return E_INVALIDARG;
   2468 
   2469   *num_attribs = max_attribs;
   2470   if (*num_attribs > html_attributes().size())
   2471     *num_attribs = html_attributes().size();
   2472 
   2473   for (unsigned short i = 0; i < *num_attribs; ++i) {
   2474     attrib_names[i] = SysAllocString(
   2475         UTF8ToUTF16(html_attributes()[i].first).c_str());
   2476     name_space_id[i] = 0;
   2477     attrib_values[i] = SysAllocString(
   2478         UTF8ToUTF16(html_attributes()[i].second).c_str());
   2479   }
   2480   return S_OK;
   2481 }
   2482 
   2483 STDMETHODIMP BrowserAccessibilityWin::get_attributesForNames(
   2484     unsigned short num_attribs,
   2485     BSTR* attrib_names,
   2486     short* name_space_id,
   2487     BSTR* attrib_values) {
   2488   if (!instance_active())
   2489     return E_FAIL;
   2490 
   2491   if (!attrib_names || !name_space_id || !attrib_values)
   2492     return E_INVALIDARG;
   2493 
   2494   for (unsigned short i = 0; i < num_attribs; ++i) {
   2495     name_space_id[i] = 0;
   2496     bool found = false;
   2497     std::string name = UTF16ToUTF8((LPCWSTR)attrib_names[i]);
   2498     for (unsigned int j = 0;  j < html_attributes().size(); ++j) {
   2499       if (html_attributes()[j].first == name) {
   2500         attrib_values[i] = SysAllocString(
   2501             UTF8ToUTF16(html_attributes()[j].second).c_str());
   2502         found = true;
   2503         break;
   2504       }
   2505     }
   2506     if (!found) {
   2507       attrib_values[i] = NULL;
   2508     }
   2509   }
   2510   return S_OK;
   2511 }
   2512 
   2513 STDMETHODIMP BrowserAccessibilityWin::get_computedStyle(
   2514     unsigned short max_style_properties,
   2515     boolean use_alternate_view,
   2516     BSTR* style_properties,
   2517     BSTR* style_values,
   2518     unsigned short *num_style_properties)  {
   2519   if (!instance_active())
   2520     return E_FAIL;
   2521 
   2522   if (!style_properties || !style_values)
   2523     return E_INVALIDARG;
   2524 
   2525   // We only cache a single style property for now: DISPLAY
   2526 
   2527   base::string16 display;
   2528   if (max_style_properties == 0 ||
   2529       !GetString16Attribute(AccessibilityNodeData::ATTR_DISPLAY, &display)) {
   2530     *num_style_properties = 0;
   2531     return S_OK;
   2532   }
   2533 
   2534   *num_style_properties = 1;
   2535   style_properties[0] = SysAllocString(L"display");
   2536   style_values[0] = SysAllocString(display.c_str());
   2537 
   2538   return S_OK;
   2539 }
   2540 
   2541 STDMETHODIMP BrowserAccessibilityWin::get_computedStyleForProperties(
   2542     unsigned short num_style_properties,
   2543     boolean use_alternate_view,
   2544     BSTR* style_properties,
   2545     BSTR* style_values) {
   2546   if (!instance_active())
   2547     return E_FAIL;
   2548 
   2549   if (!style_properties || !style_values)
   2550     return E_INVALIDARG;
   2551 
   2552   // We only cache a single style property for now: DISPLAY
   2553 
   2554   for (unsigned short i = 0; i < num_style_properties; ++i) {
   2555     base::string16 name = (LPCWSTR)style_properties[i];
   2556     StringToLowerASCII(&name);
   2557     if (name == L"display") {
   2558       base::string16 display = GetString16Attribute(
   2559           AccessibilityNodeData::ATTR_DISPLAY);
   2560       style_values[i] = SysAllocString(display.c_str());
   2561     } else {
   2562       style_values[i] = NULL;
   2563     }
   2564   }
   2565 
   2566   return S_OK;
   2567 }
   2568 
   2569 STDMETHODIMP BrowserAccessibilityWin::scrollTo(boolean placeTopLeft) {
   2570   return scrollTo(placeTopLeft ?
   2571       IA2_SCROLL_TYPE_TOP_LEFT : IA2_SCROLL_TYPE_ANYWHERE);
   2572 }
   2573 
   2574 STDMETHODIMP BrowserAccessibilityWin::get_parentNode(ISimpleDOMNode** node) {
   2575   if (!instance_active())
   2576     return E_FAIL;
   2577 
   2578   if (!node)
   2579     return E_INVALIDARG;
   2580 
   2581   *node = parent()->ToBrowserAccessibilityWin()->NewReference();
   2582   return S_OK;
   2583 }
   2584 
   2585 STDMETHODIMP BrowserAccessibilityWin::get_firstChild(ISimpleDOMNode** node)  {
   2586   if (!instance_active())
   2587     return E_FAIL;
   2588 
   2589   if (!node)
   2590     return E_INVALIDARG;
   2591 
   2592   if (PlatformChildCount() == 0) {
   2593     *node = NULL;
   2594     return S_FALSE;
   2595   }
   2596 
   2597   *node = PlatformGetChild(0)->ToBrowserAccessibilityWin()->NewReference();
   2598   return S_OK;
   2599 }
   2600 
   2601 STDMETHODIMP BrowserAccessibilityWin::get_lastChild(ISimpleDOMNode** node) {
   2602   if (!instance_active())
   2603     return E_FAIL;
   2604 
   2605   if (!node)
   2606     return E_INVALIDARG;
   2607 
   2608   if (PlatformChildCount() == 0) {
   2609     *node = NULL;
   2610     return S_FALSE;
   2611   }
   2612 
   2613   *node = PlatformGetChild(PlatformChildCount() - 1)
   2614       ->ToBrowserAccessibilityWin()->NewReference();
   2615   return S_OK;
   2616 }
   2617 
   2618 STDMETHODIMP BrowserAccessibilityWin::get_previousSibling(
   2619     ISimpleDOMNode** node) {
   2620   if (!instance_active())
   2621     return E_FAIL;
   2622 
   2623   if (!node)
   2624     return E_INVALIDARG;
   2625 
   2626   if (!parent() || index_in_parent() <= 0) {
   2627     *node = NULL;
   2628     return S_FALSE;
   2629   }
   2630 
   2631   *node = parent()->children()[index_in_parent() - 1]->
   2632       ToBrowserAccessibilityWin()->NewReference();
   2633   return S_OK;
   2634 }
   2635 
   2636 STDMETHODIMP BrowserAccessibilityWin::get_nextSibling(ISimpleDOMNode** node) {
   2637   if (!instance_active())
   2638     return E_FAIL;
   2639 
   2640   if (!node)
   2641     return E_INVALIDARG;
   2642 
   2643   if (!parent() ||
   2644       index_in_parent() < 0 ||
   2645       index_in_parent() >= static_cast<int>(parent()->children().size()) - 1) {
   2646     *node = NULL;
   2647     return S_FALSE;
   2648   }
   2649 
   2650   *node = parent()->children()[index_in_parent() + 1]->
   2651       ToBrowserAccessibilityWin()->NewReference();
   2652   return S_OK;
   2653 }
   2654 
   2655 STDMETHODIMP BrowserAccessibilityWin::get_childAt(
   2656     unsigned int child_index,
   2657     ISimpleDOMNode** node) {
   2658   if (!instance_active())
   2659     return E_FAIL;
   2660 
   2661   if (!node)
   2662     return E_INVALIDARG;
   2663 
   2664   if (child_index >= PlatformChildCount())
   2665     return E_INVALIDARG;
   2666 
   2667   BrowserAccessibility* child = PlatformGetChild(child_index);
   2668   if (!child) {
   2669     *node = NULL;
   2670     return S_FALSE;
   2671   }
   2672 
   2673   *node = child->ToBrowserAccessibilityWin()->NewReference();
   2674   return S_OK;
   2675 }
   2676 
   2677 //
   2678 // ISimpleDOMText methods.
   2679 //
   2680 
   2681 STDMETHODIMP BrowserAccessibilityWin::get_domText(BSTR* dom_text) {
   2682   if (!instance_active())
   2683     return E_FAIL;
   2684 
   2685   if (!dom_text)
   2686     return E_INVALIDARG;
   2687 
   2688   return GetStringAttributeAsBstr(
   2689       AccessibilityNodeData::ATTR_NAME, dom_text);
   2690 }
   2691 
   2692 STDMETHODIMP BrowserAccessibilityWin::get_clippedSubstringBounds(
   2693     unsigned int start_index,
   2694     unsigned int end_index,
   2695     int* out_x,
   2696     int* out_y,
   2697     int* out_width,
   2698     int* out_height) {
   2699   // TODO(dmazzoni): fully support this API by intersecting the
   2700   // rect with the container's rect.
   2701   return get_unclippedSubstringBounds(
   2702       start_index, end_index, out_x, out_y, out_width, out_height);
   2703 }
   2704 
   2705 STDMETHODIMP BrowserAccessibilityWin::get_unclippedSubstringBounds(
   2706     unsigned int start_index,
   2707     unsigned int end_index,
   2708     int* out_x,
   2709     int* out_y,
   2710     int* out_width,
   2711     int* out_height) {
   2712   if (!instance_active())
   2713     return E_FAIL;
   2714 
   2715   if (!out_x || !out_y || !out_width || !out_height)
   2716     return E_INVALIDARG;
   2717 
   2718   const base::string16& text_str = TextForIAccessibleText();
   2719   if (start_index > text_str.size() ||
   2720       end_index > text_str.size() ||
   2721       start_index > end_index) {
   2722     return E_INVALIDARG;
   2723   }
   2724 
   2725   if (blink_role() != blink::WebAXRoleStaticText)
   2726     return E_FAIL;
   2727 
   2728   gfx::Rect bounds = GetGlobalBoundsForRange(
   2729       start_index, end_index - start_index);
   2730   *out_x = bounds.x();
   2731   *out_y = bounds.y();
   2732   *out_width = bounds.width();
   2733   *out_height = bounds.height();
   2734   return S_OK;
   2735 }
   2736 
   2737 STDMETHODIMP BrowserAccessibilityWin::scrollToSubstring(
   2738     unsigned int start_index,
   2739     unsigned int end_index) {
   2740   if (!instance_active())
   2741     return E_FAIL;
   2742 
   2743   const base::string16& text_str = TextForIAccessibleText();
   2744   if (start_index > text_str.size() ||
   2745       end_index > text_str.size() ||
   2746       start_index > end_index) {
   2747     return E_INVALIDARG;
   2748   }
   2749 
   2750   manager()->ScrollToMakeVisible(*this, GetLocalBoundsForRange(
   2751       start_index, end_index - start_index));
   2752   manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
   2753 
   2754   return S_OK;
   2755 }
   2756 
   2757 //
   2758 // IServiceProvider methods.
   2759 //
   2760 
   2761 STDMETHODIMP BrowserAccessibilityWin::QueryService(REFGUID guidService,
   2762                                                    REFIID riid,
   2763                                                    void** object) {
   2764   if (!instance_active())
   2765     return E_FAIL;
   2766 
   2767   // The system uses IAccessible APIs for many purposes, but only
   2768   // assistive technology like screen readers uses IAccessible2.
   2769   // Enable full accessibility support when IAccessible2 APIs are queried.
   2770   if (riid == IID_IAccessible2)
   2771     BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility();
   2772 
   2773   if (guidService == GUID_IAccessibleContentDocument) {
   2774     // Special Mozilla extension: return the accessible for the root document.
   2775     // Screen readers use this to distinguish between a document loaded event
   2776     // on the root document vs on an iframe.
   2777     return manager()->GetRoot()->ToBrowserAccessibilityWin()->QueryInterface(
   2778         IID_IAccessible2, object);
   2779   }
   2780 
   2781   if (guidService == IID_IAccessible ||
   2782       guidService == IID_IAccessible2 ||
   2783       guidService == IID_IAccessibleAction ||
   2784       guidService == IID_IAccessibleApplication ||
   2785       guidService == IID_IAccessibleHyperlink ||
   2786       guidService == IID_IAccessibleHypertext ||
   2787       guidService == IID_IAccessibleImage ||
   2788       guidService == IID_IAccessibleTable ||
   2789       guidService == IID_IAccessibleTable2 ||
   2790       guidService == IID_IAccessibleTableCell ||
   2791       guidService == IID_IAccessibleText ||
   2792       guidService == IID_IAccessibleValue ||
   2793       guidService == IID_ISimpleDOMDocument ||
   2794       guidService == IID_ISimpleDOMNode ||
   2795       guidService == IID_ISimpleDOMText ||
   2796       guidService == GUID_ISimpleDOM) {
   2797     return QueryInterface(riid, object);
   2798   }
   2799 
   2800   // We only support the IAccessibleEx interface on Windows 8 and above. This
   2801   // is needed for the on-screen Keyboard to show up in metro mode, when the
   2802   // user taps an editable portion on the page.
   2803   // All methods in the IAccessibleEx interface are unimplemented.
   2804   if (riid == IID_IAccessibleEx &&
   2805       base::win::GetVersion() >= base::win::VERSION_WIN8) {
   2806     return QueryInterface(riid, object);
   2807   }
   2808 
   2809   *object = NULL;
   2810   return E_FAIL;
   2811 }
   2812 
   2813 STDMETHODIMP BrowserAccessibilityWin::GetPatternProvider(PATTERNID id,
   2814                                                          IUnknown** provider) {
   2815   DVLOG(1) << "In Function: "
   2816            << __FUNCTION__
   2817            << " for pattern id: "
   2818            << id;
   2819   if (id == UIA_ValuePatternId || id == UIA_TextPatternId) {
   2820     if (IsEditableText()) {
   2821       // The BrowserAccessibilityManager keeps track of instances when
   2822       // we don't want to show the on-screen keyboard.
   2823       if (!manager()->IsOSKAllowed(GetGlobalBoundsRect()))
   2824         return E_NOTIMPL;
   2825 
   2826       DVLOG(1) << "Returning UIA text provider";
   2827       base::win::UIATextProvider::CreateTextProvider(true, provider);
   2828       return S_OK;
   2829     }
   2830   }
   2831   return E_NOTIMPL;
   2832 }
   2833 
   2834 STDMETHODIMP BrowserAccessibilityWin::GetPropertyValue(PROPERTYID id,
   2835                                                        VARIANT* ret) {
   2836   DVLOG(1) << "In Function: "
   2837            << __FUNCTION__
   2838            << " for property id: "
   2839            << id;
   2840   V_VT(ret) = VT_EMPTY;
   2841   if (id == UIA_ControlTypePropertyId) {
   2842     if (IsEditableText()) {
   2843       V_VT(ret) = VT_I4;
   2844       ret->lVal = UIA_EditControlTypeId;
   2845       DVLOG(1) << "Returning Edit control type";
   2846     } else {
   2847       DVLOG(1) << "Returning empty control type";
   2848     }
   2849   }
   2850   return S_OK;
   2851 }
   2852 
   2853 //
   2854 // CComObjectRootEx methods.
   2855 //
   2856 
   2857 HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface(
   2858     void* this_ptr,
   2859     const _ATL_INTMAP_ENTRY* entries,
   2860     REFIID iid,
   2861     void** object) {
   2862   if (iid == IID_IAccessibleImage) {
   2863     if (ia_role_ != ROLE_SYSTEM_GRAPHIC) {
   2864       *object = NULL;
   2865       return E_NOINTERFACE;
   2866     }
   2867   } else if (iid == IID_IAccessibleTable || iid == IID_IAccessibleTable2) {
   2868     if (ia_role_ != ROLE_SYSTEM_TABLE) {
   2869       *object = NULL;
   2870       return E_NOINTERFACE;
   2871     }
   2872   } else if (iid == IID_IAccessibleTableCell) {
   2873     if (ia_role_ != ROLE_SYSTEM_CELL) {
   2874       *object = NULL;
   2875       return E_NOINTERFACE;
   2876     }
   2877   } else if (iid == IID_IAccessibleValue) {
   2878     if (ia_role_ != ROLE_SYSTEM_PROGRESSBAR &&
   2879         ia_role_ != ROLE_SYSTEM_SCROLLBAR &&
   2880         ia_role_ != ROLE_SYSTEM_SLIDER) {
   2881       *object = NULL;
   2882       return E_NOINTERFACE;
   2883     }
   2884   } else if (iid == IID_ISimpleDOMDocument) {
   2885     if (ia_role_ != ROLE_SYSTEM_DOCUMENT) {
   2886       *object = NULL;
   2887       return E_NOINTERFACE;
   2888     }
   2889   }
   2890 
   2891   return CComObjectRootBase::InternalQueryInterface(
   2892       this_ptr, entries, iid, object);
   2893 }
   2894 
   2895 //
   2896 // Private methods.
   2897 //
   2898 
   2899 // Initialize this object and mark it as active.
   2900 void BrowserAccessibilityWin::PreInitialize() {
   2901   BrowserAccessibility::PreInitialize();
   2902 
   2903   InitRoleAndState();
   2904 
   2905   // Expose the "display" and "tag" attributes.
   2906   StringAttributeToIA2(AccessibilityNodeData::ATTR_DISPLAY, "display");
   2907   StringAttributeToIA2(AccessibilityNodeData::ATTR_HTML_TAG, "tag");
   2908   StringAttributeToIA2(AccessibilityNodeData::ATTR_ROLE, "xml-roles");
   2909 
   2910   // Expose "level" attribute for headings, trees, etc.
   2911   IntAttributeToIA2(AccessibilityNodeData::ATTR_HIERARCHICAL_LEVEL, "level");
   2912 
   2913   // Expose the set size and position in set for listbox options.
   2914   if (blink_role() == blink::WebAXRoleListBoxOption &&
   2915       parent() &&
   2916       parent()->role() == blink::WebAXRoleListBox) {
   2917     ia2_attributes_.push_back(
   2918         L"setsize:" + base::IntToString16(parent()->PlatformChildCount()));
   2919     ia2_attributes_.push_back(
   2920         L"setsize:" + base::IntToString16(index_in_parent() + 1));
   2921   }
   2922 
   2923   if (ia_role_ == ROLE_SYSTEM_CHECKBUTTON ||
   2924       ia_role_ == ROLE_SYSTEM_RADIOBUTTON ||
   2925       ia2_role_ == IA2_ROLE_TOGGLE_BUTTON) {
   2926     ia2_attributes_.push_back(L"checkable:true");
   2927   }
   2928 
   2929   // Expose live region attributes.
   2930   StringAttributeToIA2(AccessibilityNodeData::ATTR_LIVE_STATUS, "live");
   2931   StringAttributeToIA2(AccessibilityNodeData::ATTR_LIVE_RELEVANT, "relevant");
   2932   BoolAttributeToIA2(AccessibilityNodeData::ATTR_LIVE_ATOMIC, "atomic");
   2933   BoolAttributeToIA2(AccessibilityNodeData::ATTR_LIVE_BUSY, "busy");
   2934 
   2935   // Expose container live region attributes.
   2936   StringAttributeToIA2(AccessibilityNodeData::ATTR_CONTAINER_LIVE_STATUS,
   2937                        "container-live");
   2938   StringAttributeToIA2(AccessibilityNodeData::ATTR_CONTAINER_LIVE_RELEVANT,
   2939                        "container-relevant");
   2940   BoolAttributeToIA2(AccessibilityNodeData::ATTR_CONTAINER_LIVE_ATOMIC,
   2941                      "container-atomic");
   2942   BoolAttributeToIA2(AccessibilityNodeData::ATTR_CONTAINER_LIVE_BUSY,
   2943                      "container-busy");
   2944 
   2945   // Expose slider value.
   2946   if (ia_role_ == ROLE_SYSTEM_PROGRESSBAR ||
   2947       ia_role_ == ROLE_SYSTEM_SCROLLBAR ||
   2948       ia_role_ == ROLE_SYSTEM_SLIDER) {
   2949     ia2_attributes_.push_back(L"valuetext:" + GetValueText());
   2950   }
   2951 
   2952   // Expose table cell index.
   2953   if (ia_role_ == ROLE_SYSTEM_CELL) {
   2954     BrowserAccessibility* table = parent();
   2955     while (table && table->role() != blink::WebAXRoleTable)
   2956       table = table->parent();
   2957     if (table) {
   2958       const std::vector<int32>& unique_cell_ids = table->GetIntListAttribute(
   2959           AccessibilityNodeData::ATTR_UNIQUE_CELL_IDS);
   2960       for (size_t i = 0; i < unique_cell_ids.size(); ++i) {
   2961         if (unique_cell_ids[i] == renderer_id()) {
   2962           ia2_attributes_.push_back(
   2963               base::string16(L"table-cell-index:") + base::IntToString16(i));
   2964         }
   2965       }
   2966     }
   2967   }
   2968 
   2969   // The calculation of the accessible name of an element has been
   2970   // standardized in the HTML to Platform Accessibility APIs Implementation
   2971   // Guide (http://www.w3.org/TR/html-aapi/). In order to return the
   2972   // appropriate accessible name on Windows, we need to apply some logic
   2973   // to the fields we get from WebKit.
   2974   //
   2975   // TODO(dmazzoni): move most of this logic into WebKit.
   2976   //
   2977   // WebKit gives us:
   2978   //
   2979   //   name: the default name, e.g. inner text
   2980   //   title ui element: a reference to a <label> element on the same
   2981   //       page that labels this node.
   2982   //   description: accessible labels that override the default name:
   2983   //       aria-label or aria-labelledby or aria-describedby
   2984   //   help: the value of the "title" attribute
   2985   //
   2986   // On Windows, the logic we apply lets some fields take precedence and
   2987   // always returns the primary name in "name" and the secondary name,
   2988   // if any, in "description".
   2989 
   2990   int title_elem_id = GetIntAttribute(
   2991       AccessibilityNodeData::ATTR_TITLE_UI_ELEMENT);
   2992   std::string help = GetStringAttribute(AccessibilityNodeData::ATTR_HELP);
   2993   std::string description = GetStringAttribute(
   2994       AccessibilityNodeData::ATTR_DESCRIPTION);
   2995 
   2996   // WebKit annoyingly puts the title in the description if there's no other
   2997   // description, which just confuses the rest of the logic. Put it back.
   2998   // Now "help" is always the value of the "title" attribute, if present.
   2999   std::string title_attr;
   3000   if (GetHtmlAttribute("title", &title_attr) &&
   3001       description == title_attr &&
   3002       help.empty()) {
   3003     help = description;
   3004     description.clear();
   3005   }
   3006 
   3007   // Now implement the main logic: the descripion should become the name if
   3008   // it's nonempty, and the help should become the description if
   3009   // there's no description - or the name if there's no name or description.
   3010   if (!description.empty()) {
   3011     set_name(description);
   3012     description.clear();
   3013   }
   3014   if (!help.empty() && description.empty()) {
   3015     description = help;
   3016     help.clear();
   3017   }
   3018   if (!description.empty() && name().empty() && !title_elem_id) {
   3019     set_name(description);
   3020     description.clear();
   3021   }
   3022 
   3023   // If it's a text field, also consider the placeholder.
   3024   std::string placeholder;
   3025   if (blink_role() == blink::WebAXRoleTextField &&
   3026       HasState(blink::WebAXStateFocusable) &&
   3027       GetHtmlAttribute("placeholder", &placeholder)) {
   3028     if (name().empty() && !title_elem_id) {
   3029       set_name(placeholder);
   3030     } else if (description.empty()) {
   3031       description = placeholder;
   3032     }
   3033   }
   3034 
   3035   SetStringAttribute(AccessibilityNodeData::ATTR_DESCRIPTION, description);
   3036   SetStringAttribute(AccessibilityNodeData::ATTR_HELP, help);
   3037 
   3038   // On Windows, the value of a document should be its url.
   3039   if (blink_role() == blink::WebAXRoleRootWebArea ||
   3040       blink_role() == blink::WebAXRoleWebArea) {
   3041     set_value(GetStringAttribute(AccessibilityNodeData::ATTR_DOC_URL));
   3042   }
   3043 
   3044   // For certain roles (listbox option, static text, and list marker)
   3045   // WebKit stores the main accessible text in the "value" - swap it so
   3046   // that it's the "name".
   3047   if (name().empty() &&
   3048       (blink_role() == blink::WebAXRoleListBoxOption ||
   3049        blink_role() == blink::WebAXRoleStaticText ||
   3050        blink_role() == blink::WebAXRoleListMarker)) {
   3051     std::string tmp = value();
   3052     set_value(name());
   3053     set_name(tmp);
   3054   }
   3055 
   3056   // If this doesn't have a value and is linked then set its value to the url
   3057   // attribute. This allows screen readers to read an empty link's destination.
   3058   if (value().empty() && (ia_state_ & STATE_SYSTEM_LINKED))
   3059     set_value(GetStringAttribute(AccessibilityNodeData::ATTR_URL));
   3060 
   3061   // Clear any old relationships between this node and other nodes.
   3062   for (size_t i = 0; i < relations_.size(); ++i)
   3063     relations_[i]->Release();
   3064   relations_.clear();
   3065 
   3066   // Handle title UI element.
   3067   if (title_elem_id) {
   3068     // Add a labelled by relationship.
   3069     CComObject<BrowserAccessibilityRelation>* relation;
   3070     HRESULT hr = CComObject<BrowserAccessibilityRelation>::CreateInstance(
   3071         &relation);
   3072     DCHECK(SUCCEEDED(hr));
   3073     relation->AddRef();
   3074     relation->Initialize(this, IA2_RELATION_LABELLED_BY);
   3075     relation->AddTarget(title_elem_id);
   3076     relations_.push_back(relation);
   3077   }
   3078 }
   3079 
   3080 void BrowserAccessibilityWin::PostInitialize() {
   3081   BrowserAccessibility::PostInitialize();
   3082 
   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->role() == blink::WebAXRoleStaticText) {
   3090       hypertext_ += 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 (blink_role() == blink::WebAXRoleAlert && first_time_)
   3101     manager()->NotifyAccessibilityEvent(blink::WebAXEventAlert, 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           blink::WebAXEventShow, 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 (blink_role() == blink::WebAXRoleListBoxOption &&
   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(AccessibilityNodeData::ATTR_SCROLL_X, &sx) &&
   3151       GetIntAttribute(AccessibilityNodeData::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::SetLocation(const gfx::Rect& new_location) {
   3177   BrowserAccessibility::SetLocation(new_location);
   3178   manager()->ToBrowserAccessibilityManagerWin()->MaybeCallNotifyWinEvent(
   3179       EVENT_OBJECT_LOCATIONCHANGE, unique_id_win());
   3180 }
   3181 
   3182 BrowserAccessibilityWin* BrowserAccessibilityWin::NewReference() {
   3183   AddRef();
   3184   return this;
   3185 }
   3186 
   3187 BrowserAccessibilityWin* BrowserAccessibilityWin::GetTargetFromChildID(
   3188     const VARIANT& var_id) {
   3189   if (var_id.vt != VT_I4)
   3190     return NULL;
   3191 
   3192   LONG child_id = var_id.lVal;
   3193   if (child_id == CHILDID_SELF)
   3194     return this;
   3195 
   3196   if (child_id >= 1 && child_id <= static_cast<LONG>(PlatformChildCount()))
   3197     return PlatformGetChild(child_id - 1)->ToBrowserAccessibilityWin();
   3198 
   3199   return manager()->ToBrowserAccessibilityManagerWin()->
   3200       GetFromUniqueIdWin(child_id);
   3201 }
   3202 
   3203 HRESULT BrowserAccessibilityWin::GetStringAttributeAsBstr(
   3204     AccessibilityNodeData::StringAttribute attribute,
   3205     BSTR* value_bstr) {
   3206   base::string16 str;
   3207 
   3208   if (!GetString16Attribute(attribute, &str))
   3209     return S_FALSE;
   3210 
   3211   if (str.empty())
   3212     return S_FALSE;
   3213 
   3214   *value_bstr = SysAllocString(str.c_str());
   3215   DCHECK(*value_bstr);
   3216 
   3217   return S_OK;
   3218 }
   3219 
   3220 void BrowserAccessibilityWin::StringAttributeToIA2(
   3221     AccessibilityNodeData::StringAttribute attribute,
   3222     const char* ia2_attr) {
   3223   base::string16 value;
   3224   if (GetString16Attribute(attribute, &value))
   3225     ia2_attributes_.push_back(ASCIIToUTF16(ia2_attr) + L":" + value);
   3226 }
   3227 
   3228 void BrowserAccessibilityWin::BoolAttributeToIA2(
   3229     AccessibilityNodeData::BoolAttribute attribute,
   3230     const char* ia2_attr) {
   3231   bool value;
   3232   if (GetBoolAttribute(attribute, &value)) {
   3233     ia2_attributes_.push_back((ASCIIToUTF16(ia2_attr) + L":") +
   3234                               (value ? L"true" : L"false"));
   3235   }
   3236 }
   3237 
   3238 void BrowserAccessibilityWin::IntAttributeToIA2(
   3239     AccessibilityNodeData::IntAttribute attribute,
   3240     const char* ia2_attr) {
   3241   int value;
   3242   if (GetIntAttribute(attribute, &value)) {
   3243     ia2_attributes_.push_back(ASCIIToUTF16(ia2_attr) + L":" +
   3244                               base::IntToString16(value));
   3245   }
   3246 }
   3247 
   3248 base::string16 BrowserAccessibilityWin::GetValueText() {
   3249   float fval;
   3250   base::string16 value = UTF8ToUTF16(this->value());
   3251 
   3252   if (value.empty() &&
   3253       GetFloatAttribute(AccessibilityNodeData::ATTR_VALUE_FOR_RANGE, &fval)) {
   3254     value = UTF8ToUTF16(base::DoubleToString(fval));
   3255   }
   3256   return value;
   3257 }
   3258 
   3259 base::string16 BrowserAccessibilityWin::TextForIAccessibleText() {
   3260   if (IsEditableText())
   3261     return UTF8ToUTF16(value());
   3262   return (blink_role() == blink::WebAXRoleStaticText) ?
   3263       UTF8ToUTF16(name()) : hypertext_;
   3264 }
   3265 
   3266 void BrowserAccessibilityWin::HandleSpecialTextOffset(
   3267     const base::string16& text,
   3268     LONG* offset) {
   3269   if (*offset == IA2_TEXT_OFFSET_LENGTH)
   3270     *offset = static_cast<LONG>(text.size());
   3271   else if (*offset == IA2_TEXT_OFFSET_CARET)
   3272     get_caretOffset(offset);
   3273 }
   3274 
   3275 ui::TextBoundaryType BrowserAccessibilityWin::IA2TextBoundaryToTextBoundary(
   3276     IA2TextBoundaryType ia2_boundary) {
   3277   switch(ia2_boundary) {
   3278     case IA2_TEXT_BOUNDARY_CHAR: return ui::CHAR_BOUNDARY;
   3279     case IA2_TEXT_BOUNDARY_WORD: return ui::WORD_BOUNDARY;
   3280     case IA2_TEXT_BOUNDARY_LINE: return ui::LINE_BOUNDARY;
   3281     case IA2_TEXT_BOUNDARY_SENTENCE: return ui::SENTENCE_BOUNDARY;
   3282     case IA2_TEXT_BOUNDARY_PARAGRAPH: return ui::PARAGRAPH_BOUNDARY;
   3283     case IA2_TEXT_BOUNDARY_ALL: return ui::ALL_BOUNDARY;
   3284     default:
   3285       NOTREACHED();
   3286       return ui::CHAR_BOUNDARY;
   3287   }
   3288 }
   3289 
   3290 LONG BrowserAccessibilityWin::FindBoundary(
   3291     const base::string16& text,
   3292     IA2TextBoundaryType ia2_boundary,
   3293     LONG start_offset,
   3294     ui::TextBoundaryDirection direction) {
   3295   HandleSpecialTextOffset(text, &start_offset);
   3296   ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary);
   3297   const std::vector<int32>& line_breaks = GetIntListAttribute(
   3298       AccessibilityNodeData::ATTR_LINE_BREAKS);
   3299   return ui::FindAccessibleTextBoundary(
   3300       text, line_breaks, boundary, start_offset, direction);
   3301 }
   3302 
   3303 BrowserAccessibilityWin* BrowserAccessibilityWin::GetFromRendererID(
   3304     int32 renderer_id) {
   3305   return manager()->GetFromRendererID(renderer_id)->ToBrowserAccessibilityWin();
   3306 }
   3307 
   3308 void BrowserAccessibilityWin::InitRoleAndState() {
   3309   ia_state_ = 0;
   3310   ia2_state_ = IA2_STATE_OPAQUE;
   3311   ia2_attributes_.clear();
   3312 
   3313   if (HasState(blink::WebAXStateBusy))
   3314     ia_state_ |= STATE_SYSTEM_BUSY;
   3315   if (HasState(blink::WebAXStateChecked))
   3316     ia_state_ |= STATE_SYSTEM_CHECKED;
   3317   if (HasState(blink::WebAXStateCollapsed))
   3318     ia_state_ |= STATE_SYSTEM_COLLAPSED;
   3319   if (HasState(blink::WebAXStateExpanded))
   3320     ia_state_ |= STATE_SYSTEM_EXPANDED;
   3321   if (HasState(blink::WebAXStateFocusable))
   3322     ia_state_ |= STATE_SYSTEM_FOCUSABLE;
   3323   if (HasState(blink::WebAXStateHaspopup))
   3324     ia_state_ |= STATE_SYSTEM_HASPOPUP;
   3325   if (HasState(blink::WebAXStateHovered))
   3326     ia_state_ |= STATE_SYSTEM_HOTTRACKED;
   3327   if (HasState(blink::WebAXStateIndeterminate))
   3328     ia_state_ |= STATE_SYSTEM_INDETERMINATE;
   3329   if (HasState(blink::WebAXStateInvisible))
   3330     ia_state_ |= STATE_SYSTEM_INVISIBLE;
   3331   if (HasState(blink::WebAXStateLinked))
   3332     ia_state_ |= STATE_SYSTEM_LINKED;
   3333   if (HasState(blink::WebAXStateMultiselectable)) {
   3334     ia_state_ |= STATE_SYSTEM_EXTSELECTABLE;
   3335     ia_state_ |= STATE_SYSTEM_MULTISELECTABLE;
   3336   }
   3337   // TODO(ctguil): Support STATE_SYSTEM_EXTSELECTABLE/accSelect.
   3338   if (HasState(blink::WebAXStateOffscreen))
   3339     ia_state_ |= STATE_SYSTEM_OFFSCREEN;
   3340   if (HasState(blink::WebAXStatePressed))
   3341     ia_state_ |= STATE_SYSTEM_PRESSED;
   3342   if (HasState(blink::WebAXStateProtected))
   3343     ia_state_ |= STATE_SYSTEM_PROTECTED;
   3344   if (HasState(blink::WebAXStateRequired))
   3345     ia2_state_ |= IA2_STATE_REQUIRED;
   3346   if (HasState(blink::WebAXStateSelectable))
   3347     ia_state_ |= STATE_SYSTEM_SELECTABLE;
   3348   if (HasState(blink::WebAXStateSelected))
   3349     ia_state_ |= STATE_SYSTEM_SELECTED;
   3350   if (HasState(blink::WebAXStateVisited))
   3351     ia_state_ |= STATE_SYSTEM_TRAVERSED;
   3352   if (!HasState(blink::WebAXStateEnabled))
   3353     ia_state_ |= STATE_SYSTEM_UNAVAILABLE;
   3354   if (HasState(blink::WebAXStateVertical)) {
   3355     ia2_state_ |= IA2_STATE_VERTICAL;
   3356   } else {
   3357     ia2_state_ |= IA2_STATE_HORIZONTAL;
   3358   }
   3359   if (HasState(blink::WebAXStateVisited))
   3360     ia_state_ |= STATE_SYSTEM_TRAVERSED;
   3361 
   3362   // WebKit marks everything as readonly unless it's editable text, so if it's
   3363   // not readonly, mark it as editable now. The final computation of the
   3364   // READONLY state for MSAA is below, after the switch.
   3365   if (!HasState(blink::WebAXStateReadonly))
   3366     ia2_state_ |= IA2_STATE_EDITABLE;
   3367 
   3368   base::string16 invalid;
   3369   if (GetHtmlAttribute("aria-invalid", &invalid))
   3370     ia2_state_ |= IA2_STATE_INVALID_ENTRY;
   3371 
   3372   if (GetBoolAttribute(AccessibilityNodeData::ATTR_BUTTON_MIXED))
   3373     ia_state_ |= STATE_SYSTEM_MIXED;
   3374 
   3375   if (GetBoolAttribute(AccessibilityNodeData::ATTR_CAN_SET_VALUE))
   3376     ia2_state_ |= IA2_STATE_EDITABLE;
   3377 
   3378   base::string16 html_tag = GetString16Attribute(
   3379       AccessibilityNodeData::ATTR_HTML_TAG);
   3380   ia_role_ = 0;
   3381   ia2_role_ = 0;
   3382   switch (blink_role()) {
   3383     case blink::WebAXRoleAlert:
   3384       ia_role_ = ROLE_SYSTEM_ALERT;
   3385       break;
   3386     case blink::WebAXRoleAlertDialog:
   3387       ia_role_ = ROLE_SYSTEM_DIALOG;
   3388       break;
   3389     case blink::WebAXRoleApplication:
   3390       ia_role_ = ROLE_SYSTEM_APPLICATION;
   3391       break;
   3392     case blink::WebAXRoleArticle:
   3393       ia_role_ = ROLE_SYSTEM_GROUPING;
   3394       ia2_role_ = IA2_ROLE_SECTION;
   3395       ia_state_ |= STATE_SYSTEM_READONLY;
   3396       break;
   3397     case blink::WebAXRoleBusyIndicator:
   3398       ia_role_ = ROLE_SYSTEM_ANIMATION;
   3399       ia_state_ |= STATE_SYSTEM_READONLY;
   3400       break;
   3401     case blink::WebAXRoleButton:
   3402       ia_role_ = ROLE_SYSTEM_PUSHBUTTON;
   3403       bool is_aria_pressed_defined;
   3404       bool is_mixed;
   3405       if (GetAriaTristate("aria-pressed", &is_aria_pressed_defined, &is_mixed))
   3406         ia_state_ |= STATE_SYSTEM_PRESSED;
   3407       if (is_aria_pressed_defined)
   3408         ia2_role_ = IA2_ROLE_TOGGLE_BUTTON;
   3409       if (is_mixed)
   3410         ia_state_ |= STATE_SYSTEM_MIXED;
   3411       break;
   3412     case blink::WebAXRoleCanvas:
   3413       if (GetBoolAttribute(AccessibilityNodeData::ATTR_CANVAS_HAS_FALLBACK)) {
   3414         role_name_ = L"canvas";
   3415         ia2_role_ = IA2_ROLE_CANVAS;
   3416       } else {
   3417         ia_role_ = ROLE_SYSTEM_GRAPHIC;
   3418       }
   3419       break;
   3420     case blink::WebAXRoleCell:
   3421       ia_role_ = ROLE_SYSTEM_CELL;
   3422       break;
   3423     case blink::WebAXRoleCheckBox:
   3424       ia_role_ = ROLE_SYSTEM_CHECKBUTTON;
   3425       break;
   3426     case blink::WebAXRoleColorWell:
   3427       ia_role_ = ROLE_SYSTEM_CLIENT;
   3428       ia2_role_ = IA2_ROLE_COLOR_CHOOSER;
   3429       break;
   3430     case blink::WebAXRoleColumn:
   3431       ia_role_ = ROLE_SYSTEM_COLUMN;
   3432       ia_state_ |= STATE_SYSTEM_READONLY;
   3433       break;
   3434     case blink::WebAXRoleColumnHeader:
   3435       ia_role_ = ROLE_SYSTEM_COLUMNHEADER;
   3436       ia_state_ |= STATE_SYSTEM_READONLY;
   3437       break;
   3438     case blink::WebAXRoleComboBox:
   3439       ia_role_ = ROLE_SYSTEM_COMBOBOX;
   3440       break;
   3441     case blink::WebAXRoleDiv:
   3442       role_name_ = L"div";
   3443       ia2_role_ = IA2_ROLE_SECTION;
   3444       break;
   3445     case blink::WebAXRoleDefinition:
   3446       role_name_ = html_tag;
   3447       ia2_role_ = IA2_ROLE_PARAGRAPH;
   3448       ia_state_ |= STATE_SYSTEM_READONLY;
   3449       break;
   3450     case blink::WebAXRoleDescriptionListDetail:
   3451       role_name_ = html_tag;
   3452       ia2_role_ = IA2_ROLE_PARAGRAPH;
   3453       ia_state_ |= STATE_SYSTEM_READONLY;
   3454       break;
   3455     case blink::WebAXRoleDescriptionListTerm:
   3456       ia_role_ = ROLE_SYSTEM_LISTITEM;
   3457       ia_state_ |= STATE_SYSTEM_READONLY;
   3458       break;
   3459     case blink::WebAXRoleDialog:
   3460       ia_role_ = ROLE_SYSTEM_DIALOG;
   3461       ia_state_ |= STATE_SYSTEM_READONLY;
   3462       break;
   3463     case blink::WebAXRoleDisclosureTriangle:
   3464       ia_role_ = ROLE_SYSTEM_OUTLINEBUTTON;
   3465       ia_state_ |= STATE_SYSTEM_READONLY;
   3466       break;
   3467     case blink::WebAXRoleDocument:
   3468     case blink::WebAXRoleRootWebArea:
   3469     case blink::WebAXRoleWebArea:
   3470       ia_role_ = ROLE_SYSTEM_DOCUMENT;
   3471       ia_state_ |= STATE_SYSTEM_READONLY;
   3472       ia_state_ |= STATE_SYSTEM_FOCUSABLE;
   3473       break;
   3474     case blink::WebAXRoleEditableText:
   3475       ia_role_ = ROLE_SYSTEM_TEXT;
   3476       ia2_state_ |= IA2_STATE_SINGLE_LINE;
   3477       ia2_state_ |= IA2_STATE_EDITABLE;
   3478       break;
   3479     case blink::WebAXRoleForm:
   3480       role_name_ = L"form";
   3481       ia2_role_ = IA2_ROLE_FORM;
   3482       break;
   3483     case blink::WebAXRoleFooter:
   3484       ia_role_ = IA2_ROLE_FOOTER;
   3485       ia_state_ |= STATE_SYSTEM_READONLY;
   3486       break;
   3487     case blink::WebAXRoleGrid:
   3488       ia_role_ = ROLE_SYSTEM_TABLE;
   3489       ia_state_ |= STATE_SYSTEM_READONLY;
   3490       break;
   3491     case blink::WebAXRoleGroup: {
   3492       base::string16 aria_role = GetString16Attribute(
   3493           AccessibilityNodeData::ATTR_ROLE);
   3494       if (aria_role == L"group" || html_tag == L"fieldset") {
   3495         ia_role_ = ROLE_SYSTEM_GROUPING;
   3496       } else if (html_tag == L"li") {
   3497         ia_role_ = ROLE_SYSTEM_LISTITEM;
   3498       } else {
   3499         if (html_tag.empty())
   3500           role_name_ = L"div";
   3501         else
   3502           role_name_ = html_tag;
   3503         ia2_role_ = IA2_ROLE_SECTION;
   3504       }
   3505       ia_state_ |= STATE_SYSTEM_READONLY;
   3506       break;
   3507     }
   3508     case blink::WebAXRoleGrowArea:
   3509       ia_role_ = ROLE_SYSTEM_GRIP;
   3510       ia_state_ |= STATE_SYSTEM_READONLY;
   3511       break;
   3512     case blink::WebAXRoleHeading:
   3513       role_name_ = html_tag;
   3514       ia2_role_ = IA2_ROLE_HEADING;
   3515       ia_state_ |= STATE_SYSTEM_READONLY;
   3516       break;
   3517     case blink::WebAXRoleHorizontalRule:
   3518       ia_role_ = ROLE_SYSTEM_SEPARATOR;
   3519       break;
   3520     case blink::WebAXRoleImage:
   3521       ia_role_ = ROLE_SYSTEM_GRAPHIC;
   3522       ia_state_ |= STATE_SYSTEM_READONLY;
   3523       break;
   3524     case blink::WebAXRoleImageMap:
   3525       role_name_ = html_tag;
   3526       ia2_role_ = IA2_ROLE_IMAGE_MAP;
   3527       ia_state_ |= STATE_SYSTEM_READONLY;
   3528       break;
   3529     case blink::WebAXRoleImageMapLink:
   3530       ia_role_ = ROLE_SYSTEM_LINK;
   3531       ia_state_ |= STATE_SYSTEM_LINKED;
   3532       ia_state_ |= STATE_SYSTEM_READONLY;
   3533       break;
   3534     case blink::WebAXRoleLabel:
   3535       ia_role_ = ROLE_SYSTEM_TEXT;
   3536       ia2_role_ = IA2_ROLE_LABEL;
   3537       break;
   3538     case blink::WebAXRoleBanner:
   3539     case blink::WebAXRoleComplementary:
   3540     case blink::WebAXRoleContentInfo:
   3541     case blink::WebAXRoleMain:
   3542     case blink::WebAXRoleNavigation:
   3543     case blink::WebAXRoleSearch:
   3544       ia_role_ = ROLE_SYSTEM_GROUPING;
   3545       ia2_role_ = IA2_ROLE_SECTION;
   3546       ia_state_ |= STATE_SYSTEM_READONLY;
   3547       break;
   3548     case blink::WebAXRoleLink:
   3549       ia_role_ = ROLE_SYSTEM_LINK;
   3550       ia_state_ |= STATE_SYSTEM_LINKED;
   3551       break;
   3552     case blink::WebAXRoleList:
   3553       ia_role_ = ROLE_SYSTEM_LIST;
   3554       ia_state_ |= STATE_SYSTEM_READONLY;
   3555       break;
   3556     case blink::WebAXRoleListBox:
   3557       ia_role_ = ROLE_SYSTEM_LIST;
   3558       break;
   3559     case blink::WebAXRoleListBoxOption:
   3560       ia_role_ = ROLE_SYSTEM_LISTITEM;
   3561       if (ia_state_ & STATE_SYSTEM_SELECTABLE) {
   3562         ia_state_ |= STATE_SYSTEM_FOCUSABLE;
   3563         if (HasState(blink::WebAXStateFocused))
   3564           ia_state_ |= STATE_SYSTEM_FOCUSED;
   3565       }
   3566       break;
   3567     case blink::WebAXRoleListItem:
   3568       ia_role_ = ROLE_SYSTEM_LISTITEM;
   3569       ia_state_ |= STATE_SYSTEM_READONLY;
   3570       break;
   3571     case blink::WebAXRoleListMarker:
   3572       ia_role_ = ROLE_SYSTEM_TEXT;
   3573       ia_state_ |= STATE_SYSTEM_READONLY;
   3574       break;
   3575     case blink::WebAXRoleMath:
   3576       ia_role_ = ROLE_SYSTEM_EQUATION;
   3577       ia_state_ |= STATE_SYSTEM_READONLY;
   3578       break;
   3579     case blink::WebAXRoleMenu:
   3580     case blink::WebAXRoleMenuButton:
   3581       ia_role_ = ROLE_SYSTEM_MENUPOPUP;
   3582       break;
   3583     case blink::WebAXRoleMenuBar:
   3584       ia_role_ = ROLE_SYSTEM_MENUBAR;
   3585       break;
   3586     case blink::WebAXRoleMenuItem:
   3587       ia_role_ = ROLE_SYSTEM_MENUITEM;
   3588       break;
   3589     case blink::WebAXRoleMenuListPopup:
   3590       ia_role_ = ROLE_SYSTEM_CLIENT;
   3591       break;
   3592     case blink::WebAXRoleMenuListOption:
   3593       ia_role_ = ROLE_SYSTEM_LISTITEM;
   3594       if (ia_state_ & STATE_SYSTEM_SELECTABLE) {
   3595         ia_state_ |= STATE_SYSTEM_FOCUSABLE;
   3596         if (HasState(blink::WebAXStateFocused))
   3597           ia_state_ |= STATE_SYSTEM_FOCUSED;
   3598       }
   3599       break;
   3600     case blink::WebAXRoleNote:
   3601       ia_role_ = ROLE_SYSTEM_GROUPING;
   3602       ia2_role_ = IA2_ROLE_NOTE;
   3603       ia_state_ |= STATE_SYSTEM_READONLY;
   3604       break;
   3605     case blink::WebAXRoleOutline:
   3606       ia_role_ = ROLE_SYSTEM_OUTLINE;
   3607       ia_state_ |= STATE_SYSTEM_READONLY;
   3608       break;
   3609     case blink::WebAXRoleParagraph:
   3610       role_name_ = L"P";
   3611       ia2_role_ = IA2_ROLE_PARAGRAPH;
   3612       break;
   3613     case blink::WebAXRolePopUpButton:
   3614       if (html_tag == L"select") {
   3615         ia_role_ = ROLE_SYSTEM_COMBOBOX;
   3616       } else {
   3617         ia_role_ = ROLE_SYSTEM_BUTTONMENU;
   3618       }
   3619       break;
   3620     case blink::WebAXRoleProgressIndicator:
   3621       ia_role_ = ROLE_SYSTEM_PROGRESSBAR;
   3622       ia_state_ |= STATE_SYSTEM_READONLY;
   3623       break;
   3624     case blink::WebAXRoleRadioButton:
   3625       ia_role_ = ROLE_SYSTEM_RADIOBUTTON;
   3626       break;
   3627     case blink::WebAXRoleRadioGroup:
   3628       ia_role_ = ROLE_SYSTEM_GROUPING;
   3629       ia2_role_ = IA2_ROLE_SECTION;
   3630       break;
   3631     case blink::WebAXRoleRegion:
   3632       ia_role_ = ROLE_SYSTEM_GROUPING;
   3633       ia2_role_ = IA2_ROLE_SECTION;
   3634       ia_state_ |= STATE_SYSTEM_READONLY;
   3635       break;
   3636     case blink::WebAXRoleRow:
   3637       ia_role_ = ROLE_SYSTEM_ROW;
   3638       ia_state_ |= STATE_SYSTEM_READONLY;
   3639       break;
   3640     case blink::WebAXRoleRowHeader:
   3641       ia_role_ = ROLE_SYSTEM_ROWHEADER;
   3642       ia_state_ |= STATE_SYSTEM_READONLY;
   3643       break;
   3644     case blink::WebAXRoleRuler:
   3645       ia_role_ = ROLE_SYSTEM_CLIENT;
   3646       ia2_role_ = IA2_ROLE_RULER;
   3647       ia_state_ |= STATE_SYSTEM_READONLY;
   3648       break;
   3649     case blink::WebAXRoleScrollArea:
   3650       ia_role_ = ROLE_SYSTEM_CLIENT;
   3651       ia2_role_ = IA2_ROLE_SCROLL_PANE;
   3652       ia_state_ |= STATE_SYSTEM_READONLY;
   3653       break;
   3654     case blink::WebAXRoleScrollBar:
   3655       ia_role_ = ROLE_SYSTEM_SCROLLBAR;
   3656       break;
   3657     case blink::WebAXRoleSlider:
   3658       ia_role_ = ROLE_SYSTEM_SLIDER;
   3659       break;
   3660     case blink::WebAXRoleSpinButton:
   3661       ia_role_ = ROLE_SYSTEM_SPINBUTTON;
   3662       break;
   3663     case blink::WebAXRoleSpinButtonPart:
   3664       ia_role_ = ROLE_SYSTEM_PUSHBUTTON;
   3665       break;
   3666     case blink::WebAXRoleSplitGroup:
   3667       ia_role_ = ROLE_SYSTEM_CLIENT;
   3668       ia2_role_ = IA2_ROLE_SPLIT_PANE;
   3669       ia_state_ |= STATE_SYSTEM_READONLY;
   3670       break;
   3671     case blink::WebAXRoleAnnotation:
   3672     case blink::WebAXRoleStaticText:
   3673       ia_role_ = ROLE_SYSTEM_TEXT;
   3674       ia_state_ |= STATE_SYSTEM_READONLY;
   3675       break;
   3676     case blink::WebAXRoleStatus:
   3677       ia_role_ = ROLE_SYSTEM_STATUSBAR;
   3678       ia_state_ |= STATE_SYSTEM_READONLY;
   3679       break;
   3680     case blink::WebAXRoleSplitter:
   3681       ia_role_ = ROLE_SYSTEM_SEPARATOR;
   3682       break;
   3683     case blink::WebAXRoleSVGRoot:
   3684       ia_role_ = ROLE_SYSTEM_GRAPHIC;
   3685       break;
   3686     case blink::WebAXRoleTab:
   3687       ia_role_ = ROLE_SYSTEM_PAGETAB;
   3688       break;
   3689     case blink::WebAXRoleTable: {
   3690       base::string16 aria_role = GetString16Attribute(
   3691           AccessibilityNodeData::ATTR_ROLE);
   3692       if (aria_role == L"treegrid") {
   3693         ia_role_ = ROLE_SYSTEM_OUTLINE;
   3694       } else {
   3695         ia_role_ = ROLE_SYSTEM_TABLE;
   3696         ia_state_ |= STATE_SYSTEM_READONLY;
   3697       }
   3698       break;
   3699     }
   3700     case blink::WebAXRoleTableHeaderContainer:
   3701       ia_role_ = ROLE_SYSTEM_GROUPING;
   3702       ia2_role_ = IA2_ROLE_SECTION;
   3703       ia_state_ |= STATE_SYSTEM_READONLY;
   3704       break;
   3705     case blink::WebAXRoleTabList:
   3706       ia_role_ = ROLE_SYSTEM_PAGETABLIST;
   3707       break;
   3708     case blink::WebAXRoleTabPanel:
   3709       ia_role_ = ROLE_SYSTEM_PROPERTYPAGE;
   3710       break;
   3711     case blink::WebAXRoleToggleButton:
   3712       ia_role_ = ROLE_SYSTEM_PUSHBUTTON;
   3713       ia2_role_ = IA2_ROLE_TOGGLE_BUTTON;
   3714       break;
   3715     case blink::WebAXRoleTextArea:
   3716       ia_role_ = ROLE_SYSTEM_TEXT;
   3717       ia2_state_ |= IA2_STATE_MULTI_LINE;
   3718       ia2_state_ |= IA2_STATE_EDITABLE;
   3719       ia2_state_ |= IA2_STATE_SELECTABLE_TEXT;
   3720       break;
   3721     case blink::WebAXRoleTextField:
   3722       ia_role_ = ROLE_SYSTEM_TEXT;
   3723       ia2_state_ |= IA2_STATE_SINGLE_LINE;
   3724       ia2_state_ |= IA2_STATE_EDITABLE;
   3725       ia2_state_ |= IA2_STATE_SELECTABLE_TEXT;
   3726       break;
   3727     case blink::WebAXRoleTimer:
   3728       ia_role_ = ROLE_SYSTEM_CLOCK;
   3729       ia_state_ |= STATE_SYSTEM_READONLY;
   3730       break;
   3731     case blink::WebAXRoleToolbar:
   3732       ia_role_ = ROLE_SYSTEM_TOOLBAR;
   3733       ia_state_ |= STATE_SYSTEM_READONLY;
   3734       break;
   3735     case blink::WebAXRoleUserInterfaceTooltip:
   3736       ia_role_ = ROLE_SYSTEM_TOOLTIP;
   3737       ia_state_ |= STATE_SYSTEM_READONLY;
   3738       break;
   3739     case blink::WebAXRoleTree:
   3740       ia_role_ = ROLE_SYSTEM_OUTLINE;
   3741       ia_state_ |= STATE_SYSTEM_READONLY;
   3742       break;
   3743     case blink::WebAXRoleTreeGrid:
   3744       ia_role_ = ROLE_SYSTEM_OUTLINE;
   3745       ia_state_ |= STATE_SYSTEM_READONLY;
   3746       break;
   3747     case blink::WebAXRoleTreeItem:
   3748       ia_role_ = ROLE_SYSTEM_OUTLINEITEM;
   3749       ia_state_ |= STATE_SYSTEM_READONLY;
   3750       break;
   3751     case blink::WebAXRoleWindow:
   3752       ia_role_ = ROLE_SYSTEM_WINDOW;
   3753       break;
   3754 
   3755     // TODO(dmazzoni): figure out the proper MSAA role for all of these.
   3756     case blink::WebAXRoleBrowser:
   3757     case blink::WebAXRoleDirectory:
   3758     case blink::WebAXRoleDrawer:
   3759     case blink::WebAXRoleHelpTag:
   3760     case blink::WebAXRoleIgnored:
   3761     case blink::WebAXRoleIncrementor:
   3762     case blink::WebAXRoleLog:
   3763     case blink::WebAXRoleMarquee:
   3764     case blink::WebAXRoleMatte:
   3765     case blink::WebAXRolePresentational:
   3766     case blink::WebAXRoleRulerMarker:
   3767     case blink::WebAXRoleSheet:
   3768     case blink::WebAXRoleSliderThumb:
   3769     case blink::WebAXRoleSystemWide:
   3770     case blink::WebAXRoleValueIndicator:
   3771     default:
   3772       ia_role_ = ROLE_SYSTEM_CLIENT;
   3773       break;
   3774   }
   3775 
   3776   // Compute the final value of READONLY for MSAA.
   3777   //
   3778   // We always set the READONLY state for elements that have the
   3779   // aria-readonly attribute and for a few roles (in the switch above).
   3780   // We clear the READONLY state on focusable controls and on a document.
   3781   // Everything else, the majority of objects, do not have this state set.
   3782   if (HasState(blink::WebAXStateFocusable) &&
   3783       ia_role_ != ROLE_SYSTEM_DOCUMENT) {
   3784     ia_state_ &= ~(STATE_SYSTEM_READONLY);
   3785   }
   3786   if (!HasState(blink::WebAXStateReadonly))
   3787     ia_state_ &= ~(STATE_SYSTEM_READONLY);
   3788   if (GetBoolAttribute(AccessibilityNodeData::ATTR_ARIA_READONLY))
   3789     ia_state_ |= STATE_SYSTEM_READONLY;
   3790 
   3791   // The role should always be set.
   3792   DCHECK(!role_name_.empty() || ia_role_);
   3793 
   3794   // If we didn't explicitly set the IAccessible2 role, make it the same
   3795   // as the MSAA role.
   3796   if (!ia2_role_)
   3797     ia2_role_ = ia_role_;
   3798 }
   3799 
   3800 }  // namespace content
   3801