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.
5 #include "content/browser/accessibility/browser_accessibility_win.h"
7 #include <UIAutomationClient.h>
8 #include <UIAutomationCoreApi.h>
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/win/enum_variant.h"
15 #include "base/win/scoped_comptr.h"
16 #include "base/win/windows_version.h"
17 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
18 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
19 #include "content/common/accessibility_messages.h"
20 #include "content/public/common/content_client.h"
21 #include "ui/accessibility/ax_text_utils.h"
22 #include "ui/base/win/accessibility_ids_win.h"
23 #include "ui/base/win/accessibility_misc_utils.h"
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};
37 const base::char16
BrowserAccessibilityWin::kEmbeddedCharacter
[] = L
"\xfffc";
40 LONG
BrowserAccessibilityWin::next_unique_id_win_
=
41 base::win::kFirstBrowserAccessibilityManagerAccessibilityId
;
44 // BrowserAccessibilityRelation
46 // A simple implementation of IAccessibleRelation, used to represent
47 // a relationship between two accessible nodes in the tree.
50 class BrowserAccessibilityRelation
51 : public CComObjectRootEx
<CComMultiThreadModel
>,
52 public IAccessibleRelation
{
53 BEGIN_COM_MAP(BrowserAccessibilityRelation
)
54 COM_INTERFACE_ENTRY(IAccessibleRelation
)
57 CONTENT_EXPORT
BrowserAccessibilityRelation() {}
58 CONTENT_EXPORT
virtual ~BrowserAccessibilityRelation() {}
60 CONTENT_EXPORT
void Initialize(BrowserAccessibilityWin
* owner
,
61 const base::string16
& type
);
62 CONTENT_EXPORT
void AddTarget(int target_id
);
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
,
72 // IAccessibleRelation methods not implemented.
73 CONTENT_EXPORT STDMETHODIMP
get_localizedRelationType(BSTR
* relation_type
) {
79 base::win::ScopedComPtr
<BrowserAccessibilityWin
> owner_
;
80 std::vector
<int> target_ids_
;
83 void BrowserAccessibilityRelation::Initialize(BrowserAccessibilityWin
* owner
,
84 const base::string16
& type
) {
89 void BrowserAccessibilityRelation::AddTarget(int target_id
) {
90 target_ids_
.push_back(target_id
);
93 STDMETHODIMP
BrowserAccessibilityRelation::get_relationType(
94 BSTR
* relation_type
) {
98 if (!owner_
->instance_active())
101 *relation_type
= SysAllocString(type_
.c_str());
102 DCHECK(*relation_type
);
106 STDMETHODIMP
BrowserAccessibilityRelation::get_nTargets(long* n_targets
) {
110 if (!owner_
->instance_active())
113 *n_targets
= static_cast<long>(target_ids_
.size());
115 BrowserAccessibilityManager
* manager
= owner_
->manager();
116 for (long i
= *n_targets
- 1; i
>= 0; --i
) {
117 BrowserAccessibility
* result
= manager
->GetFromID(target_ids_
[i
]);
118 if (!result
|| !result
->instance_active()) {
126 STDMETHODIMP
BrowserAccessibilityRelation::get_target(long target_index
,
131 if (!owner_
->instance_active())
134 if (target_index
< 0 ||
135 target_index
>= static_cast<long>(target_ids_
.size())) {
139 BrowserAccessibilityManager
* manager
= owner_
->manager();
140 BrowserAccessibility
* result
=
141 manager
->GetFromID(target_ids_
[target_index
]);
142 if (!result
|| !result
->instance_active())
145 *target
= static_cast<IAccessible
*>(
146 result
->ToBrowserAccessibilityWin()->NewReference());
150 STDMETHODIMP
BrowserAccessibilityRelation::get_targets(long max_targets
,
153 if (!targets
|| !n_targets
)
156 if (!owner_
->instance_active())
159 long count
= static_cast<long>(target_ids_
.size());
160 if (count
> max_targets
)
167 for (long i
= 0; i
< count
; ++i
) {
168 HRESULT result
= get_target(i
, &targets
[i
]);
177 // BrowserAccessibilityWin
181 BrowserAccessibility
* BrowserAccessibility::Create() {
182 CComObject
<BrowserAccessibilityWin
>* instance
;
183 HRESULT hr
= CComObject
<BrowserAccessibilityWin
>::CreateInstance(&instance
);
184 DCHECK(SUCCEEDED(hr
));
185 return instance
->NewReference();
188 BrowserAccessibilityWin
* BrowserAccessibility::ToBrowserAccessibilityWin() {
189 return static_cast<BrowserAccessibilityWin
*>(this);
192 BrowserAccessibilityWin::BrowserAccessibilityWin()
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
;
210 next_unique_id_win_
--;
213 BrowserAccessibilityWin::~BrowserAccessibilityWin() {
214 for (size_t i
= 0; i
< relations_
.size(); ++i
)
215 relations_
[i
]->Release();
219 // IAccessible methods.
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.
227 HRESULT
BrowserAccessibilityWin::accDoDefaultAction(VARIANT var_id
) {
228 if (!instance_active())
231 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
235 manager()->DoDefaultAction(*target
);
239 STDMETHODIMP
BrowserAccessibilityWin::accHitTest(LONG x_left
,
242 if (!instance_active())
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
;
255 BrowserAccessibility
* result
= BrowserAccessibilityForPoint(point
);
256 if (result
== this) {
257 // Point is within this object.
259 child
->lVal
= CHILDID_SELF
;
261 child
->vt
= VT_DISPATCH
;
262 child
->pdispVal
= result
->ToBrowserAccessibilityWin()->NewReference();
267 STDMETHODIMP
BrowserAccessibilityWin::accLocation(LONG
* x_left
,
272 if (!instance_active())
275 if (!x_left
|| !y_top
|| !width
|| !height
)
278 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
282 gfx::Rect bounds
= target
->GetGlobalBoundsRect();
283 *x_left
= bounds
.x();
285 *width
= bounds
.width();
286 *height
= bounds
.height();
291 STDMETHODIMP
BrowserAccessibilityWin::accNavigate(LONG nav_dir
,
294 BrowserAccessibilityWin
* target
= GetTargetFromChildID(start
);
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.
304 uint32 child_count
= target
->PlatformChildCount();
306 BrowserAccessibility
* result
= NULL
;
312 // These directions are not implemented, matching Mozilla and IE.
314 case NAVDIR_FIRSTCHILD
:
316 result
= target
->PlatformGetChild(0);
318 case NAVDIR_LASTCHILD
:
320 result
= target
->PlatformGetChild(child_count
- 1);
323 result
= target
->GetNextSibling();
325 case NAVDIR_PREVIOUS
:
326 result
= target
->GetPreviousSibling();
335 end
->vt
= VT_DISPATCH
;
336 end
->pdispVal
= result
->ToBrowserAccessibilityWin()->NewReference();
340 STDMETHODIMP
BrowserAccessibilityWin::get_accChild(VARIANT var_child
,
341 IDispatch
** disp_child
) {
342 if (!instance_active())
350 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_child
);
354 (*disp_child
) = target
->NewReference();
358 STDMETHODIMP
BrowserAccessibilityWin::get_accChildCount(LONG
* child_count
) {
359 if (!instance_active())
365 *child_count
= PlatformChildCount();
370 STDMETHODIMP
BrowserAccessibilityWin::get_accDefaultAction(VARIANT var_id
,
372 if (!instance_active())
378 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
382 return target
->GetStringAttributeAsBstr(
383 ui::AX_ATTR_SHORTCUT
, def_action
);
386 STDMETHODIMP
BrowserAccessibilityWin::get_accDescription(VARIANT var_id
,
388 if (!instance_active())
394 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
398 return target
->GetStringAttributeAsBstr(
399 ui::AX_ATTR_DESCRIPTION
, desc
);
402 STDMETHODIMP
BrowserAccessibilityWin::get_accFocus(VARIANT
* focus_child
) {
403 if (!instance_active())
409 BrowserAccessibilityWin
* focus
= static_cast<BrowserAccessibilityWin
*>(
410 manager()->GetFocus(this));
412 focus_child
->vt
= VT_I4
;
413 focus_child
->lVal
= CHILDID_SELF
;
414 } else if (focus
== NULL
) {
415 focus_child
->vt
= VT_EMPTY
;
417 focus_child
->vt
= VT_DISPATCH
;
418 focus_child
->pdispVal
= focus
->NewReference();
424 STDMETHODIMP
BrowserAccessibilityWin::get_accHelp(VARIANT var_id
, BSTR
* help
) {
425 if (!instance_active())
431 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
435 return target
->GetStringAttributeAsBstr(
436 ui::AX_ATTR_HELP
, help
);
439 STDMETHODIMP
BrowserAccessibilityWin::get_accKeyboardShortcut(VARIANT var_id
,
441 if (!instance_active())
447 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
451 return target
->GetStringAttributeAsBstr(
452 ui::AX_ATTR_SHORTCUT
, acc_key
);
455 STDMETHODIMP
BrowserAccessibilityWin::get_accName(VARIANT var_id
, BSTR
* name
) {
456 if (!instance_active())
462 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
466 std::string name_str
= target
->name();
468 // If the name is empty, see if it's labeled by another element.
469 if (name_str
.empty()) {
471 if (target
->GetIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT
,
473 BrowserAccessibility
* title_elem
=
474 manager()->GetFromID(title_elem_id
);
476 name_str
= title_elem
->GetTextRecursive();
480 if (name_str
.empty())
483 *name
= SysAllocString(base::UTF8ToUTF16(name_str
).c_str());
489 STDMETHODIMP
BrowserAccessibilityWin::get_accParent(IDispatch
** disp_parent
) {
490 if (!instance_active())
496 IAccessible
* parent_obj
= GetParent()->ToBrowserAccessibilityWin();
497 if (parent_obj
== NULL
) {
498 // This happens if we're the root of the tree;
499 // return the IAccessible for the window.
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.
508 DVLOG(1) << "In Function: "
510 << ". Parent IAccessible interface is NULL. Returning failure";
514 parent_obj
->AddRef();
515 *disp_parent
= parent_obj
;
519 STDMETHODIMP
BrowserAccessibilityWin::get_accRole(VARIANT var_id
,
521 if (!instance_active())
527 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
531 if (!target
->role_name_
.empty()) {
533 role
->bstrVal
= SysAllocString(target
->role_name_
.c_str());
536 role
->lVal
= target
->ia_role_
;
541 STDMETHODIMP
BrowserAccessibilityWin::get_accState(VARIANT var_id
,
543 if (!instance_active())
549 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
554 state
->lVal
= target
->ia_state_
;
555 if (manager()->GetFocus(NULL
) == this)
556 state
->lVal
|= STATE_SYSTEM_FOCUSED
;
561 STDMETHODIMP
BrowserAccessibilityWin::get_accValue(VARIANT var_id
,
563 if (!instance_active())
569 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
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());
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());
599 *value
= SysAllocString(base::UTF8ToUTF16(target
->value()).c_str());
604 STDMETHODIMP
BrowserAccessibilityWin::get_accHelpTopic(BSTR
* help_file
,
610 STDMETHODIMP
BrowserAccessibilityWin::get_accSelection(VARIANT
* selected
) {
611 if (!instance_active())
614 if (GetRole() != ui::AX_ROLE_LIST_BOX
)
617 unsigned long selected_count
= 0;
618 for (size_t i
= 0; i
< InternalChildCount(); ++i
) {
619 if (InternalGetChild(i
)->HasState(ui::AX_STATE_SELECTED
))
623 if (selected_count
== 0) {
624 selected
->vt
= VT_EMPTY
;
628 if (selected_count
== 1) {
629 for (size_t i
= 0; i
< InternalChildCount(); ++i
) {
630 if (InternalGetChild(i
)->HasState(ui::AX_STATE_SELECTED
)) {
631 selected
->vt
= VT_DISPATCH
;
633 InternalGetChild(i
)->ToBrowserAccessibilityWin()->NewReference();
639 // Multiple items are selected.
640 base::win::EnumVariant
* enum_variant
=
641 new base::win::EnumVariant(selected_count
);
642 enum_variant
->AddRef();
643 unsigned long index
= 0;
644 for (size_t i
= 0; i
< InternalChildCount(); ++i
) {
645 if (InternalGetChild(i
)->HasState(ui::AX_STATE_SELECTED
)) {
646 enum_variant
->ItemAt(index
)->vt
= VT_DISPATCH
;
647 enum_variant
->ItemAt(index
)->pdispVal
=
648 InternalGetChild(i
)->ToBrowserAccessibilityWin()->NewReference();
652 selected
->vt
= VT_UNKNOWN
;
653 selected
->punkVal
= static_cast<IUnknown
*>(
654 static_cast<base::win::IUnknownImpl
*>(enum_variant
));
658 STDMETHODIMP
BrowserAccessibilityWin::accSelect(
659 LONG flags_sel
, VARIANT var_id
) {
660 if (!instance_active())
663 if (flags_sel
& SELFLAG_TAKEFOCUS
) {
664 manager()->SetFocus(this, true);
672 // IAccessible2 methods.
675 STDMETHODIMP
BrowserAccessibilityWin::role(LONG
* role
) {
676 if (!instance_active())
687 STDMETHODIMP
BrowserAccessibilityWin::get_attributes(BSTR
* attributes
) {
688 if (!instance_active())
694 // The iaccessible2 attributes are a set of key-value pairs
695 // separated by semicolons, with a colon between the key and the value.
697 for (unsigned int i
= 0; i
< ia2_attributes_
.size(); ++i
) {
700 str
+= ia2_attributes_
[i
];
706 *attributes
= SysAllocString(str
.c_str());
711 STDMETHODIMP
BrowserAccessibilityWin::get_states(AccessibleStates
* states
) {
712 if (!instance_active())
718 *states
= ia2_state_
;
723 STDMETHODIMP
BrowserAccessibilityWin::get_uniqueID(LONG
* unique_id
) {
724 if (!instance_active())
730 *unique_id
= unique_id_win_
;
734 STDMETHODIMP
BrowserAccessibilityWin::get_windowHandle(HWND
* window_handle
) {
735 if (!instance_active())
741 *window_handle
= manager()->ToBrowserAccessibilityManagerWin()->parent_hwnd();
745 STDMETHODIMP
BrowserAccessibilityWin::get_indexInParent(LONG
* index_in_parent
) {
746 if (!instance_active())
749 if (!index_in_parent
)
752 *index_in_parent
= this->GetIndexInParent();
756 STDMETHODIMP
BrowserAccessibilityWin::get_nRelations(LONG
* n_relations
) {
757 if (!instance_active())
763 *n_relations
= relations_
.size();
767 STDMETHODIMP
BrowserAccessibilityWin::get_relation(
769 IAccessibleRelation
** relation
) {
770 if (!instance_active())
773 if (relation_index
< 0 ||
774 relation_index
>= static_cast<long>(relations_
.size())) {
781 relations_
[relation_index
]->AddRef();
782 *relation
= relations_
[relation_index
];
786 STDMETHODIMP
BrowserAccessibilityWin::get_relations(
788 IAccessibleRelation
** relations
,
790 if (!instance_active())
793 if (!relations
|| !n_relations
)
796 long count
= static_cast<long>(relations_
.size());
797 *n_relations
= count
;
801 for (long i
= 0; i
< count
; ++i
) {
802 relations_
[i
]->AddRef();
803 relations
[i
] = relations_
[i
];
809 STDMETHODIMP
BrowserAccessibilityWin::scrollTo(enum IA2ScrollType scroll_type
) {
810 if (!instance_active())
813 gfx::Rect r
= GetLocation();
814 switch(scroll_type
) {
815 case IA2_SCROLL_TYPE_TOP_LEFT
:
816 manager()->ScrollToMakeVisible(*this, gfx::Rect(r
.x(), r
.y(), 0, 0));
818 case IA2_SCROLL_TYPE_BOTTOM_RIGHT
:
819 manager()->ScrollToMakeVisible(
820 *this, gfx::Rect(r
.right(), r
.bottom(), 0, 0));
822 case IA2_SCROLL_TYPE_TOP_EDGE
:
823 manager()->ScrollToMakeVisible(
824 *this, gfx::Rect(r
.x(), r
.y(), r
.width(), 0));
826 case IA2_SCROLL_TYPE_BOTTOM_EDGE
:
827 manager()->ScrollToMakeVisible(
828 *this, gfx::Rect(r
.x(), r
.bottom(), r
.width(), 0));
830 case IA2_SCROLL_TYPE_LEFT_EDGE
:
831 manager()->ScrollToMakeVisible(
832 *this, gfx::Rect(r
.x(), r
.y(), 0, r
.height()));
834 case IA2_SCROLL_TYPE_RIGHT_EDGE
:
835 manager()->ScrollToMakeVisible(
836 *this, gfx::Rect(r
.right(), r
.y(), 0, r
.height()));
838 case IA2_SCROLL_TYPE_ANYWHERE
:
840 manager()->ScrollToMakeVisible(*this, r
);
844 manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
849 STDMETHODIMP
BrowserAccessibilityWin::scrollToPoint(
850 enum IA2CoordinateType coordinate_type
,
853 if (!instance_active())
856 gfx::Point
scroll_to(x
, y
);
858 if (coordinate_type
== IA2_COORDTYPE_SCREEN_RELATIVE
) {
859 scroll_to
-= manager()->GetViewBounds().OffsetFromOrigin();
860 } else if (coordinate_type
== IA2_COORDTYPE_PARENT_RELATIVE
) {
862 scroll_to
+= GetParent()->GetLocation().OffsetFromOrigin();
867 manager()->ScrollToPoint(*this, scroll_to
);
868 manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
873 STDMETHODIMP
BrowserAccessibilityWin::get_groupPosition(
875 LONG
* similar_items_in_group
,
876 LONG
* position_in_group
) {
877 if (!instance_active())
880 if (!group_level
|| !similar_items_in_group
|| !position_in_group
)
883 if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION
&&
885 GetParent()->GetRole() == ui::AX_ROLE_LIST_BOX
) {
887 *similar_items_in_group
= GetParent()->PlatformChildCount();
888 *position_in_group
= GetIndexInParent() + 1;
896 // IAccessibleApplication methods.
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.
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)
913 *app_name
= SysAllocString(base::UTF8ToUTF16(product_components
[0]).c_str());
915 return *app_name
? S_OK
: E_FAIL
;
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.
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)
933 SysAllocString(base::UTF8ToUTF16(product_components
[1]).c_str());
934 DCHECK(*app_version
);
935 return *app_version
? S_OK
: E_FAIL
;
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.
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
;
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.
958 if (!toolkit_version
)
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
;
968 // IAccessibleImage methods.
971 STDMETHODIMP
BrowserAccessibilityWin::get_description(BSTR
* desc
) {
972 if (!instance_active())
978 return GetStringAttributeAsBstr(
979 ui::AX_ATTR_DESCRIPTION
, desc
);
982 STDMETHODIMP
BrowserAccessibilityWin::get_imagePosition(
983 enum IA2CoordinateType coordinate_type
,
986 if (!instance_active())
992 if (coordinate_type
== IA2_COORDTYPE_SCREEN_RELATIVE
) {
994 manager()->ToBrowserAccessibilityManagerWin()->parent_hwnd();
995 POINT top_left
= {0, 0};
996 ::ClientToScreen(parent_hwnd
, &top_left
);
997 *x
= GetLocation().x() + top_left
.x
;
998 *y
= GetLocation().y() + top_left
.y
;
999 } else if (coordinate_type
== IA2_COORDTYPE_PARENT_RELATIVE
) {
1000 *x
= GetLocation().x();
1001 *y
= GetLocation().y();
1003 *x
-= GetParent()->GetLocation().x();
1004 *y
-= GetParent()->GetLocation().y();
1007 return E_INVALIDARG
;
1013 STDMETHODIMP
BrowserAccessibilityWin::get_imageSize(LONG
* height
, LONG
* width
) {
1014 if (!instance_active())
1017 if (!height
|| !width
)
1018 return E_INVALIDARG
;
1020 *height
= GetLocation().height();
1021 *width
= GetLocation().width();
1026 // IAccessibleTable methods.
1029 STDMETHODIMP
BrowserAccessibilityWin::get_accessibleAt(
1032 IUnknown
** accessible
) {
1033 if (!instance_active())
1037 return E_INVALIDARG
;
1041 if (!GetIntAttribute(
1042 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1044 ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1050 if (row
< 0 || row
>= rows
|| column
< 0 || column
>= columns
)
1051 return E_INVALIDARG
;
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()));
1057 int cell_id
= cell_ids
[row
* columns
+ column
];
1058 BrowserAccessibilityWin
* cell
= GetFromID(cell_id
);
1060 *accessible
= static_cast<IAccessible
*>(cell
->NewReference());
1065 return E_INVALIDARG
;
1068 STDMETHODIMP
BrowserAccessibilityWin::get_caption(IUnknown
** accessible
) {
1069 if (!instance_active())
1073 return E_INVALIDARG
;
1075 // TODO(dmazzoni): implement
1079 STDMETHODIMP
BrowserAccessibilityWin::get_childIndex(long row
,
1082 if (!instance_active())
1086 return E_INVALIDARG
;
1090 if (!GetIntAttribute(
1091 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1093 ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1099 if (row
< 0 || row
>= rows
|| column
< 0 || column
>= columns
)
1100 return E_INVALIDARG
;
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
;
1118 STDMETHODIMP
BrowserAccessibilityWin::get_columnDescription(long column
,
1119 BSTR
* description
) {
1120 if (!instance_active())
1124 return E_INVALIDARG
;
1128 if (!GetIntAttribute(
1129 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1130 !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1136 if (column
< 0 || column
>= columns
)
1137 return E_INVALIDARG
;
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()->GetFromID(cell_id
));
1145 if (cell
&& cell
->GetRole() == ui::AX_ROLE_COLUMN_HEADER
) {
1146 base::string16 cell_name
= cell
->GetString16Attribute(
1148 if (cell_name
.size() > 0) {
1149 *description
= SysAllocString(cell_name
.c_str());
1153 return cell
->GetStringAttributeAsBstr(
1154 ui::AX_ATTR_DESCRIPTION
, description
);
1161 STDMETHODIMP
BrowserAccessibilityWin::get_columnExtentAt(
1164 long* n_columns_spanned
) {
1165 if (!instance_active())
1168 if (!n_columns_spanned
)
1169 return E_INVALIDARG
;
1173 if (!GetIntAttribute(
1174 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1175 !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1181 if (row
< 0 || row
>= rows
|| column
< 0 || column
>= columns
)
1182 return E_INVALIDARG
;
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()->GetFromID(cell_id
));
1191 cell
->GetIntAttribute(
1192 ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN
, &colspan
) &&
1194 *n_columns_spanned
= colspan
;
1201 STDMETHODIMP
BrowserAccessibilityWin::get_columnHeader(
1202 IAccessibleTable
** accessible_table
,
1203 long* starting_row_index
) {
1204 // TODO(dmazzoni): implement
1208 STDMETHODIMP
BrowserAccessibilityWin::get_columnIndex(long cell_index
,
1209 long* column_index
) {
1210 if (!instance_active())
1214 return E_INVALIDARG
;
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());
1220 return E_INVALIDARG
;
1221 if (cell_index
>= cell_id_count
)
1224 int cell_id
= unique_cell_ids
[cell_index
];
1225 BrowserAccessibilityWin
* cell
=
1226 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1229 cell
->GetIntAttribute(
1230 ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &col_index
)) {
1231 *column_index
= col_index
;
1238 STDMETHODIMP
BrowserAccessibilityWin::get_nColumns(long* column_count
) {
1239 if (!instance_active())
1243 return E_INVALIDARG
;
1246 if (GetIntAttribute(
1247 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
)) {
1248 *column_count
= columns
;
1255 STDMETHODIMP
BrowserAccessibilityWin::get_nRows(long* row_count
) {
1256 if (!instance_active())
1260 return E_INVALIDARG
;
1263 if (GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
)) {
1271 STDMETHODIMP
BrowserAccessibilityWin::get_nSelectedChildren(long* cell_count
) {
1272 if (!instance_active())
1276 return E_INVALIDARG
;
1278 // TODO(dmazzoni): add support for selected cells/rows/columns in tables.
1283 STDMETHODIMP
BrowserAccessibilityWin::get_nSelectedColumns(long* column_count
) {
1284 if (!instance_active())
1288 return E_INVALIDARG
;
1294 STDMETHODIMP
BrowserAccessibilityWin::get_nSelectedRows(long* row_count
) {
1295 if (!instance_active())
1299 return E_INVALIDARG
;
1305 STDMETHODIMP
BrowserAccessibilityWin::get_rowDescription(long row
,
1306 BSTR
* description
) {
1307 if (!instance_active())
1311 return E_INVALIDARG
;
1315 if (!GetIntAttribute(
1316 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1317 !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1323 if (row
< 0 || row
>= rows
)
1324 return E_INVALIDARG
;
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()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1332 if (cell
&& cell
->GetRole() == ui::AX_ROLE_ROW_HEADER
) {
1333 base::string16 cell_name
= cell
->GetString16Attribute(
1335 if (cell_name
.size() > 0) {
1336 *description
= SysAllocString(cell_name
.c_str());
1340 return cell
->GetStringAttributeAsBstr(
1341 ui::AX_ATTR_DESCRIPTION
, description
);
1348 STDMETHODIMP
BrowserAccessibilityWin::get_rowExtentAt(long row
,
1350 long* n_rows_spanned
) {
1351 if (!instance_active())
1354 if (!n_rows_spanned
)
1355 return E_INVALIDARG
;
1359 if (!GetIntAttribute(
1360 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1361 !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1367 if (row
< 0 || row
>= rows
|| column
< 0 || column
>= columns
)
1368 return E_INVALIDARG
;
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()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1377 cell
->GetIntAttribute(
1378 ui::AX_ATTR_TABLE_CELL_ROW_SPAN
, &rowspan
) &&
1380 *n_rows_spanned
= rowspan
;
1387 STDMETHODIMP
BrowserAccessibilityWin::get_rowHeader(
1388 IAccessibleTable
** accessible_table
,
1389 long* starting_column_index
) {
1390 // TODO(dmazzoni): implement
1394 STDMETHODIMP
BrowserAccessibilityWin::get_rowIndex(long cell_index
,
1396 if (!instance_active())
1400 return E_INVALIDARG
;
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());
1406 return E_INVALIDARG
;
1407 if (cell_index
>= cell_id_count
)
1410 int cell_id
= unique_cell_ids
[cell_index
];
1411 BrowserAccessibilityWin
* cell
=
1412 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1415 cell
->GetIntAttribute(
1416 ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &cell_row_index
)) {
1417 *row_index
= cell_row_index
;
1424 STDMETHODIMP
BrowserAccessibilityWin::get_selectedChildren(long max_children
,
1427 if (!instance_active())
1430 if (!children
|| !n_children
)
1431 return E_INVALIDARG
;
1433 // TODO(dmazzoni): Implement this.
1438 STDMETHODIMP
BrowserAccessibilityWin::get_selectedColumns(long max_columns
,
1441 if (!instance_active())
1444 if (!columns
|| !n_columns
)
1445 return E_INVALIDARG
;
1447 // TODO(dmazzoni): Implement this.
1452 STDMETHODIMP
BrowserAccessibilityWin::get_selectedRows(long max_rows
,
1455 if (!instance_active())
1458 if (!rows
|| !n_rows
)
1459 return E_INVALIDARG
;
1461 // TODO(dmazzoni): Implement this.
1466 STDMETHODIMP
BrowserAccessibilityWin::get_summary(IUnknown
** accessible
) {
1467 if (!instance_active())
1471 return E_INVALIDARG
;
1473 // TODO(dmazzoni): implement
1477 STDMETHODIMP
BrowserAccessibilityWin::get_isColumnSelected(
1479 boolean
* is_selected
) {
1480 if (!instance_active())
1484 return E_INVALIDARG
;
1486 // TODO(dmazzoni): Implement this.
1487 *is_selected
= false;
1491 STDMETHODIMP
BrowserAccessibilityWin::get_isRowSelected(long row
,
1492 boolean
* is_selected
) {
1493 if (!instance_active())
1497 return E_INVALIDARG
;
1499 // TODO(dmazzoni): Implement this.
1500 *is_selected
= false;
1504 STDMETHODIMP
BrowserAccessibilityWin::get_isSelected(long row
,
1506 boolean
* is_selected
) {
1507 if (!instance_active())
1511 return E_INVALIDARG
;
1513 // TODO(dmazzoni): Implement this.
1514 *is_selected
= false;
1518 STDMETHODIMP
BrowserAccessibilityWin::get_rowColumnExtentsAtIndex(
1523 long* column_extents
,
1524 boolean
* is_selected
) {
1525 if (!instance_active())
1528 if (!row
|| !column
|| !row_extents
|| !column_extents
|| !is_selected
)
1529 return E_INVALIDARG
;
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());
1535 return E_INVALIDARG
;
1536 if (index
>= cell_id_count
)
1539 int cell_id
= unique_cell_ids
[index
];
1540 BrowserAccessibilityWin
* cell
=
1541 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1545 cell
->GetIntAttribute(
1546 ui::AX_ATTR_TABLE_CELL_ROW_SPAN
, &rowspan
) &&
1547 cell
->GetIntAttribute(
1548 ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN
, &colspan
) &&
1551 *row_extents
= rowspan
;
1552 *column_extents
= colspan
;
1560 // IAccessibleTable2 methods.
1563 STDMETHODIMP
BrowserAccessibilityWin::get_cellAt(long row
,
1566 return get_accessibleAt(row
, column
, cell
);
1569 STDMETHODIMP
BrowserAccessibilityWin::get_nSelectedCells(long* cell_count
) {
1570 return get_nSelectedChildren(cell_count
);
1573 STDMETHODIMP
BrowserAccessibilityWin::get_selectedCells(
1575 long* n_selected_cells
) {
1576 if (!instance_active())
1579 if (!cells
|| !n_selected_cells
)
1580 return E_INVALIDARG
;
1582 // TODO(dmazzoni): Implement this.
1583 *n_selected_cells
= 0;
1587 STDMETHODIMP
BrowserAccessibilityWin::get_selectedColumns(long** columns
,
1589 if (!instance_active())
1592 if (!columns
|| !n_columns
)
1593 return E_INVALIDARG
;
1595 // TODO(dmazzoni): Implement this.
1600 STDMETHODIMP
BrowserAccessibilityWin::get_selectedRows(long** rows
,
1602 if (!instance_active())
1605 if (!rows
|| !n_rows
)
1606 return E_INVALIDARG
;
1608 // TODO(dmazzoni): Implement this.
1615 // IAccessibleTableCell methods.
1618 STDMETHODIMP
BrowserAccessibilityWin::get_columnExtent(
1619 long* n_columns_spanned
) {
1620 if (!instance_active())
1623 if (!n_columns_spanned
)
1624 return E_INVALIDARG
;
1627 if (GetIntAttribute(
1628 ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN
, &colspan
) &&
1630 *n_columns_spanned
= colspan
;
1637 STDMETHODIMP
BrowserAccessibilityWin::get_columnHeaderCells(
1638 IUnknown
*** cell_accessibles
,
1639 long* n_column_header_cells
) {
1640 if (!instance_active())
1643 if (!cell_accessibles
|| !n_column_header_cells
)
1644 return E_INVALIDARG
;
1646 *n_column_header_cells
= 0;
1649 if (!GetIntAttribute(
1650 ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &column
)) {
1654 BrowserAccessibility
* table
= GetParent();
1655 while (table
&& table
->GetRole() != ui::AX_ROLE_TABLE
)
1656 table
= table
->GetParent();
1664 if (!table
->GetIntAttribute(
1665 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1666 !table
->GetIntAttribute(
1667 ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
)) {
1670 if (columns
<= 0 || rows
<= 0 || column
< 0 || column
>= columns
)
1673 const std::vector
<int32
>& cell_ids
= table
->GetIntListAttribute(
1674 ui::AX_ATTR_CELL_IDS
);
1676 for (int i
= 0; i
< rows
; ++i
) {
1677 int cell_id
= cell_ids
[i
* columns
+ column
];
1678 BrowserAccessibilityWin
* cell
=
1679 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1680 if (cell
&& cell
->GetRole() == ui::AX_ROLE_COLUMN_HEADER
)
1681 (*n_column_header_cells
)++;
1684 *cell_accessibles
= static_cast<IUnknown
**>(CoTaskMemAlloc(
1685 (*n_column_header_cells
) * sizeof(cell_accessibles
[0])));
1687 for (int i
= 0; i
< rows
; ++i
) {
1688 int cell_id
= cell_ids
[i
* columns
+ column
];
1689 BrowserAccessibility
* cell
= manager()->GetFromID(cell_id
);
1690 if (cell
&& cell
->GetRole() == ui::AX_ROLE_COLUMN_HEADER
) {
1691 (*cell_accessibles
)[index
] = static_cast<IAccessible
*>(
1692 cell
->ToBrowserAccessibilityWin()->NewReference());
1700 STDMETHODIMP
BrowserAccessibilityWin::get_columnIndex(long* column_index
) {
1701 if (!instance_active())
1705 return E_INVALIDARG
;
1708 if (GetIntAttribute(
1709 ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &column
)) {
1710 *column_index
= column
;
1717 STDMETHODIMP
BrowserAccessibilityWin::get_rowExtent(long* n_rows_spanned
) {
1718 if (!instance_active())
1721 if (!n_rows_spanned
)
1722 return E_INVALIDARG
;
1725 if (GetIntAttribute(
1726 ui::AX_ATTR_TABLE_CELL_ROW_SPAN
, &rowspan
) &&
1728 *n_rows_spanned
= rowspan
;
1735 STDMETHODIMP
BrowserAccessibilityWin::get_rowHeaderCells(
1736 IUnknown
*** cell_accessibles
,
1737 long* n_row_header_cells
) {
1738 if (!instance_active())
1741 if (!cell_accessibles
|| !n_row_header_cells
)
1742 return E_INVALIDARG
;
1744 *n_row_header_cells
= 0;
1747 if (!GetIntAttribute(
1748 ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &row
)) {
1752 BrowserAccessibility
* table
= GetParent();
1753 while (table
&& table
->GetRole() != ui::AX_ROLE_TABLE
)
1754 table
= table
->GetParent();
1762 if (!table
->GetIntAttribute(
1763 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1764 !table
->GetIntAttribute(
1765 ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
)) {
1768 if (columns
<= 0 || rows
<= 0 || row
< 0 || row
>= rows
)
1771 const std::vector
<int32
>& cell_ids
= table
->GetIntListAttribute(
1772 ui::AX_ATTR_CELL_IDS
);
1774 for (int i
= 0; i
< columns
; ++i
) {
1775 int cell_id
= cell_ids
[row
* columns
+ i
];
1776 BrowserAccessibility
* cell
= manager()->GetFromID(cell_id
);
1777 if (cell
&& cell
->GetRole() == ui::AX_ROLE_ROW_HEADER
)
1778 (*n_row_header_cells
)++;
1781 *cell_accessibles
= static_cast<IUnknown
**>(CoTaskMemAlloc(
1782 (*n_row_header_cells
) * sizeof(cell_accessibles
[0])));
1784 for (int i
= 0; i
< columns
; ++i
) {
1785 int cell_id
= cell_ids
[row
* columns
+ i
];
1786 BrowserAccessibility
* cell
= manager()->GetFromID(cell_id
);
1787 if (cell
&& cell
->GetRole() == ui::AX_ROLE_ROW_HEADER
) {
1788 (*cell_accessibles
)[index
] = static_cast<IAccessible
*>(
1789 cell
->ToBrowserAccessibilityWin()->NewReference());
1797 STDMETHODIMP
BrowserAccessibilityWin::get_rowIndex(long* row_index
) {
1798 if (!instance_active())
1802 return E_INVALIDARG
;
1805 if (GetIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &row
)) {
1812 STDMETHODIMP
BrowserAccessibilityWin::get_isSelected(boolean
* is_selected
) {
1813 if (!instance_active())
1817 return E_INVALIDARG
;
1819 *is_selected
= false;
1823 STDMETHODIMP
BrowserAccessibilityWin::get_rowColumnExtents(
1827 long* column_extents
,
1828 boolean
* is_selected
) {
1829 if (!instance_active())
1837 return E_INVALIDARG
;
1844 if (GetIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &row
) &&
1846 ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &column
) &&
1848 ui::AX_ATTR_TABLE_CELL_ROW_SPAN
, &rowspan
) &&
1850 ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN
, &colspan
)) {
1852 *column_index
= column
;
1853 *row_extents
= rowspan
;
1854 *column_extents
= colspan
;
1855 *is_selected
= false;
1862 STDMETHODIMP
BrowserAccessibilityWin::get_table(IUnknown
** table
) {
1863 if (!instance_active())
1867 return E_INVALIDARG
;
1872 GetIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &row
);
1873 GetIntAttribute(ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &column
);
1875 BrowserAccessibility
* find_table
= GetParent();
1876 while (find_table
&& find_table
->GetRole() != ui::AX_ROLE_TABLE
)
1877 find_table
= find_table
->GetParent();
1883 *table
= static_cast<IAccessibleTable
*>(
1884 find_table
->ToBrowserAccessibilityWin()->NewReference());
1890 // IAccessibleText methods.
1893 STDMETHODIMP
BrowserAccessibilityWin::get_nCharacters(LONG
* n_characters
) {
1894 if (!instance_active())
1898 return E_INVALIDARG
;
1900 *n_characters
= TextForIAccessibleText().length();
1904 STDMETHODIMP
BrowserAccessibilityWin::get_caretOffset(LONG
* offset
) {
1905 if (!instance_active())
1909 return E_INVALIDARG
;
1912 if (GetRole() == ui::AX_ROLE_TEXT_FIELD
||
1913 GetRole() == ui::AX_ROLE_TEXT_AREA
) {
1915 if (GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START
,
1917 *offset
= sel_start
;
1923 STDMETHODIMP
BrowserAccessibilityWin::get_characterExtents(
1925 enum IA2CoordinateType coordinate_type
,
1930 if (!instance_active())
1933 if (!out_x
|| !out_y
|| !out_width
|| !out_height
)
1934 return E_INVALIDARG
;
1936 const base::string16
& text_str
= TextForIAccessibleText();
1937 HandleSpecialTextOffset(text_str
, &offset
);
1939 if (offset
< 0 || offset
> static_cast<LONG
>(text_str
.size()))
1940 return E_INVALIDARG
;
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
-= GetLocation().OffsetFromOrigin();
1949 return E_INVALIDARG
;
1952 *out_x
= character_bounds
.x();
1953 *out_y
= character_bounds
.y();
1954 *out_width
= character_bounds
.width();
1955 *out_height
= character_bounds
.height();
1960 STDMETHODIMP
BrowserAccessibilityWin::get_nSelections(LONG
* n_selections
) {
1961 if (!instance_active())
1965 return E_INVALIDARG
;
1968 if (GetRole() == ui::AX_ROLE_TEXT_FIELD
||
1969 GetRole() == ui::AX_ROLE_TEXT_AREA
) {
1972 if (GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START
,
1974 GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END
, &sel_end
) &&
1975 sel_start
!= sel_end
)
1982 STDMETHODIMP
BrowserAccessibilityWin::get_selection(LONG selection_index
,
1985 if (!instance_active())
1988 if (!start_offset
|| !end_offset
|| selection_index
!= 0)
1989 return E_INVALIDARG
;
1993 if (GetRole() == ui::AX_ROLE_TEXT_FIELD
||
1994 GetRole() == ui::AX_ROLE_TEXT_AREA
) {
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
;
2008 STDMETHODIMP
BrowserAccessibilityWin::get_text(LONG start_offset
,
2011 if (!instance_active())
2015 return E_INVALIDARG
;
2017 const base::string16
& text_str
= TextForIAccessibleText();
2019 // Handle special text offsets.
2020 HandleSpecialTextOffset(text_str
, &start_offset
);
2021 HandleSpecialTextOffset(text_str
, &end_offset
);
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
;
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
;
2038 base::string16 substr
= text_str
.substr(start_offset
,
2039 end_offset
- start_offset
);
2043 *text
= SysAllocString(substr
.c_str());
2048 STDMETHODIMP
BrowserAccessibilityWin::get_textAtOffset(
2050 enum IA2TextBoundaryType boundary_type
,
2054 if (!instance_active())
2057 if (!start_offset
|| !end_offset
|| !text
)
2058 return E_INVALIDARG
;
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
) {
2069 const base::string16
& text_str
= TextForIAccessibleText();
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
);
2078 STDMETHODIMP
BrowserAccessibilityWin::get_textBeforeOffset(
2080 enum IA2TextBoundaryType boundary_type
,
2084 if (!instance_active())
2087 if (!start_offset
|| !end_offset
|| !text
)
2088 return E_INVALIDARG
;
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
) {
2099 const base::string16
& text_str
= TextForIAccessibleText();
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
);
2107 STDMETHODIMP
BrowserAccessibilityWin::get_textAfterOffset(
2109 enum IA2TextBoundaryType boundary_type
,
2113 if (!instance_active())
2116 if (!start_offset
|| !end_offset
|| !text
)
2117 return E_INVALIDARG
;
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
) {
2128 const base::string16
& text_str
= TextForIAccessibleText();
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
);
2136 STDMETHODIMP
BrowserAccessibilityWin::get_newText(IA2TextSegment
* new_text
) {
2137 if (!instance_active())
2141 return E_INVALIDARG
;
2143 base::string16 text
= TextForIAccessibleText();
2145 new_text
->text
= SysAllocString(text
.c_str());
2146 new_text
->start
= 0;
2147 new_text
->end
= static_cast<long>(text
.size());
2151 STDMETHODIMP
BrowserAccessibilityWin::get_oldText(IA2TextSegment
* old_text
) {
2152 if (!instance_active())
2156 return E_INVALIDARG
;
2158 old_text
->text
= SysAllocString(old_text_
.c_str());
2159 old_text
->start
= 0;
2160 old_text
->end
= static_cast<long>(old_text_
.size());
2164 STDMETHODIMP
BrowserAccessibilityWin::get_offsetAtPoint(
2167 enum IA2CoordinateType coord_type
,
2169 if (!instance_active())
2173 return E_INVALIDARG
;
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.
2182 STDMETHODIMP
BrowserAccessibilityWin::scrollSubstringTo(
2185 enum IA2ScrollType scroll_type
) {
2186 // TODO(dmazzoni): adjust this for the start and end index, too.
2187 return scrollTo(scroll_type
);
2190 STDMETHODIMP
BrowserAccessibilityWin::scrollSubstringToPoint(
2193 enum IA2CoordinateType coordinate_type
,
2195 // TODO(dmazzoni): adjust this for the start and end index, too.
2196 return scrollToPoint(coordinate_type
, x
, y
);
2199 STDMETHODIMP
BrowserAccessibilityWin::addSelection(LONG start_offset
,
2201 if (!instance_active())
2204 const base::string16
& text_str
= TextForIAccessibleText();
2205 HandleSpecialTextOffset(text_str
, &start_offset
);
2206 HandleSpecialTextOffset(text_str
, &end_offset
);
2208 manager()->SetTextSelection(*this, start_offset
, end_offset
);
2212 STDMETHODIMP
BrowserAccessibilityWin::removeSelection(LONG selection_index
) {
2213 if (!instance_active())
2216 if (selection_index
!= 0)
2217 return E_INVALIDARG
;
2219 manager()->SetTextSelection(*this, 0, 0);
2223 STDMETHODIMP
BrowserAccessibilityWin::setCaretOffset(LONG offset
) {
2224 if (!instance_active())
2227 const base::string16
& text_str
= TextForIAccessibleText();
2228 HandleSpecialTextOffset(text_str
, &offset
);
2229 manager()->SetTextSelection(*this, offset
, offset
);
2233 STDMETHODIMP
BrowserAccessibilityWin::setSelection(LONG selection_index
,
2236 if (!instance_active())
2239 if (selection_index
!= 0)
2240 return E_INVALIDARG
;
2242 const base::string16
& text_str
= TextForIAccessibleText();
2243 HandleSpecialTextOffset(text_str
, &start_offset
);
2244 HandleSpecialTextOffset(text_str
, &end_offset
);
2246 manager()->SetTextSelection(*this, start_offset
, end_offset
);
2251 // IAccessibleHypertext methods.
2254 STDMETHODIMP
BrowserAccessibilityWin::get_nHyperlinks(long* hyperlink_count
) {
2255 if (!instance_active())
2258 if (!hyperlink_count
)
2259 return E_INVALIDARG
;
2261 *hyperlink_count
= hyperlink_offset_to_index_
.size();
2265 STDMETHODIMP
BrowserAccessibilityWin::get_hyperlink(
2267 IAccessibleHyperlink
** hyperlink
) {
2268 if (!instance_active())
2273 index
>= static_cast<long>(hyperlinks_
.size())) {
2274 return E_INVALIDARG
;
2277 BrowserAccessibilityWin
* child
=
2278 InternalGetChild(hyperlinks_
[index
])->ToBrowserAccessibilityWin();
2279 *hyperlink
= static_cast<IAccessibleHyperlink
*>(child
->NewReference());
2283 STDMETHODIMP
BrowserAccessibilityWin::get_hyperlinkIndex(
2285 long* hyperlink_index
) {
2286 if (!instance_active())
2289 if (!hyperlink_index
)
2290 return E_INVALIDARG
;
2292 *hyperlink_index
= -1;
2294 if (char_index
< 0 || char_index
>= static_cast<long>(hypertext_
.size()))
2295 return E_INVALIDARG
;
2297 std::map
<int32
, int32
>::iterator it
=
2298 hyperlink_offset_to_index_
.find(char_index
);
2299 if (it
== hyperlink_offset_to_index_
.end())
2302 *hyperlink_index
= it
->second
;
2307 // IAccessibleValue methods.
2310 STDMETHODIMP
BrowserAccessibilityWin::get_currentValue(VARIANT
* value
) {
2311 if (!instance_active())
2315 return E_INVALIDARG
;
2318 if (GetFloatAttribute(
2319 ui::AX_ATTR_VALUE_FOR_RANGE
, &float_val
)) {
2321 value
->dblVal
= float_val
;
2325 value
->vt
= VT_EMPTY
;
2329 STDMETHODIMP
BrowserAccessibilityWin::get_minimumValue(VARIANT
* value
) {
2330 if (!instance_active())
2334 return E_INVALIDARG
;
2337 if (GetFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE
,
2340 value
->dblVal
= float_val
;
2344 value
->vt
= VT_EMPTY
;
2348 STDMETHODIMP
BrowserAccessibilityWin::get_maximumValue(VARIANT
* value
) {
2349 if (!instance_active())
2353 return E_INVALIDARG
;
2356 if (GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE
,
2359 value
->dblVal
= float_val
;
2363 value
->vt
= VT_EMPTY
;
2367 STDMETHODIMP
BrowserAccessibilityWin::setCurrentValue(VARIANT new_value
) {
2368 // TODO(dmazzoni): Implement this.
2373 // ISimpleDOMDocument methods.
2376 STDMETHODIMP
BrowserAccessibilityWin::get_URL(BSTR
* url
) {
2377 if (!instance_active())
2381 return E_INVALIDARG
;
2383 return GetStringAttributeAsBstr(ui::AX_ATTR_DOC_URL
, url
);
2386 STDMETHODIMP
BrowserAccessibilityWin::get_title(BSTR
* title
) {
2387 if (!instance_active())
2391 return E_INVALIDARG
;
2393 return GetStringAttributeAsBstr(ui::AX_ATTR_DOC_TITLE
, title
);
2396 STDMETHODIMP
BrowserAccessibilityWin::get_mimeType(BSTR
* mime_type
) {
2397 if (!instance_active())
2401 return E_INVALIDARG
;
2403 return GetStringAttributeAsBstr(
2404 ui::AX_ATTR_DOC_MIMETYPE
, mime_type
);
2407 STDMETHODIMP
BrowserAccessibilityWin::get_docType(BSTR
* doc_type
) {
2408 if (!instance_active())
2412 return E_INVALIDARG
;
2414 return GetStringAttributeAsBstr(
2415 ui::AX_ATTR_DOC_DOCTYPE
, doc_type
);
2419 // ISimpleDOMNode methods.
2422 STDMETHODIMP
BrowserAccessibilityWin::get_nodeInfo(
2424 short* name_space_id
,
2426 unsigned int* num_children
,
2427 unsigned int* unique_id
,
2428 unsigned short* node_type
) {
2429 if (!instance_active())
2432 if (!node_name
|| !name_space_id
|| !node_value
|| !num_children
||
2433 !unique_id
|| !node_type
) {
2434 return E_INVALIDARG
;
2438 if (GetString16Attribute(ui::AX_ATTR_HTML_TAG
, &tag
))
2439 *node_name
= SysAllocString(tag
.c_str());
2444 *node_value
= SysAllocString(base::UTF8ToUTF16(value()).c_str());
2445 *num_children
= PlatformChildCount();
2446 *unique_id
= unique_id_win_
;
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
;
2454 *node_type
= NODETYPE_ELEMENT
;
2460 STDMETHODIMP
BrowserAccessibilityWin::get_attributes(
2461 unsigned short max_attribs
,
2463 short* name_space_id
,
2464 BSTR
* attrib_values
,
2465 unsigned short* num_attribs
) {
2466 if (!instance_active())
2469 if (!attrib_names
|| !name_space_id
|| !attrib_values
|| !num_attribs
)
2470 return E_INVALIDARG
;
2472 *num_attribs
= max_attribs
;
2473 if (*num_attribs
> GetHtmlAttributes().size())
2474 *num_attribs
= GetHtmlAttributes().size();
2476 for (unsigned short i
= 0; i
< *num_attribs
; ++i
) {
2477 attrib_names
[i
] = SysAllocString(
2478 base::UTF8ToUTF16(GetHtmlAttributes()[i
].first
).c_str());
2479 name_space_id
[i
] = 0;
2480 attrib_values
[i
] = SysAllocString(
2481 base::UTF8ToUTF16(GetHtmlAttributes()[i
].second
).c_str());
2486 STDMETHODIMP
BrowserAccessibilityWin::get_attributesForNames(
2487 unsigned short num_attribs
,
2489 short* name_space_id
,
2490 BSTR
* attrib_values
) {
2491 if (!instance_active())
2494 if (!attrib_names
|| !name_space_id
|| !attrib_values
)
2495 return E_INVALIDARG
;
2497 for (unsigned short i
= 0; i
< num_attribs
; ++i
) {
2498 name_space_id
[i
] = 0;
2500 std::string name
= base::UTF16ToUTF8((LPCWSTR
)attrib_names
[i
]);
2501 for (unsigned int j
= 0; j
< GetHtmlAttributes().size(); ++j
) {
2502 if (GetHtmlAttributes()[j
].first
== name
) {
2503 attrib_values
[i
] = SysAllocString(
2504 base::UTF8ToUTF16(GetHtmlAttributes()[j
].second
).c_str());
2510 attrib_values
[i
] = NULL
;
2516 STDMETHODIMP
BrowserAccessibilityWin::get_computedStyle(
2517 unsigned short max_style_properties
,
2518 boolean use_alternate_view
,
2519 BSTR
* style_properties
,
2521 unsigned short *num_style_properties
) {
2522 if (!instance_active())
2525 if (!style_properties
|| !style_values
)
2526 return E_INVALIDARG
;
2528 // We only cache a single style property for now: DISPLAY
2530 base::string16 display
;
2531 if (max_style_properties
== 0 ||
2532 !GetString16Attribute(ui::AX_ATTR_DISPLAY
, &display
)) {
2533 *num_style_properties
= 0;
2537 *num_style_properties
= 1;
2538 style_properties
[0] = SysAllocString(L
"display");
2539 style_values
[0] = SysAllocString(display
.c_str());
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())
2552 if (!style_properties
|| !style_values
)
2553 return E_INVALIDARG
;
2555 // We only cache a single style property for now: DISPLAY
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());
2565 style_values
[i
] = NULL
;
2572 STDMETHODIMP
BrowserAccessibilityWin::scrollTo(boolean placeTopLeft
) {
2573 return scrollTo(placeTopLeft
?
2574 IA2_SCROLL_TYPE_TOP_LEFT
: IA2_SCROLL_TYPE_ANYWHERE
);
2577 STDMETHODIMP
BrowserAccessibilityWin::get_parentNode(ISimpleDOMNode
** node
) {
2578 if (!instance_active())
2582 return E_INVALIDARG
;
2584 *node
= GetParent()->ToBrowserAccessibilityWin()->NewReference();
2588 STDMETHODIMP
BrowserAccessibilityWin::get_firstChild(ISimpleDOMNode
** node
) {
2589 if (!instance_active())
2593 return E_INVALIDARG
;
2595 if (PlatformChildCount() == 0) {
2600 *node
= PlatformGetChild(0)->ToBrowserAccessibilityWin()->NewReference();
2604 STDMETHODIMP
BrowserAccessibilityWin::get_lastChild(ISimpleDOMNode
** node
) {
2605 if (!instance_active())
2609 return E_INVALIDARG
;
2611 if (PlatformChildCount() == 0) {
2616 *node
= PlatformGetChild(PlatformChildCount() - 1)
2617 ->ToBrowserAccessibilityWin()->NewReference();
2621 STDMETHODIMP
BrowserAccessibilityWin::get_previousSibling(
2622 ISimpleDOMNode
** node
) {
2623 if (!instance_active())
2627 return E_INVALIDARG
;
2629 if (!GetParent() || GetIndexInParent() <= 0) {
2634 *node
= GetParent()->InternalGetChild(GetIndexInParent() - 1)->
2635 ToBrowserAccessibilityWin()->NewReference();
2639 STDMETHODIMP
BrowserAccessibilityWin::get_nextSibling(ISimpleDOMNode
** node
) {
2640 if (!instance_active())
2644 return E_INVALIDARG
;
2647 GetIndexInParent() < 0 ||
2648 GetIndexInParent() >= static_cast<int>(
2649 GetParent()->InternalChildCount()) - 1) {
2654 *node
= GetParent()->InternalGetChild(GetIndexInParent() + 1)->
2655 ToBrowserAccessibilityWin()->NewReference();
2659 STDMETHODIMP
BrowserAccessibilityWin::get_childAt(
2660 unsigned int child_index
,
2661 ISimpleDOMNode
** node
) {
2662 if (!instance_active())
2666 return E_INVALIDARG
;
2668 if (child_index
>= PlatformChildCount())
2669 return E_INVALIDARG
;
2671 BrowserAccessibility
* child
= PlatformGetChild(child_index
);
2677 *node
= child
->ToBrowserAccessibilityWin()->NewReference();
2682 // ISimpleDOMText methods.
2685 STDMETHODIMP
BrowserAccessibilityWin::get_domText(BSTR
* dom_text
) {
2686 if (!instance_active())
2690 return E_INVALIDARG
;
2692 return GetStringAttributeAsBstr(
2693 ui::AX_ATTR_NAME
, dom_text
);
2696 STDMETHODIMP
BrowserAccessibilityWin::get_clippedSubstringBounds(
2697 unsigned int start_index
,
2698 unsigned int end_index
,
2703 // TODO(dmazzoni): fully support this API by intersecting the
2704 // rect with the container's rect.
2705 return get_unclippedSubstringBounds(
2706 start_index
, end_index
, out_x
, out_y
, out_width
, out_height
);
2709 STDMETHODIMP
BrowserAccessibilityWin::get_unclippedSubstringBounds(
2710 unsigned int start_index
,
2711 unsigned int end_index
,
2716 if (!instance_active())
2719 if (!out_x
|| !out_y
|| !out_width
|| !out_height
)
2720 return E_INVALIDARG
;
2722 const base::string16
& text_str
= TextForIAccessibleText();
2723 if (start_index
> text_str
.size() ||
2724 end_index
> text_str
.size() ||
2725 start_index
> end_index
) {
2726 return E_INVALIDARG
;
2729 gfx::Rect bounds
= GetGlobalBoundsForRange(
2730 start_index
, end_index
- start_index
);
2731 *out_x
= bounds
.x();
2732 *out_y
= bounds
.y();
2733 *out_width
= bounds
.width();
2734 *out_height
= bounds
.height();
2738 STDMETHODIMP
BrowserAccessibilityWin::scrollToSubstring(
2739 unsigned int start_index
,
2740 unsigned int end_index
) {
2741 if (!instance_active())
2744 const base::string16
& text_str
= TextForIAccessibleText();
2745 if (start_index
> text_str
.size() ||
2746 end_index
> text_str
.size() ||
2747 start_index
> end_index
) {
2748 return E_INVALIDARG
;
2751 manager()->ScrollToMakeVisible(*this, GetLocalBoundsForRange(
2752 start_index
, end_index
- start_index
));
2753 manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
2759 // IServiceProvider methods.
2762 STDMETHODIMP
BrowserAccessibilityWin::QueryService(REFGUID guidService
,
2765 if (!instance_active())
2768 // The system uses IAccessible APIs for many purposes, but only
2769 // assistive technology like screen readers uses IAccessible2.
2770 // Enable full accessibility support when IAccessible2 APIs are queried.
2771 if (riid
== IID_IAccessible2
)
2772 BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility();
2774 if (guidService
== GUID_IAccessibleContentDocument
) {
2775 // Special Mozilla extension: return the accessible for the root document.
2776 // Screen readers use this to distinguish between a document loaded event
2777 // on the root document vs on an iframe.
2778 return manager()->GetRoot()->ToBrowserAccessibilityWin()->QueryInterface(
2779 IID_IAccessible2
, object
);
2782 if (guidService
== IID_IAccessible
||
2783 guidService
== IID_IAccessible2
||
2784 guidService
== IID_IAccessibleAction
||
2785 guidService
== IID_IAccessibleApplication
||
2786 guidService
== IID_IAccessibleHyperlink
||
2787 guidService
== IID_IAccessibleHypertext
||
2788 guidService
== IID_IAccessibleImage
||
2789 guidService
== IID_IAccessibleTable
||
2790 guidService
== IID_IAccessibleTable2
||
2791 guidService
== IID_IAccessibleTableCell
||
2792 guidService
== IID_IAccessibleText
||
2793 guidService
== IID_IAccessibleValue
||
2794 guidService
== IID_ISimpleDOMDocument
||
2795 guidService
== IID_ISimpleDOMNode
||
2796 guidService
== IID_ISimpleDOMText
||
2797 guidService
== GUID_ISimpleDOM
) {
2798 return QueryInterface(riid
, object
);
2801 // We only support the IAccessibleEx interface on Windows 8 and above. This
2802 // is needed for the on-screen Keyboard to show up in metro mode, when the
2803 // user taps an editable portion on the page.
2804 // All methods in the IAccessibleEx interface are unimplemented.
2805 if (riid
== IID_IAccessibleEx
&&
2806 base::win::GetVersion() >= base::win::VERSION_WIN8
) {
2807 return QueryInterface(riid
, object
);
2814 STDMETHODIMP
BrowserAccessibilityWin::GetPatternProvider(PATTERNID id
,
2815 IUnknown
** provider
) {
2816 DVLOG(1) << "In Function: "
2818 << " for pattern id: "
2820 if (id
== UIA_ValuePatternId
|| id
== UIA_TextPatternId
) {
2821 if (IsEditableText()) {
2822 DVLOG(1) << "Returning UIA text provider";
2823 base::win::UIATextProvider::CreateTextProvider(true, provider
);
2830 STDMETHODIMP
BrowserAccessibilityWin::GetPropertyValue(PROPERTYID id
,
2832 DVLOG(1) << "In Function: "
2834 << " for property id: "
2836 V_VT(ret
) = VT_EMPTY
;
2837 if (id
== UIA_ControlTypePropertyId
) {
2838 if (IsEditableText()) {
2840 ret
->lVal
= UIA_EditControlTypeId
;
2841 DVLOG(1) << "Returning Edit control type";
2843 DVLOG(1) << "Returning empty control type";
2850 // CComObjectRootEx methods.
2853 HRESULT WINAPI
BrowserAccessibilityWin::InternalQueryInterface(
2855 const _ATL_INTMAP_ENTRY
* entries
,
2858 if (iid
== IID_IAccessibleImage
) {
2859 if (ia_role_
!= ROLE_SYSTEM_GRAPHIC
) {
2861 return E_NOINTERFACE
;
2863 } else if (iid
== IID_IAccessibleTable
|| iid
== IID_IAccessibleTable2
) {
2864 if (ia_role_
!= ROLE_SYSTEM_TABLE
) {
2866 return E_NOINTERFACE
;
2868 } else if (iid
== IID_IAccessibleTableCell
) {
2869 if (ia_role_
!= ROLE_SYSTEM_CELL
) {
2871 return E_NOINTERFACE
;
2873 } else if (iid
== IID_IAccessibleValue
) {
2874 if (ia_role_
!= ROLE_SYSTEM_PROGRESSBAR
&&
2875 ia_role_
!= ROLE_SYSTEM_SCROLLBAR
&&
2876 ia_role_
!= ROLE_SYSTEM_SLIDER
) {
2878 return E_NOINTERFACE
;
2880 } else if (iid
== IID_ISimpleDOMDocument
) {
2881 if (ia_role_
!= ROLE_SYSTEM_DOCUMENT
) {
2883 return E_NOINTERFACE
;
2887 return CComObjectRootBase::InternalQueryInterface(
2888 this_ptr
, entries
, iid
, object
);
2895 // Called every time this node's data changes.
2896 void BrowserAccessibilityWin::OnDataChanged() {
2897 BrowserAccessibility::OnDataChanged();
2901 // Expose the "display" and "tag" attributes.
2902 StringAttributeToIA2(ui::AX_ATTR_DISPLAY
, "display");
2903 StringAttributeToIA2(ui::AX_ATTR_HTML_TAG
, "tag");
2904 StringAttributeToIA2(ui::AX_ATTR_ROLE
, "xml-roles");
2906 // Expose "level" attribute for headings, trees, etc.
2907 IntAttributeToIA2(ui::AX_ATTR_HIERARCHICAL_LEVEL
, "level");
2909 // Expose the set size and position in set for listbox options.
2910 if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION
&&
2912 GetParent()->GetRole() == ui::AX_ROLE_LIST_BOX
) {
2913 ia2_attributes_
.push_back(
2914 L
"setsize:" + base::IntToString16(GetParent()->PlatformChildCount()));
2915 ia2_attributes_
.push_back(
2916 L
"setsize:" + base::IntToString16(GetIndexInParent() + 1));
2919 if (ia_role_
== ROLE_SYSTEM_CHECKBUTTON
||
2920 ia_role_
== ROLE_SYSTEM_RADIOBUTTON
||
2921 ia2_role_
== IA2_ROLE_TOGGLE_BUTTON
) {
2922 ia2_attributes_
.push_back(L
"checkable:true");
2925 // Expose live region attributes.
2926 StringAttributeToIA2(ui::AX_ATTR_LIVE_STATUS
, "live");
2927 StringAttributeToIA2(ui::AX_ATTR_LIVE_RELEVANT
, "relevant");
2928 BoolAttributeToIA2(ui::AX_ATTR_LIVE_ATOMIC
, "atomic");
2929 BoolAttributeToIA2(ui::AX_ATTR_LIVE_BUSY
, "busy");
2931 // Expose container live region attributes.
2932 StringAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_STATUS
,
2934 StringAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_RELEVANT
,
2935 "container-relevant");
2936 BoolAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_ATOMIC
,
2937 "container-atomic");
2938 BoolAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_BUSY
,
2941 // Expose slider value.
2942 if (ia_role_
== ROLE_SYSTEM_PROGRESSBAR
||
2943 ia_role_
== ROLE_SYSTEM_SCROLLBAR
||
2944 ia_role_
== ROLE_SYSTEM_SLIDER
) {
2945 ia2_attributes_
.push_back(L
"valuetext:" + GetValueText());
2948 // Expose table cell index.
2949 if (ia_role_
== ROLE_SYSTEM_CELL
) {
2950 BrowserAccessibility
* table
= GetParent();
2951 while (table
&& table
->GetRole() != ui::AX_ROLE_TABLE
)
2952 table
= table
->GetParent();
2954 const std::vector
<int32
>& unique_cell_ids
= table
->GetIntListAttribute(
2955 ui::AX_ATTR_UNIQUE_CELL_IDS
);
2956 for (size_t i
= 0; i
< unique_cell_ids
.size(); ++i
) {
2957 if (unique_cell_ids
[i
] == GetId()) {
2958 ia2_attributes_
.push_back(
2959 base::string16(L
"table-cell-index:") + base::IntToString16(i
));
2965 // The calculation of the accessible name of an element has been
2966 // standardized in the HTML to Platform Accessibility APIs Implementation
2967 // Guide (http://www.w3.org/TR/html-aapi/). In order to return the
2968 // appropriate accessible name on Windows, we need to apply some logic
2969 // to the fields we get from WebKit.
2971 // TODO(dmazzoni): move most of this logic into WebKit.
2975 // name: the default name, e.g. inner text
2976 // title ui element: a reference to a <label> element on the same
2977 // page that labels this node.
2978 // description: accessible labels that override the default name:
2979 // aria-label or aria-labelledby or aria-describedby
2980 // help: the value of the "title" attribute
2982 // On Windows, the logic we apply lets some fields take precedence and
2983 // always returns the primary name in "name" and the secondary name,
2984 // if any, in "description".
2986 int title_elem_id
= GetIntAttribute(
2987 ui::AX_ATTR_TITLE_UI_ELEMENT
);
2988 std::string help
= GetStringAttribute(ui::AX_ATTR_HELP
);
2989 std::string description
= GetStringAttribute(
2990 ui::AX_ATTR_DESCRIPTION
);
2992 // WebKit annoyingly puts the title in the description if there's no other
2993 // description, which just confuses the rest of the logic. Put it back.
2994 // Now "help" is always the value of the "title" attribute, if present.
2995 std::string title_attr
;
2996 if (GetHtmlAttribute("title", &title_attr
) &&
2997 description
== title_attr
&&
3000 description
.clear();
3003 // Now implement the main logic: the descripion should become the name if
3004 // it's nonempty, and the help should become the description if
3005 // there's no description - or the name if there's no name or description.
3006 if (!description
.empty()) {
3007 set_name(description
);
3008 description
.clear();
3010 if (!help
.empty() && description
.empty()) {
3014 if (!description
.empty() && name().empty() && !title_elem_id
) {
3015 set_name(description
);
3016 description
.clear();
3019 // If it's a text field, also consider the placeholder.
3020 std::string placeholder
;
3021 if (GetRole() == ui::AX_ROLE_TEXT_FIELD
&&
3022 HasState(ui::AX_STATE_FOCUSABLE
) &&
3023 GetHtmlAttribute("placeholder", &placeholder
)) {
3024 if (name().empty() && !title_elem_id
) {
3025 set_name(placeholder
);
3026 } else if (description
.empty()) {
3027 description
= placeholder
;
3031 SetStringAttribute(ui::AX_ATTR_DESCRIPTION
, description
);
3032 SetStringAttribute(ui::AX_ATTR_HELP
, help
);
3034 // On Windows, the value of a document should be its url.
3035 if (GetRole() == ui::AX_ROLE_ROOT_WEB_AREA
||
3036 GetRole() == ui::AX_ROLE_WEB_AREA
) {
3037 set_value(GetStringAttribute(ui::AX_ATTR_DOC_URL
));
3040 // For certain roles (listbox option, static text, and list marker)
3041 // WebKit stores the main accessible text in the "value" - swap it so
3042 // that it's the "name".
3043 if (name().empty() &&
3044 (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION
||
3045 GetRole() == ui::AX_ROLE_STATIC_TEXT
||
3046 GetRole() == ui::AX_ROLE_LIST_MARKER
)) {
3047 std::string tmp
= value();
3052 // If this doesn't have a value and is linked then set its value to the url
3053 // attribute. This allows screen readers to read an empty link's destination.
3054 if (value().empty() && (ia_state_
& STATE_SYSTEM_LINKED
))
3055 set_value(GetStringAttribute(ui::AX_ATTR_URL
));
3057 // Clear any old relationships between this node and other nodes.
3058 for (size_t i
= 0; i
< relations_
.size(); ++i
)
3059 relations_
[i
]->Release();
3062 // Handle title UI element.
3063 if (title_elem_id
) {
3064 // Add a labelled by relationship.
3065 CComObject
<BrowserAccessibilityRelation
>* relation
;
3066 HRESULT hr
= CComObject
<BrowserAccessibilityRelation
>::CreateInstance(
3068 DCHECK(SUCCEEDED(hr
));
3070 relation
->Initialize(this, IA2_RELATION_LABELLED_BY
);
3071 relation
->AddTarget(title_elem_id
);
3072 relations_
.push_back(relation
);
3076 void BrowserAccessibilityWin::OnUpdateFinished() {
3077 // Construct the hypertext for this node.
3078 hyperlink_offset_to_index_
.clear();
3079 hyperlinks_
.clear();
3081 for (unsigned int i
= 0; i
< PlatformChildCount(); ++i
) {
3082 BrowserAccessibility
* child
= PlatformGetChild(i
);
3083 if (child
->GetRole() == ui::AX_ROLE_STATIC_TEXT
) {
3084 hypertext_
+= base::UTF8ToUTF16(child
->name());
3086 hyperlink_offset_to_index_
[hypertext_
.size()] = hyperlinks_
.size();
3087 hypertext_
+= kEmbeddedCharacter
;
3088 hyperlinks_
.push_back(i
);
3091 DCHECK_EQ(hyperlink_offset_to_index_
.size(), hyperlinks_
.size());
3093 // Fire an event when an alert first appears.
3094 if (GetRole() == ui::AX_ROLE_ALERT
&& first_time_
)
3095 manager()->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT
, this);
3097 // Fire events if text has changed.
3098 base::string16 text
= TextForIAccessibleText();
3099 if (previous_text_
!= text
) {
3100 if (!previous_text_
.empty() && !text
.empty()) {
3101 manager()->NotifyAccessibilityEvent(
3102 ui::AX_EVENT_SHOW
, this);
3105 // TODO(dmazzoni): Look into HIDE events, too.
3107 old_text_
= previous_text_
;
3108 previous_text_
= text
;
3111 BrowserAccessibilityManagerWin
* manager
=
3112 this->manager()->ToBrowserAccessibilityManagerWin();
3114 // Fire events if the state has changed.
3115 if (!first_time_
&& ia_state_
!= old_ia_state_
) {
3116 // Normally focus events are handled elsewhere, however
3117 // focus for managed descendants is platform-specific.
3118 // Fire a focus event if the focused descendant in a multi-select
3119 // list box changes.
3120 if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION
&&
3121 (ia_state_
& STATE_SYSTEM_FOCUSABLE
) &&
3122 (ia_state_
& STATE_SYSTEM_SELECTABLE
) &&
3123 (ia_state_
& STATE_SYSTEM_FOCUSED
) &&
3124 !(old_ia_state_
& STATE_SYSTEM_FOCUSED
)) {
3125 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_FOCUS
, unique_id_win());
3128 if ((ia_state_
& STATE_SYSTEM_SELECTED
) &&
3129 !(old_ia_state_
& STATE_SYSTEM_SELECTED
)) {
3130 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONADD
,
3132 } else if (!(ia_state_
& STATE_SYSTEM_SELECTED
) &&
3133 (old_ia_state_
& STATE_SYSTEM_SELECTED
)) {
3134 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONREMOVE
,
3138 old_ia_state_
= ia_state_
;
3141 // Fire an event if this container object has scrolled.
3144 if (GetIntAttribute(ui::AX_ATTR_SCROLL_X
, &sx
) &&
3145 GetIntAttribute(ui::AX_ATTR_SCROLL_Y
, &sy
)) {
3147 (sx
!= previous_scroll_x_
|| sy
!= previous_scroll_y_
)) {
3148 manager
->MaybeCallNotifyWinEvent(EVENT_SYSTEM_SCROLLINGEND
,
3151 previous_scroll_x_
= sx
;
3152 previous_scroll_y_
= sy
;
3155 first_time_
= false;
3158 void BrowserAccessibilityWin::NativeAddReference() {
3162 void BrowserAccessibilityWin::NativeReleaseReference() {
3166 bool BrowserAccessibilityWin::IsNative() const {
3170 void BrowserAccessibilityWin::OnLocationChanged() const {
3171 manager()->ToBrowserAccessibilityManagerWin()->MaybeCallNotifyWinEvent(
3172 EVENT_OBJECT_LOCATIONCHANGE
, unique_id_win());
3175 BrowserAccessibilityWin
* BrowserAccessibilityWin::NewReference() {
3180 BrowserAccessibilityWin
* BrowserAccessibilityWin::GetTargetFromChildID(
3181 const VARIANT
& var_id
) {
3182 if (var_id
.vt
!= VT_I4
)
3185 LONG child_id
= var_id
.lVal
;
3186 if (child_id
== CHILDID_SELF
)
3189 if (child_id
>= 1 && child_id
<= static_cast<LONG
>(PlatformChildCount()))
3190 return PlatformGetChild(child_id
- 1)->ToBrowserAccessibilityWin();
3192 return manager()->ToBrowserAccessibilityManagerWin()->
3193 GetFromUniqueIdWin(child_id
);
3196 HRESULT
BrowserAccessibilityWin::GetStringAttributeAsBstr(
3197 ui::AXStringAttribute attribute
,
3201 if (!GetString16Attribute(attribute
, &str
))
3207 *value_bstr
= SysAllocString(str
.c_str());
3208 DCHECK(*value_bstr
);
3213 void BrowserAccessibilityWin::StringAttributeToIA2(
3214 ui::AXStringAttribute attribute
,
3215 const char* ia2_attr
) {
3216 base::string16 value
;
3217 if (GetString16Attribute(attribute
, &value
))
3218 ia2_attributes_
.push_back(base::ASCIIToUTF16(ia2_attr
) + L
":" + value
);
3221 void BrowserAccessibilityWin::BoolAttributeToIA2(
3222 ui::AXBoolAttribute attribute
,
3223 const char* ia2_attr
) {
3225 if (GetBoolAttribute(attribute
, &value
)) {
3226 ia2_attributes_
.push_back((base::ASCIIToUTF16(ia2_attr
) + L
":") +
3227 (value
? L
"true" : L
"false"));
3231 void BrowserAccessibilityWin::IntAttributeToIA2(
3232 ui::AXIntAttribute attribute
,
3233 const char* ia2_attr
) {
3235 if (GetIntAttribute(attribute
, &value
)) {
3236 ia2_attributes_
.push_back(base::ASCIIToUTF16(ia2_attr
) + L
":" +
3237 base::IntToString16(value
));
3241 base::string16
BrowserAccessibilityWin::GetValueText() {
3243 base::string16 value
= base::UTF8ToUTF16(this->value());
3245 if (value
.empty() &&
3246 GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE
, &fval
)) {
3247 value
= base::UTF8ToUTF16(base::DoubleToString(fval
));
3252 base::string16
BrowserAccessibilityWin::TextForIAccessibleText() {
3253 if (IsEditableText())
3254 return base::UTF8ToUTF16(value());
3255 return (GetRole() == ui::AX_ROLE_STATIC_TEXT
) ?
3256 base::UTF8ToUTF16(name()) : hypertext_
;
3259 void BrowserAccessibilityWin::HandleSpecialTextOffset(
3260 const base::string16
& text
,
3262 if (*offset
== IA2_TEXT_OFFSET_LENGTH
)
3263 *offset
= static_cast<LONG
>(text
.size());
3264 else if (*offset
== IA2_TEXT_OFFSET_CARET
)
3265 get_caretOffset(offset
);
3268 ui::TextBoundaryType
BrowserAccessibilityWin::IA2TextBoundaryToTextBoundary(
3269 IA2TextBoundaryType ia2_boundary
) {
3270 switch(ia2_boundary
) {
3271 case IA2_TEXT_BOUNDARY_CHAR
: return ui::CHAR_BOUNDARY
;
3272 case IA2_TEXT_BOUNDARY_WORD
: return ui::WORD_BOUNDARY
;
3273 case IA2_TEXT_BOUNDARY_LINE
: return ui::LINE_BOUNDARY
;
3274 case IA2_TEXT_BOUNDARY_SENTENCE
: return ui::SENTENCE_BOUNDARY
;
3275 case IA2_TEXT_BOUNDARY_PARAGRAPH
: return ui::PARAGRAPH_BOUNDARY
;
3276 case IA2_TEXT_BOUNDARY_ALL
: return ui::ALL_BOUNDARY
;
3279 return ui::CHAR_BOUNDARY
;
3283 LONG
BrowserAccessibilityWin::FindBoundary(
3284 const base::string16
& text
,
3285 IA2TextBoundaryType ia2_boundary
,
3287 ui::TextBoundaryDirection direction
) {
3288 HandleSpecialTextOffset(text
, &start_offset
);
3289 ui::TextBoundaryType boundary
= IA2TextBoundaryToTextBoundary(ia2_boundary
);
3290 const std::vector
<int32
>& line_breaks
= GetIntListAttribute(
3291 ui::AX_ATTR_LINE_BREAKS
);
3292 return ui::FindAccessibleTextBoundary(
3293 text
, line_breaks
, boundary
, start_offset
, direction
);
3296 BrowserAccessibilityWin
* BrowserAccessibilityWin::GetFromID(int32 id
) {
3297 return manager()->GetFromID(id
)->ToBrowserAccessibilityWin();
3300 void BrowserAccessibilityWin::InitRoleAndState() {
3302 ia2_state_
= IA2_STATE_OPAQUE
;
3303 ia2_attributes_
.clear();
3305 if (HasState(ui::AX_STATE_BUSY
))
3306 ia_state_
|= STATE_SYSTEM_BUSY
;
3307 if (HasState(ui::AX_STATE_CHECKED
))
3308 ia_state_
|= STATE_SYSTEM_CHECKED
;
3309 if (HasState(ui::AX_STATE_COLLAPSED
))
3310 ia_state_
|= STATE_SYSTEM_COLLAPSED
;
3311 if (HasState(ui::AX_STATE_EXPANDED
))
3312 ia_state_
|= STATE_SYSTEM_EXPANDED
;
3313 if (HasState(ui::AX_STATE_FOCUSABLE
))
3314 ia_state_
|= STATE_SYSTEM_FOCUSABLE
;
3315 if (HasState(ui::AX_STATE_HASPOPUP
))
3316 ia_state_
|= STATE_SYSTEM_HASPOPUP
;
3317 if (HasState(ui::AX_STATE_HOVERED
))
3318 ia_state_
|= STATE_SYSTEM_HOTTRACKED
;
3319 if (HasState(ui::AX_STATE_INDETERMINATE
))
3320 ia_state_
|= STATE_SYSTEM_INDETERMINATE
;
3321 if (HasState(ui::AX_STATE_INVISIBLE
))
3322 ia_state_
|= STATE_SYSTEM_INVISIBLE
;
3323 if (HasState(ui::AX_STATE_LINKED
))
3324 ia_state_
|= STATE_SYSTEM_LINKED
;
3325 if (HasState(ui::AX_STATE_MULTISELECTABLE
)) {
3326 ia_state_
|= STATE_SYSTEM_EXTSELECTABLE
;
3327 ia_state_
|= STATE_SYSTEM_MULTISELECTABLE
;
3329 // TODO(ctguil): Support STATE_SYSTEM_EXTSELECTABLE/accSelect.
3330 if (HasState(ui::AX_STATE_OFFSCREEN
))
3331 ia_state_
|= STATE_SYSTEM_OFFSCREEN
;
3332 if (HasState(ui::AX_STATE_PRESSED
))
3333 ia_state_
|= STATE_SYSTEM_PRESSED
;
3334 if (HasState(ui::AX_STATE_PROTECTED
))
3335 ia_state_
|= STATE_SYSTEM_PROTECTED
;
3336 if (HasState(ui::AX_STATE_REQUIRED
))
3337 ia2_state_
|= IA2_STATE_REQUIRED
;
3338 if (HasState(ui::AX_STATE_SELECTABLE
))
3339 ia_state_
|= STATE_SYSTEM_SELECTABLE
;
3340 if (HasState(ui::AX_STATE_SELECTED
))
3341 ia_state_
|= STATE_SYSTEM_SELECTED
;
3342 if (HasState(ui::AX_STATE_VISITED
))
3343 ia_state_
|= STATE_SYSTEM_TRAVERSED
;
3344 if (!HasState(ui::AX_STATE_ENABLED
))
3345 ia_state_
|= STATE_SYSTEM_UNAVAILABLE
;
3346 if (HasState(ui::AX_STATE_VERTICAL
)) {
3347 ia2_state_
|= IA2_STATE_VERTICAL
;
3349 ia2_state_
|= IA2_STATE_HORIZONTAL
;
3351 if (HasState(ui::AX_STATE_VISITED
))
3352 ia_state_
|= STATE_SYSTEM_TRAVERSED
;
3354 // WebKit marks everything as readonly unless it's editable text, so if it's
3355 // not readonly, mark it as editable now. The final computation of the
3356 // READONLY state for MSAA is below, after the switch.
3357 if (!HasState(ui::AX_STATE_READ_ONLY
))
3358 ia2_state_
|= IA2_STATE_EDITABLE
;
3360 base::string16 invalid
;
3361 if (GetHtmlAttribute("aria-invalid", &invalid
))
3362 ia2_state_
|= IA2_STATE_INVALID_ENTRY
;
3364 if (GetBoolAttribute(ui::AX_ATTR_BUTTON_MIXED
))
3365 ia_state_
|= STATE_SYSTEM_MIXED
;
3367 if (GetBoolAttribute(ui::AX_ATTR_CAN_SET_VALUE
))
3368 ia2_state_
|= IA2_STATE_EDITABLE
;
3370 base::string16 html_tag
= GetString16Attribute(
3371 ui::AX_ATTR_HTML_TAG
);
3374 switch (GetRole()) {
3375 case ui::AX_ROLE_ALERT
:
3376 ia_role_
= ROLE_SYSTEM_ALERT
;
3378 case ui::AX_ROLE_ALERT_DIALOG
:
3379 ia_role_
= ROLE_SYSTEM_DIALOG
;
3381 case ui::AX_ROLE_APPLICATION
:
3382 ia_role_
= ROLE_SYSTEM_APPLICATION
;
3384 case ui::AX_ROLE_ARTICLE
:
3385 ia_role_
= ROLE_SYSTEM_GROUPING
;
3386 ia2_role_
= IA2_ROLE_SECTION
;
3387 ia_state_
|= STATE_SYSTEM_READONLY
;
3389 case ui::AX_ROLE_BUSY_INDICATOR
:
3390 ia_role_
= ROLE_SYSTEM_ANIMATION
;
3391 ia_state_
|= STATE_SYSTEM_READONLY
;
3393 case ui::AX_ROLE_BUTTON
:
3394 ia_role_
= ROLE_SYSTEM_PUSHBUTTON
;
3395 bool is_aria_pressed_defined
;
3397 if (GetAriaTristate("aria-pressed", &is_aria_pressed_defined
, &is_mixed
))
3398 ia_state_
|= STATE_SYSTEM_PRESSED
;
3399 if (is_aria_pressed_defined
)
3400 ia2_role_
= IA2_ROLE_TOGGLE_BUTTON
;
3402 ia_state_
|= STATE_SYSTEM_MIXED
;
3404 case ui::AX_ROLE_CANVAS
:
3405 if (GetBoolAttribute(ui::AX_ATTR_CANVAS_HAS_FALLBACK
)) {
3406 role_name_
= L
"canvas";
3407 ia2_role_
= IA2_ROLE_CANVAS
;
3409 ia_role_
= ROLE_SYSTEM_GRAPHIC
;
3412 case ui::AX_ROLE_CELL
:
3413 ia_role_
= ROLE_SYSTEM_CELL
;
3415 case ui::AX_ROLE_CHECK_BOX
:
3416 ia_role_
= ROLE_SYSTEM_CHECKBUTTON
;
3418 case ui::AX_ROLE_COLOR_WELL
:
3419 ia_role_
= ROLE_SYSTEM_CLIENT
;
3420 ia2_role_
= IA2_ROLE_COLOR_CHOOSER
;
3422 case ui::AX_ROLE_COLUMN
:
3423 ia_role_
= ROLE_SYSTEM_COLUMN
;
3424 ia_state_
|= STATE_SYSTEM_READONLY
;
3426 case ui::AX_ROLE_COLUMN_HEADER
:
3427 ia_role_
= ROLE_SYSTEM_COLUMNHEADER
;
3428 ia_state_
|= STATE_SYSTEM_READONLY
;
3430 case ui::AX_ROLE_COMBO_BOX
:
3431 ia_role_
= ROLE_SYSTEM_COMBOBOX
;
3433 case ui::AX_ROLE_DIV
:
3434 role_name_
= L
"div";
3435 ia2_role_
= IA2_ROLE_SECTION
;
3437 case ui::AX_ROLE_DEFINITION
:
3438 role_name_
= html_tag
;
3439 ia2_role_
= IA2_ROLE_PARAGRAPH
;
3440 ia_state_
|= STATE_SYSTEM_READONLY
;
3442 case ui::AX_ROLE_DESCRIPTION_LIST_DETAIL
:
3443 role_name_
= html_tag
;
3444 ia2_role_
= IA2_ROLE_PARAGRAPH
;
3445 ia_state_
|= STATE_SYSTEM_READONLY
;
3447 case ui::AX_ROLE_DESCRIPTION_LIST_TERM
:
3448 ia_role_
= ROLE_SYSTEM_LISTITEM
;
3449 ia_state_
|= STATE_SYSTEM_READONLY
;
3451 case ui::AX_ROLE_DIALOG
:
3452 ia_role_
= ROLE_SYSTEM_DIALOG
;
3453 ia_state_
|= STATE_SYSTEM_READONLY
;
3455 case ui::AX_ROLE_DISCLOSURE_TRIANGLE
:
3456 ia_role_
= ROLE_SYSTEM_OUTLINEBUTTON
;
3457 ia_state_
|= STATE_SYSTEM_READONLY
;
3459 case ui::AX_ROLE_DOCUMENT
:
3460 case ui::AX_ROLE_ROOT_WEB_AREA
:
3461 case ui::AX_ROLE_WEB_AREA
:
3462 ia_role_
= ROLE_SYSTEM_DOCUMENT
;
3463 ia_state_
|= STATE_SYSTEM_READONLY
;
3464 ia_state_
|= STATE_SYSTEM_FOCUSABLE
;
3466 case ui::AX_ROLE_EDITABLE_TEXT
:
3467 ia_role_
= ROLE_SYSTEM_TEXT
;
3468 ia2_state_
|= IA2_STATE_SINGLE_LINE
;
3469 ia2_state_
|= IA2_STATE_EDITABLE
;
3471 case ui::AX_ROLE_FORM
:
3472 role_name_
= L
"form";
3473 ia2_role_
= IA2_ROLE_FORM
;
3475 case ui::AX_ROLE_FOOTER
:
3476 ia_role_
= IA2_ROLE_FOOTER
;
3477 ia_state_
|= STATE_SYSTEM_READONLY
;
3479 case ui::AX_ROLE_GRID
:
3480 ia_role_
= ROLE_SYSTEM_TABLE
;
3481 ia_state_
|= STATE_SYSTEM_READONLY
;
3483 case ui::AX_ROLE_GROUP
: {
3484 base::string16 aria_role
= GetString16Attribute(
3486 if (aria_role
== L
"group" || html_tag
== L
"fieldset") {
3487 ia_role_
= ROLE_SYSTEM_GROUPING
;
3488 } else if (html_tag
== L
"li") {
3489 ia_role_
= ROLE_SYSTEM_LISTITEM
;
3491 if (html_tag
.empty())
3492 role_name_
= L
"div";
3494 role_name_
= html_tag
;
3495 ia2_role_
= IA2_ROLE_SECTION
;
3497 ia_state_
|= STATE_SYSTEM_READONLY
;
3500 case ui::AX_ROLE_GROW_AREA
:
3501 ia_role_
= ROLE_SYSTEM_GRIP
;
3502 ia_state_
|= STATE_SYSTEM_READONLY
;
3504 case ui::AX_ROLE_HEADING
:
3505 role_name_
= html_tag
;
3506 ia2_role_
= IA2_ROLE_HEADING
;
3507 ia_state_
|= STATE_SYSTEM_READONLY
;
3509 case ui::AX_ROLE_HORIZONTAL_RULE
:
3510 ia_role_
= ROLE_SYSTEM_SEPARATOR
;
3512 case ui::AX_ROLE_IFRAME
:
3513 ia_role_
= ROLE_SYSTEM_CLIENT
;
3514 ia2_role_
= IA2_ROLE_INTERNAL_FRAME
;
3516 case ui::AX_ROLE_IMAGE
:
3517 ia_role_
= ROLE_SYSTEM_GRAPHIC
;
3518 ia_state_
|= STATE_SYSTEM_READONLY
;
3520 case ui::AX_ROLE_IMAGE_MAP
:
3521 role_name_
= html_tag
;
3522 ia2_role_
= IA2_ROLE_IMAGE_MAP
;
3523 ia_state_
|= STATE_SYSTEM_READONLY
;
3525 case ui::AX_ROLE_IMAGE_MAP_LINK
:
3526 ia_role_
= ROLE_SYSTEM_LINK
;
3527 ia_state_
|= STATE_SYSTEM_LINKED
;
3528 ia_state_
|= STATE_SYSTEM_READONLY
;
3530 case ui::AX_ROLE_LABEL_TEXT
:
3531 ia_role_
= ROLE_SYSTEM_TEXT
;
3532 ia2_role_
= IA2_ROLE_LABEL
;
3534 case ui::AX_ROLE_BANNER
:
3535 case ui::AX_ROLE_COMPLEMENTARY
:
3536 case ui::AX_ROLE_CONTENT_INFO
:
3537 case ui::AX_ROLE_MAIN
:
3538 case ui::AX_ROLE_NAVIGATION
:
3539 case ui::AX_ROLE_SEARCH
:
3540 ia_role_
= ROLE_SYSTEM_GROUPING
;
3541 ia2_role_
= IA2_ROLE_SECTION
;
3542 ia_state_
|= STATE_SYSTEM_READONLY
;
3544 case ui::AX_ROLE_LINK
:
3545 ia_role_
= ROLE_SYSTEM_LINK
;
3546 ia_state_
|= STATE_SYSTEM_LINKED
;
3548 case ui::AX_ROLE_LIST
:
3549 ia_role_
= ROLE_SYSTEM_LIST
;
3550 ia_state_
|= STATE_SYSTEM_READONLY
;
3552 case ui::AX_ROLE_LIST_BOX
:
3553 ia_role_
= ROLE_SYSTEM_LIST
;
3555 case ui::AX_ROLE_LIST_BOX_OPTION
:
3556 ia_role_
= ROLE_SYSTEM_LISTITEM
;
3557 if (ia_state_
& STATE_SYSTEM_SELECTABLE
) {
3558 ia_state_
|= STATE_SYSTEM_FOCUSABLE
;
3559 if (HasState(ui::AX_STATE_FOCUSED
))
3560 ia_state_
|= STATE_SYSTEM_FOCUSED
;
3563 case ui::AX_ROLE_LIST_ITEM
:
3564 ia_role_
= ROLE_SYSTEM_LISTITEM
;
3565 ia_state_
|= STATE_SYSTEM_READONLY
;
3567 case ui::AX_ROLE_MATH_ELEMENT
:
3568 ia_role_
= ROLE_SYSTEM_EQUATION
;
3569 ia_state_
|= STATE_SYSTEM_READONLY
;
3571 case ui::AX_ROLE_MENU
:
3572 case ui::AX_ROLE_MENU_BUTTON
:
3573 ia_role_
= ROLE_SYSTEM_MENUPOPUP
;
3575 case ui::AX_ROLE_MENU_BAR
:
3576 ia_role_
= ROLE_SYSTEM_MENUBAR
;
3578 case ui::AX_ROLE_MENU_ITEM
:
3579 ia_role_
= ROLE_SYSTEM_MENUITEM
;
3581 case ui::AX_ROLE_MENU_LIST_POPUP
:
3582 ia_role_
= ROLE_SYSTEM_CLIENT
;
3584 case ui::AX_ROLE_MENU_LIST_OPTION
:
3585 ia_role_
= ROLE_SYSTEM_LISTITEM
;
3586 if (ia_state_
& STATE_SYSTEM_SELECTABLE
) {
3587 ia_state_
|= STATE_SYSTEM_FOCUSABLE
;
3588 if (HasState(ui::AX_STATE_FOCUSED
))
3589 ia_state_
|= STATE_SYSTEM_FOCUSED
;
3592 case ui::AX_ROLE_NOTE
:
3593 ia_role_
= ROLE_SYSTEM_GROUPING
;
3594 ia2_role_
= IA2_ROLE_NOTE
;
3595 ia_state_
|= STATE_SYSTEM_READONLY
;
3597 case ui::AX_ROLE_OUTLINE
:
3598 ia_role_
= ROLE_SYSTEM_OUTLINE
;
3599 ia_state_
|= STATE_SYSTEM_READONLY
;
3601 case ui::AX_ROLE_PARAGRAPH
:
3603 ia2_role_
= IA2_ROLE_PARAGRAPH
;
3605 case ui::AX_ROLE_POP_UP_BUTTON
:
3606 if (html_tag
== L
"select") {
3607 ia_role_
= ROLE_SYSTEM_COMBOBOX
;
3609 ia_role_
= ROLE_SYSTEM_BUTTONMENU
;
3612 case ui::AX_ROLE_PROGRESS_INDICATOR
:
3613 ia_role_
= ROLE_SYSTEM_PROGRESSBAR
;
3614 ia_state_
|= STATE_SYSTEM_READONLY
;
3616 case ui::AX_ROLE_RADIO_BUTTON
:
3617 ia_role_
= ROLE_SYSTEM_RADIOBUTTON
;
3619 case ui::AX_ROLE_RADIO_GROUP
:
3620 ia_role_
= ROLE_SYSTEM_GROUPING
;
3621 ia2_role_
= IA2_ROLE_SECTION
;
3623 case ui::AX_ROLE_REGION
:
3624 ia_role_
= ROLE_SYSTEM_GROUPING
;
3625 ia2_role_
= IA2_ROLE_SECTION
;
3626 ia_state_
|= STATE_SYSTEM_READONLY
;
3628 case ui::AX_ROLE_ROW
:
3629 ia_role_
= ROLE_SYSTEM_ROW
;
3630 ia_state_
|= STATE_SYSTEM_READONLY
;
3632 case ui::AX_ROLE_ROW_HEADER
:
3633 ia_role_
= ROLE_SYSTEM_ROWHEADER
;
3634 ia_state_
|= STATE_SYSTEM_READONLY
;
3636 case ui::AX_ROLE_RULER
:
3637 ia_role_
= ROLE_SYSTEM_CLIENT
;
3638 ia2_role_
= IA2_ROLE_RULER
;
3639 ia_state_
|= STATE_SYSTEM_READONLY
;
3641 case ui::AX_ROLE_SCROLL_AREA
:
3642 ia_role_
= ROLE_SYSTEM_CLIENT
;
3643 ia2_role_
= IA2_ROLE_SCROLL_PANE
;
3644 ia_state_
|= STATE_SYSTEM_READONLY
;
3646 case ui::AX_ROLE_SCROLL_BAR
:
3647 ia_role_
= ROLE_SYSTEM_SCROLLBAR
;
3649 case ui::AX_ROLE_SLIDER
:
3650 ia_role_
= ROLE_SYSTEM_SLIDER
;
3652 case ui::AX_ROLE_SPIN_BUTTON
:
3653 ia_role_
= ROLE_SYSTEM_SPINBUTTON
;
3655 case ui::AX_ROLE_SPIN_BUTTON_PART
:
3656 ia_role_
= ROLE_SYSTEM_PUSHBUTTON
;
3658 case ui::AX_ROLE_SPLIT_GROUP
:
3659 ia_role_
= ROLE_SYSTEM_CLIENT
;
3660 ia2_role_
= IA2_ROLE_SPLIT_PANE
;
3661 ia_state_
|= STATE_SYSTEM_READONLY
;
3663 case ui::AX_ROLE_ANNOTATION
:
3664 case ui::AX_ROLE_LIST_MARKER
:
3665 case ui::AX_ROLE_STATIC_TEXT
:
3666 ia_role_
= ROLE_SYSTEM_STATICTEXT
;
3668 case ui::AX_ROLE_STATUS
:
3669 ia_role_
= ROLE_SYSTEM_STATUSBAR
;
3670 ia_state_
|= STATE_SYSTEM_READONLY
;
3672 case ui::AX_ROLE_SPLITTER
:
3673 ia_role_
= ROLE_SYSTEM_SEPARATOR
;
3675 case ui::AX_ROLE_SVG_ROOT
:
3676 ia_role_
= ROLE_SYSTEM_GRAPHIC
;
3678 case ui::AX_ROLE_TAB
:
3679 ia_role_
= ROLE_SYSTEM_PAGETAB
;
3681 case ui::AX_ROLE_TABLE
: {
3682 base::string16 aria_role
= GetString16Attribute(
3684 if (aria_role
== L
"treegrid") {
3685 ia_role_
= ROLE_SYSTEM_OUTLINE
;
3687 ia_role_
= ROLE_SYSTEM_TABLE
;
3688 ia_state_
|= STATE_SYSTEM_READONLY
;
3692 case ui::AX_ROLE_TABLE_HEADER_CONTAINER
:
3693 ia_role_
= ROLE_SYSTEM_GROUPING
;
3694 ia2_role_
= IA2_ROLE_SECTION
;
3695 ia_state_
|= STATE_SYSTEM_READONLY
;
3697 case ui::AX_ROLE_TAB_LIST
:
3698 ia_role_
= ROLE_SYSTEM_PAGETABLIST
;
3700 case ui::AX_ROLE_TAB_PANEL
:
3701 ia_role_
= ROLE_SYSTEM_PROPERTYPAGE
;
3703 case ui::AX_ROLE_TOGGLE_BUTTON
:
3704 ia_role_
= ROLE_SYSTEM_PUSHBUTTON
;
3705 ia2_role_
= IA2_ROLE_TOGGLE_BUTTON
;
3707 case ui::AX_ROLE_TEXT_AREA
:
3708 ia_role_
= ROLE_SYSTEM_TEXT
;
3709 ia2_state_
|= IA2_STATE_MULTI_LINE
;
3710 ia2_state_
|= IA2_STATE_EDITABLE
;
3711 ia2_state_
|= IA2_STATE_SELECTABLE_TEXT
;
3713 case ui::AX_ROLE_TEXT_FIELD
:
3714 ia_role_
= ROLE_SYSTEM_TEXT
;
3715 ia2_state_
|= IA2_STATE_SINGLE_LINE
;
3716 ia2_state_
|= IA2_STATE_EDITABLE
;
3717 ia2_state_
|= IA2_STATE_SELECTABLE_TEXT
;
3719 case ui::AX_ROLE_TIMER
:
3720 ia_role_
= ROLE_SYSTEM_CLOCK
;
3721 ia_state_
|= STATE_SYSTEM_READONLY
;
3723 case ui::AX_ROLE_TOOLBAR
:
3724 ia_role_
= ROLE_SYSTEM_TOOLBAR
;
3725 ia_state_
|= STATE_SYSTEM_READONLY
;
3727 case ui::AX_ROLE_TOOLTIP
:
3728 ia_role_
= ROLE_SYSTEM_TOOLTIP
;
3729 ia_state_
|= STATE_SYSTEM_READONLY
;
3731 case ui::AX_ROLE_TREE
:
3732 ia_role_
= ROLE_SYSTEM_OUTLINE
;
3733 ia_state_
|= STATE_SYSTEM_READONLY
;
3735 case ui::AX_ROLE_TREE_GRID
:
3736 ia_role_
= ROLE_SYSTEM_OUTLINE
;
3737 ia_state_
|= STATE_SYSTEM_READONLY
;
3739 case ui::AX_ROLE_TREE_ITEM
:
3740 ia_role_
= ROLE_SYSTEM_OUTLINEITEM
;
3741 ia_state_
|= STATE_SYSTEM_READONLY
;
3743 case ui::AX_ROLE_WINDOW
:
3744 ia_role_
= ROLE_SYSTEM_WINDOW
;
3747 // TODO(dmazzoni): figure out the proper MSAA role for all of these.
3748 case ui::AX_ROLE_BROWSER
:
3749 case ui::AX_ROLE_DIRECTORY
:
3750 case ui::AX_ROLE_DRAWER
:
3751 case ui::AX_ROLE_HELP_TAG
:
3752 case ui::AX_ROLE_IGNORED
:
3753 case ui::AX_ROLE_INCREMENTOR
:
3754 case ui::AX_ROLE_LOG
:
3755 case ui::AX_ROLE_MARQUEE
:
3756 case ui::AX_ROLE_MATTE
:
3757 case ui::AX_ROLE_PRESENTATIONAL
:
3758 case ui::AX_ROLE_RULER_MARKER
:
3759 case ui::AX_ROLE_SHEET
:
3760 case ui::AX_ROLE_SLIDER_THUMB
:
3761 case ui::AX_ROLE_SYSTEM_WIDE
:
3762 case ui::AX_ROLE_VALUE_INDICATOR
:
3764 ia_role_
= ROLE_SYSTEM_CLIENT
;
3768 // Compute the final value of READONLY for MSAA.
3770 // We always set the READONLY state for elements that have the
3771 // aria-readonly attribute and for a few roles (in the switch above).
3772 // We clear the READONLY state on focusable controls and on a document.
3773 // Everything else, the majority of objects, do not have this state set.
3774 if (HasState(ui::AX_STATE_FOCUSABLE
) &&
3775 ia_role_
!= ROLE_SYSTEM_DOCUMENT
) {
3776 ia_state_
&= ~(STATE_SYSTEM_READONLY
);
3778 if (!HasState(ui::AX_STATE_READ_ONLY
))
3779 ia_state_
&= ~(STATE_SYSTEM_READONLY
);
3780 if (GetBoolAttribute(ui::AX_ATTR_ARIA_READONLY
))
3781 ia_state_
|= STATE_SYSTEM_READONLY
;
3783 // The role should always be set.
3784 DCHECK(!role_name_
.empty() || ia_role_
);
3786 // If we didn't explicitly set the IAccessible2 role, make it the same
3787 // as the MSAA role.
3789 ia2_role_
= ia_role_
;
3792 } // namespace content