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