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