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"
24 #include "ui/base/win/atl_module.h"
28 // These nonstandard GUIDs are taken directly from the Mozilla sources
29 // (accessible/src/msaa/nsAccessNodeWrap.cpp); some documentation is here:
30 // http://developer.mozilla.org/en/Accessibility/AT-APIs/ImplementationFeatures/MSAA
31 const GUID GUID_ISimpleDOM
= {
32 0x0c539790, 0x12e4, 0x11cf,
33 0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8};
34 const GUID GUID_IAccessibleContentDocument
= {
35 0xa5d8e1f3, 0x3571, 0x4d8f,
36 0x95, 0x21, 0x07, 0xed, 0x28, 0xfb, 0x07, 0x2e};
38 const base::char16
BrowserAccessibilityWin::kEmbeddedCharacter
[] = L
"\xfffc";
41 LONG
BrowserAccessibilityWin::next_unique_id_win_
=
42 base::win::kFirstBrowserAccessibilityManagerAccessibilityId
;
45 // BrowserAccessibilityRelation
47 // A simple implementation of IAccessibleRelation, used to represent
48 // a relationship between two accessible nodes in the tree.
51 class BrowserAccessibilityRelation
52 : public CComObjectRootEx
<CComMultiThreadModel
>,
53 public IAccessibleRelation
{
54 BEGIN_COM_MAP(BrowserAccessibilityRelation
)
55 COM_INTERFACE_ENTRY(IAccessibleRelation
)
58 CONTENT_EXPORT
BrowserAccessibilityRelation() {}
59 CONTENT_EXPORT
virtual ~BrowserAccessibilityRelation() {}
61 CONTENT_EXPORT
void Initialize(BrowserAccessibilityWin
* owner
,
62 const base::string16
& type
);
63 CONTENT_EXPORT
void AddTarget(int target_id
);
65 // IAccessibleRelation methods.
66 CONTENT_EXPORT STDMETHODIMP
get_relationType(BSTR
* relation_type
);
67 CONTENT_EXPORT STDMETHODIMP
get_nTargets(long* n_targets
);
68 CONTENT_EXPORT STDMETHODIMP
get_target(long target_index
, IUnknown
** target
);
69 CONTENT_EXPORT STDMETHODIMP
get_targets(long max_targets
,
73 // IAccessibleRelation methods not implemented.
74 CONTENT_EXPORT STDMETHODIMP
get_localizedRelationType(BSTR
* relation_type
) {
80 base::win::ScopedComPtr
<BrowserAccessibilityWin
> owner_
;
81 std::vector
<int> target_ids_
;
84 void BrowserAccessibilityRelation::Initialize(BrowserAccessibilityWin
* owner
,
85 const base::string16
& type
) {
90 void BrowserAccessibilityRelation::AddTarget(int target_id
) {
91 target_ids_
.push_back(target_id
);
94 STDMETHODIMP
BrowserAccessibilityRelation::get_relationType(
95 BSTR
* relation_type
) {
99 if (!owner_
->instance_active())
102 *relation_type
= SysAllocString(type_
.c_str());
103 DCHECK(*relation_type
);
107 STDMETHODIMP
BrowserAccessibilityRelation::get_nTargets(long* n_targets
) {
111 if (!owner_
->instance_active())
114 *n_targets
= static_cast<long>(target_ids_
.size());
116 BrowserAccessibilityManager
* manager
= owner_
->manager();
117 for (long i
= *n_targets
- 1; i
>= 0; --i
) {
118 BrowserAccessibility
* result
= manager
->GetFromID(target_ids_
[i
]);
119 if (!result
|| !result
->instance_active()) {
127 STDMETHODIMP
BrowserAccessibilityRelation::get_target(long target_index
,
132 if (!owner_
->instance_active())
135 if (target_index
< 0 ||
136 target_index
>= static_cast<long>(target_ids_
.size())) {
140 BrowserAccessibilityManager
* manager
= owner_
->manager();
141 BrowserAccessibility
* result
=
142 manager
->GetFromID(target_ids_
[target_index
]);
143 if (!result
|| !result
->instance_active())
146 *target
= static_cast<IAccessible
*>(
147 result
->ToBrowserAccessibilityWin()->NewReference());
151 STDMETHODIMP
BrowserAccessibilityRelation::get_targets(long max_targets
,
154 if (!targets
|| !n_targets
)
157 if (!owner_
->instance_active())
160 long count
= static_cast<long>(target_ids_
.size());
161 if (count
> max_targets
)
168 for (long i
= 0; i
< count
; ++i
) {
169 HRESULT result
= get_target(i
, &targets
[i
]);
178 // BrowserAccessibilityWin
182 BrowserAccessibility
* BrowserAccessibility::Create() {
183 ui::win::CreateATLModuleIfNeeded();
184 CComObject
<BrowserAccessibilityWin
>* instance
;
185 HRESULT hr
= CComObject
<BrowserAccessibilityWin
>::CreateInstance(&instance
);
186 DCHECK(SUCCEEDED(hr
));
187 return instance
->NewReference();
190 BrowserAccessibilityWin
* BrowserAccessibility::ToBrowserAccessibilityWin() {
191 return static_cast<BrowserAccessibilityWin
*>(this);
194 BrowserAccessibilityWin::BrowserAccessibilityWin()
201 previous_scroll_x_(0),
202 previous_scroll_y_(0) {
203 // Start unique IDs at -1 and decrement each time, because get_accChild
204 // uses positive IDs to enumerate children, so we use negative IDs to
205 // clearly distinguish between indices and unique IDs.
206 unique_id_win_
= next_unique_id_win_
;
207 if (next_unique_id_win_
==
208 base::win::kLastBrowserAccessibilityManagerAccessibilityId
) {
209 next_unique_id_win_
=
210 base::win::kFirstBrowserAccessibilityManagerAccessibilityId
;
212 next_unique_id_win_
--;
215 BrowserAccessibilityWin::~BrowserAccessibilityWin() {
216 for (size_t i
= 0; i
< relations_
.size(); ++i
)
217 relations_
[i
]->Release();
221 // IAccessible methods.
224 // * Always test for instance_active() first and return E_FAIL if it's false.
225 // * Always check for invalid arguments first, even if they're unused.
226 // * Return S_FALSE if the only output is a string argument and it's empty.
229 HRESULT
BrowserAccessibilityWin::accDoDefaultAction(VARIANT var_id
) {
230 if (!instance_active())
233 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
237 manager()->DoDefaultAction(*target
);
241 STDMETHODIMP
BrowserAccessibilityWin::accHitTest(LONG x_left
,
244 if (!instance_active())
250 gfx::Point
point(x_left
, y_top
);
251 if (!GetGlobalBoundsRect().Contains(point
)) {
252 // Return S_FALSE and VT_EMPTY when the outside the object's boundaries.
253 child
->vt
= VT_EMPTY
;
257 BrowserAccessibility
* result
= BrowserAccessibilityForPoint(point
);
258 if (result
== this) {
259 // Point is within this object.
261 child
->lVal
= CHILDID_SELF
;
263 child
->vt
= VT_DISPATCH
;
264 child
->pdispVal
= result
->ToBrowserAccessibilityWin()->NewReference();
269 STDMETHODIMP
BrowserAccessibilityWin::accLocation(LONG
* x_left
,
274 if (!instance_active())
277 if (!x_left
|| !y_top
|| !width
|| !height
)
280 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
284 gfx::Rect bounds
= target
->GetGlobalBoundsRect();
285 *x_left
= bounds
.x();
287 *width
= bounds
.width();
288 *height
= bounds
.height();
293 STDMETHODIMP
BrowserAccessibilityWin::accNavigate(LONG nav_dir
,
296 BrowserAccessibilityWin
* target
= GetTargetFromChildID(start
);
300 if ((nav_dir
== NAVDIR_LASTCHILD
|| nav_dir
== NAVDIR_FIRSTCHILD
) &&
301 start
.lVal
!= CHILDID_SELF
) {
302 // MSAA states that navigating to first/last child can only be from self.
306 uint32 child_count
= target
->PlatformChildCount();
308 BrowserAccessibility
* result
= NULL
;
314 // These directions are not implemented, matching Mozilla and IE.
316 case NAVDIR_FIRSTCHILD
:
318 result
= target
->PlatformGetChild(0);
320 case NAVDIR_LASTCHILD
:
322 result
= target
->PlatformGetChild(child_count
- 1);
325 result
= target
->GetNextSibling();
327 case NAVDIR_PREVIOUS
:
328 result
= target
->GetPreviousSibling();
337 end
->vt
= VT_DISPATCH
;
338 end
->pdispVal
= result
->ToBrowserAccessibilityWin()->NewReference();
342 STDMETHODIMP
BrowserAccessibilityWin::get_accChild(VARIANT var_child
,
343 IDispatch
** disp_child
) {
344 if (!instance_active())
352 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_child
);
356 (*disp_child
) = target
->NewReference();
360 STDMETHODIMP
BrowserAccessibilityWin::get_accChildCount(LONG
* child_count
) {
361 if (!instance_active())
367 *child_count
= PlatformChildCount();
372 STDMETHODIMP
BrowserAccessibilityWin::get_accDefaultAction(VARIANT var_id
,
374 if (!instance_active())
380 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
384 return target
->GetStringAttributeAsBstr(
385 ui::AX_ATTR_SHORTCUT
, def_action
);
388 STDMETHODIMP
BrowserAccessibilityWin::get_accDescription(VARIANT var_id
,
390 if (!instance_active())
396 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
400 return target
->GetStringAttributeAsBstr(
401 ui::AX_ATTR_DESCRIPTION
, desc
);
404 STDMETHODIMP
BrowserAccessibilityWin::get_accFocus(VARIANT
* focus_child
) {
405 if (!instance_active())
411 BrowserAccessibilityWin
* focus
= static_cast<BrowserAccessibilityWin
*>(
412 manager()->GetFocus(this));
414 focus_child
->vt
= VT_I4
;
415 focus_child
->lVal
= CHILDID_SELF
;
416 } else if (focus
== NULL
) {
417 focus_child
->vt
= VT_EMPTY
;
419 focus_child
->vt
= VT_DISPATCH
;
420 focus_child
->pdispVal
= focus
->NewReference();
426 STDMETHODIMP
BrowserAccessibilityWin::get_accHelp(VARIANT var_id
, BSTR
* help
) {
427 if (!instance_active())
433 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
437 return target
->GetStringAttributeAsBstr(
438 ui::AX_ATTR_HELP
, help
);
441 STDMETHODIMP
BrowserAccessibilityWin::get_accKeyboardShortcut(VARIANT var_id
,
443 if (!instance_active())
449 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
453 return target
->GetStringAttributeAsBstr(
454 ui::AX_ATTR_SHORTCUT
, acc_key
);
457 STDMETHODIMP
BrowserAccessibilityWin::get_accName(VARIANT var_id
, BSTR
* name
) {
458 if (!instance_active())
464 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
468 std::string name_str
= target
->name();
470 // If the name is empty, see if it's labeled by another element.
471 if (name_str
.empty()) {
473 if (target
->GetIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT
,
475 BrowserAccessibility
* title_elem
=
476 manager()->GetFromID(title_elem_id
);
478 name_str
= title_elem
->GetTextRecursive();
482 if (name_str
.empty())
485 *name
= SysAllocString(base::UTF8ToUTF16(name_str
).c_str());
491 STDMETHODIMP
BrowserAccessibilityWin::get_accParent(IDispatch
** disp_parent
) {
492 if (!instance_active())
498 IAccessible
* parent_obj
= GetParent()->ToBrowserAccessibilityWin();
499 if (parent_obj
== NULL
) {
500 // This happens if we're the root of the tree;
501 // return the IAccessible for the window.
503 manager()->ToBrowserAccessibilityManagerWin()->GetParentIAccessible();
504 // |parent| can only be NULL if the manager was created before the parent
505 // IAccessible was known and it wasn't subsequently set before a client
506 // requested it. This has been fixed. |parent| may also be NULL during
507 // destruction. Possible cases where this could occur include tabs being
508 // dragged to a new window, etc.
510 DVLOG(1) << "In Function: "
512 << ". Parent IAccessible interface is NULL. Returning failure";
516 parent_obj
->AddRef();
517 *disp_parent
= parent_obj
;
521 STDMETHODIMP
BrowserAccessibilityWin::get_accRole(VARIANT var_id
,
523 if (!instance_active())
529 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
533 if (!target
->role_name_
.empty()) {
535 role
->bstrVal
= SysAllocString(target
->role_name_
.c_str());
538 role
->lVal
= target
->ia_role_
;
543 STDMETHODIMP
BrowserAccessibilityWin::get_accState(VARIANT var_id
,
545 if (!instance_active())
551 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
556 state
->lVal
= target
->ia_state_
;
557 if (manager()->GetFocus(NULL
) == this)
558 state
->lVal
|= STATE_SYSTEM_FOCUSED
;
563 STDMETHODIMP
BrowserAccessibilityWin::get_accValue(VARIANT var_id
,
565 if (!instance_active())
571 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
575 if (target
->ia_role() == ROLE_SYSTEM_PROGRESSBAR
||
576 target
->ia_role() == ROLE_SYSTEM_SCROLLBAR
||
577 target
->ia_role() == ROLE_SYSTEM_SLIDER
) {
578 base::string16 value_text
= target
->GetValueText();
579 *value
= SysAllocString(value_text
.c_str());
584 // Expose color well value.
585 if (target
->ia2_role() == IA2_ROLE_COLOR_CHOOSER
) {
586 int r
= target
->GetIntAttribute(
587 ui::AX_ATTR_COLOR_VALUE_RED
);
588 int g
= target
->GetIntAttribute(
589 ui::AX_ATTR_COLOR_VALUE_GREEN
);
590 int b
= target
->GetIntAttribute(
591 ui::AX_ATTR_COLOR_VALUE_BLUE
);
592 base::string16 value_text
;
593 value_text
= base::IntToString16((r
* 100) / 255) + L
"% red " +
594 base::IntToString16((g
* 100) / 255) + L
"% green " +
595 base::IntToString16((b
* 100) / 255) + L
"% blue";
596 *value
= SysAllocString(value_text
.c_str());
601 *value
= SysAllocString(base::UTF8ToUTF16(target
->value()).c_str());
606 STDMETHODIMP
BrowserAccessibilityWin::get_accHelpTopic(BSTR
* help_file
,
612 STDMETHODIMP
BrowserAccessibilityWin::get_accSelection(VARIANT
* selected
) {
613 if (!instance_active())
616 if (GetRole() != ui::AX_ROLE_LIST_BOX
)
619 unsigned long selected_count
= 0;
620 for (size_t i
= 0; i
< InternalChildCount(); ++i
) {
621 if (InternalGetChild(i
)->HasState(ui::AX_STATE_SELECTED
))
625 if (selected_count
== 0) {
626 selected
->vt
= VT_EMPTY
;
630 if (selected_count
== 1) {
631 for (size_t i
= 0; i
< InternalChildCount(); ++i
) {
632 if (InternalGetChild(i
)->HasState(ui::AX_STATE_SELECTED
)) {
633 selected
->vt
= VT_DISPATCH
;
635 InternalGetChild(i
)->ToBrowserAccessibilityWin()->NewReference();
641 // Multiple items are selected.
642 base::win::EnumVariant
* enum_variant
=
643 new base::win::EnumVariant(selected_count
);
644 enum_variant
->AddRef();
645 unsigned long index
= 0;
646 for (size_t i
= 0; i
< InternalChildCount(); ++i
) {
647 if (InternalGetChild(i
)->HasState(ui::AX_STATE_SELECTED
)) {
648 enum_variant
->ItemAt(index
)->vt
= VT_DISPATCH
;
649 enum_variant
->ItemAt(index
)->pdispVal
=
650 InternalGetChild(i
)->ToBrowserAccessibilityWin()->NewReference();
654 selected
->vt
= VT_UNKNOWN
;
655 selected
->punkVal
= static_cast<IUnknown
*>(
656 static_cast<base::win::IUnknownImpl
*>(enum_variant
));
660 STDMETHODIMP
BrowserAccessibilityWin::accSelect(
661 LONG flags_sel
, VARIANT var_id
) {
662 if (!instance_active())
665 if (flags_sel
& SELFLAG_TAKEFOCUS
) {
666 manager()->SetFocus(this, true);
674 // IAccessible2 methods.
677 STDMETHODIMP
BrowserAccessibilityWin::role(LONG
* role
) {
678 if (!instance_active())
689 STDMETHODIMP
BrowserAccessibilityWin::get_attributes(BSTR
* attributes
) {
690 if (!instance_active())
696 // The iaccessible2 attributes are a set of key-value pairs
697 // separated by semicolons, with a colon between the key and the value.
699 const std::vector
<base::string16
>& attributes_list
= ia2_attributes();
700 for (unsigned int i
= 0; i
< attributes_list
.size(); ++i
) {
701 str
+= attributes_list
[i
] + L
';';
707 *attributes
= SysAllocString(str
.c_str());
712 STDMETHODIMP
BrowserAccessibilityWin::get_states(AccessibleStates
* states
) {
713 if (!instance_active())
719 *states
= ia2_state_
;
724 STDMETHODIMP
BrowserAccessibilityWin::get_uniqueID(LONG
* unique_id
) {
725 if (!instance_active())
731 *unique_id
= unique_id_win_
;
735 STDMETHODIMP
BrowserAccessibilityWin::get_windowHandle(HWND
* window_handle
) {
736 if (!instance_active())
743 manager()->ToBrowserAccessibilityManagerWin()->GetParentHWND();
750 STDMETHODIMP
BrowserAccessibilityWin::get_indexInParent(LONG
* index_in_parent
) {
751 if (!instance_active())
754 if (!index_in_parent
)
757 *index_in_parent
= this->GetIndexInParent();
761 STDMETHODIMP
BrowserAccessibilityWin::get_nRelations(LONG
* n_relations
) {
762 if (!instance_active())
768 *n_relations
= relations_
.size();
772 STDMETHODIMP
BrowserAccessibilityWin::get_relation(
774 IAccessibleRelation
** relation
) {
775 if (!instance_active())
778 if (relation_index
< 0 ||
779 relation_index
>= static_cast<long>(relations_
.size())) {
786 relations_
[relation_index
]->AddRef();
787 *relation
= relations_
[relation_index
];
791 STDMETHODIMP
BrowserAccessibilityWin::get_relations(
793 IAccessibleRelation
** relations
,
795 if (!instance_active())
798 if (!relations
|| !n_relations
)
801 long count
= static_cast<long>(relations_
.size());
802 *n_relations
= count
;
806 for (long i
= 0; i
< count
; ++i
) {
807 relations_
[i
]->AddRef();
808 relations
[i
] = relations_
[i
];
814 STDMETHODIMP
BrowserAccessibilityWin::scrollTo(enum IA2ScrollType scroll_type
) {
815 if (!instance_active())
818 gfx::Rect r
= GetLocation();
819 switch(scroll_type
) {
820 case IA2_SCROLL_TYPE_TOP_LEFT
:
821 manager()->ScrollToMakeVisible(*this, gfx::Rect(r
.x(), r
.y(), 0, 0));
823 case IA2_SCROLL_TYPE_BOTTOM_RIGHT
:
824 manager()->ScrollToMakeVisible(
825 *this, gfx::Rect(r
.right(), r
.bottom(), 0, 0));
827 case IA2_SCROLL_TYPE_TOP_EDGE
:
828 manager()->ScrollToMakeVisible(
829 *this, gfx::Rect(r
.x(), r
.y(), r
.width(), 0));
831 case IA2_SCROLL_TYPE_BOTTOM_EDGE
:
832 manager()->ScrollToMakeVisible(
833 *this, gfx::Rect(r
.x(), r
.bottom(), r
.width(), 0));
835 case IA2_SCROLL_TYPE_LEFT_EDGE
:
836 manager()->ScrollToMakeVisible(
837 *this, gfx::Rect(r
.x(), r
.y(), 0, r
.height()));
839 case IA2_SCROLL_TYPE_RIGHT_EDGE
:
840 manager()->ScrollToMakeVisible(
841 *this, gfx::Rect(r
.right(), r
.y(), 0, r
.height()));
843 case IA2_SCROLL_TYPE_ANYWHERE
:
845 manager()->ScrollToMakeVisible(*this, r
);
849 manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
854 STDMETHODIMP
BrowserAccessibilityWin::scrollToPoint(
855 enum IA2CoordinateType coordinate_type
,
858 if (!instance_active())
861 gfx::Point
scroll_to(x
, y
);
863 if (coordinate_type
== IA2_COORDTYPE_SCREEN_RELATIVE
) {
864 scroll_to
-= manager()->GetViewBounds().OffsetFromOrigin();
865 } else if (coordinate_type
== IA2_COORDTYPE_PARENT_RELATIVE
) {
867 scroll_to
+= GetParent()->GetLocation().OffsetFromOrigin();
872 manager()->ScrollToPoint(*this, scroll_to
);
873 manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
878 STDMETHODIMP
BrowserAccessibilityWin::get_groupPosition(
880 LONG
* similar_items_in_group
,
881 LONG
* position_in_group
) {
882 if (!instance_active())
885 if (!group_level
|| !similar_items_in_group
|| !position_in_group
)
888 if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION
&&
890 GetParent()->GetRole() == ui::AX_ROLE_LIST_BOX
) {
892 *similar_items_in_group
= GetParent()->PlatformChildCount();
893 *position_in_group
= GetIndexInParent() + 1;
901 // IAccessibleApplication methods.
904 STDMETHODIMP
BrowserAccessibilityWin::get_appName(BSTR
* app_name
) {
905 // No need to check |instance_active()| because this interface is
906 // global, and doesn't depend on any local state.
911 // GetProduct() returns a string like "Chrome/aa.bb.cc.dd", split out
912 // the part before the "/".
913 std::vector
<std::string
> product_components
;
914 base::SplitString(GetContentClient()->GetProduct(), '/', &product_components
);
915 DCHECK_EQ(2U, product_components
.size());
916 if (product_components
.size() != 2)
918 *app_name
= SysAllocString(base::UTF8ToUTF16(product_components
[0]).c_str());
920 return *app_name
? S_OK
: E_FAIL
;
923 STDMETHODIMP
BrowserAccessibilityWin::get_appVersion(BSTR
* app_version
) {
924 // No need to check |instance_active()| because this interface is
925 // global, and doesn't depend on any local state.
930 // GetProduct() returns a string like "Chrome/aa.bb.cc.dd", split out
931 // the part after the "/".
932 std::vector
<std::string
> product_components
;
933 base::SplitString(GetContentClient()->GetProduct(), '/', &product_components
);
934 DCHECK_EQ(2U, product_components
.size());
935 if (product_components
.size() != 2)
938 SysAllocString(base::UTF8ToUTF16(product_components
[1]).c_str());
939 DCHECK(*app_version
);
940 return *app_version
? S_OK
: E_FAIL
;
943 STDMETHODIMP
BrowserAccessibilityWin::get_toolkitName(BSTR
* toolkit_name
) {
944 // No need to check |instance_active()| because this interface is
945 // global, and doesn't depend on any local state.
950 // This is hard-coded; all products based on the Chromium engine
951 // will have the same toolkit name, so that assistive technology can
952 // detect any Chrome-based product.
953 *toolkit_name
= SysAllocString(L
"Chrome");
954 DCHECK(*toolkit_name
);
955 return *toolkit_name
? S_OK
: E_FAIL
;
958 STDMETHODIMP
BrowserAccessibilityWin::get_toolkitVersion(
959 BSTR
* toolkit_version
) {
960 // No need to check |instance_active()| because this interface is
961 // global, and doesn't depend on any local state.
963 if (!toolkit_version
)
966 std::string user_agent
= GetContentClient()->GetUserAgent();
967 *toolkit_version
= SysAllocString(base::UTF8ToUTF16(user_agent
).c_str());
968 DCHECK(*toolkit_version
);
969 return *toolkit_version
? S_OK
: E_FAIL
;
973 // IAccessibleImage methods.
976 STDMETHODIMP
BrowserAccessibilityWin::get_description(BSTR
* desc
) {
977 if (!instance_active())
983 return GetStringAttributeAsBstr(
984 ui::AX_ATTR_DESCRIPTION
, desc
);
987 STDMETHODIMP
BrowserAccessibilityWin::get_imagePosition(
988 enum IA2CoordinateType coordinate_type
,
991 if (!instance_active())
997 if (coordinate_type
== IA2_COORDTYPE_SCREEN_RELATIVE
) {
999 manager()->ToBrowserAccessibilityManagerWin()->GetParentHWND();
1002 POINT top_left
= {0, 0};
1003 ::ClientToScreen(parent_hwnd
, &top_left
);
1004 *x
= GetLocation().x() + top_left
.x
;
1005 *y
= GetLocation().y() + top_left
.y
;
1006 } else if (coordinate_type
== IA2_COORDTYPE_PARENT_RELATIVE
) {
1007 *x
= GetLocation().x();
1008 *y
= GetLocation().y();
1010 *x
-= GetParent()->GetLocation().x();
1011 *y
-= GetParent()->GetLocation().y();
1014 return E_INVALIDARG
;
1020 STDMETHODIMP
BrowserAccessibilityWin::get_imageSize(LONG
* height
, LONG
* width
) {
1021 if (!instance_active())
1024 if (!height
|| !width
)
1025 return E_INVALIDARG
;
1027 *height
= GetLocation().height();
1028 *width
= GetLocation().width();
1033 // IAccessibleTable methods.
1036 STDMETHODIMP
BrowserAccessibilityWin::get_accessibleAt(
1039 IUnknown
** accessible
) {
1040 if (!instance_active())
1044 return E_INVALIDARG
;
1048 if (!GetIntAttribute(
1049 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1051 ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1057 if (row
< 0 || row
>= rows
|| column
< 0 || column
>= columns
)
1058 return E_INVALIDARG
;
1060 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1061 ui::AX_ATTR_CELL_IDS
);
1062 DCHECK_EQ(columns
* rows
, static_cast<int>(cell_ids
.size()));
1064 int cell_id
= cell_ids
[row
* columns
+ column
];
1065 BrowserAccessibilityWin
* cell
= GetFromID(cell_id
);
1067 *accessible
= static_cast<IAccessible
*>(cell
->NewReference());
1072 return E_INVALIDARG
;
1075 STDMETHODIMP
BrowserAccessibilityWin::get_caption(IUnknown
** accessible
) {
1076 if (!instance_active())
1080 return E_INVALIDARG
;
1082 // TODO(dmazzoni): implement
1086 STDMETHODIMP
BrowserAccessibilityWin::get_childIndex(long row
,
1089 if (!instance_active())
1093 return E_INVALIDARG
;
1097 if (!GetIntAttribute(
1098 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1100 ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1106 if (row
< 0 || row
>= rows
|| column
< 0 || column
>= columns
)
1107 return E_INVALIDARG
;
1109 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1110 ui::AX_ATTR_CELL_IDS
);
1111 const std::vector
<int32
>& unique_cell_ids
= GetIntListAttribute(
1112 ui::AX_ATTR_UNIQUE_CELL_IDS
);
1113 DCHECK_EQ(columns
* rows
, static_cast<int>(cell_ids
.size()));
1114 int cell_id
= cell_ids
[row
* columns
+ column
];
1115 for (size_t i
= 0; i
< unique_cell_ids
.size(); ++i
) {
1116 if (unique_cell_ids
[i
] == cell_id
) {
1117 *cell_index
= (long)i
;
1125 STDMETHODIMP
BrowserAccessibilityWin::get_columnDescription(long column
,
1126 BSTR
* description
) {
1127 if (!instance_active())
1131 return E_INVALIDARG
;
1135 if (!GetIntAttribute(
1136 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1137 !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1143 if (column
< 0 || column
>= columns
)
1144 return E_INVALIDARG
;
1146 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1147 ui::AX_ATTR_CELL_IDS
);
1148 for (int i
= 0; i
< rows
; ++i
) {
1149 int cell_id
= cell_ids
[i
* columns
+ column
];
1150 BrowserAccessibilityWin
* cell
= static_cast<BrowserAccessibilityWin
*>(
1151 manager()->GetFromID(cell_id
));
1152 if (cell
&& cell
->GetRole() == ui::AX_ROLE_COLUMN_HEADER
) {
1153 base::string16 cell_name
= cell
->GetString16Attribute(
1155 if (cell_name
.size() > 0) {
1156 *description
= SysAllocString(cell_name
.c_str());
1160 return cell
->GetStringAttributeAsBstr(
1161 ui::AX_ATTR_DESCRIPTION
, description
);
1168 STDMETHODIMP
BrowserAccessibilityWin::get_columnExtentAt(
1171 long* n_columns_spanned
) {
1172 if (!instance_active())
1175 if (!n_columns_spanned
)
1176 return E_INVALIDARG
;
1180 if (!GetIntAttribute(
1181 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1182 !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1188 if (row
< 0 || row
>= rows
|| column
< 0 || column
>= columns
)
1189 return E_INVALIDARG
;
1191 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1192 ui::AX_ATTR_CELL_IDS
);
1193 int cell_id
= cell_ids
[row
* columns
+ column
];
1194 BrowserAccessibilityWin
* cell
= static_cast<BrowserAccessibilityWin
*>(
1195 manager()->GetFromID(cell_id
));
1198 cell
->GetIntAttribute(
1199 ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN
, &colspan
) &&
1201 *n_columns_spanned
= colspan
;
1208 STDMETHODIMP
BrowserAccessibilityWin::get_columnHeader(
1209 IAccessibleTable
** accessible_table
,
1210 long* starting_row_index
) {
1211 // TODO(dmazzoni): implement
1215 STDMETHODIMP
BrowserAccessibilityWin::get_columnIndex(long cell_index
,
1216 long* column_index
) {
1217 if (!instance_active())
1221 return E_INVALIDARG
;
1223 const std::vector
<int32
>& unique_cell_ids
= GetIntListAttribute(
1224 ui::AX_ATTR_UNIQUE_CELL_IDS
);
1225 int cell_id_count
= static_cast<int>(unique_cell_ids
.size());
1227 return E_INVALIDARG
;
1228 if (cell_index
>= cell_id_count
)
1231 int cell_id
= unique_cell_ids
[cell_index
];
1232 BrowserAccessibilityWin
* cell
=
1233 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1236 cell
->GetIntAttribute(
1237 ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &col_index
)) {
1238 *column_index
= col_index
;
1245 STDMETHODIMP
BrowserAccessibilityWin::get_nColumns(long* column_count
) {
1246 if (!instance_active())
1250 return E_INVALIDARG
;
1253 if (GetIntAttribute(
1254 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
)) {
1255 *column_count
= columns
;
1262 STDMETHODIMP
BrowserAccessibilityWin::get_nRows(long* row_count
) {
1263 if (!instance_active())
1267 return E_INVALIDARG
;
1270 if (GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
)) {
1278 STDMETHODIMP
BrowserAccessibilityWin::get_nSelectedChildren(long* cell_count
) {
1279 if (!instance_active())
1283 return E_INVALIDARG
;
1285 // TODO(dmazzoni): add support for selected cells/rows/columns in tables.
1290 STDMETHODIMP
BrowserAccessibilityWin::get_nSelectedColumns(long* column_count
) {
1291 if (!instance_active())
1295 return E_INVALIDARG
;
1301 STDMETHODIMP
BrowserAccessibilityWin::get_nSelectedRows(long* row_count
) {
1302 if (!instance_active())
1306 return E_INVALIDARG
;
1312 STDMETHODIMP
BrowserAccessibilityWin::get_rowDescription(long row
,
1313 BSTR
* description
) {
1314 if (!instance_active())
1318 return E_INVALIDARG
;
1322 if (!GetIntAttribute(
1323 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1324 !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1330 if (row
< 0 || row
>= rows
)
1331 return E_INVALIDARG
;
1333 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1334 ui::AX_ATTR_CELL_IDS
);
1335 for (int i
= 0; i
< columns
; ++i
) {
1336 int cell_id
= cell_ids
[row
* columns
+ i
];
1337 BrowserAccessibilityWin
* cell
=
1338 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1339 if (cell
&& cell
->GetRole() == ui::AX_ROLE_ROW_HEADER
) {
1340 base::string16 cell_name
= cell
->GetString16Attribute(
1342 if (cell_name
.size() > 0) {
1343 *description
= SysAllocString(cell_name
.c_str());
1347 return cell
->GetStringAttributeAsBstr(
1348 ui::AX_ATTR_DESCRIPTION
, description
);
1355 STDMETHODIMP
BrowserAccessibilityWin::get_rowExtentAt(long row
,
1357 long* n_rows_spanned
) {
1358 if (!instance_active())
1361 if (!n_rows_spanned
)
1362 return E_INVALIDARG
;
1366 if (!GetIntAttribute(
1367 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1368 !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1374 if (row
< 0 || row
>= rows
|| column
< 0 || column
>= columns
)
1375 return E_INVALIDARG
;
1377 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1378 ui::AX_ATTR_CELL_IDS
);
1379 int cell_id
= cell_ids
[row
* columns
+ column
];
1380 BrowserAccessibilityWin
* cell
=
1381 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1384 cell
->GetIntAttribute(
1385 ui::AX_ATTR_TABLE_CELL_ROW_SPAN
, &rowspan
) &&
1387 *n_rows_spanned
= rowspan
;
1394 STDMETHODIMP
BrowserAccessibilityWin::get_rowHeader(
1395 IAccessibleTable
** accessible_table
,
1396 long* starting_column_index
) {
1397 // TODO(dmazzoni): implement
1401 STDMETHODIMP
BrowserAccessibilityWin::get_rowIndex(long cell_index
,
1403 if (!instance_active())
1407 return E_INVALIDARG
;
1409 const std::vector
<int32
>& unique_cell_ids
= GetIntListAttribute(
1410 ui::AX_ATTR_UNIQUE_CELL_IDS
);
1411 int cell_id_count
= static_cast<int>(unique_cell_ids
.size());
1413 return E_INVALIDARG
;
1414 if (cell_index
>= cell_id_count
)
1417 int cell_id
= unique_cell_ids
[cell_index
];
1418 BrowserAccessibilityWin
* cell
=
1419 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1422 cell
->GetIntAttribute(
1423 ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &cell_row_index
)) {
1424 *row_index
= cell_row_index
;
1431 STDMETHODIMP
BrowserAccessibilityWin::get_selectedChildren(long max_children
,
1434 if (!instance_active())
1437 if (!children
|| !n_children
)
1438 return E_INVALIDARG
;
1440 // TODO(dmazzoni): Implement this.
1445 STDMETHODIMP
BrowserAccessibilityWin::get_selectedColumns(long max_columns
,
1448 if (!instance_active())
1451 if (!columns
|| !n_columns
)
1452 return E_INVALIDARG
;
1454 // TODO(dmazzoni): Implement this.
1459 STDMETHODIMP
BrowserAccessibilityWin::get_selectedRows(long max_rows
,
1462 if (!instance_active())
1465 if (!rows
|| !n_rows
)
1466 return E_INVALIDARG
;
1468 // TODO(dmazzoni): Implement this.
1473 STDMETHODIMP
BrowserAccessibilityWin::get_summary(IUnknown
** accessible
) {
1474 if (!instance_active())
1478 return E_INVALIDARG
;
1480 // TODO(dmazzoni): implement
1484 STDMETHODIMP
BrowserAccessibilityWin::get_isColumnSelected(
1486 boolean
* is_selected
) {
1487 if (!instance_active())
1491 return E_INVALIDARG
;
1493 // TODO(dmazzoni): Implement this.
1494 *is_selected
= false;
1498 STDMETHODIMP
BrowserAccessibilityWin::get_isRowSelected(long row
,
1499 boolean
* is_selected
) {
1500 if (!instance_active())
1504 return E_INVALIDARG
;
1506 // TODO(dmazzoni): Implement this.
1507 *is_selected
= false;
1511 STDMETHODIMP
BrowserAccessibilityWin::get_isSelected(long row
,
1513 boolean
* is_selected
) {
1514 if (!instance_active())
1518 return E_INVALIDARG
;
1520 // TODO(dmazzoni): Implement this.
1521 *is_selected
= false;
1525 STDMETHODIMP
BrowserAccessibilityWin::get_rowColumnExtentsAtIndex(
1530 long* column_extents
,
1531 boolean
* is_selected
) {
1532 if (!instance_active())
1535 if (!row
|| !column
|| !row_extents
|| !column_extents
|| !is_selected
)
1536 return E_INVALIDARG
;
1538 const std::vector
<int32
>& unique_cell_ids
= GetIntListAttribute(
1539 ui::AX_ATTR_UNIQUE_CELL_IDS
);
1540 int cell_id_count
= static_cast<int>(unique_cell_ids
.size());
1542 return E_INVALIDARG
;
1543 if (index
>= cell_id_count
)
1546 int cell_id
= unique_cell_ids
[index
];
1547 BrowserAccessibilityWin
* cell
=
1548 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1552 cell
->GetIntAttribute(
1553 ui::AX_ATTR_TABLE_CELL_ROW_SPAN
, &rowspan
) &&
1554 cell
->GetIntAttribute(
1555 ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN
, &colspan
) &&
1558 *row_extents
= rowspan
;
1559 *column_extents
= colspan
;
1567 // IAccessibleTable2 methods.
1570 STDMETHODIMP
BrowserAccessibilityWin::get_cellAt(long row
,
1573 return get_accessibleAt(row
, column
, cell
);
1576 STDMETHODIMP
BrowserAccessibilityWin::get_nSelectedCells(long* cell_count
) {
1577 return get_nSelectedChildren(cell_count
);
1580 STDMETHODIMP
BrowserAccessibilityWin::get_selectedCells(
1582 long* n_selected_cells
) {
1583 if (!instance_active())
1586 if (!cells
|| !n_selected_cells
)
1587 return E_INVALIDARG
;
1589 // TODO(dmazzoni): Implement this.
1590 *n_selected_cells
= 0;
1594 STDMETHODIMP
BrowserAccessibilityWin::get_selectedColumns(long** columns
,
1596 if (!instance_active())
1599 if (!columns
|| !n_columns
)
1600 return E_INVALIDARG
;
1602 // TODO(dmazzoni): Implement this.
1607 STDMETHODIMP
BrowserAccessibilityWin::get_selectedRows(long** rows
,
1609 if (!instance_active())
1612 if (!rows
|| !n_rows
)
1613 return E_INVALIDARG
;
1615 // TODO(dmazzoni): Implement this.
1622 // IAccessibleTableCell methods.
1625 STDMETHODIMP
BrowserAccessibilityWin::get_columnExtent(
1626 long* n_columns_spanned
) {
1627 if (!instance_active())
1630 if (!n_columns_spanned
)
1631 return E_INVALIDARG
;
1634 if (GetIntAttribute(
1635 ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN
, &colspan
) &&
1637 *n_columns_spanned
= colspan
;
1644 STDMETHODIMP
BrowserAccessibilityWin::get_columnHeaderCells(
1645 IUnknown
*** cell_accessibles
,
1646 long* n_column_header_cells
) {
1647 if (!instance_active())
1650 if (!cell_accessibles
|| !n_column_header_cells
)
1651 return E_INVALIDARG
;
1653 *n_column_header_cells
= 0;
1656 if (!GetIntAttribute(
1657 ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &column
)) {
1661 BrowserAccessibility
* table
= GetParent();
1662 while (table
&& table
->GetRole() != ui::AX_ROLE_TABLE
)
1663 table
= table
->GetParent();
1671 if (!table
->GetIntAttribute(
1672 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1673 !table
->GetIntAttribute(
1674 ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
)) {
1677 if (columns
<= 0 || rows
<= 0 || column
< 0 || column
>= columns
)
1680 const std::vector
<int32
>& cell_ids
= table
->GetIntListAttribute(
1681 ui::AX_ATTR_CELL_IDS
);
1683 for (int i
= 0; i
< rows
; ++i
) {
1684 int cell_id
= cell_ids
[i
* columns
+ column
];
1685 BrowserAccessibilityWin
* cell
=
1686 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1687 if (cell
&& cell
->GetRole() == ui::AX_ROLE_COLUMN_HEADER
)
1688 (*n_column_header_cells
)++;
1691 *cell_accessibles
= static_cast<IUnknown
**>(CoTaskMemAlloc(
1692 (*n_column_header_cells
) * sizeof(cell_accessibles
[0])));
1694 for (int i
= 0; i
< rows
; ++i
) {
1695 int cell_id
= cell_ids
[i
* columns
+ column
];
1696 BrowserAccessibility
* cell
= manager()->GetFromID(cell_id
);
1697 if (cell
&& cell
->GetRole() == ui::AX_ROLE_COLUMN_HEADER
) {
1698 (*cell_accessibles
)[index
] = static_cast<IAccessible
*>(
1699 cell
->ToBrowserAccessibilityWin()->NewReference());
1707 STDMETHODIMP
BrowserAccessibilityWin::get_columnIndex(long* column_index
) {
1708 if (!instance_active())
1712 return E_INVALIDARG
;
1715 if (GetIntAttribute(
1716 ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &column
)) {
1717 *column_index
= column
;
1724 STDMETHODIMP
BrowserAccessibilityWin::get_rowExtent(long* n_rows_spanned
) {
1725 if (!instance_active())
1728 if (!n_rows_spanned
)
1729 return E_INVALIDARG
;
1732 if (GetIntAttribute(
1733 ui::AX_ATTR_TABLE_CELL_ROW_SPAN
, &rowspan
) &&
1735 *n_rows_spanned
= rowspan
;
1742 STDMETHODIMP
BrowserAccessibilityWin::get_rowHeaderCells(
1743 IUnknown
*** cell_accessibles
,
1744 long* n_row_header_cells
) {
1745 if (!instance_active())
1748 if (!cell_accessibles
|| !n_row_header_cells
)
1749 return E_INVALIDARG
;
1751 *n_row_header_cells
= 0;
1754 if (!GetIntAttribute(
1755 ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &row
)) {
1759 BrowserAccessibility
* table
= GetParent();
1760 while (table
&& table
->GetRole() != ui::AX_ROLE_TABLE
)
1761 table
= table
->GetParent();
1769 if (!table
->GetIntAttribute(
1770 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1771 !table
->GetIntAttribute(
1772 ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
)) {
1775 if (columns
<= 0 || rows
<= 0 || row
< 0 || row
>= rows
)
1778 const std::vector
<int32
>& cell_ids
= table
->GetIntListAttribute(
1779 ui::AX_ATTR_CELL_IDS
);
1781 for (int i
= 0; i
< columns
; ++i
) {
1782 int cell_id
= cell_ids
[row
* columns
+ i
];
1783 BrowserAccessibility
* cell
= manager()->GetFromID(cell_id
);
1784 if (cell
&& cell
->GetRole() == ui::AX_ROLE_ROW_HEADER
)
1785 (*n_row_header_cells
)++;
1788 *cell_accessibles
= static_cast<IUnknown
**>(CoTaskMemAlloc(
1789 (*n_row_header_cells
) * sizeof(cell_accessibles
[0])));
1791 for (int i
= 0; i
< columns
; ++i
) {
1792 int cell_id
= cell_ids
[row
* columns
+ i
];
1793 BrowserAccessibility
* cell
= manager()->GetFromID(cell_id
);
1794 if (cell
&& cell
->GetRole() == ui::AX_ROLE_ROW_HEADER
) {
1795 (*cell_accessibles
)[index
] = static_cast<IAccessible
*>(
1796 cell
->ToBrowserAccessibilityWin()->NewReference());
1804 STDMETHODIMP
BrowserAccessibilityWin::get_rowIndex(long* row_index
) {
1805 if (!instance_active())
1809 return E_INVALIDARG
;
1812 if (GetIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &row
)) {
1819 STDMETHODIMP
BrowserAccessibilityWin::get_isSelected(boolean
* is_selected
) {
1820 if (!instance_active())
1824 return E_INVALIDARG
;
1826 *is_selected
= false;
1830 STDMETHODIMP
BrowserAccessibilityWin::get_rowColumnExtents(
1834 long* column_extents
,
1835 boolean
* is_selected
) {
1836 if (!instance_active())
1844 return E_INVALIDARG
;
1851 if (GetIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &row
) &&
1853 ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &column
) &&
1855 ui::AX_ATTR_TABLE_CELL_ROW_SPAN
, &rowspan
) &&
1857 ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN
, &colspan
)) {
1859 *column_index
= column
;
1860 *row_extents
= rowspan
;
1861 *column_extents
= colspan
;
1862 *is_selected
= false;
1869 STDMETHODIMP
BrowserAccessibilityWin::get_table(IUnknown
** table
) {
1870 if (!instance_active())
1874 return E_INVALIDARG
;
1879 GetIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &row
);
1880 GetIntAttribute(ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &column
);
1882 BrowserAccessibility
* find_table
= GetParent();
1883 while (find_table
&& find_table
->GetRole() != ui::AX_ROLE_TABLE
)
1884 find_table
= find_table
->GetParent();
1890 *table
= static_cast<IAccessibleTable
*>(
1891 find_table
->ToBrowserAccessibilityWin()->NewReference());
1897 // IAccessibleText methods.
1900 STDMETHODIMP
BrowserAccessibilityWin::get_nCharacters(LONG
* n_characters
) {
1901 if (!instance_active())
1905 return E_INVALIDARG
;
1907 *n_characters
= TextForIAccessibleText().length();
1911 STDMETHODIMP
BrowserAccessibilityWin::get_caretOffset(LONG
* offset
) {
1912 if (!instance_active())
1916 return E_INVALIDARG
;
1919 if (GetRole() == ui::AX_ROLE_TEXT_FIELD
||
1920 GetRole() == ui::AX_ROLE_TEXT_AREA
) {
1922 if (GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START
,
1924 *offset
= sel_start
;
1930 STDMETHODIMP
BrowserAccessibilityWin::get_characterExtents(
1932 enum IA2CoordinateType coordinate_type
,
1937 if (!instance_active())
1940 if (!out_x
|| !out_y
|| !out_width
|| !out_height
)
1941 return E_INVALIDARG
;
1943 const base::string16
& text_str
= TextForIAccessibleText();
1944 HandleSpecialTextOffset(text_str
, &offset
);
1946 if (offset
< 0 || offset
> static_cast<LONG
>(text_str
.size()))
1947 return E_INVALIDARG
;
1949 gfx::Rect character_bounds
;
1950 if (coordinate_type
== IA2_COORDTYPE_SCREEN_RELATIVE
) {
1951 character_bounds
= GetGlobalBoundsForRange(offset
, 1);
1952 } else if (coordinate_type
== IA2_COORDTYPE_PARENT_RELATIVE
) {
1953 character_bounds
= GetLocalBoundsForRange(offset
, 1);
1954 character_bounds
-= GetLocation().OffsetFromOrigin();
1956 return E_INVALIDARG
;
1959 *out_x
= character_bounds
.x();
1960 *out_y
= character_bounds
.y();
1961 *out_width
= character_bounds
.width();
1962 *out_height
= character_bounds
.height();
1967 STDMETHODIMP
BrowserAccessibilityWin::get_nSelections(LONG
* n_selections
) {
1968 if (!instance_active())
1972 return E_INVALIDARG
;
1975 if (GetRole() == ui::AX_ROLE_TEXT_FIELD
||
1976 GetRole() == ui::AX_ROLE_TEXT_AREA
) {
1979 if (GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START
,
1981 GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END
, &sel_end
) &&
1982 sel_start
!= sel_end
)
1989 STDMETHODIMP
BrowserAccessibilityWin::get_selection(LONG selection_index
,
1992 if (!instance_active())
1995 if (!start_offset
|| !end_offset
|| selection_index
!= 0)
1996 return E_INVALIDARG
;
2000 if (GetRole() == ui::AX_ROLE_TEXT_FIELD
||
2001 GetRole() == ui::AX_ROLE_TEXT_AREA
) {
2004 if (GetIntAttribute(
2005 ui::AX_ATTR_TEXT_SEL_START
, &sel_start
) &&
2006 GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END
, &sel_end
)) {
2007 *start_offset
= sel_start
;
2008 *end_offset
= sel_end
;
2015 STDMETHODIMP
BrowserAccessibilityWin::get_text(LONG start_offset
,
2018 if (!instance_active())
2022 return E_INVALIDARG
;
2024 const base::string16
& text_str
= TextForIAccessibleText();
2026 // Handle special text offsets.
2027 HandleSpecialTextOffset(text_str
, &start_offset
);
2028 HandleSpecialTextOffset(text_str
, &end_offset
);
2030 // The spec allows the arguments to be reversed.
2031 if (start_offset
> end_offset
) {
2032 LONG tmp
= start_offset
;
2033 start_offset
= end_offset
;
2037 // The spec does not allow the start or end offsets to be out or range;
2038 // we must return an error if so.
2039 LONG len
= text_str
.length();
2040 if (start_offset
< 0)
2041 return E_INVALIDARG
;
2042 if (end_offset
> len
)
2043 return E_INVALIDARG
;
2045 base::string16 substr
= text_str
.substr(start_offset
,
2046 end_offset
- start_offset
);
2050 *text
= SysAllocString(substr
.c_str());
2055 STDMETHODIMP
BrowserAccessibilityWin::get_textAtOffset(
2057 enum IA2TextBoundaryType boundary_type
,
2061 if (!instance_active())
2064 if (!start_offset
|| !end_offset
|| !text
)
2065 return E_INVALIDARG
;
2067 // The IAccessible2 spec says we don't have to implement the "sentence"
2068 // boundary type, we can just let the screenreader handle it.
2069 if (boundary_type
== IA2_TEXT_BOUNDARY_SENTENCE
) {
2076 const base::string16
& text_str
= TextForIAccessibleText();
2078 *start_offset
= FindBoundary(
2079 text_str
, boundary_type
, offset
, ui::BACKWARDS_DIRECTION
);
2080 *end_offset
= FindBoundary(
2081 text_str
, boundary_type
, offset
, ui::FORWARDS_DIRECTION
);
2082 return get_text(*start_offset
, *end_offset
, text
);
2085 STDMETHODIMP
BrowserAccessibilityWin::get_textBeforeOffset(
2087 enum IA2TextBoundaryType boundary_type
,
2091 if (!instance_active())
2094 if (!start_offset
|| !end_offset
|| !text
)
2095 return E_INVALIDARG
;
2097 // The IAccessible2 spec says we don't have to implement the "sentence"
2098 // boundary type, we can just let the screenreader handle it.
2099 if (boundary_type
== IA2_TEXT_BOUNDARY_SENTENCE
) {
2106 const base::string16
& text_str
= TextForIAccessibleText();
2108 *start_offset
= FindBoundary(
2109 text_str
, boundary_type
, offset
, ui::BACKWARDS_DIRECTION
);
2110 *end_offset
= offset
;
2111 return get_text(*start_offset
, *end_offset
, text
);
2114 STDMETHODIMP
BrowserAccessibilityWin::get_textAfterOffset(
2116 enum IA2TextBoundaryType boundary_type
,
2120 if (!instance_active())
2123 if (!start_offset
|| !end_offset
|| !text
)
2124 return E_INVALIDARG
;
2126 // The IAccessible2 spec says we don't have to implement the "sentence"
2127 // boundary type, we can just let the screenreader handle it.
2128 if (boundary_type
== IA2_TEXT_BOUNDARY_SENTENCE
) {
2135 const base::string16
& text_str
= TextForIAccessibleText();
2137 *start_offset
= offset
;
2138 *end_offset
= FindBoundary(
2139 text_str
, boundary_type
, offset
, ui::FORWARDS_DIRECTION
);
2140 return get_text(*start_offset
, *end_offset
, text
);
2143 STDMETHODIMP
BrowserAccessibilityWin::get_newText(IA2TextSegment
* new_text
) {
2144 if (!instance_active())
2148 return E_INVALIDARG
;
2150 base::string16 text
= TextForIAccessibleText();
2152 new_text
->text
= SysAllocString(text
.c_str());
2153 new_text
->start
= 0;
2154 new_text
->end
= static_cast<long>(text
.size());
2158 STDMETHODIMP
BrowserAccessibilityWin::get_oldText(IA2TextSegment
* old_text
) {
2159 if (!instance_active())
2163 return E_INVALIDARG
;
2165 old_text
->text
= SysAllocString(old_text_
.c_str());
2166 old_text
->start
= 0;
2167 old_text
->end
= static_cast<long>(old_text_
.size());
2171 STDMETHODIMP
BrowserAccessibilityWin::get_offsetAtPoint(
2174 enum IA2CoordinateType coord_type
,
2176 if (!instance_active())
2180 return E_INVALIDARG
;
2182 // TODO(dmazzoni): implement this. We're returning S_OK for now so that
2183 // screen readers still return partially accurate results rather than
2184 // completely failing.
2189 STDMETHODIMP
BrowserAccessibilityWin::scrollSubstringTo(
2192 enum IA2ScrollType scroll_type
) {
2193 // TODO(dmazzoni): adjust this for the start and end index, too.
2194 return scrollTo(scroll_type
);
2197 STDMETHODIMP
BrowserAccessibilityWin::scrollSubstringToPoint(
2200 enum IA2CoordinateType coordinate_type
,
2202 // TODO(dmazzoni): adjust this for the start and end index, too.
2203 return scrollToPoint(coordinate_type
, x
, y
);
2206 STDMETHODIMP
BrowserAccessibilityWin::addSelection(LONG start_offset
,
2208 if (!instance_active())
2211 const base::string16
& text_str
= TextForIAccessibleText();
2212 HandleSpecialTextOffset(text_str
, &start_offset
);
2213 HandleSpecialTextOffset(text_str
, &end_offset
);
2215 manager()->SetTextSelection(*this, start_offset
, end_offset
);
2219 STDMETHODIMP
BrowserAccessibilityWin::removeSelection(LONG selection_index
) {
2220 if (!instance_active())
2223 if (selection_index
!= 0)
2224 return E_INVALIDARG
;
2226 manager()->SetTextSelection(*this, 0, 0);
2230 STDMETHODIMP
BrowserAccessibilityWin::setCaretOffset(LONG offset
) {
2231 if (!instance_active())
2234 const base::string16
& text_str
= TextForIAccessibleText();
2235 HandleSpecialTextOffset(text_str
, &offset
);
2236 manager()->SetTextSelection(*this, offset
, offset
);
2240 STDMETHODIMP
BrowserAccessibilityWin::setSelection(LONG selection_index
,
2243 if (!instance_active())
2246 if (selection_index
!= 0)
2247 return E_INVALIDARG
;
2249 const base::string16
& text_str
= TextForIAccessibleText();
2250 HandleSpecialTextOffset(text_str
, &start_offset
);
2251 HandleSpecialTextOffset(text_str
, &end_offset
);
2253 manager()->SetTextSelection(*this, start_offset
, end_offset
);
2258 // IAccessibleHypertext methods.
2261 STDMETHODIMP
BrowserAccessibilityWin::get_nHyperlinks(long* hyperlink_count
) {
2262 if (!instance_active())
2265 if (!hyperlink_count
)
2266 return E_INVALIDARG
;
2268 *hyperlink_count
= hyperlink_offset_to_index_
.size();
2272 STDMETHODIMP
BrowserAccessibilityWin::get_hyperlink(
2274 IAccessibleHyperlink
** hyperlink
) {
2275 if (!instance_active())
2280 index
>= static_cast<long>(hyperlinks_
.size())) {
2281 return E_INVALIDARG
;
2284 BrowserAccessibilityWin
* child
=
2285 InternalGetChild(hyperlinks_
[index
])->ToBrowserAccessibilityWin();
2286 *hyperlink
= static_cast<IAccessibleHyperlink
*>(child
->NewReference());
2290 STDMETHODIMP
BrowserAccessibilityWin::get_hyperlinkIndex(
2292 long* hyperlink_index
) {
2293 if (!instance_active())
2296 if (!hyperlink_index
)
2297 return E_INVALIDARG
;
2299 *hyperlink_index
= -1;
2301 if (char_index
< 0 || char_index
>= static_cast<long>(hypertext_
.size()))
2302 return E_INVALIDARG
;
2304 std::map
<int32
, int32
>::iterator it
=
2305 hyperlink_offset_to_index_
.find(char_index
);
2306 if (it
== hyperlink_offset_to_index_
.end())
2309 *hyperlink_index
= it
->second
;
2314 // IAccessibleValue methods.
2317 STDMETHODIMP
BrowserAccessibilityWin::get_currentValue(VARIANT
* value
) {
2318 if (!instance_active())
2322 return E_INVALIDARG
;
2325 if (GetFloatAttribute(
2326 ui::AX_ATTR_VALUE_FOR_RANGE
, &float_val
)) {
2328 value
->dblVal
= float_val
;
2332 value
->vt
= VT_EMPTY
;
2336 STDMETHODIMP
BrowserAccessibilityWin::get_minimumValue(VARIANT
* value
) {
2337 if (!instance_active())
2341 return E_INVALIDARG
;
2344 if (GetFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE
,
2347 value
->dblVal
= float_val
;
2351 value
->vt
= VT_EMPTY
;
2355 STDMETHODIMP
BrowserAccessibilityWin::get_maximumValue(VARIANT
* value
) {
2356 if (!instance_active())
2360 return E_INVALIDARG
;
2363 if (GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE
,
2366 value
->dblVal
= float_val
;
2370 value
->vt
= VT_EMPTY
;
2374 STDMETHODIMP
BrowserAccessibilityWin::setCurrentValue(VARIANT new_value
) {
2375 // TODO(dmazzoni): Implement this.
2380 // ISimpleDOMDocument methods.
2383 STDMETHODIMP
BrowserAccessibilityWin::get_URL(BSTR
* url
) {
2384 if (!instance_active())
2388 return E_INVALIDARG
;
2390 return GetStringAttributeAsBstr(ui::AX_ATTR_DOC_URL
, url
);
2393 STDMETHODIMP
BrowserAccessibilityWin::get_title(BSTR
* title
) {
2394 if (!instance_active())
2398 return E_INVALIDARG
;
2400 return GetStringAttributeAsBstr(ui::AX_ATTR_DOC_TITLE
, title
);
2403 STDMETHODIMP
BrowserAccessibilityWin::get_mimeType(BSTR
* mime_type
) {
2404 if (!instance_active())
2408 return E_INVALIDARG
;
2410 return GetStringAttributeAsBstr(
2411 ui::AX_ATTR_DOC_MIMETYPE
, mime_type
);
2414 STDMETHODIMP
BrowserAccessibilityWin::get_docType(BSTR
* doc_type
) {
2415 if (!instance_active())
2419 return E_INVALIDARG
;
2421 return GetStringAttributeAsBstr(
2422 ui::AX_ATTR_DOC_DOCTYPE
, doc_type
);
2426 // ISimpleDOMNode methods.
2429 STDMETHODIMP
BrowserAccessibilityWin::get_nodeInfo(
2431 short* name_space_id
,
2433 unsigned int* num_children
,
2434 unsigned int* unique_id
,
2435 unsigned short* node_type
) {
2436 if (!instance_active())
2439 if (!node_name
|| !name_space_id
|| !node_value
|| !num_children
||
2440 !unique_id
|| !node_type
) {
2441 return E_INVALIDARG
;
2445 if (GetString16Attribute(ui::AX_ATTR_HTML_TAG
, &tag
))
2446 *node_name
= SysAllocString(tag
.c_str());
2451 *node_value
= SysAllocString(base::UTF8ToUTF16(value()).c_str());
2452 *num_children
= PlatformChildCount();
2453 *unique_id
= unique_id_win_
;
2455 if (ia_role_
== ROLE_SYSTEM_DOCUMENT
) {
2456 *node_type
= NODETYPE_DOCUMENT
;
2457 } else if (ia_role_
== ROLE_SYSTEM_TEXT
&&
2458 ((ia2_state_
& IA2_STATE_EDITABLE
) == 0)) {
2459 *node_type
= NODETYPE_TEXT
;
2461 *node_type
= NODETYPE_ELEMENT
;
2467 STDMETHODIMP
BrowserAccessibilityWin::get_attributes(
2468 unsigned short max_attribs
,
2470 short* name_space_id
,
2471 BSTR
* attrib_values
,
2472 unsigned short* num_attribs
) {
2473 if (!instance_active())
2476 if (!attrib_names
|| !name_space_id
|| !attrib_values
|| !num_attribs
)
2477 return E_INVALIDARG
;
2479 *num_attribs
= max_attribs
;
2480 if (*num_attribs
> GetHtmlAttributes().size())
2481 *num_attribs
= GetHtmlAttributes().size();
2483 for (unsigned short i
= 0; i
< *num_attribs
; ++i
) {
2484 attrib_names
[i
] = SysAllocString(
2485 base::UTF8ToUTF16(GetHtmlAttributes()[i
].first
).c_str());
2486 name_space_id
[i
] = 0;
2487 attrib_values
[i
] = SysAllocString(
2488 base::UTF8ToUTF16(GetHtmlAttributes()[i
].second
).c_str());
2493 STDMETHODIMP
BrowserAccessibilityWin::get_attributesForNames(
2494 unsigned short num_attribs
,
2496 short* name_space_id
,
2497 BSTR
* attrib_values
) {
2498 if (!instance_active())
2501 if (!attrib_names
|| !name_space_id
|| !attrib_values
)
2502 return E_INVALIDARG
;
2504 for (unsigned short i
= 0; i
< num_attribs
; ++i
) {
2505 name_space_id
[i
] = 0;
2507 std::string name
= base::UTF16ToUTF8((LPCWSTR
)attrib_names
[i
]);
2508 for (unsigned int j
= 0; j
< GetHtmlAttributes().size(); ++j
) {
2509 if (GetHtmlAttributes()[j
].first
== name
) {
2510 attrib_values
[i
] = SysAllocString(
2511 base::UTF8ToUTF16(GetHtmlAttributes()[j
].second
).c_str());
2517 attrib_values
[i
] = NULL
;
2523 STDMETHODIMP
BrowserAccessibilityWin::get_computedStyle(
2524 unsigned short max_style_properties
,
2525 boolean use_alternate_view
,
2526 BSTR
* style_properties
,
2528 unsigned short *num_style_properties
) {
2529 if (!instance_active())
2532 if (!style_properties
|| !style_values
)
2533 return E_INVALIDARG
;
2535 // We only cache a single style property for now: DISPLAY
2537 base::string16 display
;
2538 if (max_style_properties
== 0 ||
2539 !GetString16Attribute(ui::AX_ATTR_DISPLAY
, &display
)) {
2540 *num_style_properties
= 0;
2544 *num_style_properties
= 1;
2545 style_properties
[0] = SysAllocString(L
"display");
2546 style_values
[0] = SysAllocString(display
.c_str());
2551 STDMETHODIMP
BrowserAccessibilityWin::get_computedStyleForProperties(
2552 unsigned short num_style_properties
,
2553 boolean use_alternate_view
,
2554 BSTR
* style_properties
,
2555 BSTR
* style_values
) {
2556 if (!instance_active())
2559 if (!style_properties
|| !style_values
)
2560 return E_INVALIDARG
;
2562 // We only cache a single style property for now: DISPLAY
2564 for (unsigned short i
= 0; i
< num_style_properties
; ++i
) {
2565 base::string16 name
= (LPCWSTR
)style_properties
[i
];
2566 base::StringToLowerASCII(&name
);
2567 if (name
== L
"display") {
2568 base::string16 display
= GetString16Attribute(
2569 ui::AX_ATTR_DISPLAY
);
2570 style_values
[i
] = SysAllocString(display
.c_str());
2572 style_values
[i
] = NULL
;
2579 STDMETHODIMP
BrowserAccessibilityWin::scrollTo(boolean placeTopLeft
) {
2580 return scrollTo(placeTopLeft
?
2581 IA2_SCROLL_TYPE_TOP_LEFT
: IA2_SCROLL_TYPE_ANYWHERE
);
2584 STDMETHODIMP
BrowserAccessibilityWin::get_parentNode(ISimpleDOMNode
** node
) {
2585 if (!instance_active())
2589 return E_INVALIDARG
;
2591 *node
= GetParent()->ToBrowserAccessibilityWin()->NewReference();
2595 STDMETHODIMP
BrowserAccessibilityWin::get_firstChild(ISimpleDOMNode
** node
) {
2596 if (!instance_active())
2600 return E_INVALIDARG
;
2602 if (PlatformChildCount() == 0) {
2607 *node
= PlatformGetChild(0)->ToBrowserAccessibilityWin()->NewReference();
2611 STDMETHODIMP
BrowserAccessibilityWin::get_lastChild(ISimpleDOMNode
** node
) {
2612 if (!instance_active())
2616 return E_INVALIDARG
;
2618 if (PlatformChildCount() == 0) {
2623 *node
= PlatformGetChild(PlatformChildCount() - 1)
2624 ->ToBrowserAccessibilityWin()->NewReference();
2628 STDMETHODIMP
BrowserAccessibilityWin::get_previousSibling(
2629 ISimpleDOMNode
** node
) {
2630 if (!instance_active())
2634 return E_INVALIDARG
;
2636 if (!GetParent() || GetIndexInParent() <= 0) {
2641 *node
= GetParent()->InternalGetChild(GetIndexInParent() - 1)->
2642 ToBrowserAccessibilityWin()->NewReference();
2646 STDMETHODIMP
BrowserAccessibilityWin::get_nextSibling(ISimpleDOMNode
** node
) {
2647 if (!instance_active())
2651 return E_INVALIDARG
;
2654 GetIndexInParent() < 0 ||
2655 GetIndexInParent() >= static_cast<int>(
2656 GetParent()->InternalChildCount()) - 1) {
2661 *node
= GetParent()->InternalGetChild(GetIndexInParent() + 1)->
2662 ToBrowserAccessibilityWin()->NewReference();
2666 STDMETHODIMP
BrowserAccessibilityWin::get_childAt(
2667 unsigned int child_index
,
2668 ISimpleDOMNode
** node
) {
2669 if (!instance_active())
2673 return E_INVALIDARG
;
2675 if (child_index
>= PlatformChildCount())
2676 return E_INVALIDARG
;
2678 BrowserAccessibility
* child
= PlatformGetChild(child_index
);
2684 *node
= child
->ToBrowserAccessibilityWin()->NewReference();
2689 // ISimpleDOMText methods.
2692 STDMETHODIMP
BrowserAccessibilityWin::get_domText(BSTR
* dom_text
) {
2693 if (!instance_active())
2697 return E_INVALIDARG
;
2699 return GetStringAttributeAsBstr(
2700 ui::AX_ATTR_NAME
, dom_text
);
2703 STDMETHODIMP
BrowserAccessibilityWin::get_clippedSubstringBounds(
2704 unsigned int start_index
,
2705 unsigned int end_index
,
2710 // TODO(dmazzoni): fully support this API by intersecting the
2711 // rect with the container's rect.
2712 return get_unclippedSubstringBounds(
2713 start_index
, end_index
, out_x
, out_y
, out_width
, out_height
);
2716 STDMETHODIMP
BrowserAccessibilityWin::get_unclippedSubstringBounds(
2717 unsigned int start_index
,
2718 unsigned int end_index
,
2723 if (!instance_active())
2726 if (!out_x
|| !out_y
|| !out_width
|| !out_height
)
2727 return E_INVALIDARG
;
2729 const base::string16
& text_str
= TextForIAccessibleText();
2730 if (start_index
> text_str
.size() ||
2731 end_index
> text_str
.size() ||
2732 start_index
> end_index
) {
2733 return E_INVALIDARG
;
2736 gfx::Rect bounds
= GetGlobalBoundsForRange(
2737 start_index
, end_index
- start_index
);
2738 *out_x
= bounds
.x();
2739 *out_y
= bounds
.y();
2740 *out_width
= bounds
.width();
2741 *out_height
= bounds
.height();
2745 STDMETHODIMP
BrowserAccessibilityWin::scrollToSubstring(
2746 unsigned int start_index
,
2747 unsigned int end_index
) {
2748 if (!instance_active())
2751 const base::string16
& text_str
= TextForIAccessibleText();
2752 if (start_index
> text_str
.size() ||
2753 end_index
> text_str
.size() ||
2754 start_index
> end_index
) {
2755 return E_INVALIDARG
;
2758 manager()->ScrollToMakeVisible(*this, GetLocalBoundsForRange(
2759 start_index
, end_index
- start_index
));
2760 manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
2766 // IServiceProvider methods.
2769 STDMETHODIMP
BrowserAccessibilityWin::QueryService(REFGUID guidService
,
2772 if (!instance_active())
2775 // The system uses IAccessible APIs for many purposes, but only
2776 // assistive technology like screen readers uses IAccessible2.
2777 // Enable full accessibility support when IAccessible2 APIs are queried.
2778 if (riid
== IID_IAccessible2
)
2779 BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility();
2781 if (guidService
== GUID_IAccessibleContentDocument
) {
2782 // Special Mozilla extension: return the accessible for the root document.
2783 // Screen readers use this to distinguish between a document loaded event
2784 // on the root document vs on an iframe.
2785 return manager()->GetRoot()->ToBrowserAccessibilityWin()->QueryInterface(
2786 IID_IAccessible2
, object
);
2789 if (guidService
== IID_IAccessible
||
2790 guidService
== IID_IAccessible2
||
2791 guidService
== IID_IAccessibleAction
||
2792 guidService
== IID_IAccessibleApplication
||
2793 guidService
== IID_IAccessibleHyperlink
||
2794 guidService
== IID_IAccessibleHypertext
||
2795 guidService
== IID_IAccessibleImage
||
2796 guidService
== IID_IAccessibleTable
||
2797 guidService
== IID_IAccessibleTable2
||
2798 guidService
== IID_IAccessibleTableCell
||
2799 guidService
== IID_IAccessibleText
||
2800 guidService
== IID_IAccessibleValue
||
2801 guidService
== IID_ISimpleDOMDocument
||
2802 guidService
== IID_ISimpleDOMNode
||
2803 guidService
== IID_ISimpleDOMText
||
2804 guidService
== GUID_ISimpleDOM
) {
2805 return QueryInterface(riid
, object
);
2808 // We only support the IAccessibleEx interface on Windows 8 and above. This
2809 // is needed for the on-screen Keyboard to show up in metro mode, when the
2810 // user taps an editable portion on the page.
2811 // All methods in the IAccessibleEx interface are unimplemented.
2812 if (riid
== IID_IAccessibleEx
&&
2813 base::win::GetVersion() >= base::win::VERSION_WIN8
) {
2814 return QueryInterface(riid
, object
);
2821 STDMETHODIMP
BrowserAccessibilityWin::GetPatternProvider(PATTERNID id
,
2822 IUnknown
** provider
) {
2823 DVLOG(1) << "In Function: "
2825 << " for pattern id: "
2827 if (id
== UIA_ValuePatternId
|| id
== UIA_TextPatternId
) {
2828 if (IsEditableText()) {
2829 DVLOG(1) << "Returning UIA text provider";
2830 base::win::UIATextProvider::CreateTextProvider(
2831 GetValueText(), true, provider
);
2838 STDMETHODIMP
BrowserAccessibilityWin::GetPropertyValue(PROPERTYID id
,
2840 DVLOG(1) << "In Function: "
2842 << " for property id: "
2844 V_VT(ret
) = VT_EMPTY
;
2845 if (id
== UIA_ControlTypePropertyId
) {
2846 if (IsEditableText()) {
2848 ret
->lVal
= UIA_EditControlTypeId
;
2849 DVLOG(1) << "Returning Edit control type";
2851 DVLOG(1) << "Returning empty control type";
2858 // CComObjectRootEx methods.
2862 HRESULT WINAPI
BrowserAccessibilityWin::InternalQueryInterface(
2864 const _ATL_INTMAP_ENTRY
* entries
,
2867 BrowserAccessibilityWin
* accessibility
=
2868 reinterpret_cast<BrowserAccessibilityWin
*>(this_ptr
);
2869 int32 ia_role
= accessibility
->ia_role_
;
2870 if (iid
== IID_IAccessibleImage
) {
2871 if (ia_role
!= ROLE_SYSTEM_GRAPHIC
) {
2873 return E_NOINTERFACE
;
2875 } else if (iid
== IID_IAccessibleTable
|| iid
== IID_IAccessibleTable2
) {
2876 if (ia_role
!= ROLE_SYSTEM_TABLE
) {
2878 return E_NOINTERFACE
;
2880 } else if (iid
== IID_IAccessibleTableCell
) {
2881 if (!accessibility
->IsCellOrTableHeaderRole()) {
2883 return E_NOINTERFACE
;
2885 } else if (iid
== IID_IAccessibleValue
) {
2886 if (ia_role
!= ROLE_SYSTEM_PROGRESSBAR
&&
2887 ia_role
!= ROLE_SYSTEM_SCROLLBAR
&&
2888 ia_role
!= ROLE_SYSTEM_SLIDER
) {
2890 return E_NOINTERFACE
;
2892 } else if (iid
== IID_ISimpleDOMDocument
) {
2893 if (ia_role
!= ROLE_SYSTEM_DOCUMENT
) {
2895 return E_NOINTERFACE
;
2899 return CComObjectRootBase::InternalQueryInterface(
2900 this_ptr
, entries
, iid
, object
);
2907 // Called every time this node's data changes.
2908 void BrowserAccessibilityWin::OnDataChanged() {
2909 BrowserAccessibility::OnDataChanged();
2913 // Expose autocomplete attribute for combobox and textbox.
2914 StringAttributeToIA2(ui::AX_ATTR_AUTO_COMPLETE
, "autocomplete");
2916 // Expose the "display" and "tag" attributes.
2917 StringAttributeToIA2(ui::AX_ATTR_DISPLAY
, "display");
2918 StringAttributeToIA2(ui::AX_ATTR_TEXT_INPUT_TYPE
, "text-input-type");
2919 StringAttributeToIA2(ui::AX_ATTR_HTML_TAG
, "tag");
2920 StringAttributeToIA2(ui::AX_ATTR_ROLE
, "xml-roles");
2922 // Expose "level" attribute for headings, trees, etc.
2923 IntAttributeToIA2(ui::AX_ATTR_HIERARCHICAL_LEVEL
, "level");
2925 // Expose the set size and position in set for listbox options.
2926 if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION
&&
2928 GetParent()->GetRole() == ui::AX_ROLE_LIST_BOX
) {
2929 ia2_attributes_
.push_back(
2930 L
"setsize:" + base::IntToString16(GetParent()->PlatformChildCount()));
2931 ia2_attributes_
.push_back(
2932 L
"setsize:" + base::IntToString16(GetIndexInParent() + 1));
2935 if (ia_role_
== ROLE_SYSTEM_CHECKBUTTON
||
2936 ia_role_
== ROLE_SYSTEM_RADIOBUTTON
||
2937 ia2_role_
== IA2_ROLE_CHECK_MENU_ITEM
||
2938 ia2_role_
== IA2_ROLE_RADIO_MENU_ITEM
||
2939 ia2_role_
== IA2_ROLE_TOGGLE_BUTTON
) {
2940 ia2_attributes_
.push_back(L
"checkable:true");
2943 // Expose live region attributes.
2944 StringAttributeToIA2(ui::AX_ATTR_LIVE_STATUS
, "live");
2945 StringAttributeToIA2(ui::AX_ATTR_LIVE_RELEVANT
, "relevant");
2946 BoolAttributeToIA2(ui::AX_ATTR_LIVE_ATOMIC
, "atomic");
2947 BoolAttributeToIA2(ui::AX_ATTR_LIVE_BUSY
, "busy");
2949 // Expose container live region attributes.
2950 StringAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_STATUS
,
2952 StringAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_RELEVANT
,
2953 "container-relevant");
2954 BoolAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_ATOMIC
,
2955 "container-atomic");
2956 BoolAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_BUSY
,
2959 // Expose slider value.
2960 if (ia_role_
== ROLE_SYSTEM_PROGRESSBAR
||
2961 ia_role_
== ROLE_SYSTEM_SCROLLBAR
||
2962 ia_role_
== ROLE_SYSTEM_SLIDER
) {
2963 ia2_attributes_
.push_back(L
"valuetext:" + GetValueText());
2966 // Expose table cell index.
2967 if (IsCellOrTableHeaderRole()) {
2968 BrowserAccessibility
* table
= GetParent();
2969 while (table
&& table
->GetRole() != ui::AX_ROLE_TABLE
)
2970 table
= table
->GetParent();
2972 const std::vector
<int32
>& unique_cell_ids
= table
->GetIntListAttribute(
2973 ui::AX_ATTR_UNIQUE_CELL_IDS
);
2974 for (size_t i
= 0; i
< unique_cell_ids
.size(); ++i
) {
2975 if (unique_cell_ids
[i
] == GetId()) {
2976 ia2_attributes_
.push_back(
2977 base::string16(L
"table-cell-index:") + base::IntToString16(i
));
2983 // Expose invalid state for form controls and elements with aria-invalid.
2985 if (GetIntAttribute(ui::AX_ATTR_INVALID_STATE
, &invalid_state
)) {
2986 // TODO(nektar): Handle the possibility of having multiple aria-invalid
2987 // attributes defined, e.g., "invalid:spelling,grammar".
2988 switch (invalid_state
) {
2989 case ui::AX_INVALID_STATE_NONE
:
2991 case ui::AX_INVALID_STATE_FALSE
:
2992 ia2_attributes_
.push_back(L
"invalid:false");
2994 case ui::AX_INVALID_STATE_TRUE
:
2995 ia2_attributes_
.push_back(L
"invalid:true");
2997 case ui::AX_INVALID_STATE_SPELLING
:
2998 ia2_attributes_
.push_back(L
"invalid:spelling");
3000 case ui::AX_INVALID_STATE_GRAMMAR
:
3001 ia2_attributes_
.push_back(L
"invalid:grammar");
3003 case ui::AX_INVALID_STATE_OTHER
:
3005 base::string16 aria_invalid_value
;
3006 if (GetString16Attribute(ui::AX_ATTR_ARIA_INVALID_VALUE
,
3007 &aria_invalid_value
)) {
3008 ia2_attributes_
.push_back(L
"invalid:" + aria_invalid_value
);
3010 // Set the attribute to L"true", since we cannot be more specific.
3011 ia2_attributes_
.push_back(L
"invalid:true");
3020 // The calculation of the accessible name of an element has been
3021 // standardized in the HTML to Platform Accessibility APIs Implementation
3022 // Guide (http://www.w3.org/TR/html-aapi/). In order to return the
3023 // appropriate accessible name on Windows, we need to apply some logic
3024 // to the fields we get from WebKit.
3026 // TODO(dmazzoni): move most of this logic into WebKit.
3030 // name: the default name, e.g. inner text
3031 // title ui element: a reference to a <label> element on the same
3032 // page that labels this node.
3033 // description: accessible labels that override the default name:
3034 // aria-label or aria-labelledby or aria-describedby
3035 // help: the value of the "title" attribute
3037 // On Windows, the logic we apply lets some fields take precedence and
3038 // always returns the primary name in "name" and the secondary name,
3039 // if any, in "description".
3041 int title_elem_id
= GetIntAttribute(
3042 ui::AX_ATTR_TITLE_UI_ELEMENT
);
3043 std::string help
= GetStringAttribute(ui::AX_ATTR_HELP
);
3044 std::string description
= GetStringAttribute(
3045 ui::AX_ATTR_DESCRIPTION
);
3047 // WebKit annoyingly puts the title in the description if there's no other
3048 // description, which just confuses the rest of the logic. Put it back.
3049 // Now "help" is always the value of the "title" attribute, if present.
3050 std::string title_attr
;
3051 if (GetHtmlAttribute("title", &title_attr
) &&
3052 description
== title_attr
&&
3055 description
.clear();
3058 // Now implement the main logic: the descripion should become the name if
3059 // it's nonempty, and the help should become the description if
3060 // there's no description - or the name if there's no name or description.
3061 if (!description
.empty()) {
3062 set_name(description
);
3063 description
.clear();
3065 if (!help
.empty() && description
.empty()) {
3069 if (!description
.empty() && name().empty() && !title_elem_id
) {
3070 set_name(description
);
3071 description
.clear();
3074 // If it's a text field, also consider the placeholder.
3075 std::string placeholder
;
3076 if (GetRole() == ui::AX_ROLE_TEXT_FIELD
&&
3077 HasState(ui::AX_STATE_FOCUSABLE
) &&
3078 GetHtmlAttribute("placeholder", &placeholder
)) {
3079 if (name().empty() && !title_elem_id
) {
3080 set_name(placeholder
);
3081 } else if (description
.empty()) {
3082 description
= placeholder
;
3086 SetStringAttribute(ui::AX_ATTR_DESCRIPTION
, description
);
3087 SetStringAttribute(ui::AX_ATTR_HELP
, help
);
3089 // On Windows, the value of a document should be its url.
3090 if (GetRole() == ui::AX_ROLE_ROOT_WEB_AREA
||
3091 GetRole() == ui::AX_ROLE_WEB_AREA
) {
3092 set_value(GetStringAttribute(ui::AX_ATTR_DOC_URL
));
3095 // For certain roles (listbox option, static text, and list marker)
3096 // WebKit stores the main accessible text in the "value" - swap it so
3097 // that it's the "name".
3098 if (name().empty() &&
3099 (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION
||
3100 GetRole() == ui::AX_ROLE_STATIC_TEXT
||
3101 GetRole() == ui::AX_ROLE_LIST_MARKER
)) {
3102 std::string tmp
= value();
3107 // If this doesn't have a value and is linked then set its value to the url
3108 // attribute. This allows screen readers to read an empty link's destination.
3109 if (value().empty() && (ia_state_
& STATE_SYSTEM_LINKED
))
3110 set_value(GetStringAttribute(ui::AX_ATTR_URL
));
3112 // Clear any old relationships between this node and other nodes.
3113 for (size_t i
= 0; i
< relations_
.size(); ++i
)
3114 relations_
[i
]->Release();
3117 // Handle title UI element.
3118 if (title_elem_id
) {
3119 // Add a labelled by relationship.
3120 CComObject
<BrowserAccessibilityRelation
>* relation
;
3121 HRESULT hr
= CComObject
<BrowserAccessibilityRelation
>::CreateInstance(
3123 DCHECK(SUCCEEDED(hr
));
3125 relation
->Initialize(this, IA2_RELATION_LABELLED_BY
);
3126 relation
->AddTarget(title_elem_id
);
3127 relations_
.push_back(relation
);
3130 // If this is a web area for a presentational iframe, give it a role of
3131 // something other than DOCUMENT so that the fact that it's a separate doc
3132 // is not exposed to AT.
3133 if (IsWebAreaForPresentationalIframe()) {
3134 ia_role_
= ROLE_SYSTEM_GROUPING
;
3135 ia2_role_
= ROLE_SYSTEM_GROUPING
;
3139 void BrowserAccessibilityWin::OnUpdateFinished() {
3140 // Construct the hypertext for this node.
3141 hyperlink_offset_to_index_
.clear();
3142 hyperlinks_
.clear();
3144 for (unsigned int i
= 0; i
< PlatformChildCount(); ++i
) {
3145 BrowserAccessibility
* child
= PlatformGetChild(i
);
3146 if (child
->GetRole() == ui::AX_ROLE_STATIC_TEXT
) {
3147 hypertext_
+= base::UTF8ToUTF16(child
->name());
3149 hyperlink_offset_to_index_
[hypertext_
.size()] = hyperlinks_
.size();
3150 hypertext_
+= kEmbeddedCharacter
;
3151 hyperlinks_
.push_back(i
);
3154 DCHECK_EQ(hyperlink_offset_to_index_
.size(), hyperlinks_
.size());
3156 // Fire an event when an alert first appears.
3157 if (GetRole() == ui::AX_ROLE_ALERT
&& first_time_
)
3158 manager()->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT
, this);
3160 // Fire events if text has changed.
3161 base::string16 text
= TextForIAccessibleText();
3162 if (previous_text_
!= text
) {
3163 if (!previous_text_
.empty() && !text
.empty()) {
3164 manager()->NotifyAccessibilityEvent(
3165 ui::AX_EVENT_SHOW
, this);
3168 // TODO(dmazzoni): Look into HIDE events, too.
3170 old_text_
= previous_text_
;
3171 previous_text_
= text
;
3174 BrowserAccessibilityManagerWin
* manager
=
3175 this->manager()->ToBrowserAccessibilityManagerWin();
3177 // Fire events if the state has changed.
3178 if (!first_time_
&& ia_state_
!= old_ia_state_
) {
3179 // Normally focus events are handled elsewhere, however
3180 // focus for managed descendants is platform-specific.
3181 // Fire a focus event if the focused descendant in a multi-select
3182 // list box changes.
3183 if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION
&&
3184 (ia_state_
& STATE_SYSTEM_FOCUSABLE
) &&
3185 (ia_state_
& STATE_SYSTEM_SELECTABLE
) &&
3186 (ia_state_
& STATE_SYSTEM_FOCUSED
) &&
3187 !(old_ia_state_
& STATE_SYSTEM_FOCUSED
)) {
3188 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_FOCUS
, unique_id_win());
3191 if ((ia_state_
& STATE_SYSTEM_SELECTED
) &&
3192 !(old_ia_state_
& STATE_SYSTEM_SELECTED
)) {
3193 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONADD
,
3195 } else if (!(ia_state_
& STATE_SYSTEM_SELECTED
) &&
3196 (old_ia_state_
& STATE_SYSTEM_SELECTED
)) {
3197 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONREMOVE
,
3201 old_ia_state_
= ia_state_
;
3204 // Fire an event if this container object has scrolled.
3207 if (GetIntAttribute(ui::AX_ATTR_SCROLL_X
, &sx
) &&
3208 GetIntAttribute(ui::AX_ATTR_SCROLL_Y
, &sy
)) {
3210 (sx
!= previous_scroll_x_
|| sy
!= previous_scroll_y_
)) {
3211 manager
->MaybeCallNotifyWinEvent(EVENT_SYSTEM_SCROLLINGEND
,
3214 previous_scroll_x_
= sx
;
3215 previous_scroll_y_
= sy
;
3218 first_time_
= false;
3221 void BrowserAccessibilityWin::NativeAddReference() {
3225 void BrowserAccessibilityWin::NativeReleaseReference() {
3229 bool BrowserAccessibilityWin::IsNative() const {
3233 void BrowserAccessibilityWin::OnLocationChanged() {
3234 manager()->ToBrowserAccessibilityManagerWin()->MaybeCallNotifyWinEvent(
3235 EVENT_OBJECT_LOCATIONCHANGE
, unique_id_win());
3238 BrowserAccessibilityWin
* BrowserAccessibilityWin::NewReference() {
3243 BrowserAccessibilityWin
* BrowserAccessibilityWin::GetTargetFromChildID(
3244 const VARIANT
& var_id
) {
3245 if (var_id
.vt
!= VT_I4
)
3248 LONG child_id
= var_id
.lVal
;
3249 if (child_id
== CHILDID_SELF
)
3252 if (child_id
>= 1 && child_id
<= static_cast<LONG
>(PlatformChildCount()))
3253 return PlatformGetChild(child_id
- 1)->ToBrowserAccessibilityWin();
3255 return manager()->ToBrowserAccessibilityManagerWin()->
3256 GetFromUniqueIdWin(child_id
);
3259 HRESULT
BrowserAccessibilityWin::GetStringAttributeAsBstr(
3260 ui::AXStringAttribute attribute
,
3264 if (!GetString16Attribute(attribute
, &str
))
3270 *value_bstr
= SysAllocString(str
.c_str());
3271 DCHECK(*value_bstr
);
3276 void BrowserAccessibilityWin::StringAttributeToIA2(
3277 ui::AXStringAttribute attribute
,
3278 const char* ia2_attr
) {
3279 base::string16 value
;
3280 if (GetString16Attribute(attribute
, &value
))
3281 ia2_attributes_
.push_back(base::ASCIIToUTF16(ia2_attr
) + L
":" + value
);
3284 void BrowserAccessibilityWin::BoolAttributeToIA2(
3285 ui::AXBoolAttribute attribute
,
3286 const char* ia2_attr
) {
3288 if (GetBoolAttribute(attribute
, &value
)) {
3289 ia2_attributes_
.push_back((base::ASCIIToUTF16(ia2_attr
) + L
":") +
3290 (value
? L
"true" : L
"false"));
3294 void BrowserAccessibilityWin::IntAttributeToIA2(
3295 ui::AXIntAttribute attribute
,
3296 const char* ia2_attr
) {
3298 if (GetIntAttribute(attribute
, &value
)) {
3299 ia2_attributes_
.push_back(base::ASCIIToUTF16(ia2_attr
) + L
":" +
3300 base::IntToString16(value
));
3304 base::string16
BrowserAccessibilityWin::GetValueText() {
3306 base::string16 value
= base::UTF8ToUTF16(this->value());
3308 if (value
.empty() &&
3309 GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE
, &fval
)) {
3310 value
= base::UTF8ToUTF16(base::DoubleToString(fval
));
3315 base::string16
BrowserAccessibilityWin::TextForIAccessibleText() {
3316 if (IsEditableText())
3317 return base::UTF8ToUTF16(value());
3318 return (GetRole() == ui::AX_ROLE_STATIC_TEXT
) ?
3319 base::UTF8ToUTF16(name()) : hypertext_
;
3322 void BrowserAccessibilityWin::HandleSpecialTextOffset(
3323 const base::string16
& text
,
3325 if (*offset
== IA2_TEXT_OFFSET_LENGTH
)
3326 *offset
= static_cast<LONG
>(text
.size());
3327 else if (*offset
== IA2_TEXT_OFFSET_CARET
)
3328 get_caretOffset(offset
);
3331 ui::TextBoundaryType
BrowserAccessibilityWin::IA2TextBoundaryToTextBoundary(
3332 IA2TextBoundaryType ia2_boundary
) {
3333 switch(ia2_boundary
) {
3334 case IA2_TEXT_BOUNDARY_CHAR
:
3335 return ui::CHAR_BOUNDARY
;
3336 case IA2_TEXT_BOUNDARY_WORD
:
3337 return ui::WORD_BOUNDARY
;
3338 case IA2_TEXT_BOUNDARY_LINE
:
3339 return ui::LINE_BOUNDARY
;
3340 case IA2_TEXT_BOUNDARY_SENTENCE
:
3341 return ui::SENTENCE_BOUNDARY
;
3342 case IA2_TEXT_BOUNDARY_PARAGRAPH
:
3343 return ui::PARAGRAPH_BOUNDARY
;
3344 case IA2_TEXT_BOUNDARY_ALL
:
3345 return ui::ALL_BOUNDARY
;
3349 return ui::CHAR_BOUNDARY
;
3352 LONG
BrowserAccessibilityWin::FindBoundary(
3353 const base::string16
& text
,
3354 IA2TextBoundaryType ia2_boundary
,
3356 ui::TextBoundaryDirection direction
) {
3357 HandleSpecialTextOffset(text
, &start_offset
);
3358 ui::TextBoundaryType boundary
= IA2TextBoundaryToTextBoundary(ia2_boundary
);
3359 const std::vector
<int32
>& line_breaks
= GetIntListAttribute(
3360 ui::AX_ATTR_LINE_BREAKS
);
3361 return ui::FindAccessibleTextBoundary(
3362 text
, line_breaks
, boundary
, start_offset
, direction
);
3365 BrowserAccessibilityWin
* BrowserAccessibilityWin::GetFromID(int32 id
) {
3366 return manager()->GetFromID(id
)->ToBrowserAccessibilityWin();
3369 void BrowserAccessibilityWin::InitRoleAndState() {
3371 ia2_state_
= IA2_STATE_OPAQUE
;
3372 ia2_attributes_
.clear();
3374 if (HasState(ui::AX_STATE_BUSY
))
3375 ia_state_
|= STATE_SYSTEM_BUSY
;
3376 if (HasState(ui::AX_STATE_CHECKED
))
3377 ia_state_
|= STATE_SYSTEM_CHECKED
;
3378 if (HasState(ui::AX_STATE_COLLAPSED
))
3379 ia_state_
|= STATE_SYSTEM_COLLAPSED
;
3380 if (HasState(ui::AX_STATE_EXPANDED
))
3381 ia_state_
|= STATE_SYSTEM_EXPANDED
;
3382 if (HasState(ui::AX_STATE_FOCUSABLE
))
3383 ia_state_
|= STATE_SYSTEM_FOCUSABLE
;
3384 if (HasState(ui::AX_STATE_HASPOPUP
))
3385 ia_state_
|= STATE_SYSTEM_HASPOPUP
;
3386 if (HasState(ui::AX_STATE_HOVERED
))
3387 ia_state_
|= STATE_SYSTEM_HOTTRACKED
;
3388 if (HasState(ui::AX_STATE_INDETERMINATE
))
3389 ia_state_
|= STATE_SYSTEM_INDETERMINATE
;
3390 if (HasIntAttribute(ui::AX_ATTR_INVALID_STATE
) &&
3391 GetIntAttribute(ui::AX_ATTR_INVALID_STATE
) != ui::AX_INVALID_STATE_FALSE
)
3392 ia2_state_
|= IA2_STATE_INVALID_ENTRY
;
3393 if (HasState(ui::AX_STATE_INVISIBLE
))
3394 ia_state_
|= STATE_SYSTEM_INVISIBLE
;
3395 if (HasState(ui::AX_STATE_LINKED
))
3396 ia_state_
|= STATE_SYSTEM_LINKED
;
3397 if (HasState(ui::AX_STATE_MULTISELECTABLE
)) {
3398 ia_state_
|= STATE_SYSTEM_EXTSELECTABLE
;
3399 ia_state_
|= STATE_SYSTEM_MULTISELECTABLE
;
3401 // TODO(ctguil): Support STATE_SYSTEM_EXTSELECTABLE/accSelect.
3402 if (HasState(ui::AX_STATE_OFFSCREEN
))
3403 ia_state_
|= STATE_SYSTEM_OFFSCREEN
;
3404 if (HasState(ui::AX_STATE_PRESSED
))
3405 ia_state_
|= STATE_SYSTEM_PRESSED
;
3406 if (HasState(ui::AX_STATE_PROTECTED
))
3407 ia_state_
|= STATE_SYSTEM_PROTECTED
;
3408 if (HasState(ui::AX_STATE_REQUIRED
))
3409 ia2_state_
|= IA2_STATE_REQUIRED
;
3410 if (HasState(ui::AX_STATE_SELECTABLE
))
3411 ia_state_
|= STATE_SYSTEM_SELECTABLE
;
3412 if (HasState(ui::AX_STATE_SELECTED
))
3413 ia_state_
|= STATE_SYSTEM_SELECTED
;
3414 if (HasState(ui::AX_STATE_VISITED
))
3415 ia_state_
|= STATE_SYSTEM_TRAVERSED
;
3416 if (!HasState(ui::AX_STATE_ENABLED
))
3417 ia_state_
|= STATE_SYSTEM_UNAVAILABLE
;
3418 if (HasState(ui::AX_STATE_VERTICAL
))
3419 ia2_state_
|= IA2_STATE_VERTICAL
;
3420 if (HasState(ui::AX_STATE_HORIZONTAL
))
3421 ia2_state_
|= IA2_STATE_HORIZONTAL
;
3422 if (HasState(ui::AX_STATE_VISITED
))
3423 ia_state_
|= STATE_SYSTEM_TRAVERSED
;
3425 // WebKit marks everything as readonly unless it's editable text, so if it's
3426 // not readonly, mark it as editable now. The final computation of the
3427 // READONLY state for MSAA is below, after the switch.
3428 if (!HasState(ui::AX_STATE_READ_ONLY
))
3429 ia2_state_
|= IA2_STATE_EDITABLE
;
3431 if (GetBoolAttribute(ui::AX_ATTR_BUTTON_MIXED
))
3432 ia_state_
|= STATE_SYSTEM_MIXED
;
3434 if (GetBoolAttribute(ui::AX_ATTR_CAN_SET_VALUE
))
3435 ia2_state_
|= IA2_STATE_EDITABLE
;
3437 if (!GetStringAttribute(ui::AX_ATTR_AUTO_COMPLETE
).empty())
3438 ia2_state_
|= IA2_STATE_SUPPORTS_AUTOCOMPLETION
;
3440 base::string16 html_tag
= GetString16Attribute(
3441 ui::AX_ATTR_HTML_TAG
);
3444 switch (GetRole()) {
3445 case ui::AX_ROLE_ALERT
:
3446 ia_role_
= ROLE_SYSTEM_ALERT
;
3448 case ui::AX_ROLE_ALERT_DIALOG
:
3449 ia_role_
= ROLE_SYSTEM_DIALOG
;
3451 case ui::AX_ROLE_APPLICATION
:
3452 ia_role_
= ROLE_SYSTEM_APPLICATION
;
3454 case ui::AX_ROLE_ARTICLE
:
3455 ia_role_
= ROLE_SYSTEM_DOCUMENT
;
3456 ia_state_
|= STATE_SYSTEM_READONLY
;
3458 case ui::AX_ROLE_BANNER
:
3459 ia_role_
= ROLE_SYSTEM_GROUPING
;
3460 ia2_role_
= IA2_ROLE_HEADER
;
3462 case ui::AX_ROLE_BLOCKQUOTE
:
3463 role_name_
= html_tag
;
3464 ia2_role_
= IA2_ROLE_SECTION
;
3466 case ui::AX_ROLE_BUSY_INDICATOR
:
3467 ia_role_
= ROLE_SYSTEM_ANIMATION
;
3468 ia_state_
|= STATE_SYSTEM_READONLY
;
3470 case ui::AX_ROLE_BUTTON
:
3471 ia_role_
= ROLE_SYSTEM_PUSHBUTTON
;
3473 case ui::AX_ROLE_CANVAS
:
3474 if (GetBoolAttribute(ui::AX_ATTR_CANVAS_HAS_FALLBACK
)) {
3475 role_name_
= L
"canvas";
3476 ia2_role_
= IA2_ROLE_CANVAS
;
3478 ia_role_
= ROLE_SYSTEM_GRAPHIC
;
3481 case ui::AX_ROLE_CAPTION
:
3482 ia_role_
= ROLE_SYSTEM_TEXT
;
3483 ia2_role_
= IA2_ROLE_CAPTION
;
3485 case ui::AX_ROLE_CELL
:
3486 ia_role_
= ROLE_SYSTEM_CELL
;
3488 case ui::AX_ROLE_CHECK_BOX
:
3489 ia_role_
= ROLE_SYSTEM_CHECKBUTTON
;
3490 ia2_state_
|= IA2_STATE_CHECKABLE
;
3492 case ui::AX_ROLE_COLOR_WELL
:
3493 ia_role_
= ROLE_SYSTEM_TEXT
;
3494 ia2_role_
= IA2_ROLE_COLOR_CHOOSER
;
3496 case ui::AX_ROLE_COLUMN
:
3497 ia_role_
= ROLE_SYSTEM_COLUMN
;
3499 case ui::AX_ROLE_COLUMN_HEADER
:
3500 ia_role_
= ROLE_SYSTEM_COLUMNHEADER
;
3502 case ui::AX_ROLE_COMBO_BOX
:
3503 ia_role_
= ROLE_SYSTEM_COMBOBOX
;
3505 case ui::AX_ROLE_COMPLEMENTARY
:
3506 ia_role_
= ROLE_SYSTEM_GROUPING
;
3507 ia2_role_
= IA2_ROLE_NOTE
;
3509 case ui::AX_ROLE_CONTENT_INFO
:
3510 ia_role_
= ROLE_SYSTEM_TEXT
;
3511 ia2_role_
= IA2_ROLE_PARAGRAPH
;
3513 case ui::AX_ROLE_DATE
:
3514 case ui::AX_ROLE_DATE_TIME
:
3515 ia_role_
= ROLE_SYSTEM_DROPLIST
;
3516 ia2_role_
= IA2_ROLE_DATE_EDITOR
;
3518 case ui::AX_ROLE_DIV
:
3519 role_name_
= L
"div";
3520 ia_role_
= ROLE_SYSTEM_GROUPING
;
3521 ia2_role_
= IA2_ROLE_SECTION
;
3523 case ui::AX_ROLE_DEFINITION
:
3524 role_name_
= html_tag
;
3525 ia2_role_
= IA2_ROLE_PARAGRAPH
;
3526 ia_state_
|= STATE_SYSTEM_READONLY
;
3528 case ui::AX_ROLE_DESCRIPTION_LIST_DETAIL
:
3529 role_name_
= html_tag
;
3530 ia_role_
= ROLE_SYSTEM_TEXT
;
3531 ia2_role_
= IA2_ROLE_PARAGRAPH
;
3533 case ui::AX_ROLE_DESCRIPTION_LIST
:
3534 role_name_
= html_tag
;
3535 ia_role_
= ROLE_SYSTEM_LIST
;
3536 ia_state_
|= STATE_SYSTEM_READONLY
;
3538 case ui::AX_ROLE_DESCRIPTION_LIST_TERM
:
3539 ia_role_
= ROLE_SYSTEM_LISTITEM
;
3540 ia_state_
|= STATE_SYSTEM_READONLY
;
3542 case ui::AX_ROLE_DETAILS
:
3543 role_name_
= html_tag
;
3544 ia_role_
= ROLE_SYSTEM_GROUPING
;
3546 case ui::AX_ROLE_DIALOG
:
3547 ia_role_
= ROLE_SYSTEM_DIALOG
;
3549 case ui::AX_ROLE_DISCLOSURE_TRIANGLE
:
3550 ia_role_
= ROLE_SYSTEM_PUSHBUTTON
;
3552 case ui::AX_ROLE_DOCUMENT
:
3553 case ui::AX_ROLE_ROOT_WEB_AREA
:
3554 case ui::AX_ROLE_WEB_AREA
:
3555 ia_role_
= ROLE_SYSTEM_DOCUMENT
;
3556 ia_state_
|= STATE_SYSTEM_READONLY
;
3557 ia_state_
|= STATE_SYSTEM_FOCUSABLE
;
3559 case ui::AX_ROLE_EMBEDDED_OBJECT
:
3560 ia_role_
= ROLE_SYSTEM_CLIENT
;
3561 ia2_role_
= IA2_ROLE_EMBEDDED_OBJECT
;
3563 case ui::AX_ROLE_FIGCAPTION
:
3564 role_name_
= html_tag
;
3565 ia2_role_
= IA2_ROLE_CAPTION
;
3567 case ui::AX_ROLE_FIGURE
:
3568 ia_role_
= ROLE_SYSTEM_GROUPING
;
3570 case ui::AX_ROLE_FORM
:
3571 role_name_
= L
"form";
3572 ia2_role_
= IA2_ROLE_FORM
;
3574 case ui::AX_ROLE_FOOTER
:
3575 ia_role_
= ROLE_SYSTEM_GROUPING
;
3576 ia2_role_
= IA2_ROLE_FOOTER
;
3578 case ui::AX_ROLE_GRID
:
3579 ia_role_
= ROLE_SYSTEM_TABLE
;
3580 ia_state_
|= STATE_SYSTEM_READONLY
;
3582 case ui::AX_ROLE_GROUP
: {
3583 base::string16 aria_role
= GetString16Attribute(
3585 if (aria_role
== L
"group" || html_tag
== L
"fieldset") {
3586 ia_role_
= ROLE_SYSTEM_GROUPING
;
3587 } else if (html_tag
== L
"li") {
3588 ia_role_
= ROLE_SYSTEM_LISTITEM
;
3589 ia_state_
|= STATE_SYSTEM_READONLY
;
3591 if (html_tag
.empty())
3592 role_name_
= L
"div";
3594 role_name_
= html_tag
;
3595 ia2_role_
= IA2_ROLE_SECTION
;
3599 case ui::AX_ROLE_HEADING
:
3600 role_name_
= html_tag
;
3601 ia2_role_
= IA2_ROLE_HEADING
;
3603 case ui::AX_ROLE_IFRAME
:
3604 ia_role_
= ROLE_SYSTEM_DOCUMENT
;
3605 ia2_role_
= IA2_ROLE_INTERNAL_FRAME
;
3606 ia_state_
= STATE_SYSTEM_READONLY
;
3608 case ui::AX_ROLE_IFRAME_PRESENTATIONAL
:
3609 ia_role_
= ROLE_SYSTEM_GROUPING
;
3611 case ui::AX_ROLE_IMAGE
:
3612 ia_role_
= ROLE_SYSTEM_GRAPHIC
;
3613 ia_state_
|= STATE_SYSTEM_READONLY
;
3615 case ui::AX_ROLE_IMAGE_MAP
:
3616 role_name_
= html_tag
;
3617 ia2_role_
= IA2_ROLE_IMAGE_MAP
;
3618 ia_state_
|= STATE_SYSTEM_READONLY
;
3620 case ui::AX_ROLE_IMAGE_MAP_LINK
:
3621 ia_role_
= ROLE_SYSTEM_LINK
;
3622 ia_state_
|= STATE_SYSTEM_LINKED
;
3623 ia_state_
|= STATE_SYSTEM_READONLY
;
3625 case ui::AX_ROLE_LABEL_TEXT
:
3626 case ui::AX_ROLE_LEGEND
:
3627 ia_role_
= ROLE_SYSTEM_TEXT
;
3628 ia2_role_
= IA2_ROLE_LABEL
;
3630 case ui::AX_ROLE_SEARCH
:
3631 ia_role_
= ROLE_SYSTEM_GROUPING
;
3632 ia2_role_
= IA2_ROLE_SECTION
;
3634 case ui::AX_ROLE_LINK
:
3635 ia_role_
= ROLE_SYSTEM_LINK
;
3636 ia_state_
|= STATE_SYSTEM_LINKED
;
3638 case ui::AX_ROLE_LIST
:
3639 ia_role_
= ROLE_SYSTEM_LIST
;
3640 ia_state_
|= STATE_SYSTEM_READONLY
;
3642 case ui::AX_ROLE_LIST_BOX
:
3643 ia_role_
= ROLE_SYSTEM_LIST
;
3645 case ui::AX_ROLE_LIST_BOX_OPTION
:
3646 ia_role_
= ROLE_SYSTEM_LISTITEM
;
3647 if (ia_state_
& STATE_SYSTEM_SELECTABLE
) {
3648 ia_state_
|= STATE_SYSTEM_FOCUSABLE
;
3649 if (HasState(ui::AX_STATE_FOCUSED
))
3650 ia_state_
|= STATE_SYSTEM_FOCUSED
;
3653 case ui::AX_ROLE_LIST_ITEM
:
3654 ia_role_
= ROLE_SYSTEM_LISTITEM
;
3655 ia_state_
|= STATE_SYSTEM_READONLY
;
3657 case ui::AX_ROLE_MAIN
:
3658 ia_role_
= ROLE_SYSTEM_GROUPING
;
3659 ia2_role_
= IA2_ROLE_PARAGRAPH
;
3661 case ui::AX_ROLE_MARQUEE
:
3662 ia_role_
= ROLE_SYSTEM_ANIMATION
;
3664 case ui::AX_ROLE_MATH
:
3665 ia_role_
= ROLE_SYSTEM_EQUATION
;
3667 case ui::AX_ROLE_MENU
:
3668 case ui::AX_ROLE_MENU_BUTTON
:
3669 ia_role_
= ROLE_SYSTEM_MENUPOPUP
;
3671 case ui::AX_ROLE_MENU_BAR
:
3672 ia_role_
= ROLE_SYSTEM_MENUBAR
;
3674 case ui::AX_ROLE_MENU_ITEM
:
3675 ia_role_
= ROLE_SYSTEM_MENUITEM
;
3677 case ui::AX_ROLE_MENU_ITEM_CHECK_BOX
:
3678 ia_role_
= ROLE_SYSTEM_MENUITEM
;
3679 ia2_role_
= IA2_ROLE_CHECK_MENU_ITEM
;
3680 ia2_state_
|= IA2_STATE_CHECKABLE
;
3682 case ui::AX_ROLE_MENU_ITEM_RADIO
:
3683 ia_role_
= ROLE_SYSTEM_MENUITEM
;
3684 ia2_role_
= IA2_ROLE_RADIO_MENU_ITEM
;
3686 case ui::AX_ROLE_MENU_LIST_POPUP
:
3687 ia_role_
= ROLE_SYSTEM_CLIENT
;
3689 case ui::AX_ROLE_MENU_LIST_OPTION
:
3690 ia_role_
= ROLE_SYSTEM_LISTITEM
;
3691 if (ia_state_
& STATE_SYSTEM_SELECTABLE
) {
3692 ia_state_
|= STATE_SYSTEM_FOCUSABLE
;
3693 if (HasState(ui::AX_STATE_FOCUSED
))
3694 ia_state_
|= STATE_SYSTEM_FOCUSED
;
3697 case ui::AX_ROLE_METER
:
3698 role_name_
= html_tag
;
3699 ia_role_
= ROLE_SYSTEM_PROGRESSBAR
;
3701 case ui::AX_ROLE_NAVIGATION
:
3702 ia_role_
= ROLE_SYSTEM_GROUPING
;
3703 ia2_role_
= IA2_ROLE_SECTION
;
3705 case ui::AX_ROLE_NOTE
:
3706 ia_role_
= ROLE_SYSTEM_GROUPING
;
3707 ia2_role_
= IA2_ROLE_NOTE
;
3709 case ui::AX_ROLE_OUTLINE
:
3710 ia_role_
= ROLE_SYSTEM_OUTLINE
;
3712 case ui::AX_ROLE_PARAGRAPH
:
3714 ia2_role_
= IA2_ROLE_PARAGRAPH
;
3716 case ui::AX_ROLE_POP_UP_BUTTON
:
3717 if (html_tag
== L
"select") {
3718 ia_role_
= ROLE_SYSTEM_COMBOBOX
;
3720 ia_role_
= ROLE_SYSTEM_BUTTONMENU
;
3723 case ui::AX_ROLE_PRE
:
3724 role_name_
= html_tag
;
3725 ia_role_
= ROLE_SYSTEM_TEXT
;
3726 ia2_role_
= IA2_ROLE_PARAGRAPH
;
3728 case ui::AX_ROLE_PROGRESS_INDICATOR
:
3729 ia_role_
= ROLE_SYSTEM_PROGRESSBAR
;
3730 ia_state_
|= STATE_SYSTEM_READONLY
;
3732 case ui::AX_ROLE_RADIO_BUTTON
:
3733 ia_role_
= ROLE_SYSTEM_RADIOBUTTON
;
3734 ia2_state_
= IA2_STATE_CHECKABLE
;
3736 case ui::AX_ROLE_RADIO_GROUP
:
3737 ia_role_
= ROLE_SYSTEM_GROUPING
;
3739 case ui::AX_ROLE_REGION
:
3740 if (html_tag
== L
"section") {
3741 ia_role_
= ROLE_SYSTEM_GROUPING
;
3742 ia2_role_
= IA2_ROLE_SECTION
;
3744 ia_role_
= ROLE_SYSTEM_PANE
;
3747 case ui::AX_ROLE_ROW
:
3748 ia_role_
= ROLE_SYSTEM_ROW
;
3750 case ui::AX_ROLE_ROW_HEADER
:
3751 ia_role_
= ROLE_SYSTEM_ROWHEADER
;
3753 case ui::AX_ROLE_RUBY
:
3754 ia_role_
= ROLE_SYSTEM_TEXT
;
3755 ia2_role_
= IA2_ROLE_TEXT_FRAME
;
3757 case ui::AX_ROLE_RULER
:
3758 ia_role_
= ROLE_SYSTEM_CLIENT
;
3759 ia2_role_
= IA2_ROLE_RULER
;
3760 ia_state_
|= STATE_SYSTEM_READONLY
;
3762 case ui::AX_ROLE_SCROLL_AREA
:
3763 ia_role_
= ROLE_SYSTEM_CLIENT
;
3764 ia2_role_
= IA2_ROLE_SCROLL_PANE
;
3765 ia_state_
|= STATE_SYSTEM_READONLY
;
3766 ia2_state_
&= ~(IA2_STATE_EDITABLE
);
3768 case ui::AX_ROLE_SCROLL_BAR
:
3769 ia_role_
= ROLE_SYSTEM_SCROLLBAR
;
3771 case ui::AX_ROLE_SLIDER
:
3772 ia_role_
= ROLE_SYSTEM_SLIDER
;
3774 case ui::AX_ROLE_SPIN_BUTTON
:
3775 ia_role_
= ROLE_SYSTEM_SPINBUTTON
;
3777 case ui::AX_ROLE_SPIN_BUTTON_PART
:
3778 ia_role_
= ROLE_SYSTEM_PUSHBUTTON
;
3780 case ui::AX_ROLE_ANNOTATION
:
3781 case ui::AX_ROLE_LIST_MARKER
:
3782 case ui::AX_ROLE_STATIC_TEXT
:
3783 ia_role_
= ROLE_SYSTEM_STATICTEXT
;
3785 case ui::AX_ROLE_STATUS
:
3786 ia_role_
= ROLE_SYSTEM_STATUSBAR
;
3788 case ui::AX_ROLE_SPLITTER
:
3789 ia_role_
= ROLE_SYSTEM_SEPARATOR
;
3791 case ui::AX_ROLE_SVG_ROOT
:
3792 ia_role_
= ROLE_SYSTEM_GRAPHIC
;
3794 case ui::AX_ROLE_TAB
:
3795 ia_role_
= ROLE_SYSTEM_PAGETAB
;
3797 case ui::AX_ROLE_TABLE
: {
3798 base::string16 aria_role
= GetString16Attribute(
3800 if (aria_role
== L
"treegrid") {
3801 ia_role_
= ROLE_SYSTEM_OUTLINE
;
3803 ia_role_
= ROLE_SYSTEM_TABLE
;
3807 case ui::AX_ROLE_TABLE_HEADER_CONTAINER
:
3808 ia_role_
= ROLE_SYSTEM_GROUPING
;
3809 ia2_role_
= IA2_ROLE_SECTION
;
3810 ia_state_
|= STATE_SYSTEM_READONLY
;
3812 case ui::AX_ROLE_TAB_LIST
:
3813 ia_role_
= ROLE_SYSTEM_PAGETABLIST
;
3815 case ui::AX_ROLE_TAB_PANEL
:
3816 ia_role_
= ROLE_SYSTEM_PROPERTYPAGE
;
3818 case ui::AX_ROLE_TOGGLE_BUTTON
:
3819 ia_role_
= ROLE_SYSTEM_PUSHBUTTON
;
3820 ia2_role_
= IA2_ROLE_TOGGLE_BUTTON
;
3822 case ui::AX_ROLE_TEXT_AREA
:
3823 ia_role_
= ROLE_SYSTEM_TEXT
;
3824 ia2_state_
|= IA2_STATE_MULTI_LINE
;
3825 ia2_state_
|= IA2_STATE_EDITABLE
;
3826 ia2_state_
|= IA2_STATE_SELECTABLE_TEXT
;
3828 case ui::AX_ROLE_TEXT_FIELD
:
3829 ia_role_
= ROLE_SYSTEM_TEXT
;
3830 ia2_state_
|= IA2_STATE_SINGLE_LINE
;
3831 ia2_state_
|= IA2_STATE_EDITABLE
;
3832 ia2_state_
|= IA2_STATE_SELECTABLE_TEXT
;
3834 case ui::AX_ROLE_TIME
:
3835 ia_role_
= ROLE_SYSTEM_SPINBUTTON
;
3837 case ui::AX_ROLE_TIMER
:
3838 ia_role_
= ROLE_SYSTEM_CLOCK
;
3839 ia_state_
|= STATE_SYSTEM_READONLY
;
3841 case ui::AX_ROLE_TOOLBAR
:
3842 ia_role_
= ROLE_SYSTEM_TOOLBAR
;
3843 ia_state_
|= STATE_SYSTEM_READONLY
;
3845 case ui::AX_ROLE_TOOLTIP
:
3846 ia_role_
= ROLE_SYSTEM_TOOLTIP
;
3847 ia_state_
|= STATE_SYSTEM_READONLY
;
3849 case ui::AX_ROLE_TREE
:
3850 ia_role_
= ROLE_SYSTEM_OUTLINE
;
3852 case ui::AX_ROLE_TREE_GRID
:
3853 ia_role_
= ROLE_SYSTEM_OUTLINE
;
3855 case ui::AX_ROLE_TREE_ITEM
:
3856 ia_role_
= ROLE_SYSTEM_OUTLINEITEM
;
3858 case ui::AX_ROLE_LINE_BREAK
:
3859 ia_role_
= ROLE_SYSTEM_WHITESPACE
;
3861 case ui::AX_ROLE_WINDOW
:
3862 ia_role_
= ROLE_SYSTEM_WINDOW
;
3865 // TODO(dmazzoni): figure out the proper MSAA role for all of these.
3866 case ui::AX_ROLE_DIRECTORY
:
3867 case ui::AX_ROLE_IGNORED
:
3868 case ui::AX_ROLE_LOG
:
3869 case ui::AX_ROLE_NONE
:
3870 case ui::AX_ROLE_PRESENTATIONAL
:
3871 case ui::AX_ROLE_SLIDER_THUMB
:
3873 ia_role_
= ROLE_SYSTEM_CLIENT
;
3877 // Compute the final value of READONLY for MSAA.
3879 // We always set the READONLY state for elements that have the
3880 // aria-readonly attribute and for a few roles (in the switch above).
3881 // We clear the READONLY state on focusable controls and on a document.
3882 // Everything else, the majority of objects, do not have this state set.
3883 if (HasState(ui::AX_STATE_FOCUSABLE
) &&
3884 ia_role_
!= ROLE_SYSTEM_DOCUMENT
) {
3885 ia_state_
&= ~(STATE_SYSTEM_READONLY
);
3887 if (!HasState(ui::AX_STATE_READ_ONLY
))
3888 ia_state_
&= ~(STATE_SYSTEM_READONLY
);
3889 if (GetBoolAttribute(ui::AX_ATTR_ARIA_READONLY
))
3890 ia_state_
|= STATE_SYSTEM_READONLY
;
3892 // The role should always be set.
3893 DCHECK(!role_name_
.empty() || ia_role_
);
3895 // If we didn't explicitly set the IAccessible2 role, make it the same
3896 // as the MSAA role.
3898 ia2_role_
= ia_role_
;
3901 } // namespace content