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
= {0x0c539790,
34 {0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8}};
35 const GUID GUID_IAccessibleContentDocument
= {
39 {0x95, 0x21, 0x07, 0xed, 0x28, 0xfb, 0x07, 0x2e}};
41 const base::char16
BrowserAccessibilityWin::kEmbeddedCharacter
= L
'\xfffc';
44 LONG
BrowserAccessibilityWin::next_unique_id_win_
=
45 base::win::kFirstBrowserAccessibilityManagerAccessibilityId
;
48 // BrowserAccessibilityRelation
50 // A simple implementation of IAccessibleRelation, used to represent
51 // a relationship between two accessible nodes in the tree.
54 class BrowserAccessibilityRelation
55 : public CComObjectRootEx
<CComMultiThreadModel
>,
56 public IAccessibleRelation
{
57 BEGIN_COM_MAP(BrowserAccessibilityRelation
)
58 COM_INTERFACE_ENTRY(IAccessibleRelation
)
61 CONTENT_EXPORT
BrowserAccessibilityRelation() {}
62 CONTENT_EXPORT
virtual ~BrowserAccessibilityRelation() {}
64 CONTENT_EXPORT
void Initialize(BrowserAccessibilityWin
* owner
,
65 const base::string16
& type
);
66 CONTENT_EXPORT
void AddTarget(int target_id
);
68 // IAccessibleRelation methods.
69 CONTENT_EXPORT STDMETHODIMP
get_relationType(BSTR
* relation_type
) override
;
70 CONTENT_EXPORT STDMETHODIMP
get_nTargets(long* n_targets
) override
;
71 CONTENT_EXPORT STDMETHODIMP
72 get_target(long target_index
, IUnknown
** target
) override
;
73 CONTENT_EXPORT STDMETHODIMP
74 get_targets(long max_targets
, IUnknown
** targets
, long* n_targets
) override
;
76 // IAccessibleRelation methods not implemented.
77 CONTENT_EXPORT STDMETHODIMP
78 get_localizedRelationType(BSTR
* relation_type
) override
{
84 base::win::ScopedComPtr
<BrowserAccessibilityWin
> owner_
;
85 std::vector
<int> target_ids_
;
88 void BrowserAccessibilityRelation::Initialize(BrowserAccessibilityWin
* owner
,
89 const base::string16
& type
) {
94 void BrowserAccessibilityRelation::AddTarget(int target_id
) {
95 target_ids_
.push_back(target_id
);
98 STDMETHODIMP
BrowserAccessibilityRelation::get_relationType(
99 BSTR
* relation_type
) {
103 if (!owner_
->instance_active())
106 *relation_type
= SysAllocString(type_
.c_str());
107 DCHECK(*relation_type
);
111 STDMETHODIMP
BrowserAccessibilityRelation::get_nTargets(long* n_targets
) {
115 if (!owner_
->instance_active())
118 *n_targets
= static_cast<long>(target_ids_
.size());
120 BrowserAccessibilityManager
* manager
= owner_
->manager();
121 for (long i
= *n_targets
- 1; i
>= 0; --i
) {
122 BrowserAccessibility
* result
= manager
->GetFromID(target_ids_
[i
]);
123 if (!result
|| !result
->instance_active()) {
131 STDMETHODIMP
BrowserAccessibilityRelation::get_target(long target_index
,
136 if (!owner_
->instance_active())
139 if (target_index
< 0 ||
140 target_index
>= static_cast<long>(target_ids_
.size())) {
144 BrowserAccessibilityManager
* manager
= owner_
->manager();
145 BrowserAccessibility
* result
=
146 manager
->GetFromID(target_ids_
[target_index
]);
147 if (!result
|| !result
->instance_active())
150 *target
= static_cast<IAccessible
*>(
151 result
->ToBrowserAccessibilityWin()->NewReference());
155 STDMETHODIMP
BrowserAccessibilityRelation::get_targets(long max_targets
,
158 if (!targets
|| !n_targets
)
161 if (!owner_
->instance_active())
164 long count
= static_cast<long>(target_ids_
.size());
165 if (count
> max_targets
)
172 for (long i
= 0; i
< count
; ++i
) {
173 HRESULT result
= get_target(i
, &targets
[i
]);
182 // BrowserAccessibilityWin::WinAttributes
185 BrowserAccessibilityWin::WinAttributes::WinAttributes()
192 BrowserAccessibilityWin::WinAttributes::~WinAttributes() {
196 // BrowserAccessibilityWin
200 BrowserAccessibility
* BrowserAccessibility::Create() {
201 ui::win::CreateATLModuleIfNeeded();
202 CComObject
<BrowserAccessibilityWin
>* instance
;
203 HRESULT hr
= CComObject
<BrowserAccessibilityWin
>::CreateInstance(&instance
);
204 DCHECK(SUCCEEDED(hr
));
205 return instance
->NewReference();
208 BrowserAccessibilityWin
* BrowserAccessibility::ToBrowserAccessibilityWin() {
209 return static_cast<BrowserAccessibilityWin
*>(this);
212 BrowserAccessibilityWin::BrowserAccessibilityWin()
213 : win_attributes_(new WinAttributes()),
214 previous_scroll_x_(0),
215 previous_scroll_y_(0) {
216 // Start unique IDs at -1 and decrement each time, because get_accChild
217 // uses positive IDs to enumerate children, so we use negative IDs to
218 // clearly distinguish between indices and unique IDs.
219 unique_id_win_
= next_unique_id_win_
;
220 if (next_unique_id_win_
==
221 base::win::kLastBrowserAccessibilityManagerAccessibilityId
) {
222 next_unique_id_win_
=
223 base::win::kFirstBrowserAccessibilityManagerAccessibilityId
;
225 next_unique_id_win_
--;
228 BrowserAccessibilityWin::~BrowserAccessibilityWin() {
229 for (size_t i
= 0; i
< relations_
.size(); ++i
)
230 relations_
[i
]->Release();
234 // IAccessible methods.
237 // * Always test for instance_active() first and return E_FAIL if it's false.
238 // * Always check for invalid arguments first, even if they're unused.
239 // * Return S_FALSE if the only output is a string argument and it's empty.
242 HRESULT
BrowserAccessibilityWin::accDoDefaultAction(VARIANT var_id
) {
243 if (!instance_active())
246 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
250 manager()->DoDefaultAction(*target
);
254 STDMETHODIMP
BrowserAccessibilityWin::accHitTest(LONG x_left
,
257 if (!instance_active())
263 gfx::Point
point(x_left
, y_top
);
264 if (!GetGlobalBoundsRect().Contains(point
)) {
265 // Return S_FALSE and VT_EMPTY when the outside the object's boundaries.
266 child
->vt
= VT_EMPTY
;
270 BrowserAccessibility
* result
= BrowserAccessibilityForPoint(point
);
271 if (result
== this) {
272 // Point is within this object.
274 child
->lVal
= CHILDID_SELF
;
276 child
->vt
= VT_DISPATCH
;
277 child
->pdispVal
= result
->ToBrowserAccessibilityWin()->NewReference();
282 STDMETHODIMP
BrowserAccessibilityWin::accLocation(LONG
* x_left
,
287 if (!instance_active())
290 if (!x_left
|| !y_top
|| !width
|| !height
)
293 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
297 gfx::Rect bounds
= target
->GetGlobalBoundsRect();
298 *x_left
= bounds
.x();
300 *width
= bounds
.width();
301 *height
= bounds
.height();
306 STDMETHODIMP
BrowserAccessibilityWin::accNavigate(LONG nav_dir
,
309 BrowserAccessibilityWin
* target
= GetTargetFromChildID(start
);
313 if ((nav_dir
== NAVDIR_LASTCHILD
|| nav_dir
== NAVDIR_FIRSTCHILD
) &&
314 start
.lVal
!= CHILDID_SELF
) {
315 // MSAA states that navigating to first/last child can only be from self.
319 uint32 child_count
= target
->PlatformChildCount();
321 BrowserAccessibility
* result
= NULL
;
327 // These directions are not implemented, matching Mozilla and IE.
329 case NAVDIR_FIRSTCHILD
:
331 result
= target
->PlatformGetChild(0);
333 case NAVDIR_LASTCHILD
:
335 result
= target
->PlatformGetChild(child_count
- 1);
338 result
= target
->GetNextSibling();
340 case NAVDIR_PREVIOUS
:
341 result
= target
->GetPreviousSibling();
350 end
->vt
= VT_DISPATCH
;
351 end
->pdispVal
= result
->ToBrowserAccessibilityWin()->NewReference();
355 STDMETHODIMP
BrowserAccessibilityWin::get_accChild(VARIANT var_child
,
356 IDispatch
** disp_child
) {
357 if (!instance_active())
365 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_child
);
369 (*disp_child
) = target
->NewReference();
373 STDMETHODIMP
BrowserAccessibilityWin::get_accChildCount(LONG
* child_count
) {
374 if (!instance_active())
380 *child_count
= PlatformChildCount();
385 STDMETHODIMP
BrowserAccessibilityWin::get_accDefaultAction(VARIANT var_id
,
387 if (!instance_active())
393 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
397 return target
->GetStringAttributeAsBstr(
398 ui::AX_ATTR_ACTION
, def_action
);
401 STDMETHODIMP
BrowserAccessibilityWin::get_accDescription(VARIANT var_id
,
403 if (!instance_active())
409 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
413 base::string16 description_str
= target
->description();
414 if (description_str
.empty())
417 *desc
= SysAllocString(description_str
.c_str());
423 STDMETHODIMP
BrowserAccessibilityWin::get_accFocus(VARIANT
* focus_child
) {
424 if (!instance_active())
430 BrowserAccessibilityWin
* focus
= static_cast<BrowserAccessibilityWin
*>(
431 manager()->GetFocus(this));
433 focus_child
->vt
= VT_I4
;
434 focus_child
->lVal
= CHILDID_SELF
;
435 } else if (focus
== NULL
) {
436 focus_child
->vt
= VT_EMPTY
;
438 focus_child
->vt
= VT_DISPATCH
;
439 focus_child
->pdispVal
= focus
->NewReference();
445 STDMETHODIMP
BrowserAccessibilityWin::get_accHelp(VARIANT var_id
, BSTR
* help
) {
446 if (!instance_active())
452 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
456 base::string16 help_str
= target
->help();
457 if (help_str
.empty())
460 *help
= SysAllocString(help_str
.c_str());
466 STDMETHODIMP
BrowserAccessibilityWin::get_accKeyboardShortcut(VARIANT var_id
,
468 if (!instance_active())
474 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
478 return target
->GetStringAttributeAsBstr(
479 ui::AX_ATTR_SHORTCUT
, acc_key
);
482 STDMETHODIMP
BrowserAccessibilityWin::get_accName(VARIANT var_id
, BSTR
* name
) {
483 if (!instance_active())
489 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
493 base::string16 name_str
= target
->name();
495 // If the name is empty, see if it's labeled by another element.
496 if (name_str
.empty()) {
498 if (target
->GetIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT
,
500 BrowserAccessibilityWin
* title_elem
=
501 manager()->GetFromID(title_elem_id
)->ToBrowserAccessibilityWin();
503 name_str
= title_elem
->GetNameRecursive();
507 if (name_str
.empty())
510 *name
= SysAllocString(name_str
.c_str());
516 STDMETHODIMP
BrowserAccessibilityWin::get_accParent(IDispatch
** disp_parent
) {
517 if (!instance_active())
523 IAccessible
* parent_obj
= GetParent()->ToBrowserAccessibilityWin();
524 if (parent_obj
== NULL
) {
525 // This happens if we're the root of the tree;
526 // return the IAccessible for the window.
528 manager()->ToBrowserAccessibilityManagerWin()->GetParentIAccessible();
529 // |parent| can only be NULL if the manager was created before the parent
530 // IAccessible was known and it wasn't subsequently set before a client
531 // requested it. This has been fixed. |parent| may also be NULL during
532 // destruction. Possible cases where this could occur include tabs being
533 // dragged to a new window, etc.
535 DVLOG(1) << "In Function: "
537 << ". Parent IAccessible interface is NULL. Returning failure";
541 parent_obj
->AddRef();
542 *disp_parent
= parent_obj
;
546 STDMETHODIMP
BrowserAccessibilityWin::get_accRole(VARIANT var_id
,
548 if (!instance_active())
554 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
558 if (!target
->role_name().empty()) {
560 role
->bstrVal
= SysAllocString(target
->role_name().c_str());
563 role
->lVal
= target
->ia_role();
568 STDMETHODIMP
BrowserAccessibilityWin::get_accState(VARIANT var_id
,
570 if (!instance_active())
576 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
581 state
->lVal
= target
->ia_state();
582 if (manager()->GetFocus(NULL
) == this)
583 state
->lVal
|= STATE_SYSTEM_FOCUSED
;
588 STDMETHODIMP
BrowserAccessibilityWin::get_accValue(VARIANT var_id
,
590 if (!instance_active())
596 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
600 if (target
->ia_role() == ROLE_SYSTEM_PROGRESSBAR
||
601 target
->ia_role() == ROLE_SYSTEM_SCROLLBAR
||
602 target
->ia_role() == ROLE_SYSTEM_SLIDER
) {
603 base::string16 value_text
= target
->GetValueText();
604 *value
= SysAllocString(value_text
.c_str());
609 // Expose color well value.
610 if (target
->ia2_role() == IA2_ROLE_COLOR_CHOOSER
) {
611 int color
= target
->GetIntAttribute(ui::AX_ATTR_COLOR_VALUE
);
612 int red
= (color
>> 16) & 0xFF;
613 int green
= (color
>> 8) & 0xFF;
614 int blue
= color
& 0xFF;
615 base::string16 value_text
;
616 value_text
= base::IntToString16((red
* 100) / 255) + L
"% red " +
617 base::IntToString16((green
* 100) / 255) + L
"% green " +
618 base::IntToString16((blue
* 100) / 255) + L
"% blue";
619 *value
= SysAllocString(value_text
.c_str());
624 *value
= SysAllocString(target
->value().c_str());
629 STDMETHODIMP
BrowserAccessibilityWin::get_accHelpTopic(BSTR
* help_file
,
635 STDMETHODIMP
BrowserAccessibilityWin::get_accSelection(VARIANT
* selected
) {
636 if (!instance_active())
639 if (GetRole() != ui::AX_ROLE_LIST_BOX
)
642 unsigned long selected_count
= 0;
643 for (size_t i
= 0; i
< InternalChildCount(); ++i
) {
644 if (InternalGetChild(i
)->HasState(ui::AX_STATE_SELECTED
))
648 if (selected_count
== 0) {
649 selected
->vt
= VT_EMPTY
;
653 if (selected_count
== 1) {
654 for (size_t i
= 0; i
< InternalChildCount(); ++i
) {
655 if (InternalGetChild(i
)->HasState(ui::AX_STATE_SELECTED
)) {
656 selected
->vt
= VT_DISPATCH
;
658 InternalGetChild(i
)->ToBrowserAccessibilityWin()->NewReference();
664 // Multiple items are selected.
665 base::win::EnumVariant
* enum_variant
=
666 new base::win::EnumVariant(selected_count
);
667 enum_variant
->AddRef();
668 unsigned long index
= 0;
669 for (size_t i
= 0; i
< InternalChildCount(); ++i
) {
670 if (InternalGetChild(i
)->HasState(ui::AX_STATE_SELECTED
)) {
671 enum_variant
->ItemAt(index
)->vt
= VT_DISPATCH
;
672 enum_variant
->ItemAt(index
)->pdispVal
=
673 InternalGetChild(i
)->ToBrowserAccessibilityWin()->NewReference();
677 selected
->vt
= VT_UNKNOWN
;
678 selected
->punkVal
= static_cast<IUnknown
*>(
679 static_cast<base::win::IUnknownImpl
*>(enum_variant
));
683 STDMETHODIMP
BrowserAccessibilityWin::accSelect(
684 LONG flags_sel
, VARIANT var_id
) {
685 if (!instance_active())
688 if (flags_sel
& SELFLAG_TAKEFOCUS
) {
689 manager()->SetFocus(this, true);
697 BrowserAccessibilityWin::put_accName(VARIANT var_id
, BSTR put_name
) {
701 BrowserAccessibilityWin::put_accValue(VARIANT var_id
, BSTR put_val
) {
706 // IAccessible2 methods.
709 STDMETHODIMP
BrowserAccessibilityWin::role(LONG
* role
) {
710 if (!instance_active())
721 STDMETHODIMP
BrowserAccessibilityWin::get_attributes(BSTR
* attributes
) {
722 if (!instance_active())
728 // The iaccessible2 attributes are a set of key-value pairs
729 // separated by semicolons, with a colon between the key and the value.
731 const std::vector
<base::string16
>& attributes_list
= ia2_attributes();
732 for (unsigned int i
= 0; i
< attributes_list
.size(); ++i
) {
733 str
+= attributes_list
[i
] + L
';';
739 *attributes
= SysAllocString(str
.c_str());
744 STDMETHODIMP
BrowserAccessibilityWin::get_states(AccessibleStates
* states
) {
745 if (!instance_active())
751 *states
= ia2_state();
756 STDMETHODIMP
BrowserAccessibilityWin::get_uniqueID(LONG
* unique_id
) {
757 if (!instance_active())
763 *unique_id
= unique_id_win_
;
767 STDMETHODIMP
BrowserAccessibilityWin::get_windowHandle(HWND
* window_handle
) {
768 if (!instance_active())
775 manager()->ToBrowserAccessibilityManagerWin()->GetParentHWND();
782 STDMETHODIMP
BrowserAccessibilityWin::get_indexInParent(LONG
* index_in_parent
) {
783 if (!instance_active())
786 if (!index_in_parent
)
789 *index_in_parent
= this->GetIndexInParent();
793 STDMETHODIMP
BrowserAccessibilityWin::get_nRelations(LONG
* n_relations
) {
794 if (!instance_active())
800 *n_relations
= relations_
.size();
804 STDMETHODIMP
BrowserAccessibilityWin::get_relation(
806 IAccessibleRelation
** relation
) {
807 if (!instance_active())
810 if (relation_index
< 0 ||
811 relation_index
>= static_cast<long>(relations_
.size())) {
818 relations_
[relation_index
]->AddRef();
819 *relation
= relations_
[relation_index
];
823 STDMETHODIMP
BrowserAccessibilityWin::get_relations(
825 IAccessibleRelation
** relations
,
827 if (!instance_active())
830 if (!relations
|| !n_relations
)
833 long count
= static_cast<long>(relations_
.size());
834 *n_relations
= count
;
838 for (long i
= 0; i
< count
; ++i
) {
839 relations_
[i
]->AddRef();
840 relations
[i
] = relations_
[i
];
846 STDMETHODIMP
BrowserAccessibilityWin::scrollTo(enum IA2ScrollType scroll_type
) {
847 if (!instance_active())
850 gfx::Rect r
= GetLocation();
851 switch(scroll_type
) {
852 case IA2_SCROLL_TYPE_TOP_LEFT
:
853 manager()->ScrollToMakeVisible(*this, gfx::Rect(r
.x(), r
.y(), 0, 0));
855 case IA2_SCROLL_TYPE_BOTTOM_RIGHT
:
856 manager()->ScrollToMakeVisible(
857 *this, gfx::Rect(r
.right(), r
.bottom(), 0, 0));
859 case IA2_SCROLL_TYPE_TOP_EDGE
:
860 manager()->ScrollToMakeVisible(
861 *this, gfx::Rect(r
.x(), r
.y(), r
.width(), 0));
863 case IA2_SCROLL_TYPE_BOTTOM_EDGE
:
864 manager()->ScrollToMakeVisible(
865 *this, gfx::Rect(r
.x(), r
.bottom(), r
.width(), 0));
867 case IA2_SCROLL_TYPE_LEFT_EDGE
:
868 manager()->ScrollToMakeVisible(
869 *this, gfx::Rect(r
.x(), r
.y(), 0, r
.height()));
871 case IA2_SCROLL_TYPE_RIGHT_EDGE
:
872 manager()->ScrollToMakeVisible(
873 *this, gfx::Rect(r
.right(), r
.y(), 0, r
.height()));
875 case IA2_SCROLL_TYPE_ANYWHERE
:
877 manager()->ScrollToMakeVisible(*this, r
);
881 manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
886 STDMETHODIMP
BrowserAccessibilityWin::scrollToPoint(
887 enum IA2CoordinateType coordinate_type
,
890 if (!instance_active())
893 gfx::Point
scroll_to(x
, y
);
895 if (coordinate_type
== IA2_COORDTYPE_SCREEN_RELATIVE
) {
896 scroll_to
-= manager()->GetViewBounds().OffsetFromOrigin();
897 } else if (coordinate_type
== IA2_COORDTYPE_PARENT_RELATIVE
) {
899 scroll_to
+= GetParent()->GetLocation().OffsetFromOrigin();
904 manager()->ScrollToPoint(*this, scroll_to
);
905 manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
910 STDMETHODIMP
BrowserAccessibilityWin::get_groupPosition(
912 LONG
* similar_items_in_group
,
913 LONG
* position_in_group
) {
914 if (!instance_active())
917 if (!group_level
|| !similar_items_in_group
|| !position_in_group
)
921 *similar_items_in_group
= GetIntAttribute(ui::AX_ATTR_SET_SIZE
);
922 *position_in_group
= GetIntAttribute(ui::AX_ATTR_POS_IN_SET
);
927 // IAccessibleEx methods not implemented.
930 STDMETHODIMP
BrowserAccessibilityWin::get_extendedRole(BSTR
* extended_role
) {
934 BrowserAccessibilityWin::get_localizedExtendedRole(
935 BSTR
* localized_extended_role
) {
939 BrowserAccessibilityWin::get_nExtendedStates(LONG
* n_extended_states
) {
943 BrowserAccessibilityWin::get_extendedStates(LONG max_extended_states
,
944 BSTR
** extended_states
,
945 LONG
* n_extended_states
) {
949 BrowserAccessibilityWin::get_localizedExtendedStates(
950 LONG max_localized_extended_states
,
951 BSTR
** localized_extended_states
,
952 LONG
* n_localized_extended_states
) {
955 STDMETHODIMP
BrowserAccessibilityWin::get_locale(IA2Locale
* locale
) {
960 // IAccessibleApplication methods.
963 STDMETHODIMP
BrowserAccessibilityWin::get_appName(BSTR
* app_name
) {
964 // No need to check |instance_active()| because this interface is
965 // global, and doesn't depend on any local state.
970 // GetProduct() returns a string like "Chrome/aa.bb.cc.dd", split out
971 // the part before the "/".
972 std::vector
<std::string
> product_components
;
973 base::SplitString(GetContentClient()->GetProduct(), '/', &product_components
);
974 DCHECK_EQ(2U, product_components
.size());
975 if (product_components
.size() != 2)
977 *app_name
= SysAllocString(base::UTF8ToUTF16(product_components
[0]).c_str());
979 return *app_name
? S_OK
: E_FAIL
;
982 STDMETHODIMP
BrowserAccessibilityWin::get_appVersion(BSTR
* app_version
) {
983 // No need to check |instance_active()| because this interface is
984 // global, and doesn't depend on any local state.
989 // GetProduct() returns a string like "Chrome/aa.bb.cc.dd", split out
990 // the part after the "/".
991 std::vector
<std::string
> product_components
;
992 base::SplitString(GetContentClient()->GetProduct(), '/', &product_components
);
993 DCHECK_EQ(2U, product_components
.size());
994 if (product_components
.size() != 2)
997 SysAllocString(base::UTF8ToUTF16(product_components
[1]).c_str());
998 DCHECK(*app_version
);
999 return *app_version
? S_OK
: E_FAIL
;
1002 STDMETHODIMP
BrowserAccessibilityWin::get_toolkitName(BSTR
* toolkit_name
) {
1003 // No need to check |instance_active()| because this interface is
1004 // global, and doesn't depend on any local state.
1007 return E_INVALIDARG
;
1009 // This is hard-coded; all products based on the Chromium engine
1010 // will have the same toolkit name, so that assistive technology can
1011 // detect any Chrome-based product.
1012 *toolkit_name
= SysAllocString(L
"Chrome");
1013 DCHECK(*toolkit_name
);
1014 return *toolkit_name
? S_OK
: E_FAIL
;
1017 STDMETHODIMP
BrowserAccessibilityWin::get_toolkitVersion(
1018 BSTR
* toolkit_version
) {
1019 // No need to check |instance_active()| because this interface is
1020 // global, and doesn't depend on any local state.
1022 if (!toolkit_version
)
1023 return E_INVALIDARG
;
1025 std::string user_agent
= GetContentClient()->GetUserAgent();
1026 *toolkit_version
= SysAllocString(base::UTF8ToUTF16(user_agent
).c_str());
1027 DCHECK(*toolkit_version
);
1028 return *toolkit_version
? S_OK
: E_FAIL
;
1032 // IAccessibleImage methods.
1035 STDMETHODIMP
BrowserAccessibilityWin::get_description(BSTR
* desc
) {
1036 if (!instance_active())
1040 return E_INVALIDARG
;
1042 if (description().empty())
1045 *desc
= SysAllocString(description().c_str());
1051 STDMETHODIMP
BrowserAccessibilityWin::get_imagePosition(
1052 enum IA2CoordinateType coordinate_type
,
1055 if (!instance_active())
1059 return E_INVALIDARG
;
1061 if (coordinate_type
== IA2_COORDTYPE_SCREEN_RELATIVE
) {
1063 manager()->ToBrowserAccessibilityManagerWin()->GetParentHWND();
1066 POINT top_left
= {0, 0};
1067 ::ClientToScreen(parent_hwnd
, &top_left
);
1068 *x
= GetLocation().x() + top_left
.x
;
1069 *y
= GetLocation().y() + top_left
.y
;
1070 } else if (coordinate_type
== IA2_COORDTYPE_PARENT_RELATIVE
) {
1071 *x
= GetLocation().x();
1072 *y
= GetLocation().y();
1074 *x
-= GetParent()->GetLocation().x();
1075 *y
-= GetParent()->GetLocation().y();
1078 return E_INVALIDARG
;
1084 STDMETHODIMP
BrowserAccessibilityWin::get_imageSize(LONG
* height
, LONG
* width
) {
1085 if (!instance_active())
1088 if (!height
|| !width
)
1089 return E_INVALIDARG
;
1091 *height
= GetLocation().height();
1092 *width
= GetLocation().width();
1097 // IAccessibleTable methods.
1100 STDMETHODIMP
BrowserAccessibilityWin::get_accessibleAt(
1103 IUnknown
** accessible
) {
1104 if (!instance_active())
1108 return E_INVALIDARG
;
1112 if (!GetIntAttribute(
1113 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1115 ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1121 if (row
< 0 || row
>= rows
|| column
< 0 || column
>= columns
)
1122 return E_INVALIDARG
;
1124 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1125 ui::AX_ATTR_CELL_IDS
);
1126 DCHECK_EQ(columns
* rows
, static_cast<int>(cell_ids
.size()));
1128 int cell_id
= cell_ids
[row
* columns
+ column
];
1129 BrowserAccessibilityWin
* cell
= GetFromID(cell_id
);
1131 *accessible
= static_cast<IAccessible
*>(cell
->NewReference());
1136 return E_INVALIDARG
;
1139 STDMETHODIMP
BrowserAccessibilityWin::get_caption(IUnknown
** accessible
) {
1140 if (!instance_active())
1144 return E_INVALIDARG
;
1146 // TODO(dmazzoni): implement
1150 STDMETHODIMP
BrowserAccessibilityWin::get_childIndex(long row
,
1153 if (!instance_active())
1157 return E_INVALIDARG
;
1161 if (!GetIntAttribute(
1162 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1164 ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1170 if (row
< 0 || row
>= rows
|| column
< 0 || column
>= columns
)
1171 return E_INVALIDARG
;
1173 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1174 ui::AX_ATTR_CELL_IDS
);
1175 const std::vector
<int32
>& unique_cell_ids
= GetIntListAttribute(
1176 ui::AX_ATTR_UNIQUE_CELL_IDS
);
1177 DCHECK_EQ(columns
* rows
, static_cast<int>(cell_ids
.size()));
1178 int cell_id
= cell_ids
[row
* columns
+ column
];
1179 for (size_t i
= 0; i
< unique_cell_ids
.size(); ++i
) {
1180 if (unique_cell_ids
[i
] == cell_id
) {
1181 *cell_index
= (long)i
;
1189 STDMETHODIMP
BrowserAccessibilityWin::get_columnDescription(long column
,
1190 BSTR
* description
) {
1191 if (!instance_active())
1195 return E_INVALIDARG
;
1199 if (!GetIntAttribute(
1200 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1201 !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1207 if (column
< 0 || column
>= columns
)
1208 return E_INVALIDARG
;
1210 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1211 ui::AX_ATTR_CELL_IDS
);
1212 for (int i
= 0; i
< rows
; ++i
) {
1213 int cell_id
= cell_ids
[i
* columns
+ column
];
1214 BrowserAccessibilityWin
* cell
= static_cast<BrowserAccessibilityWin
*>(
1215 manager()->GetFromID(cell_id
));
1216 if (cell
&& cell
->GetRole() == ui::AX_ROLE_COLUMN_HEADER
) {
1217 base::string16 cell_name
= cell
->GetString16Attribute(
1219 if (cell_name
.size() > 0) {
1220 *description
= SysAllocString(cell_name
.c_str());
1224 if (cell
->description().size() > 0) {
1225 *description
= SysAllocString(cell
->description().c_str());
1234 STDMETHODIMP
BrowserAccessibilityWin::get_columnExtentAt(
1237 long* n_columns_spanned
) {
1238 if (!instance_active())
1241 if (!n_columns_spanned
)
1242 return E_INVALIDARG
;
1246 if (!GetIntAttribute(
1247 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1248 !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1254 if (row
< 0 || row
>= rows
|| column
< 0 || column
>= columns
)
1255 return E_INVALIDARG
;
1257 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1258 ui::AX_ATTR_CELL_IDS
);
1259 int cell_id
= cell_ids
[row
* columns
+ column
];
1260 BrowserAccessibilityWin
* cell
= static_cast<BrowserAccessibilityWin
*>(
1261 manager()->GetFromID(cell_id
));
1264 cell
->GetIntAttribute(
1265 ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN
, &colspan
) &&
1267 *n_columns_spanned
= colspan
;
1274 STDMETHODIMP
BrowserAccessibilityWin::get_columnHeader(
1275 IAccessibleTable
** accessible_table
,
1276 long* starting_row_index
) {
1277 // TODO(dmazzoni): implement
1281 STDMETHODIMP
BrowserAccessibilityWin::get_columnIndex(long cell_index
,
1282 long* column_index
) {
1283 if (!instance_active())
1287 return E_INVALIDARG
;
1289 const std::vector
<int32
>& unique_cell_ids
= GetIntListAttribute(
1290 ui::AX_ATTR_UNIQUE_CELL_IDS
);
1291 int cell_id_count
= static_cast<int>(unique_cell_ids
.size());
1293 return E_INVALIDARG
;
1294 if (cell_index
>= cell_id_count
)
1297 int cell_id
= unique_cell_ids
[cell_index
];
1298 BrowserAccessibilityWin
* cell
=
1299 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1302 cell
->GetIntAttribute(
1303 ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &col_index
)) {
1304 *column_index
= col_index
;
1311 STDMETHODIMP
BrowserAccessibilityWin::get_nColumns(long* column_count
) {
1312 if (!instance_active())
1316 return E_INVALIDARG
;
1319 if (GetIntAttribute(
1320 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
)) {
1321 *column_count
= columns
;
1328 STDMETHODIMP
BrowserAccessibilityWin::get_nRows(long* row_count
) {
1329 if (!instance_active())
1333 return E_INVALIDARG
;
1336 if (GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
)) {
1344 STDMETHODIMP
BrowserAccessibilityWin::get_nSelectedChildren(long* cell_count
) {
1345 if (!instance_active())
1349 return E_INVALIDARG
;
1351 // TODO(dmazzoni): add support for selected cells/rows/columns in tables.
1356 STDMETHODIMP
BrowserAccessibilityWin::get_nSelectedColumns(long* column_count
) {
1357 if (!instance_active())
1361 return E_INVALIDARG
;
1367 STDMETHODIMP
BrowserAccessibilityWin::get_nSelectedRows(long* row_count
) {
1368 if (!instance_active())
1372 return E_INVALIDARG
;
1378 STDMETHODIMP
BrowserAccessibilityWin::get_rowDescription(long row
,
1379 BSTR
* description
) {
1380 if (!instance_active())
1384 return E_INVALIDARG
;
1388 if (!GetIntAttribute(
1389 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1390 !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1396 if (row
< 0 || row
>= rows
)
1397 return E_INVALIDARG
;
1399 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1400 ui::AX_ATTR_CELL_IDS
);
1401 for (int i
= 0; i
< columns
; ++i
) {
1402 int cell_id
= cell_ids
[row
* columns
+ i
];
1403 BrowserAccessibilityWin
* cell
=
1404 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1405 if (cell
&& cell
->GetRole() == ui::AX_ROLE_ROW_HEADER
) {
1406 base::string16 cell_name
= cell
->GetString16Attribute(
1408 if (cell_name
.size() > 0) {
1409 *description
= SysAllocString(cell_name
.c_str());
1413 if (cell
->description().size() > 0) {
1414 *description
= SysAllocString(cell
->description().c_str());
1423 STDMETHODIMP
BrowserAccessibilityWin::get_rowExtentAt(long row
,
1425 long* n_rows_spanned
) {
1426 if (!instance_active())
1429 if (!n_rows_spanned
)
1430 return E_INVALIDARG
;
1434 if (!GetIntAttribute(
1435 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1436 !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1442 if (row
< 0 || row
>= rows
|| column
< 0 || column
>= columns
)
1443 return E_INVALIDARG
;
1445 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1446 ui::AX_ATTR_CELL_IDS
);
1447 int cell_id
= cell_ids
[row
* columns
+ column
];
1448 BrowserAccessibilityWin
* cell
=
1449 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1452 cell
->GetIntAttribute(
1453 ui::AX_ATTR_TABLE_CELL_ROW_SPAN
, &rowspan
) &&
1455 *n_rows_spanned
= rowspan
;
1462 STDMETHODIMP
BrowserAccessibilityWin::get_rowHeader(
1463 IAccessibleTable
** accessible_table
,
1464 long* starting_column_index
) {
1465 // TODO(dmazzoni): implement
1469 STDMETHODIMP
BrowserAccessibilityWin::get_rowIndex(long cell_index
,
1471 if (!instance_active())
1475 return E_INVALIDARG
;
1477 const std::vector
<int32
>& unique_cell_ids
= GetIntListAttribute(
1478 ui::AX_ATTR_UNIQUE_CELL_IDS
);
1479 int cell_id_count
= static_cast<int>(unique_cell_ids
.size());
1481 return E_INVALIDARG
;
1482 if (cell_index
>= cell_id_count
)
1485 int cell_id
= unique_cell_ids
[cell_index
];
1486 BrowserAccessibilityWin
* cell
=
1487 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1490 cell
->GetIntAttribute(
1491 ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &cell_row_index
)) {
1492 *row_index
= cell_row_index
;
1499 STDMETHODIMP
BrowserAccessibilityWin::get_selectedChildren(long max_children
,
1502 if (!instance_active())
1505 if (!children
|| !n_children
)
1506 return E_INVALIDARG
;
1508 // TODO(dmazzoni): Implement this.
1513 STDMETHODIMP
BrowserAccessibilityWin::get_selectedColumns(long max_columns
,
1516 if (!instance_active())
1519 if (!columns
|| !n_columns
)
1520 return E_INVALIDARG
;
1522 // TODO(dmazzoni): Implement this.
1527 STDMETHODIMP
BrowserAccessibilityWin::get_selectedRows(long max_rows
,
1530 if (!instance_active())
1533 if (!rows
|| !n_rows
)
1534 return E_INVALIDARG
;
1536 // TODO(dmazzoni): Implement this.
1541 STDMETHODIMP
BrowserAccessibilityWin::get_summary(IUnknown
** accessible
) {
1542 if (!instance_active())
1546 return E_INVALIDARG
;
1548 // TODO(dmazzoni): implement
1552 STDMETHODIMP
BrowserAccessibilityWin::get_isColumnSelected(
1554 boolean
* is_selected
) {
1555 if (!instance_active())
1559 return E_INVALIDARG
;
1561 // TODO(dmazzoni): Implement this.
1562 *is_selected
= false;
1566 STDMETHODIMP
BrowserAccessibilityWin::get_isRowSelected(long row
,
1567 boolean
* is_selected
) {
1568 if (!instance_active())
1572 return E_INVALIDARG
;
1574 // TODO(dmazzoni): Implement this.
1575 *is_selected
= false;
1579 STDMETHODIMP
BrowserAccessibilityWin::get_isSelected(long row
,
1581 boolean
* is_selected
) {
1582 if (!instance_active())
1586 return E_INVALIDARG
;
1588 // TODO(dmazzoni): Implement this.
1589 *is_selected
= false;
1593 STDMETHODIMP
BrowserAccessibilityWin::get_rowColumnExtentsAtIndex(
1598 long* column_extents
,
1599 boolean
* is_selected
) {
1600 if (!instance_active())
1603 if (!row
|| !column
|| !row_extents
|| !column_extents
|| !is_selected
)
1604 return E_INVALIDARG
;
1606 const std::vector
<int32
>& unique_cell_ids
= GetIntListAttribute(
1607 ui::AX_ATTR_UNIQUE_CELL_IDS
);
1608 int cell_id_count
= static_cast<int>(unique_cell_ids
.size());
1610 return E_INVALIDARG
;
1611 if (index
>= cell_id_count
)
1614 int cell_id
= unique_cell_ids
[index
];
1615 BrowserAccessibilityWin
* cell
=
1616 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1620 cell
->GetIntAttribute(
1621 ui::AX_ATTR_TABLE_CELL_ROW_SPAN
, &rowspan
) &&
1622 cell
->GetIntAttribute(
1623 ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN
, &colspan
) &&
1626 *row_extents
= rowspan
;
1627 *column_extents
= colspan
;
1634 STDMETHODIMP
BrowserAccessibilityWin::selectRow(long row
) {
1638 STDMETHODIMP
BrowserAccessibilityWin::selectColumn(long column
) {
1642 STDMETHODIMP
BrowserAccessibilityWin::unselectRow(long row
) {
1646 STDMETHODIMP
BrowserAccessibilityWin::unselectColumn(long column
) {
1651 BrowserAccessibilityWin::get_modelChange(IA2TableModelChange
* model_change
) {
1656 // IAccessibleTable2 methods.
1659 STDMETHODIMP
BrowserAccessibilityWin::get_cellAt(long row
,
1662 return get_accessibleAt(row
, column
, cell
);
1665 STDMETHODIMP
BrowserAccessibilityWin::get_nSelectedCells(long* cell_count
) {
1666 return get_nSelectedChildren(cell_count
);
1669 STDMETHODIMP
BrowserAccessibilityWin::get_selectedCells(
1671 long* n_selected_cells
) {
1672 if (!instance_active())
1675 if (!cells
|| !n_selected_cells
)
1676 return E_INVALIDARG
;
1678 // TODO(dmazzoni): Implement this.
1679 *n_selected_cells
= 0;
1683 STDMETHODIMP
BrowserAccessibilityWin::get_selectedColumns(long** columns
,
1685 if (!instance_active())
1688 if (!columns
|| !n_columns
)
1689 return E_INVALIDARG
;
1691 // TODO(dmazzoni): Implement this.
1696 STDMETHODIMP
BrowserAccessibilityWin::get_selectedRows(long** rows
,
1698 if (!instance_active())
1701 if (!rows
|| !n_rows
)
1702 return E_INVALIDARG
;
1704 // TODO(dmazzoni): Implement this.
1711 // IAccessibleTableCell methods.
1714 STDMETHODIMP
BrowserAccessibilityWin::get_columnExtent(
1715 long* n_columns_spanned
) {
1716 if (!instance_active())
1719 if (!n_columns_spanned
)
1720 return E_INVALIDARG
;
1723 if (GetIntAttribute(
1724 ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN
, &colspan
) &&
1726 *n_columns_spanned
= colspan
;
1733 STDMETHODIMP
BrowserAccessibilityWin::get_columnHeaderCells(
1734 IUnknown
*** cell_accessibles
,
1735 long* n_column_header_cells
) {
1736 if (!instance_active())
1739 if (!cell_accessibles
|| !n_column_header_cells
)
1740 return E_INVALIDARG
;
1742 *n_column_header_cells
= 0;
1745 if (!GetIntAttribute(
1746 ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &column
)) {
1750 BrowserAccessibility
* table
= GetParent();
1751 while (table
&& table
->GetRole() != ui::AX_ROLE_TABLE
)
1752 table
= table
->GetParent();
1760 if (!table
->GetIntAttribute(
1761 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1762 !table
->GetIntAttribute(
1763 ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
)) {
1766 if (columns
<= 0 || rows
<= 0 || column
< 0 || column
>= columns
)
1769 const std::vector
<int32
>& cell_ids
= table
->GetIntListAttribute(
1770 ui::AX_ATTR_CELL_IDS
);
1772 for (int i
= 0; i
< rows
; ++i
) {
1773 int cell_id
= cell_ids
[i
* columns
+ column
];
1774 BrowserAccessibilityWin
* cell
=
1775 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1776 if (cell
&& cell
->GetRole() == ui::AX_ROLE_COLUMN_HEADER
)
1777 (*n_column_header_cells
)++;
1780 *cell_accessibles
= static_cast<IUnknown
**>(CoTaskMemAlloc(
1781 (*n_column_header_cells
) * sizeof(cell_accessibles
[0])));
1783 for (int i
= 0; i
< rows
; ++i
) {
1784 int cell_id
= cell_ids
[i
* columns
+ column
];
1785 BrowserAccessibility
* cell
= manager()->GetFromID(cell_id
);
1786 if (cell
&& cell
->GetRole() == ui::AX_ROLE_COLUMN_HEADER
) {
1787 (*cell_accessibles
)[index
] = static_cast<IAccessible
*>(
1788 cell
->ToBrowserAccessibilityWin()->NewReference());
1796 STDMETHODIMP
BrowserAccessibilityWin::get_columnIndex(long* column_index
) {
1797 if (!instance_active())
1801 return E_INVALIDARG
;
1804 if (GetIntAttribute(
1805 ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &column
)) {
1806 *column_index
= column
;
1813 STDMETHODIMP
BrowserAccessibilityWin::get_rowExtent(long* n_rows_spanned
) {
1814 if (!instance_active())
1817 if (!n_rows_spanned
)
1818 return E_INVALIDARG
;
1821 if (GetIntAttribute(
1822 ui::AX_ATTR_TABLE_CELL_ROW_SPAN
, &rowspan
) &&
1824 *n_rows_spanned
= rowspan
;
1831 STDMETHODIMP
BrowserAccessibilityWin::get_rowHeaderCells(
1832 IUnknown
*** cell_accessibles
,
1833 long* n_row_header_cells
) {
1834 if (!instance_active())
1837 if (!cell_accessibles
|| !n_row_header_cells
)
1838 return E_INVALIDARG
;
1840 *n_row_header_cells
= 0;
1843 if (!GetIntAttribute(
1844 ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &row
)) {
1848 BrowserAccessibility
* table
= GetParent();
1849 while (table
&& table
->GetRole() != ui::AX_ROLE_TABLE
)
1850 table
= table
->GetParent();
1858 if (!table
->GetIntAttribute(
1859 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1860 !table
->GetIntAttribute(
1861 ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
)) {
1864 if (columns
<= 0 || rows
<= 0 || row
< 0 || row
>= rows
)
1867 const std::vector
<int32
>& cell_ids
= table
->GetIntListAttribute(
1868 ui::AX_ATTR_CELL_IDS
);
1870 for (int i
= 0; i
< columns
; ++i
) {
1871 int cell_id
= cell_ids
[row
* columns
+ i
];
1872 BrowserAccessibility
* cell
= manager()->GetFromID(cell_id
);
1873 if (cell
&& cell
->GetRole() == ui::AX_ROLE_ROW_HEADER
)
1874 (*n_row_header_cells
)++;
1877 *cell_accessibles
= static_cast<IUnknown
**>(CoTaskMemAlloc(
1878 (*n_row_header_cells
) * sizeof(cell_accessibles
[0])));
1880 for (int i
= 0; i
< columns
; ++i
) {
1881 int cell_id
= cell_ids
[row
* columns
+ i
];
1882 BrowserAccessibility
* cell
= manager()->GetFromID(cell_id
);
1883 if (cell
&& cell
->GetRole() == ui::AX_ROLE_ROW_HEADER
) {
1884 (*cell_accessibles
)[index
] = static_cast<IAccessible
*>(
1885 cell
->ToBrowserAccessibilityWin()->NewReference());
1893 STDMETHODIMP
BrowserAccessibilityWin::get_rowIndex(long* row_index
) {
1894 if (!instance_active())
1898 return E_INVALIDARG
;
1901 if (GetIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &row
)) {
1908 STDMETHODIMP
BrowserAccessibilityWin::get_isSelected(boolean
* is_selected
) {
1909 if (!instance_active())
1913 return E_INVALIDARG
;
1915 *is_selected
= false;
1919 STDMETHODIMP
BrowserAccessibilityWin::get_rowColumnExtents(
1923 long* column_extents
,
1924 boolean
* is_selected
) {
1925 if (!instance_active())
1933 return E_INVALIDARG
;
1940 if (GetIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &row
) &&
1942 ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &column
) &&
1944 ui::AX_ATTR_TABLE_CELL_ROW_SPAN
, &rowspan
) &&
1946 ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN
, &colspan
)) {
1948 *column_index
= column
;
1949 *row_extents
= rowspan
;
1950 *column_extents
= colspan
;
1951 *is_selected
= false;
1958 STDMETHODIMP
BrowserAccessibilityWin::get_table(IUnknown
** table
) {
1959 if (!instance_active())
1963 return E_INVALIDARG
;
1968 GetIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &row
);
1969 GetIntAttribute(ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &column
);
1971 BrowserAccessibility
* find_table
= GetParent();
1972 while (find_table
&& find_table
->GetRole() != ui::AX_ROLE_TABLE
)
1973 find_table
= find_table
->GetParent();
1979 *table
= static_cast<IAccessibleTable
*>(
1980 find_table
->ToBrowserAccessibilityWin()->NewReference());
1986 // IAccessibleText methods.
1989 STDMETHODIMP
BrowserAccessibilityWin::get_nCharacters(LONG
* n_characters
) {
1990 if (!instance_active())
1994 return E_INVALIDARG
;
1996 *n_characters
= TextForIAccessibleText().length();
2000 STDMETHODIMP
BrowserAccessibilityWin::get_caretOffset(LONG
* offset
) {
2001 if (!instance_active())
2005 return E_INVALIDARG
;
2007 // IA2 spec says that caret offset should be -1 if the object is not focused.
2008 if (manager()->GetFocus(this) != this) {
2014 if (IsEditableText()) {
2016 if (GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START
,
2018 *offset
= sel_start
;
2024 STDMETHODIMP
BrowserAccessibilityWin::get_characterExtents(
2026 enum IA2CoordinateType coordinate_type
,
2031 if (!instance_active())
2034 if (!out_x
|| !out_y
|| !out_width
|| !out_height
)
2035 return E_INVALIDARG
;
2037 const base::string16
& text_str
= TextForIAccessibleText();
2038 HandleSpecialTextOffset(text_str
, &offset
);
2040 if (offset
< 0 || offset
> static_cast<LONG
>(text_str
.size()))
2041 return E_INVALIDARG
;
2043 gfx::Rect character_bounds
;
2044 if (coordinate_type
== IA2_COORDTYPE_SCREEN_RELATIVE
) {
2045 character_bounds
= GetGlobalBoundsForRange(offset
, 1);
2046 } else if (coordinate_type
== IA2_COORDTYPE_PARENT_RELATIVE
) {
2047 character_bounds
= GetLocalBoundsForRange(offset
, 1);
2048 character_bounds
-= GetLocation().OffsetFromOrigin();
2050 return E_INVALIDARG
;
2053 *out_x
= character_bounds
.x();
2054 *out_y
= character_bounds
.y();
2055 *out_width
= character_bounds
.width();
2056 *out_height
= character_bounds
.height();
2061 STDMETHODIMP
BrowserAccessibilityWin::get_nSelections(LONG
* n_selections
) {
2062 if (!instance_active())
2066 return E_INVALIDARG
;
2069 if (IsEditableText()) {
2072 if (GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START
,
2074 GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END
, &sel_end
) &&
2075 sel_start
!= sel_end
)
2082 STDMETHODIMP
BrowserAccessibilityWin::get_selection(LONG selection_index
,
2085 if (!instance_active())
2088 if (!start_offset
|| !end_offset
|| selection_index
!= 0)
2089 return E_INVALIDARG
;
2091 LONG n_selections
= 0;
2092 if (FAILED(get_nSelections(&n_selections
)) || n_selections
< 1)
2093 return E_INVALIDARG
;
2097 if (IsEditableText()) {
2100 if (GetIntAttribute(
2101 ui::AX_ATTR_TEXT_SEL_START
, &sel_start
) &&
2102 GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END
, &sel_end
)) {
2103 *start_offset
= sel_start
;
2104 *end_offset
= sel_end
;
2111 STDMETHODIMP
BrowserAccessibilityWin::get_text(LONG start_offset
,
2114 if (!instance_active())
2118 return E_INVALIDARG
;
2120 const base::string16
& text_str
= TextForIAccessibleText();
2122 // Handle special text offsets.
2123 HandleSpecialTextOffset(text_str
, &start_offset
);
2124 HandleSpecialTextOffset(text_str
, &end_offset
);
2126 // The spec allows the arguments to be reversed.
2127 if (start_offset
> end_offset
) {
2128 LONG tmp
= start_offset
;
2129 start_offset
= end_offset
;
2133 // The spec does not allow the start or end offsets to be out or range;
2134 // we must return an error if so.
2135 LONG len
= text_str
.length();
2136 if (start_offset
< 0)
2137 return E_INVALIDARG
;
2138 if (end_offset
> len
)
2139 return E_INVALIDARG
;
2141 base::string16 substr
= text_str
.substr(start_offset
,
2142 end_offset
- start_offset
);
2146 *text
= SysAllocString(substr
.c_str());
2151 STDMETHODIMP
BrowserAccessibilityWin::get_textAtOffset(
2153 enum IA2TextBoundaryType boundary_type
,
2157 if (!instance_active())
2160 if (!start_offset
|| !end_offset
|| !text
)
2161 return E_INVALIDARG
;
2163 const base::string16
& text_str
= TextForIAccessibleText();
2164 HandleSpecialTextOffset(text_str
, &offset
);
2166 return E_INVALIDARG
;
2168 LONG text_len
= text_str
.length();
2169 if (offset
> text_len
)
2170 return E_INVALIDARG
;
2172 // The IAccessible2 spec says we don't have to implement the "sentence"
2173 // boundary type, we can just let the screenreader handle it.
2174 if (boundary_type
== IA2_TEXT_BOUNDARY_SENTENCE
) {
2181 // According to the IA2 Spec, only line boundaries should succeed when
2182 // the offset is one past the end of the text.
2183 if (offset
== text_len
&& boundary_type
!= IA2_TEXT_BOUNDARY_LINE
) {
2190 *start_offset
= FindBoundary(
2191 text_str
, boundary_type
, offset
, ui::BACKWARDS_DIRECTION
);
2192 *end_offset
= FindBoundary(
2193 text_str
, boundary_type
, offset
, ui::FORWARDS_DIRECTION
);
2194 return get_text(*start_offset
, *end_offset
, text
);
2197 STDMETHODIMP
BrowserAccessibilityWin::get_textBeforeOffset(
2199 enum IA2TextBoundaryType boundary_type
,
2203 if (!instance_active())
2206 if (!start_offset
|| !end_offset
|| !text
)
2207 return E_INVALIDARG
;
2209 // The IAccessible2 spec says we don't have to implement the "sentence"
2210 // boundary type, we can just let the screenreader handle it.
2211 if (boundary_type
== IA2_TEXT_BOUNDARY_SENTENCE
) {
2218 const base::string16
& text_str
= TextForIAccessibleText();
2220 *start_offset
= FindBoundary(
2221 text_str
, boundary_type
, offset
, ui::BACKWARDS_DIRECTION
);
2222 *end_offset
= offset
;
2223 return get_text(*start_offset
, *end_offset
, text
);
2226 STDMETHODIMP
BrowserAccessibilityWin::get_textAfterOffset(
2228 enum IA2TextBoundaryType boundary_type
,
2232 if (!instance_active())
2235 if (!start_offset
|| !end_offset
|| !text
)
2236 return E_INVALIDARG
;
2238 // The IAccessible2 spec says we don't have to implement the "sentence"
2239 // boundary type, we can just let the screenreader handle it.
2240 if (boundary_type
== IA2_TEXT_BOUNDARY_SENTENCE
) {
2247 const base::string16
& text_str
= TextForIAccessibleText();
2249 *start_offset
= offset
;
2250 *end_offset
= FindBoundary(
2251 text_str
, boundary_type
, offset
, ui::FORWARDS_DIRECTION
);
2252 return get_text(*start_offset
, *end_offset
, text
);
2255 STDMETHODIMP
BrowserAccessibilityWin::get_newText(IA2TextSegment
* new_text
) {
2256 if (!instance_active())
2260 return E_INVALIDARG
;
2262 if (!old_win_attributes_
)
2265 int start
, old_len
, new_len
;
2266 ComputeHypertextRemovedAndInserted(&start
, &old_len
, &new_len
);
2270 base::string16 substr
= hypertext().substr(start
, new_len
);
2271 new_text
->text
= SysAllocString(substr
.c_str());
2272 new_text
->start
= static_cast<long>(start
);
2273 new_text
->end
= static_cast<long>(start
+ new_len
);
2277 STDMETHODIMP
BrowserAccessibilityWin::get_oldText(IA2TextSegment
* old_text
) {
2278 if (!instance_active())
2282 return E_INVALIDARG
;
2284 if (!old_win_attributes_
)
2287 int start
, old_len
, new_len
;
2288 ComputeHypertextRemovedAndInserted(&start
, &old_len
, &new_len
);
2292 base::string16 old_hypertext
= old_win_attributes_
->hypertext
;
2293 base::string16 substr
= old_hypertext
.substr(start
, old_len
);
2294 old_text
->text
= SysAllocString(substr
.c_str());
2295 old_text
->start
= static_cast<long>(start
);
2296 old_text
->end
= static_cast<long>(start
+ old_len
);
2300 STDMETHODIMP
BrowserAccessibilityWin::get_offsetAtPoint(
2303 enum IA2CoordinateType coord_type
,
2305 if (!instance_active())
2309 return E_INVALIDARG
;
2311 // TODO(dmazzoni): implement this. We're returning S_OK for now so that
2312 // screen readers still return partially accurate results rather than
2313 // completely failing.
2318 STDMETHODIMP
BrowserAccessibilityWin::scrollSubstringTo(
2321 enum IA2ScrollType scroll_type
) {
2322 // TODO(dmazzoni): adjust this for the start and end index, too.
2323 return scrollTo(scroll_type
);
2326 STDMETHODIMP
BrowserAccessibilityWin::scrollSubstringToPoint(
2329 enum IA2CoordinateType coordinate_type
,
2331 // TODO(dmazzoni): adjust this for the start and end index, too.
2332 return scrollToPoint(coordinate_type
, x
, y
);
2335 STDMETHODIMP
BrowserAccessibilityWin::addSelection(LONG start_offset
,
2337 if (!instance_active())
2340 const base::string16
& text_str
= TextForIAccessibleText();
2341 HandleSpecialTextOffset(text_str
, &start_offset
);
2342 HandleSpecialTextOffset(text_str
, &end_offset
);
2344 manager()->SetTextSelection(*this, start_offset
, end_offset
);
2348 STDMETHODIMP
BrowserAccessibilityWin::removeSelection(LONG selection_index
) {
2349 if (!instance_active())
2352 if (selection_index
!= 0)
2353 return E_INVALIDARG
;
2355 manager()->SetTextSelection(*this, 0, 0);
2359 STDMETHODIMP
BrowserAccessibilityWin::setCaretOffset(LONG offset
) {
2360 if (!instance_active())
2363 const base::string16
& text_str
= TextForIAccessibleText();
2364 HandleSpecialTextOffset(text_str
, &offset
);
2365 manager()->SetTextSelection(*this, offset
, offset
);
2369 STDMETHODIMP
BrowserAccessibilityWin::setSelection(LONG selection_index
,
2372 if (!instance_active())
2375 if (selection_index
!= 0)
2376 return E_INVALIDARG
;
2378 const base::string16
& text_str
= TextForIAccessibleText();
2379 HandleSpecialTextOffset(text_str
, &start_offset
);
2380 HandleSpecialTextOffset(text_str
, &end_offset
);
2382 manager()->SetTextSelection(*this, start_offset
, end_offset
);
2387 // IAccessibleText methods not implemented.
2390 STDMETHODIMP
BrowserAccessibilityWin::get_attributes(LONG offset
,
2393 BSTR
* text_attributes
) {
2398 // IAccessibleHypertext methods.
2401 STDMETHODIMP
BrowserAccessibilityWin::get_nHyperlinks(long* hyperlink_count
) {
2402 if (!instance_active())
2405 if (!hyperlink_count
)
2406 return E_INVALIDARG
;
2408 *hyperlink_count
= hyperlink_offset_to_index().size();
2412 STDMETHODIMP
BrowserAccessibilityWin::get_hyperlink(
2414 IAccessibleHyperlink
** hyperlink
) {
2415 if (!instance_active())
2420 index
>= static_cast<long>(hyperlinks().size())) {
2421 return E_INVALIDARG
;
2424 int32 id
= hyperlinks()[index
];
2425 BrowserAccessibilityWin
* child
=
2426 manager()->GetFromID(id
)->ToBrowserAccessibilityWin();
2428 *hyperlink
= static_cast<IAccessibleHyperlink
*>(child
->NewReference());
2435 STDMETHODIMP
BrowserAccessibilityWin::get_hyperlinkIndex(
2437 long* hyperlink_index
) {
2438 if (!instance_active())
2441 if (!hyperlink_index
)
2442 return E_INVALIDARG
;
2444 *hyperlink_index
= -1;
2446 if (char_index
< 0 ||
2447 char_index
>= static_cast<long>(hypertext().size())) {
2448 return E_INVALIDARG
;
2451 std::map
<int32
, int32
>::iterator it
=
2452 hyperlink_offset_to_index().find(char_index
);
2453 if (it
== hyperlink_offset_to_index().end())
2456 *hyperlink_index
= it
->second
;
2461 // IAccessibleHyperlink not implemented.
2464 STDMETHODIMP
BrowserAccessibilityWin::get_anchor(long index
, VARIANT
* anchor
) {
2468 BrowserAccessibilityWin::get_anchorTarget(long index
, VARIANT
* anchor_target
) {
2471 STDMETHODIMP
BrowserAccessibilityWin::get_startIndex(long* index
) {
2474 STDMETHODIMP
BrowserAccessibilityWin::get_endIndex(long* index
) {
2477 STDMETHODIMP
BrowserAccessibilityWin::get_valid(boolean
* valid
) {
2482 // IAccessibleAction not implemented.
2485 STDMETHODIMP
BrowserAccessibilityWin::nActions(long* n_actions
) {
2488 STDMETHODIMP
BrowserAccessibilityWin::doAction(long action_index
) {
2492 BrowserAccessibilityWin::get_description(long action_index
, BSTR
* description
) {
2495 STDMETHODIMP
BrowserAccessibilityWin::get_keyBinding(long action_index
,
2496 long n_max_bindings
,
2497 BSTR
** key_bindings
,
2501 STDMETHODIMP
BrowserAccessibilityWin::get_name(long action_index
, BSTR
* name
) {
2505 BrowserAccessibilityWin::get_localizedName(long action_index
,
2506 BSTR
* localized_name
) {
2511 // IAccessibleValue methods.
2514 STDMETHODIMP
BrowserAccessibilityWin::get_currentValue(VARIANT
* value
) {
2515 if (!instance_active())
2519 return E_INVALIDARG
;
2522 if (GetFloatAttribute(
2523 ui::AX_ATTR_VALUE_FOR_RANGE
, &float_val
)) {
2525 value
->dblVal
= float_val
;
2529 value
->vt
= VT_EMPTY
;
2533 STDMETHODIMP
BrowserAccessibilityWin::get_minimumValue(VARIANT
* value
) {
2534 if (!instance_active())
2538 return E_INVALIDARG
;
2541 if (GetFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE
,
2544 value
->dblVal
= float_val
;
2548 value
->vt
= VT_EMPTY
;
2552 STDMETHODIMP
BrowserAccessibilityWin::get_maximumValue(VARIANT
* value
) {
2553 if (!instance_active())
2557 return E_INVALIDARG
;
2560 if (GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE
,
2563 value
->dblVal
= float_val
;
2567 value
->vt
= VT_EMPTY
;
2571 STDMETHODIMP
BrowserAccessibilityWin::setCurrentValue(VARIANT new_value
) {
2572 // TODO(dmazzoni): Implement this.
2577 // ISimpleDOMDocument methods.
2580 STDMETHODIMP
BrowserAccessibilityWin::get_URL(BSTR
* url
) {
2581 if (!instance_active())
2585 return E_INVALIDARG
;
2587 return GetStringAttributeAsBstr(ui::AX_ATTR_DOC_URL
, url
);
2590 STDMETHODIMP
BrowserAccessibilityWin::get_title(BSTR
* title
) {
2591 if (!instance_active())
2595 return E_INVALIDARG
;
2597 return GetStringAttributeAsBstr(ui::AX_ATTR_DOC_TITLE
, title
);
2600 STDMETHODIMP
BrowserAccessibilityWin::get_mimeType(BSTR
* mime_type
) {
2601 if (!instance_active())
2605 return E_INVALIDARG
;
2607 return GetStringAttributeAsBstr(
2608 ui::AX_ATTR_DOC_MIMETYPE
, mime_type
);
2611 STDMETHODIMP
BrowserAccessibilityWin::get_docType(BSTR
* doc_type
) {
2612 if (!instance_active())
2616 return E_INVALIDARG
;
2618 return GetStringAttributeAsBstr(
2619 ui::AX_ATTR_DOC_DOCTYPE
, doc_type
);
2623 BrowserAccessibilityWin::get_nameSpaceURIForID(short name_space_id
,
2624 BSTR
* name_space_uri
) {
2628 BrowserAccessibilityWin::put_alternateViewMediaTypes(
2629 BSTR
* comma_separated_media_types
) {
2634 // ISimpleDOMNode methods.
2637 STDMETHODIMP
BrowserAccessibilityWin::get_nodeInfo(
2639 short* name_space_id
,
2641 unsigned int* num_children
,
2642 unsigned int* unique_id
,
2643 unsigned short* node_type
) {
2644 if (!instance_active())
2647 if (!node_name
|| !name_space_id
|| !node_value
|| !num_children
||
2648 !unique_id
|| !node_type
) {
2649 return E_INVALIDARG
;
2653 if (GetString16Attribute(ui::AX_ATTR_HTML_TAG
, &tag
))
2654 *node_name
= SysAllocString(tag
.c_str());
2659 *node_value
= SysAllocString(value().c_str());
2660 *num_children
= PlatformChildCount();
2661 *unique_id
= unique_id_win_
;
2663 if (ia_role() == ROLE_SYSTEM_DOCUMENT
) {
2664 *node_type
= NODETYPE_DOCUMENT
;
2665 } else if (ia_role() == ROLE_SYSTEM_TEXT
&&
2666 ((ia2_state() & IA2_STATE_EDITABLE
) == 0)) {
2667 *node_type
= NODETYPE_TEXT
;
2669 *node_type
= NODETYPE_ELEMENT
;
2675 STDMETHODIMP
BrowserAccessibilityWin::get_attributes(
2676 unsigned short max_attribs
,
2678 short* name_space_id
,
2679 BSTR
* attrib_values
,
2680 unsigned short* num_attribs
) {
2681 if (!instance_active())
2684 if (!attrib_names
|| !name_space_id
|| !attrib_values
|| !num_attribs
)
2685 return E_INVALIDARG
;
2687 *num_attribs
= max_attribs
;
2688 if (*num_attribs
> GetHtmlAttributes().size())
2689 *num_attribs
= GetHtmlAttributes().size();
2691 for (unsigned short i
= 0; i
< *num_attribs
; ++i
) {
2692 attrib_names
[i
] = SysAllocString(
2693 base::UTF8ToUTF16(GetHtmlAttributes()[i
].first
).c_str());
2694 name_space_id
[i
] = 0;
2695 attrib_values
[i
] = SysAllocString(
2696 base::UTF8ToUTF16(GetHtmlAttributes()[i
].second
).c_str());
2701 STDMETHODIMP
BrowserAccessibilityWin::get_attributesForNames(
2702 unsigned short num_attribs
,
2704 short* name_space_id
,
2705 BSTR
* attrib_values
) {
2706 if (!instance_active())
2709 if (!attrib_names
|| !name_space_id
|| !attrib_values
)
2710 return E_INVALIDARG
;
2712 for (unsigned short i
= 0; i
< num_attribs
; ++i
) {
2713 name_space_id
[i
] = 0;
2715 std::string name
= base::UTF16ToUTF8((LPCWSTR
)attrib_names
[i
]);
2716 for (unsigned int j
= 0; j
< GetHtmlAttributes().size(); ++j
) {
2717 if (GetHtmlAttributes()[j
].first
== name
) {
2718 attrib_values
[i
] = SysAllocString(
2719 base::UTF8ToUTF16(GetHtmlAttributes()[j
].second
).c_str());
2725 attrib_values
[i
] = NULL
;
2731 STDMETHODIMP
BrowserAccessibilityWin::get_computedStyle(
2732 unsigned short max_style_properties
,
2733 boolean use_alternate_view
,
2734 BSTR
* style_properties
,
2736 unsigned short *num_style_properties
) {
2737 if (!instance_active())
2740 if (!style_properties
|| !style_values
)
2741 return E_INVALIDARG
;
2743 // We only cache a single style property for now: DISPLAY
2745 base::string16 display
;
2746 if (max_style_properties
== 0 ||
2747 !GetString16Attribute(ui::AX_ATTR_DISPLAY
, &display
)) {
2748 *num_style_properties
= 0;
2752 *num_style_properties
= 1;
2753 style_properties
[0] = SysAllocString(L
"display");
2754 style_values
[0] = SysAllocString(display
.c_str());
2759 STDMETHODIMP
BrowserAccessibilityWin::get_computedStyleForProperties(
2760 unsigned short num_style_properties
,
2761 boolean use_alternate_view
,
2762 BSTR
* style_properties
,
2763 BSTR
* style_values
) {
2764 if (!instance_active())
2767 if (!style_properties
|| !style_values
)
2768 return E_INVALIDARG
;
2770 // We only cache a single style property for now: DISPLAY
2772 for (unsigned short i
= 0; i
< num_style_properties
; ++i
) {
2773 base::string16 name
= (LPCWSTR
)style_properties
[i
];
2774 base::StringToLowerASCII(&name
);
2775 if (name
== L
"display") {
2776 base::string16 display
= GetString16Attribute(
2777 ui::AX_ATTR_DISPLAY
);
2778 style_values
[i
] = SysAllocString(display
.c_str());
2780 style_values
[i
] = NULL
;
2787 STDMETHODIMP
BrowserAccessibilityWin::scrollTo(boolean placeTopLeft
) {
2788 return scrollTo(placeTopLeft
?
2789 IA2_SCROLL_TYPE_TOP_LEFT
: IA2_SCROLL_TYPE_ANYWHERE
);
2792 STDMETHODIMP
BrowserAccessibilityWin::get_parentNode(ISimpleDOMNode
** node
) {
2793 if (!instance_active())
2797 return E_INVALIDARG
;
2799 *node
= GetParent()->ToBrowserAccessibilityWin()->NewReference();
2803 STDMETHODIMP
BrowserAccessibilityWin::get_firstChild(ISimpleDOMNode
** node
) {
2804 if (!instance_active())
2808 return E_INVALIDARG
;
2810 if (PlatformChildCount() == 0) {
2815 *node
= PlatformGetChild(0)->ToBrowserAccessibilityWin()->NewReference();
2819 STDMETHODIMP
BrowserAccessibilityWin::get_lastChild(ISimpleDOMNode
** node
) {
2820 if (!instance_active())
2824 return E_INVALIDARG
;
2826 if (PlatformChildCount() == 0) {
2831 *node
= PlatformGetChild(PlatformChildCount() - 1)
2832 ->ToBrowserAccessibilityWin()->NewReference();
2836 STDMETHODIMP
BrowserAccessibilityWin::get_previousSibling(
2837 ISimpleDOMNode
** node
) {
2838 if (!instance_active())
2842 return E_INVALIDARG
;
2844 if (!GetParent() || GetIndexInParent() <= 0) {
2849 *node
= GetParent()->InternalGetChild(GetIndexInParent() - 1)->
2850 ToBrowserAccessibilityWin()->NewReference();
2854 STDMETHODIMP
BrowserAccessibilityWin::get_nextSibling(ISimpleDOMNode
** node
) {
2855 if (!instance_active())
2859 return E_INVALIDARG
;
2862 GetIndexInParent() < 0 ||
2863 GetIndexInParent() >= static_cast<int>(
2864 GetParent()->InternalChildCount()) - 1) {
2869 *node
= GetParent()->InternalGetChild(GetIndexInParent() + 1)->
2870 ToBrowserAccessibilityWin()->NewReference();
2874 STDMETHODIMP
BrowserAccessibilityWin::get_childAt(
2875 unsigned int child_index
,
2876 ISimpleDOMNode
** node
) {
2877 if (!instance_active())
2881 return E_INVALIDARG
;
2883 if (child_index
>= PlatformChildCount())
2884 return E_INVALIDARG
;
2886 BrowserAccessibility
* child
= PlatformGetChild(child_index
);
2892 *node
= child
->ToBrowserAccessibilityWin()->NewReference();
2896 STDMETHODIMP
BrowserAccessibilityWin::get_innerHTML(BSTR
* innerHTML
) {
2901 BrowserAccessibilityWin::get_localInterface(void** local_interface
) {
2905 STDMETHODIMP
BrowserAccessibilityWin::get_language(BSTR
* language
) {
2910 // ISimpleDOMText methods.
2913 STDMETHODIMP
BrowserAccessibilityWin::get_domText(BSTR
* dom_text
) {
2914 if (!instance_active())
2918 return E_INVALIDARG
;
2920 return GetStringAttributeAsBstr(
2921 ui::AX_ATTR_NAME
, dom_text
);
2924 STDMETHODIMP
BrowserAccessibilityWin::get_clippedSubstringBounds(
2925 unsigned int start_index
,
2926 unsigned int end_index
,
2931 // TODO(dmazzoni): fully support this API by intersecting the
2932 // rect with the container's rect.
2933 return get_unclippedSubstringBounds(
2934 start_index
, end_index
, out_x
, out_y
, out_width
, out_height
);
2937 STDMETHODIMP
BrowserAccessibilityWin::get_unclippedSubstringBounds(
2938 unsigned int start_index
,
2939 unsigned int end_index
,
2944 if (!instance_active())
2947 if (!out_x
|| !out_y
|| !out_width
|| !out_height
)
2948 return E_INVALIDARG
;
2950 const base::string16
& text_str
= TextForIAccessibleText();
2951 if (start_index
> text_str
.size() ||
2952 end_index
> text_str
.size() ||
2953 start_index
> end_index
) {
2954 return E_INVALIDARG
;
2957 gfx::Rect bounds
= GetGlobalBoundsForRange(
2958 start_index
, end_index
- start_index
);
2959 *out_x
= bounds
.x();
2960 *out_y
= bounds
.y();
2961 *out_width
= bounds
.width();
2962 *out_height
= bounds
.height();
2966 STDMETHODIMP
BrowserAccessibilityWin::scrollToSubstring(
2967 unsigned int start_index
,
2968 unsigned int end_index
) {
2969 if (!instance_active())
2972 const base::string16
& text_str
= TextForIAccessibleText();
2973 if (start_index
> text_str
.size() ||
2974 end_index
> text_str
.size() ||
2975 start_index
> end_index
) {
2976 return E_INVALIDARG
;
2979 manager()->ScrollToMakeVisible(*this, GetLocalBoundsForRange(
2980 start_index
, end_index
- start_index
));
2981 manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
2986 STDMETHODIMP
BrowserAccessibilityWin::get_fontFamily(BSTR
* font_family
) {
2991 // IServiceProvider methods.
2994 STDMETHODIMP
BrowserAccessibilityWin::QueryService(REFGUID guidService
,
2997 if (!instance_active())
3000 // The system uses IAccessible APIs for many purposes, but only
3001 // assistive technology like screen readers uses IAccessible2.
3002 // Enable full accessibility support when IAccessible2 APIs are queried.
3003 if (riid
== IID_IAccessible2
)
3004 BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility();
3006 if (guidService
== GUID_IAccessibleContentDocument
) {
3007 // Special Mozilla extension: return the accessible for the root document.
3008 // Screen readers use this to distinguish between a document loaded event
3009 // on the root document vs on an iframe.
3010 return manager()->GetRoot()->ToBrowserAccessibilityWin()->QueryInterface(
3011 IID_IAccessible2
, object
);
3014 if (guidService
== IID_IAccessible
||
3015 guidService
== IID_IAccessible2
||
3016 guidService
== IID_IAccessibleAction
||
3017 guidService
== IID_IAccessibleApplication
||
3018 guidService
== IID_IAccessibleHyperlink
||
3019 guidService
== IID_IAccessibleHypertext
||
3020 guidService
== IID_IAccessibleImage
||
3021 guidService
== IID_IAccessibleTable
||
3022 guidService
== IID_IAccessibleTable2
||
3023 guidService
== IID_IAccessibleTableCell
||
3024 guidService
== IID_IAccessibleText
||
3025 guidService
== IID_IAccessibleValue
||
3026 guidService
== IID_ISimpleDOMDocument
||
3027 guidService
== IID_ISimpleDOMNode
||
3028 guidService
== IID_ISimpleDOMText
||
3029 guidService
== GUID_ISimpleDOM
) {
3030 return QueryInterface(riid
, object
);
3033 // We only support the IAccessibleEx interface on Windows 8 and above. This
3034 // is needed for the on-screen Keyboard to show up in metro mode, when the
3035 // user taps an editable portion on the page.
3036 // All methods in the IAccessibleEx interface are unimplemented.
3037 if (riid
== IID_IAccessibleEx
&&
3038 base::win::GetVersion() >= base::win::VERSION_WIN8
) {
3039 return QueryInterface(riid
, object
);
3047 BrowserAccessibilityWin::GetObjectForChild(long child_id
, IAccessibleEx
** ret
) {
3052 BrowserAccessibilityWin::GetIAccessiblePair(IAccessible
** acc
, long* child_id
) {
3056 STDMETHODIMP
BrowserAccessibilityWin::GetRuntimeId(SAFEARRAY
** runtime_id
) {
3061 BrowserAccessibilityWin::ConvertReturnedElement(
3062 IRawElementProviderSimple
* element
,
3063 IAccessibleEx
** acc
) {
3067 STDMETHODIMP
BrowserAccessibilityWin::GetPatternProvider(PATTERNID id
,
3068 IUnknown
** provider
) {
3069 DVLOG(1) << "In Function: "
3071 << " for pattern id: "
3073 if (id
== UIA_ValuePatternId
|| id
== UIA_TextPatternId
) {
3074 if (IsEditableText()) {
3075 DVLOG(1) << "Returning UIA text provider";
3076 base::win::UIATextProvider::CreateTextProvider(
3077 GetValueText(), true, provider
);
3084 STDMETHODIMP
BrowserAccessibilityWin::GetPropertyValue(PROPERTYID id
,
3086 DVLOG(1) << "In Function: "
3088 << " for property id: "
3090 V_VT(ret
) = VT_EMPTY
;
3091 if (id
== UIA_ControlTypePropertyId
) {
3092 if (IsEditableText()) {
3094 ret
->lVal
= UIA_EditControlTypeId
;
3095 DVLOG(1) << "Returning Edit control type";
3097 DVLOG(1) << "Returning empty control type";
3103 STDMETHODIMP
BrowserAccessibilityWin::get_ProviderOptions(
3104 enum ProviderOptions
* ret
) {
3108 STDMETHODIMP
BrowserAccessibilityWin::get_HostRawElementProvider(
3109 IRawElementProviderSimple
** provider
) {
3114 // CComObjectRootEx methods.
3118 HRESULT WINAPI
BrowserAccessibilityWin::InternalQueryInterface(
3120 const _ATL_INTMAP_ENTRY
* entries
,
3123 BrowserAccessibilityWin
* accessibility
=
3124 reinterpret_cast<BrowserAccessibilityWin
*>(this_ptr
);
3125 int32 ia_role
= accessibility
->ia_role();
3126 if (iid
== IID_IAccessibleImage
) {
3127 if (ia_role
!= ROLE_SYSTEM_GRAPHIC
) {
3129 return E_NOINTERFACE
;
3131 } else if (iid
== IID_IAccessibleTable
|| iid
== IID_IAccessibleTable2
) {
3132 if (ia_role
!= ROLE_SYSTEM_TABLE
) {
3134 return E_NOINTERFACE
;
3136 } else if (iid
== IID_IAccessibleTableCell
) {
3137 if (!accessibility
->IsCellOrTableHeaderRole()) {
3139 return E_NOINTERFACE
;
3141 } else if (iid
== IID_IAccessibleValue
) {
3142 if (ia_role
!= ROLE_SYSTEM_PROGRESSBAR
&&
3143 ia_role
!= ROLE_SYSTEM_SCROLLBAR
&&
3144 ia_role
!= ROLE_SYSTEM_SLIDER
) {
3146 return E_NOINTERFACE
;
3148 } else if (iid
== IID_ISimpleDOMDocument
) {
3149 if (ia_role
!= ROLE_SYSTEM_DOCUMENT
) {
3151 return E_NOINTERFACE
;
3155 return CComObjectRootBase::InternalQueryInterface(
3156 this_ptr
, entries
, iid
, object
);
3163 void BrowserAccessibilityWin::UpdateStep1ComputeWinAttributes() {
3164 // Swap win_attributes_ to old_win_attributes_, allowing us to see
3165 // exactly what changed and fire appropriate events. Note that
3166 // old_win_attributes_ is cleared at the end of UpdateStep3FireEvents.
3167 old_win_attributes_
.swap(win_attributes_
);
3168 win_attributes_
.reset(new WinAttributes());
3172 win_attributes_
->ia2_attributes
.clear();
3174 // Expose autocomplete attribute for combobox and textbox.
3175 StringAttributeToIA2(ui::AX_ATTR_AUTO_COMPLETE
, "autocomplete");
3177 // Expose the "display" and "tag" attributes.
3178 StringAttributeToIA2(ui::AX_ATTR_DISPLAY
, "display");
3179 StringAttributeToIA2(ui::AX_ATTR_HTML_TAG
, "tag");
3180 StringAttributeToIA2(ui::AX_ATTR_ROLE
, "xml-roles");
3182 // Expose "level" attribute for headings, trees, etc.
3183 IntAttributeToIA2(ui::AX_ATTR_HIERARCHICAL_LEVEL
, "level");
3185 // Expose the set size and position in set.
3186 IntAttributeToIA2(ui::AX_ATTR_SET_SIZE
, "setsize");
3187 IntAttributeToIA2(ui::AX_ATTR_POS_IN_SET
, "posinset");
3189 if (ia_role() == ROLE_SYSTEM_CHECKBUTTON
||
3190 ia_role() == ROLE_SYSTEM_RADIOBUTTON
||
3191 ia2_role() == IA2_ROLE_CHECK_MENU_ITEM
||
3192 ia2_role() == IA2_ROLE_RADIO_MENU_ITEM
||
3193 ia2_role() == IA2_ROLE_TOGGLE_BUTTON
) {
3194 win_attributes_
->ia2_attributes
.push_back(L
"checkable:true");
3197 // Expose live region attributes.
3198 StringAttributeToIA2(ui::AX_ATTR_LIVE_STATUS
, "live");
3199 StringAttributeToIA2(ui::AX_ATTR_LIVE_RELEVANT
, "relevant");
3200 BoolAttributeToIA2(ui::AX_ATTR_LIVE_ATOMIC
, "atomic");
3201 BoolAttributeToIA2(ui::AX_ATTR_LIVE_BUSY
, "busy");
3203 // Expose container live region attributes.
3204 StringAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_STATUS
,
3206 StringAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_RELEVANT
,
3207 "container-relevant");
3208 BoolAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_ATOMIC
,
3209 "container-atomic");
3210 BoolAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_BUSY
,
3213 // Expose table cell index.
3214 if (IsCellOrTableHeaderRole()) {
3215 BrowserAccessibility
* table
= GetParent();
3216 while (table
&& table
->GetRole() != ui::AX_ROLE_TABLE
)
3217 table
= table
->GetParent();
3219 const std::vector
<int32
>& unique_cell_ids
= table
->GetIntListAttribute(
3220 ui::AX_ATTR_UNIQUE_CELL_IDS
);
3221 for (size_t i
= 0; i
< unique_cell_ids
.size(); ++i
) {
3222 if (unique_cell_ids
[i
] == GetId()) {
3223 win_attributes_
->ia2_attributes
.push_back(
3224 base::string16(L
"table-cell-index:") + base::IntToString16(i
));
3230 // Expose invalid state for form controls and elements with aria-invalid.
3232 if (GetIntAttribute(ui::AX_ATTR_INVALID_STATE
, &invalid_state
)) {
3233 // TODO(nektar): Handle the possibility of having multiple aria-invalid
3234 // attributes defined, e.g., "invalid:spelling,grammar".
3235 switch (invalid_state
) {
3236 case ui::AX_INVALID_STATE_FALSE
:
3237 win_attributes_
->ia2_attributes
.push_back(L
"invalid:false");
3239 case ui::AX_INVALID_STATE_TRUE
:
3240 win_attributes_
->ia2_attributes
.push_back(L
"invalid:true");
3242 case ui::AX_INVALID_STATE_SPELLING
:
3243 win_attributes_
->ia2_attributes
.push_back(L
"invalid:spelling");
3245 case ui::AX_INVALID_STATE_GRAMMAR
:
3246 win_attributes_
->ia2_attributes
.push_back(L
"invalid:grammar");
3248 case ui::AX_INVALID_STATE_OTHER
:
3250 base::string16 aria_invalid_value
;
3251 if (GetString16Attribute(ui::AX_ATTR_ARIA_INVALID_VALUE
,
3252 &aria_invalid_value
)) {
3253 win_attributes_
->ia2_attributes
.push_back(
3254 L
"invalid:" + aria_invalid_value
);
3256 // Set the attribute to L"true", since we cannot be more specific.
3257 win_attributes_
->ia2_attributes
.push_back(L
"invalid:true");
3266 // Expose row or column header sort direction.
3267 int32 sort_direction
;
3268 if ((ia_role() == ROLE_SYSTEM_COLUMNHEADER
||
3269 ia_role() == ROLE_SYSTEM_ROWHEADER
) &&
3270 GetIntAttribute(ui::AX_ATTR_SORT_DIRECTION
, &sort_direction
)) {
3271 switch (sort_direction
) {
3272 case ui::AX_SORT_DIRECTION_UNSORTED
:
3273 win_attributes_
->ia2_attributes
.push_back(L
"sort:none");
3275 case ui::AX_SORT_DIRECTION_ASCENDING
:
3276 win_attributes_
->ia2_attributes
.push_back(L
"sort:ascending");
3278 case ui::AX_SORT_DIRECTION_DESCENDING
:
3279 win_attributes_
->ia2_attributes
.push_back(L
"sort:descending");
3281 case ui::AX_SORT_DIRECTION_OTHER
:
3282 win_attributes_
->ia2_attributes
.push_back(L
"sort:other");
3289 // The calculation of the accessible name of an element has been
3290 // standardized in the HTML to Platform Accessibility APIs Implementation
3291 // Guide (http://www.w3.org/TR/html-aapi/). In order to return the
3292 // appropriate accessible name on Windows, we need to apply some logic
3293 // to the fields we get from WebKit.
3295 // TODO(dmazzoni): move most of this logic into WebKit.
3299 // name: the default name, e.g. inner text
3300 // title ui element: a reference to a <label> element on the same
3301 // page that labels this node.
3302 // description: accessible labels that override the default name:
3303 // aria-label or aria-labelledby or aria-describedby
3304 // help: the value of the "title" attribute
3306 // On Windows, the logic we apply lets some fields take precedence and
3307 // always returns the primary name in "name" and the secondary name,
3308 // if any, in "description".
3310 int title_elem_id
= GetIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT
);
3311 base::string16 name
= GetString16Attribute(ui::AX_ATTR_NAME
);
3312 base::string16 description
= GetString16Attribute(ui::AX_ATTR_DESCRIPTION
);
3313 base::string16 help
= GetString16Attribute(ui::AX_ATTR_HELP
);
3314 base::string16 value
= GetString16Attribute(ui::AX_ATTR_VALUE
);
3316 // WebKit annoyingly puts the title in the description if there's no other
3317 // description, which just confuses the rest of the logic. Put it back.
3318 // Now "help" is always the value of the "title" attribute, if present.
3319 base::string16 title_attr
;
3320 if (GetHtmlAttribute("title", &title_attr
) &&
3321 description
== title_attr
&&
3324 description
.clear();
3327 // Now implement the main logic: the descripion should become the name if
3328 // it's nonempty, and the help should become the description if
3329 // there's no description - or the name if there's no name or description.
3330 if (!description
.empty()) {
3332 description
.clear();
3334 if (!help
.empty() && description
.empty()) {
3338 if (!description
.empty() && name
.empty() && !title_elem_id
) {
3340 description
.clear();
3343 // If it's a text field, also consider the placeholder.
3344 base::string16 placeholder
;
3345 if (GetRole() == ui::AX_ROLE_TEXT_FIELD
&&
3346 HasState(ui::AX_STATE_FOCUSABLE
) &&
3347 GetHtmlAttribute("placeholder", &placeholder
)) {
3348 if (name
.empty() && !title_elem_id
) {
3350 } else if (description
.empty()) {
3351 description
= placeholder
;
3355 // On Windows, the value of a document should be its url.
3356 if (GetRole() == ui::AX_ROLE_ROOT_WEB_AREA
||
3357 GetRole() == ui::AX_ROLE_WEB_AREA
) {
3358 value
= GetString16Attribute(ui::AX_ATTR_DOC_URL
);
3361 // For certain roles (listbox option, static text, and list marker)
3362 // WebKit stores the main accessible text in the "value" - swap it so
3363 // that it's the "name".
3365 (GetRole() == ui::AX_ROLE_STATIC_TEXT
||
3366 GetRole() == ui::AX_ROLE_LIST_MARKER
||
3367 IsListBoxOptionOrMenuListOption())) {
3368 base::string16 tmp
= value
;
3373 // If this doesn't have a value and is linked then set its value to the url
3374 // attribute. This allows screen readers to read an empty link's destination.
3375 if (value
.empty() && (ia_state() & STATE_SYSTEM_LINKED
))
3376 value
= GetString16Attribute(ui::AX_ATTR_URL
);
3378 win_attributes_
->name
= name
;
3379 win_attributes_
->description
= description
;
3380 win_attributes_
->help
= help
;
3381 win_attributes_
->value
= value
;
3383 // Clear any old relationships between this node and other nodes.
3384 for (size_t i
= 0; i
< relations_
.size(); ++i
)
3385 relations_
[i
]->Release();
3388 // Handle title UI element.
3389 if (title_elem_id
) {
3390 // Add a labelled by relationship.
3391 CComObject
<BrowserAccessibilityRelation
>* relation
;
3392 HRESULT hr
= CComObject
<BrowserAccessibilityRelation
>::CreateInstance(
3394 DCHECK(SUCCEEDED(hr
));
3396 relation
->Initialize(this, IA2_RELATION_LABELLED_BY
);
3397 relation
->AddTarget(title_elem_id
);
3398 relations_
.push_back(relation
);
3401 // Expose slider value.
3402 if (ia_role() == ROLE_SYSTEM_PROGRESSBAR
||
3403 ia_role() == ROLE_SYSTEM_SCROLLBAR
||
3404 ia_role() == ROLE_SYSTEM_SLIDER
) {
3405 win_attributes_
->ia2_attributes
.push_back(L
"valuetext:" + GetValueText());
3408 // Expose dropeffect attribute.
3409 base::string16 dropEffect
;
3410 if (GetHtmlAttribute("aria-dropeffect", &dropEffect
))
3411 win_attributes_
->ia2_attributes
.push_back(L
"dropeffect:" + dropEffect
);
3413 // Expose grabbed attribute.
3414 base::string16 grabbed
;
3415 if (GetHtmlAttribute("aria-grabbed", &grabbed
))
3416 win_attributes_
->ia2_attributes
.push_back(L
"grabbed:" + grabbed
);
3418 // Expose datetime attribute.
3419 base::string16 datetime
;
3420 if (GetRole() == ui::AX_ROLE_TIME
&&
3421 GetHtmlAttribute("datetime", &datetime
))
3422 win_attributes_
->ia2_attributes
.push_back(L
"datetime:" + datetime
);
3424 // Expose input-text type attribute.
3425 base::string16 type
;
3426 if (GetRole() == ui::AX_ROLE_TEXT_FIELD
&&
3427 GetHtmlAttribute("type", &type
))
3428 win_attributes_
->ia2_attributes
.push_back(L
"text-input-type:" + type
);
3430 // If this is a web area for a presentational iframe, give it a role of
3431 // something other than DOCUMENT so that the fact that it's a separate doc
3432 // is not exposed to AT.
3433 if (IsWebAreaForPresentationalIframe()) {
3434 win_attributes_
->ia_role
= ROLE_SYSTEM_GROUPING
;
3435 win_attributes_
->ia2_role
= ROLE_SYSTEM_GROUPING
;
3439 void BrowserAccessibilityWin::UpdateStep2ComputeHypertext() {
3440 // Construct the hypertext for this node, which contains the concatenation
3441 // of all of the static text of this node's children and an embedded object
3442 // character for all non-static-text children. Build up a map from the
3443 // character index of each embedded object character to the id of the
3444 // child object it points to.
3445 for (unsigned int i
= 0; i
< PlatformChildCount(); ++i
) {
3446 BrowserAccessibilityWin
* child
=
3447 PlatformGetChild(i
)->ToBrowserAccessibilityWin();
3448 if (child
->GetRole() == ui::AX_ROLE_STATIC_TEXT
) {
3449 win_attributes_
->hypertext
+= child
->name();
3451 int32 char_offset
= hypertext().size();
3452 int32 child_id
= child
->GetId();
3453 int32 index
= hyperlinks().size();
3454 win_attributes_
->hyperlink_offset_to_index
[char_offset
] = index
;
3455 win_attributes_
->hyperlinks
.push_back(child_id
);
3456 win_attributes_
->hypertext
+= kEmbeddedCharacter
;
3461 void BrowserAccessibilityWin::UpdateStep3FireEvents(bool is_subtree_creation
) {
3462 BrowserAccessibilityManagerWin
* manager
=
3463 this->manager()->ToBrowserAccessibilityManagerWin();
3465 // Fire an event when an alert first appears.
3466 if (ia_role() == ROLE_SYSTEM_ALERT
&&
3467 old_win_attributes_
->ia_role
!= ROLE_SYSTEM_ALERT
) {
3468 manager
->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT
, this);
3471 // Fire an event when a new subtree is created.
3472 if (is_subtree_creation
)
3473 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_SHOW
, this);
3475 // The rest of the events only fire on changes, not on new objects.
3476 if (old_win_attributes_
->ia_role
!= 0 ||
3477 !old_win_attributes_
->role_name
.empty()) {
3478 // Fire an event if the name, description, help, or value changes.
3479 if (name() != old_win_attributes_
->name
)
3480 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_NAMECHANGE
, this);
3481 if (description() != old_win_attributes_
->description
)
3482 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_DESCRIPTIONCHANGE
, this);
3483 if (help() != old_win_attributes_
->help
)
3484 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_HELPCHANGE
, this);
3485 if (value() != old_win_attributes_
->value
)
3486 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_VALUECHANGE
, this);
3487 if (ia_state() != old_win_attributes_
->ia_state
)
3488 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_STATECHANGE
, this);
3490 // Normally focus events are handled elsewhere, however
3491 // focus for managed descendants is platform-specific.
3492 // Fire a focus event if the focused descendant in a multi-select
3493 // list box changes.
3494 if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION
&&
3495 (ia_state() & STATE_SYSTEM_FOCUSABLE
) &&
3496 (ia_state() & STATE_SYSTEM_SELECTABLE
) &&
3497 (ia_state() & STATE_SYSTEM_FOCUSED
) &&
3498 !(old_win_attributes_
->ia_state
& STATE_SYSTEM_FOCUSED
)) {
3499 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_FOCUS
, this);
3502 // Handle selection being added or removed.
3503 bool is_selected_now
= (ia_state() & STATE_SYSTEM_SELECTED
) != 0;
3504 bool was_selected_before
=
3505 (old_win_attributes_
->ia_state
& STATE_SYSTEM_SELECTED
) != 0;
3506 if (is_selected_now
|| was_selected_before
) {
3507 bool multiselect
= false;
3508 if (GetParent() && GetParent()->HasState(ui::AX_STATE_MULTISELECTABLE
))
3512 // In a multi-select box, fire SELECTIONADD and SELECTIONREMOVE events.
3513 if (is_selected_now
&& !was_selected_before
) {
3514 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONADD
, this);
3515 } else if (!is_selected_now
&& was_selected_before
) {
3516 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONREMOVE
, this);
3518 } else if (is_selected_now
&& !was_selected_before
) {
3519 // In a single-select box, only fire SELECTION events.
3520 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTION
, this);
3524 // Fire an event if this container object has scrolled.
3527 if (GetIntAttribute(ui::AX_ATTR_SCROLL_X
, &sx
) &&
3528 GetIntAttribute(ui::AX_ATTR_SCROLL_Y
, &sy
)) {
3529 if (sx
!= previous_scroll_x_
|| sy
!= previous_scroll_y_
)
3530 manager
->MaybeCallNotifyWinEvent(EVENT_SYSTEM_SCROLLINGEND
, this);
3531 previous_scroll_x_
= sx
;
3532 previous_scroll_y_
= sy
;
3535 // Changing a static text node can affect the IAccessibleText hypertext
3536 // of the parent node, so force an update on the parent.
3537 BrowserAccessibilityWin
* parent
= GetParent()->ToBrowserAccessibilityWin();
3539 GetRole() == ui::AX_ROLE_STATIC_TEXT
&&
3540 name() != old_win_attributes_
->name
) {
3541 parent
->UpdateStep1ComputeWinAttributes();
3542 parent
->UpdateStep2ComputeHypertext();
3543 parent
->UpdateStep3FireEvents(false);
3546 // Fire hypertext-related events.
3547 int start
, old_len
, new_len
;
3548 ComputeHypertextRemovedAndInserted(&start
, &old_len
, &new_len
);
3550 // In-process screen readers may call IAccessibleText::get_oldText
3551 // in reaction to this event to retrieve the text that was removed.
3552 manager
->MaybeCallNotifyWinEvent(IA2_EVENT_TEXT_REMOVED
, this);
3555 // In-process screen readers may call IAccessibleText::get_newText
3556 // in reaction to this event to retrieve the text that was inserted.
3557 manager
->MaybeCallNotifyWinEvent(IA2_EVENT_TEXT_INSERTED
, this);
3561 old_win_attributes_
.reset(nullptr);
3564 void BrowserAccessibilityWin::OnSubtreeWillBeDeleted() {
3565 manager()->ToBrowserAccessibilityManagerWin()->MaybeCallNotifyWinEvent(
3566 EVENT_OBJECT_HIDE
, this);
3569 void BrowserAccessibilityWin::NativeAddReference() {
3573 void BrowserAccessibilityWin::NativeReleaseReference() {
3577 bool BrowserAccessibilityWin::IsNative() const {
3581 void BrowserAccessibilityWin::OnLocationChanged() {
3582 manager()->ToBrowserAccessibilityManagerWin()->MaybeCallNotifyWinEvent(
3583 EVENT_OBJECT_LOCATIONCHANGE
, this);
3586 BrowserAccessibilityWin
* BrowserAccessibilityWin::NewReference() {
3591 BrowserAccessibilityWin
* BrowserAccessibilityWin::GetTargetFromChildID(
3592 const VARIANT
& var_id
) {
3593 if (var_id
.vt
!= VT_I4
)
3596 LONG child_id
= var_id
.lVal
;
3597 if (child_id
== CHILDID_SELF
)
3600 if (child_id
>= 1 && child_id
<= static_cast<LONG
>(PlatformChildCount()))
3601 return PlatformGetChild(child_id
- 1)->ToBrowserAccessibilityWin();
3603 return manager()->ToBrowserAccessibilityManagerWin()->
3604 GetFromUniqueIdWin(child_id
);
3607 HRESULT
BrowserAccessibilityWin::GetStringAttributeAsBstr(
3608 ui::AXStringAttribute attribute
,
3612 if (!GetString16Attribute(attribute
, &str
))
3618 *value_bstr
= SysAllocString(str
.c_str());
3619 DCHECK(*value_bstr
);
3624 void BrowserAccessibilityWin::StringAttributeToIA2(
3625 ui::AXStringAttribute attribute
,
3626 const char* ia2_attr
) {
3627 base::string16 value
;
3628 if (GetString16Attribute(attribute
, &value
)) {
3629 win_attributes_
->ia2_attributes
.push_back(
3630 base::ASCIIToUTF16(ia2_attr
) + L
":" + value
);
3634 void BrowserAccessibilityWin::BoolAttributeToIA2(
3635 ui::AXBoolAttribute attribute
,
3636 const char* ia2_attr
) {
3638 if (GetBoolAttribute(attribute
, &value
)) {
3639 win_attributes_
->ia2_attributes
.push_back(
3640 (base::ASCIIToUTF16(ia2_attr
) + L
":") +
3641 (value
? L
"true" : L
"false"));
3645 void BrowserAccessibilityWin::IntAttributeToIA2(
3646 ui::AXIntAttribute attribute
,
3647 const char* ia2_attr
) {
3649 if (GetIntAttribute(attribute
, &value
)) {
3650 win_attributes_
->ia2_attributes
.push_back(
3651 base::ASCIIToUTF16(ia2_attr
) + L
":" +
3652 base::IntToString16(value
));
3656 base::string16
BrowserAccessibilityWin::GetNameRecursive() const {
3657 if (!name().empty()) {
3661 base::string16 result
;
3662 for (uint32 i
= 0; i
< PlatformChildCount(); ++i
) {
3663 result
+= PlatformGetChild(i
)->ToBrowserAccessibilityWin()->
3669 base::string16
BrowserAccessibilityWin::GetValueText() {
3671 base::string16 value
= this->value();
3673 if (value
.empty() &&
3674 GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE
, &fval
)) {
3675 value
= base::UTF8ToUTF16(base::DoubleToString(fval
));
3680 base::string16
BrowserAccessibilityWin::TextForIAccessibleText() {
3681 if (IsEditableText() || GetRole() == ui::AX_ROLE_MENU_LIST_OPTION
)
3683 return (GetRole() == ui::AX_ROLE_STATIC_TEXT
) ? name() : hypertext();
3686 bool BrowserAccessibilityWin::IsSameHypertextCharacter(size_t old_char_index
,
3687 size_t new_char_index
) {
3688 CHECK(old_win_attributes_
);
3690 // For anything other than the "embedded character", we just compare the
3691 // characters directly.
3692 base::char16 old_ch
= old_win_attributes_
->hypertext
[old_char_index
];
3693 base::char16 new_ch
= win_attributes_
->hypertext
[new_char_index
];
3694 if (old_ch
!= new_ch
)
3696 if (old_ch
== new_ch
&& new_ch
!= kEmbeddedCharacter
)
3699 // If it's an embedded character, they're only identical if the child id
3700 // the hyperlink points to is the same.
3701 std::map
<int32
, int32
>& old_offset_to_index
=
3702 old_win_attributes_
->hyperlink_offset_to_index
;
3703 std::vector
<int32
>& old_hyperlinks
= old_win_attributes_
->hyperlinks
;
3704 int32 old_hyperlinks_count
= static_cast<int32
>(old_hyperlinks
.size());
3705 std::map
<int32
, int32
>::iterator iter
;
3706 iter
= old_offset_to_index
.find(old_char_index
);
3707 int old_index
= (iter
!= old_offset_to_index
.end()) ? iter
->second
: -1;
3708 int old_child_id
= (old_index
>= 0 && old_index
< old_hyperlinks_count
) ?
3709 old_hyperlinks
[old_index
] : -1;
3711 std::map
<int32
, int32
>& new_offset_to_index
=
3712 win_attributes_
->hyperlink_offset_to_index
;
3713 std::vector
<int32
>& new_hyperlinks
= win_attributes_
->hyperlinks
;
3714 int32 new_hyperlinks_count
= static_cast<int32
>(new_hyperlinks
.size());
3715 iter
= new_offset_to_index
.find(new_char_index
);
3716 int new_index
= (iter
!= new_offset_to_index
.end()) ? iter
->second
: -1;
3717 int new_child_id
= (new_index
>= 0 && new_index
< new_hyperlinks_count
) ?
3718 new_hyperlinks
[new_index
] : -1;
3720 return old_child_id
== new_child_id
;
3723 void BrowserAccessibilityWin::ComputeHypertextRemovedAndInserted(
3724 int* start
, int* old_len
, int* new_len
) {
3725 CHECK(old_win_attributes_
);
3731 const base::string16
& old_text
= old_win_attributes_
->hypertext
;
3732 const base::string16
& new_text
= hypertext();
3734 size_t common_prefix
= 0;
3735 while (common_prefix
< old_text
.size() &&
3736 common_prefix
< new_text
.size() &&
3737 IsSameHypertextCharacter(common_prefix
, common_prefix
)) {
3741 size_t common_suffix
= 0;
3742 while (common_prefix
+ common_suffix
< old_text
.size() &&
3743 common_prefix
+ common_suffix
< new_text
.size() &&
3744 IsSameHypertextCharacter(
3745 old_text
.size() - common_suffix
- 1,
3746 new_text
.size() - common_suffix
- 1)) {
3750 *start
= common_prefix
;
3751 *old_len
= old_text
.size() - common_prefix
- common_suffix
;
3752 *new_len
= new_text
.size() - common_prefix
- common_suffix
;
3755 void BrowserAccessibilityWin::HandleSpecialTextOffset(
3756 const base::string16
& text
,
3758 if (*offset
== IA2_TEXT_OFFSET_LENGTH
)
3759 *offset
= static_cast<LONG
>(text
.size());
3760 else if (*offset
== IA2_TEXT_OFFSET_CARET
)
3761 get_caretOffset(offset
);
3764 ui::TextBoundaryType
BrowserAccessibilityWin::IA2TextBoundaryToTextBoundary(
3765 IA2TextBoundaryType ia2_boundary
) {
3766 switch(ia2_boundary
) {
3767 case IA2_TEXT_BOUNDARY_CHAR
:
3768 return ui::CHAR_BOUNDARY
;
3769 case IA2_TEXT_BOUNDARY_WORD
:
3770 return ui::WORD_BOUNDARY
;
3771 case IA2_TEXT_BOUNDARY_LINE
:
3772 return ui::LINE_BOUNDARY
;
3773 case IA2_TEXT_BOUNDARY_SENTENCE
:
3774 return ui::SENTENCE_BOUNDARY
;
3775 case IA2_TEXT_BOUNDARY_PARAGRAPH
:
3776 return ui::PARAGRAPH_BOUNDARY
;
3777 case IA2_TEXT_BOUNDARY_ALL
:
3778 return ui::ALL_BOUNDARY
;
3782 return ui::CHAR_BOUNDARY
;
3785 LONG
BrowserAccessibilityWin::FindBoundary(
3786 const base::string16
& text
,
3787 IA2TextBoundaryType ia2_boundary
,
3789 ui::TextBoundaryDirection direction
) {
3790 HandleSpecialTextOffset(text
, &start_offset
);
3791 if (ia2_boundary
== IA2_TEXT_BOUNDARY_WORD
&&
3792 GetRole() == ui::AX_ROLE_TEXT_FIELD
) {
3793 return GetWordStartBoundary(static_cast<int>(start_offset
), direction
);
3796 ui::TextBoundaryType boundary
= IA2TextBoundaryToTextBoundary(ia2_boundary
);
3797 const std::vector
<int32
>& line_breaks
= GetIntListAttribute(
3798 ui::AX_ATTR_LINE_BREAKS
);
3799 return ui::FindAccessibleTextBoundary(
3800 text
, line_breaks
, boundary
, start_offset
, direction
);
3803 BrowserAccessibilityWin
* BrowserAccessibilityWin::GetFromID(int32 id
) {
3804 return manager()->GetFromID(id
)->ToBrowserAccessibilityWin();
3807 bool BrowserAccessibilityWin::IsListBoxOptionOrMenuListOption() {
3811 int32 role
= GetRole();
3812 int32 parent_role
= GetParent()->GetRole();
3814 if (role
== ui::AX_ROLE_LIST_BOX_OPTION
&&
3815 parent_role
== ui::AX_ROLE_LIST_BOX
) {
3819 if (role
== ui::AX_ROLE_MENU_LIST_OPTION
&&
3820 parent_role
== ui::AX_ROLE_MENU_LIST_POPUP
) {
3827 void BrowserAccessibilityWin::InitRoleAndState() {
3830 base::string16 role_name
;
3832 int32 ia2_state
= IA2_STATE_OPAQUE
;
3834 if (HasState(ui::AX_STATE_BUSY
))
3835 ia_state
|= STATE_SYSTEM_BUSY
;
3836 if (HasState(ui::AX_STATE_CHECKED
))
3837 ia_state
|= STATE_SYSTEM_CHECKED
;
3838 if (HasState(ui::AX_STATE_COLLAPSED
))
3839 ia_state
|= STATE_SYSTEM_COLLAPSED
;
3840 if (HasState(ui::AX_STATE_EXPANDED
))
3841 ia_state
|= STATE_SYSTEM_EXPANDED
;
3842 if (HasState(ui::AX_STATE_FOCUSABLE
))
3843 ia_state
|= STATE_SYSTEM_FOCUSABLE
;
3844 if (HasState(ui::AX_STATE_HASPOPUP
))
3845 ia_state
|= STATE_SYSTEM_HASPOPUP
;
3846 if (HasState(ui::AX_STATE_INDETERMINATE
))
3847 ia_state
|= STATE_SYSTEM_INDETERMINATE
;
3848 if (HasIntAttribute(ui::AX_ATTR_INVALID_STATE
) &&
3849 GetIntAttribute(ui::AX_ATTR_INVALID_STATE
) != ui::AX_INVALID_STATE_FALSE
)
3850 ia2_state
|= IA2_STATE_INVALID_ENTRY
;
3851 if (HasState(ui::AX_STATE_INVISIBLE
))
3852 ia_state
|= STATE_SYSTEM_INVISIBLE
;
3853 if (HasState(ui::AX_STATE_LINKED
))
3854 ia_state
|= STATE_SYSTEM_LINKED
;
3855 if (HasState(ui::AX_STATE_MULTISELECTABLE
)) {
3856 ia_state
|= STATE_SYSTEM_EXTSELECTABLE
;
3857 ia_state
|= STATE_SYSTEM_MULTISELECTABLE
;
3859 // TODO(ctguil): Support STATE_SYSTEM_EXTSELECTABLE/accSelect.
3860 if (HasState(ui::AX_STATE_OFFSCREEN
))
3861 ia_state
|= STATE_SYSTEM_OFFSCREEN
;
3862 if (HasState(ui::AX_STATE_PRESSED
))
3863 ia_state
|= STATE_SYSTEM_PRESSED
;
3864 if (HasState(ui::AX_STATE_PROTECTED
))
3865 ia_state
|= STATE_SYSTEM_PROTECTED
;
3866 if (HasState(ui::AX_STATE_REQUIRED
))
3867 ia2_state
|= IA2_STATE_REQUIRED
;
3868 if (HasState(ui::AX_STATE_SELECTABLE
))
3869 ia_state
|= STATE_SYSTEM_SELECTABLE
;
3870 if (HasState(ui::AX_STATE_SELECTED
))
3871 ia_state
|= STATE_SYSTEM_SELECTED
;
3872 if (HasState(ui::AX_STATE_VISITED
))
3873 ia_state
|= STATE_SYSTEM_TRAVERSED
;
3874 if (!HasState(ui::AX_STATE_ENABLED
))
3875 ia_state
|= STATE_SYSTEM_UNAVAILABLE
;
3876 if (HasState(ui::AX_STATE_VERTICAL
))
3877 ia2_state
|= IA2_STATE_VERTICAL
;
3878 if (HasState(ui::AX_STATE_HORIZONTAL
))
3879 ia2_state
|= IA2_STATE_HORIZONTAL
;
3880 if (HasState(ui::AX_STATE_VISITED
))
3881 ia_state
|= STATE_SYSTEM_TRAVERSED
;
3883 // Expose whether or not the mouse is over an element, but suppress
3884 // this for tests because it can make the test results flaky depending
3885 // on the position of the mouse.
3886 BrowserAccessibilityStateImpl
* accessibility_state
=
3887 BrowserAccessibilityStateImpl::GetInstance();
3888 if (!accessibility_state
->disable_hot_tracking_for_testing()) {
3889 if (HasState(ui::AX_STATE_HOVERED
))
3890 ia_state
|= STATE_SYSTEM_HOTTRACKED
;
3893 // WebKit marks everything as readonly unless it's editable text, so if it's
3894 // not readonly, mark it as editable now. The final computation of the
3895 // READONLY state for MSAA is below, after the switch.
3896 if (!HasState(ui::AX_STATE_READ_ONLY
))
3897 ia2_state
|= IA2_STATE_EDITABLE
;
3899 if (GetBoolAttribute(ui::AX_ATTR_BUTTON_MIXED
))
3900 ia_state
|= STATE_SYSTEM_MIXED
;
3902 if (GetBoolAttribute(ui::AX_ATTR_CAN_SET_VALUE
))
3903 ia2_state
|= IA2_STATE_EDITABLE
;
3905 if (!GetStringAttribute(ui::AX_ATTR_AUTO_COMPLETE
).empty())
3906 ia2_state
|= IA2_STATE_SUPPORTS_AUTOCOMPLETION
;
3908 base::string16 html_tag
= GetString16Attribute(
3909 ui::AX_ATTR_HTML_TAG
);
3910 switch (GetRole()) {
3911 case ui::AX_ROLE_ALERT
:
3912 ia_role
= ROLE_SYSTEM_ALERT
;
3914 case ui::AX_ROLE_ALERT_DIALOG
:
3915 ia_role
= ROLE_SYSTEM_DIALOG
;
3917 case ui::AX_ROLE_APPLICATION
:
3918 ia_role
= ROLE_SYSTEM_APPLICATION
;
3920 case ui::AX_ROLE_ARTICLE
:
3921 ia_role
= ROLE_SYSTEM_DOCUMENT
;
3922 ia_state
|= STATE_SYSTEM_READONLY
;
3924 case ui::AX_ROLE_BANNER
:
3925 ia_role
= ROLE_SYSTEM_GROUPING
;
3926 ia2_role
= IA2_ROLE_HEADER
;
3928 case ui::AX_ROLE_BLOCKQUOTE
:
3929 role_name
= html_tag
;
3930 ia2_role
= IA2_ROLE_SECTION
;
3932 case ui::AX_ROLE_BUSY_INDICATOR
:
3933 ia_role
= ROLE_SYSTEM_ANIMATION
;
3934 ia_state
|= STATE_SYSTEM_READONLY
;
3936 case ui::AX_ROLE_BUTTON
:
3937 ia_role
= ROLE_SYSTEM_PUSHBUTTON
;
3939 case ui::AX_ROLE_CANVAS
:
3940 if (GetBoolAttribute(ui::AX_ATTR_CANVAS_HAS_FALLBACK
)) {
3941 role_name
= L
"canvas";
3942 ia2_role
= IA2_ROLE_CANVAS
;
3944 ia_role
= ROLE_SYSTEM_GRAPHIC
;
3947 case ui::AX_ROLE_CAPTION
:
3948 ia_role
= ROLE_SYSTEM_TEXT
;
3949 ia2_role
= IA2_ROLE_CAPTION
;
3951 case ui::AX_ROLE_CELL
:
3952 ia_role
= ROLE_SYSTEM_CELL
;
3954 case ui::AX_ROLE_CHECK_BOX
:
3955 ia_role
= ROLE_SYSTEM_CHECKBUTTON
;
3956 ia2_state
|= IA2_STATE_CHECKABLE
;
3958 case ui::AX_ROLE_COLOR_WELL
:
3959 ia_role
= ROLE_SYSTEM_TEXT
;
3960 ia2_role
= IA2_ROLE_COLOR_CHOOSER
;
3962 case ui::AX_ROLE_COLUMN
:
3963 ia_role
= ROLE_SYSTEM_COLUMN
;
3965 case ui::AX_ROLE_COLUMN_HEADER
:
3966 ia_role
= ROLE_SYSTEM_COLUMNHEADER
;
3968 case ui::AX_ROLE_COMBO_BOX
:
3969 ia_role
= ROLE_SYSTEM_COMBOBOX
;
3971 case ui::AX_ROLE_COMPLEMENTARY
:
3972 ia_role
= ROLE_SYSTEM_GROUPING
;
3973 ia2_role
= IA2_ROLE_NOTE
;
3975 case ui::AX_ROLE_CONTENT_INFO
:
3976 ia_role
= ROLE_SYSTEM_TEXT
;
3977 ia2_role
= IA2_ROLE_PARAGRAPH
;
3979 case ui::AX_ROLE_DATE
:
3980 case ui::AX_ROLE_DATE_TIME
:
3981 ia_role
= ROLE_SYSTEM_DROPLIST
;
3982 ia2_role
= IA2_ROLE_DATE_EDITOR
;
3984 case ui::AX_ROLE_DIV
:
3986 ia_role
= ROLE_SYSTEM_GROUPING
;
3987 ia2_role
= IA2_ROLE_SECTION
;
3989 case ui::AX_ROLE_DEFINITION
:
3990 role_name
= html_tag
;
3991 ia2_role
= IA2_ROLE_PARAGRAPH
;
3992 ia_state
|= STATE_SYSTEM_READONLY
;
3994 case ui::AX_ROLE_DESCRIPTION_LIST_DETAIL
:
3995 role_name
= html_tag
;
3996 ia_role
= ROLE_SYSTEM_TEXT
;
3997 ia2_role
= IA2_ROLE_PARAGRAPH
;
3999 case ui::AX_ROLE_DESCRIPTION_LIST
:
4000 role_name
= html_tag
;
4001 ia_role
= ROLE_SYSTEM_LIST
;
4002 ia_state
|= STATE_SYSTEM_READONLY
;
4004 case ui::AX_ROLE_DESCRIPTION_LIST_TERM
:
4005 ia_role
= ROLE_SYSTEM_LISTITEM
;
4006 ia_state
|= STATE_SYSTEM_READONLY
;
4008 case ui::AX_ROLE_DETAILS
:
4009 role_name
= html_tag
;
4010 ia_role
= ROLE_SYSTEM_GROUPING
;
4012 case ui::AX_ROLE_DIALOG
:
4013 ia_role
= ROLE_SYSTEM_DIALOG
;
4015 case ui::AX_ROLE_DISCLOSURE_TRIANGLE
:
4016 ia_role
= ROLE_SYSTEM_PUSHBUTTON
;
4018 case ui::AX_ROLE_DOCUMENT
:
4019 case ui::AX_ROLE_ROOT_WEB_AREA
:
4020 case ui::AX_ROLE_WEB_AREA
:
4021 ia_role
= ROLE_SYSTEM_DOCUMENT
;
4022 ia_state
|= STATE_SYSTEM_READONLY
;
4023 ia_state
|= STATE_SYSTEM_FOCUSABLE
;
4025 case ui::AX_ROLE_EMBEDDED_OBJECT
:
4026 ia_role
= ROLE_SYSTEM_CLIENT
;
4027 ia2_role
= IA2_ROLE_EMBEDDED_OBJECT
;
4029 case ui::AX_ROLE_FIGCAPTION
:
4030 role_name
= html_tag
;
4031 ia2_role
= IA2_ROLE_CAPTION
;
4033 case ui::AX_ROLE_FIGURE
:
4034 ia_role
= ROLE_SYSTEM_GROUPING
;
4036 case ui::AX_ROLE_FORM
:
4037 role_name
= L
"form";
4038 ia2_role
= IA2_ROLE_FORM
;
4040 case ui::AX_ROLE_FOOTER
:
4041 ia_role
= ROLE_SYSTEM_GROUPING
;
4042 ia2_role
= IA2_ROLE_FOOTER
;
4044 case ui::AX_ROLE_GRID
:
4045 ia_role
= ROLE_SYSTEM_TABLE
;
4046 ia_state
|= STATE_SYSTEM_READONLY
;
4048 case ui::AX_ROLE_GROUP
: {
4049 base::string16 aria_role
= GetString16Attribute(
4051 if (aria_role
== L
"group" || html_tag
== L
"fieldset") {
4052 ia_role
= ROLE_SYSTEM_GROUPING
;
4053 } else if (html_tag
== L
"li") {
4054 ia_role
= ROLE_SYSTEM_LISTITEM
;
4055 ia_state
|= STATE_SYSTEM_READONLY
;
4057 if (html_tag
.empty())
4060 role_name
= html_tag
;
4061 ia2_role
= IA2_ROLE_SECTION
;
4065 case ui::AX_ROLE_HEADING
:
4066 role_name
= html_tag
;
4067 ia2_role
= IA2_ROLE_HEADING
;
4069 case ui::AX_ROLE_IFRAME
:
4070 ia_role
= ROLE_SYSTEM_DOCUMENT
;
4071 ia2_role
= IA2_ROLE_INTERNAL_FRAME
;
4072 ia_state
= STATE_SYSTEM_READONLY
;
4074 case ui::AX_ROLE_IFRAME_PRESENTATIONAL
:
4075 ia_role
= ROLE_SYSTEM_GROUPING
;
4077 case ui::AX_ROLE_IMAGE
:
4078 ia_role
= ROLE_SYSTEM_GRAPHIC
;
4079 ia_state
|= STATE_SYSTEM_READONLY
;
4081 case ui::AX_ROLE_IMAGE_MAP
:
4082 role_name
= html_tag
;
4083 ia2_role
= IA2_ROLE_IMAGE_MAP
;
4084 ia_state
|= STATE_SYSTEM_READONLY
;
4086 case ui::AX_ROLE_IMAGE_MAP_LINK
:
4087 ia_role
= ROLE_SYSTEM_LINK
;
4088 ia_state
|= STATE_SYSTEM_LINKED
;
4089 ia_state
|= STATE_SYSTEM_READONLY
;
4091 case ui::AX_ROLE_INPUT_TIME
:
4092 ia_role
= ROLE_SYSTEM_GROUPING
;
4094 case ui::AX_ROLE_LABEL_TEXT
:
4095 case ui::AX_ROLE_LEGEND
:
4096 ia_role
= ROLE_SYSTEM_TEXT
;
4097 ia2_role
= IA2_ROLE_LABEL
;
4099 case ui::AX_ROLE_LINK
:
4100 ia_role
= ROLE_SYSTEM_LINK
;
4101 ia_state
|= STATE_SYSTEM_LINKED
;
4103 case ui::AX_ROLE_LIST
:
4104 ia_role
= ROLE_SYSTEM_LIST
;
4105 ia_state
|= STATE_SYSTEM_READONLY
;
4107 case ui::AX_ROLE_LIST_BOX
:
4108 ia_role
= ROLE_SYSTEM_LIST
;
4110 case ui::AX_ROLE_LIST_BOX_OPTION
:
4111 ia_role
= ROLE_SYSTEM_LISTITEM
;
4112 if (ia_state
& STATE_SYSTEM_SELECTABLE
) {
4113 ia_state
|= STATE_SYSTEM_FOCUSABLE
;
4114 if (HasState(ui::AX_STATE_FOCUSED
))
4115 ia_state
|= STATE_SYSTEM_FOCUSED
;
4118 case ui::AX_ROLE_LIST_ITEM
:
4119 ia_role
= ROLE_SYSTEM_LISTITEM
;
4120 ia_state
|= STATE_SYSTEM_READONLY
;
4122 case ui::AX_ROLE_MAIN
:
4123 ia_role
= ROLE_SYSTEM_GROUPING
;
4124 ia2_role
= IA2_ROLE_PARAGRAPH
;
4126 case ui::AX_ROLE_MARK
:
4127 ia_role
= ROLE_SYSTEM_TEXT
;
4128 ia2_role
= IA2_ROLE_TEXT_FRAME
;
4130 case ui::AX_ROLE_MARQUEE
:
4131 ia_role
= ROLE_SYSTEM_ANIMATION
;
4133 case ui::AX_ROLE_MATH
:
4134 ia_role
= ROLE_SYSTEM_EQUATION
;
4136 case ui::AX_ROLE_MENU
:
4137 case ui::AX_ROLE_MENU_BUTTON
:
4138 ia_role
= ROLE_SYSTEM_MENUPOPUP
;
4140 case ui::AX_ROLE_MENU_BAR
:
4141 ia_role
= ROLE_SYSTEM_MENUBAR
;
4143 case ui::AX_ROLE_MENU_ITEM
:
4144 ia_role
= ROLE_SYSTEM_MENUITEM
;
4146 case ui::AX_ROLE_MENU_ITEM_CHECK_BOX
:
4147 ia_role
= ROLE_SYSTEM_MENUITEM
;
4148 ia2_role
= IA2_ROLE_CHECK_MENU_ITEM
;
4149 ia2_state
|= IA2_STATE_CHECKABLE
;
4151 case ui::AX_ROLE_MENU_ITEM_RADIO
:
4152 ia_role
= ROLE_SYSTEM_MENUITEM
;
4153 ia2_role
= IA2_ROLE_RADIO_MENU_ITEM
;
4155 case ui::AX_ROLE_MENU_LIST_POPUP
:
4156 ia_role
= ROLE_SYSTEM_LIST
;
4157 ia2_state
&= ~(IA2_STATE_EDITABLE
);
4159 case ui::AX_ROLE_MENU_LIST_OPTION
:
4160 ia_role
= ROLE_SYSTEM_LISTITEM
;
4161 ia2_state
&= ~(IA2_STATE_EDITABLE
);
4162 if (ia_state
& STATE_SYSTEM_SELECTABLE
) {
4163 ia_state
|= STATE_SYSTEM_FOCUSABLE
;
4164 if (HasState(ui::AX_STATE_FOCUSED
))
4165 ia_state
|= STATE_SYSTEM_FOCUSED
;
4168 case ui::AX_ROLE_METER
:
4169 role_name
= html_tag
;
4170 ia_role
= ROLE_SYSTEM_PROGRESSBAR
;
4172 case ui::AX_ROLE_NAVIGATION
:
4173 ia_role
= ROLE_SYSTEM_GROUPING
;
4174 ia2_role
= IA2_ROLE_SECTION
;
4176 case ui::AX_ROLE_NOTE
:
4177 ia_role
= ROLE_SYSTEM_GROUPING
;
4178 ia2_role
= IA2_ROLE_NOTE
;
4180 case ui::AX_ROLE_OUTLINE
:
4181 ia_role
= ROLE_SYSTEM_OUTLINE
;
4183 case ui::AX_ROLE_PARAGRAPH
:
4185 ia2_role
= IA2_ROLE_PARAGRAPH
;
4187 case ui::AX_ROLE_POP_UP_BUTTON
:
4188 if (html_tag
== L
"select") {
4189 ia_role
= ROLE_SYSTEM_COMBOBOX
;
4191 ia_role
= ROLE_SYSTEM_BUTTONMENU
;
4194 case ui::AX_ROLE_PRE
:
4195 role_name
= html_tag
;
4196 ia_role
= ROLE_SYSTEM_TEXT
;
4197 ia2_role
= IA2_ROLE_PARAGRAPH
;
4199 case ui::AX_ROLE_PROGRESS_INDICATOR
:
4200 ia_role
= ROLE_SYSTEM_PROGRESSBAR
;
4201 ia_state
|= STATE_SYSTEM_READONLY
;
4203 case ui::AX_ROLE_RADIO_BUTTON
:
4204 ia_role
= ROLE_SYSTEM_RADIOBUTTON
;
4205 ia2_state
= IA2_STATE_CHECKABLE
;
4207 case ui::AX_ROLE_RADIO_GROUP
:
4208 ia_role
= ROLE_SYSTEM_GROUPING
;
4210 case ui::AX_ROLE_REGION
:
4211 if (html_tag
== L
"section") {
4212 ia_role
= ROLE_SYSTEM_GROUPING
;
4213 ia2_role
= IA2_ROLE_SECTION
;
4215 ia_role
= ROLE_SYSTEM_PANE
;
4218 case ui::AX_ROLE_ROW
:
4219 ia_role
= ROLE_SYSTEM_ROW
;
4221 case ui::AX_ROLE_ROW_HEADER
:
4222 ia_role
= ROLE_SYSTEM_ROWHEADER
;
4224 case ui::AX_ROLE_RUBY
:
4225 ia_role
= ROLE_SYSTEM_TEXT
;
4226 ia2_role
= IA2_ROLE_TEXT_FRAME
;
4228 case ui::AX_ROLE_RULER
:
4229 ia_role
= ROLE_SYSTEM_CLIENT
;
4230 ia2_role
= IA2_ROLE_RULER
;
4231 ia_state
|= STATE_SYSTEM_READONLY
;
4233 case ui::AX_ROLE_SCROLL_AREA
:
4234 ia_role
= ROLE_SYSTEM_CLIENT
;
4235 ia2_role
= IA2_ROLE_SCROLL_PANE
;
4236 ia_state
|= STATE_SYSTEM_READONLY
;
4237 ia2_state
&= ~(IA2_STATE_EDITABLE
);
4239 case ui::AX_ROLE_SCROLL_BAR
:
4240 ia_role
= ROLE_SYSTEM_SCROLLBAR
;
4242 case ui::AX_ROLE_SEARCH
:
4243 ia_role
= ROLE_SYSTEM_GROUPING
;
4244 ia2_role
= IA2_ROLE_SECTION
;
4246 case ui::AX_ROLE_SLIDER
:
4247 ia_role
= ROLE_SYSTEM_SLIDER
;
4249 case ui::AX_ROLE_SPIN_BUTTON
:
4250 ia_role
= ROLE_SYSTEM_SPINBUTTON
;
4252 case ui::AX_ROLE_SPIN_BUTTON_PART
:
4253 ia_role
= ROLE_SYSTEM_PUSHBUTTON
;
4255 case ui::AX_ROLE_ANNOTATION
:
4256 case ui::AX_ROLE_LIST_MARKER
:
4257 case ui::AX_ROLE_STATIC_TEXT
:
4258 ia_role
= ROLE_SYSTEM_STATICTEXT
;
4260 case ui::AX_ROLE_STATUS
:
4261 ia_role
= ROLE_SYSTEM_STATUSBAR
;
4263 case ui::AX_ROLE_SPLITTER
:
4264 ia_role
= ROLE_SYSTEM_SEPARATOR
;
4266 case ui::AX_ROLE_SVG_ROOT
:
4267 ia_role
= ROLE_SYSTEM_GRAPHIC
;
4269 case ui::AX_ROLE_SWITCH
:
4270 role_name
= L
"switch";
4271 ia2_role
= IA2_ROLE_TOGGLE_BUTTON
;
4273 case ui::AX_ROLE_TAB
:
4274 ia_role
= ROLE_SYSTEM_PAGETAB
;
4276 case ui::AX_ROLE_TABLE
: {
4277 base::string16 aria_role
= GetString16Attribute(
4279 if (aria_role
== L
"treegrid") {
4280 ia_role
= ROLE_SYSTEM_OUTLINE
;
4282 ia_role
= ROLE_SYSTEM_TABLE
;
4286 case ui::AX_ROLE_TABLE_HEADER_CONTAINER
:
4287 ia_role
= ROLE_SYSTEM_GROUPING
;
4288 ia2_role
= IA2_ROLE_SECTION
;
4289 ia_state
|= STATE_SYSTEM_READONLY
;
4291 case ui::AX_ROLE_TAB_LIST
:
4292 ia_role
= ROLE_SYSTEM_PAGETABLIST
;
4294 case ui::AX_ROLE_TAB_PANEL
:
4295 ia_role
= ROLE_SYSTEM_PROPERTYPAGE
;
4297 case ui::AX_ROLE_TOGGLE_BUTTON
:
4298 ia_role
= ROLE_SYSTEM_PUSHBUTTON
;
4299 ia2_role
= IA2_ROLE_TOGGLE_BUTTON
;
4301 case ui::AX_ROLE_TEXT_FIELD
:
4302 case ui::AX_ROLE_SEARCH_BOX
:
4303 ia_role
= ROLE_SYSTEM_TEXT
;
4304 if (HasState(ui::AX_STATE_MULTILINE
))
4305 ia2_state
|= IA2_STATE_MULTI_LINE
;
4307 ia2_state
|= IA2_STATE_SINGLE_LINE
;
4308 ia2_state
|= IA2_STATE_EDITABLE
;
4309 ia2_state
|= IA2_STATE_SELECTABLE_TEXT
;
4311 case ui::AX_ROLE_TIME
:
4312 role_name
= html_tag
;
4313 ia_role
= ROLE_SYSTEM_TEXT
;
4314 ia2_role
= IA2_ROLE_TEXT_FRAME
;
4316 case ui::AX_ROLE_TIMER
:
4317 ia_role
= ROLE_SYSTEM_CLOCK
;
4318 ia_state
|= STATE_SYSTEM_READONLY
;
4320 case ui::AX_ROLE_TOOLBAR
:
4321 ia_role
= ROLE_SYSTEM_TOOLBAR
;
4322 ia_state
|= STATE_SYSTEM_READONLY
;
4324 case ui::AX_ROLE_TOOLTIP
:
4325 ia_role
= ROLE_SYSTEM_TOOLTIP
;
4326 ia_state
|= STATE_SYSTEM_READONLY
;
4328 case ui::AX_ROLE_TREE
:
4329 ia_role
= ROLE_SYSTEM_OUTLINE
;
4331 case ui::AX_ROLE_TREE_GRID
:
4332 ia_role
= ROLE_SYSTEM_OUTLINE
;
4334 case ui::AX_ROLE_TREE_ITEM
:
4335 ia_role
= ROLE_SYSTEM_OUTLINEITEM
;
4337 case ui::AX_ROLE_LINE_BREAK
:
4338 ia_role
= ROLE_SYSTEM_WHITESPACE
;
4340 case ui::AX_ROLE_WINDOW
:
4341 ia_role
= ROLE_SYSTEM_WINDOW
;
4344 // TODO(dmazzoni): figure out the proper MSAA role for all of these.
4345 case ui::AX_ROLE_DIRECTORY
:
4346 case ui::AX_ROLE_IGNORED
:
4347 case ui::AX_ROLE_LOG
:
4348 case ui::AX_ROLE_NONE
:
4349 case ui::AX_ROLE_PRESENTATIONAL
:
4350 case ui::AX_ROLE_SLIDER_THUMB
:
4352 ia_role
= ROLE_SYSTEM_CLIENT
;
4356 // Compute the final value of READONLY for MSAA.
4358 // We always set the READONLY state for elements that have the
4359 // aria-readonly attribute and for a few roles (in the switch above).
4360 // We clear the READONLY state on focusable controls and on a document.
4361 // Everything else, the majority of objects, do not have this state set.
4362 if (HasState(ui::AX_STATE_FOCUSABLE
) &&
4363 ia_role
!= ROLE_SYSTEM_DOCUMENT
) {
4364 ia_state
&= ~(STATE_SYSTEM_READONLY
);
4366 if (!HasState(ui::AX_STATE_READ_ONLY
))
4367 ia_state
&= ~(STATE_SYSTEM_READONLY
);
4368 if (GetBoolAttribute(ui::AX_ATTR_ARIA_READONLY
))
4369 ia_state
|= STATE_SYSTEM_READONLY
;
4371 // The role should always be set.
4372 DCHECK(!role_name
.empty() || ia_role
);
4374 // If we didn't explicitly set the IAccessible2 role, make it the same
4375 // as the MSAA role.
4379 win_attributes_
->ia_role
= ia_role
;
4380 win_attributes_
->ia_state
= ia_state
;
4381 win_attributes_
->role_name
= role_name
;
4382 win_attributes_
->ia2_role
= ia2_role
;
4383 win_attributes_
->ia2_state
= ia2_state
;
4386 } // namespace content