1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/accessibility/browser_accessibility_win.h"
7 #include <UIAutomationClient.h>
8 #include <UIAutomationCoreApi.h>
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/win/enum_variant.h"
15 #include "base/win/scoped_comptr.h"
16 #include "base/win/windows_version.h"
17 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
18 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
19 #include "content/common/accessibility_messages.h"
20 #include "content/public/common/content_client.h"
21 #include "ui/accessibility/ax_text_utils.h"
22 #include "ui/base/win/accessibility_ids_win.h"
23 #include "ui/base/win/accessibility_misc_utils.h"
24 #include "ui/base/win/atl_module.h"
28 // These nonstandard GUIDs are taken directly from the Mozilla sources
29 // (accessible/src/msaa/nsAccessNodeWrap.cpp); some documentation is here:
30 // http://developer.mozilla.org/en/Accessibility/AT-APIs/ImplementationFeatures/MSAA
31 const GUID GUID_ISimpleDOM
= {
32 0x0c539790, 0x12e4, 0x11cf,
33 0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8};
34 const GUID GUID_IAccessibleContentDocument
= {
35 0xa5d8e1f3, 0x3571, 0x4d8f,
36 0x95, 0x21, 0x07, 0xed, 0x28, 0xfb, 0x07, 0x2e};
38 const base::char16
BrowserAccessibilityWin::kEmbeddedCharacter
= L
'\xfffc';
41 LONG
BrowserAccessibilityWin::next_unique_id_win_
=
42 base::win::kFirstBrowserAccessibilityManagerAccessibilityId
;
45 // BrowserAccessibilityRelation
47 // A simple implementation of IAccessibleRelation, used to represent
48 // a relationship between two accessible nodes in the tree.
51 class BrowserAccessibilityRelation
52 : public CComObjectRootEx
<CComMultiThreadModel
>,
53 public IAccessibleRelation
{
54 BEGIN_COM_MAP(BrowserAccessibilityRelation
)
55 COM_INTERFACE_ENTRY(IAccessibleRelation
)
58 CONTENT_EXPORT
BrowserAccessibilityRelation() {}
59 CONTENT_EXPORT
virtual ~BrowserAccessibilityRelation() {}
61 CONTENT_EXPORT
void Initialize(BrowserAccessibilityWin
* owner
,
62 const base::string16
& type
);
63 CONTENT_EXPORT
void AddTarget(int target_id
);
65 // IAccessibleRelation methods.
66 CONTENT_EXPORT STDMETHODIMP
get_relationType(BSTR
* relation_type
) override
;
67 CONTENT_EXPORT STDMETHODIMP
get_nTargets(long* n_targets
) override
;
68 CONTENT_EXPORT STDMETHODIMP
69 get_target(long target_index
, IUnknown
** target
) override
;
70 CONTENT_EXPORT STDMETHODIMP
71 get_targets(long max_targets
, IUnknown
** targets
, long* n_targets
) override
;
73 // IAccessibleRelation methods not implemented.
74 CONTENT_EXPORT STDMETHODIMP
75 get_localizedRelationType(BSTR
* relation_type
) override
{
81 base::win::ScopedComPtr
<BrowserAccessibilityWin
> owner_
;
82 std::vector
<int> target_ids_
;
85 void BrowserAccessibilityRelation::Initialize(BrowserAccessibilityWin
* owner
,
86 const base::string16
& type
) {
91 void BrowserAccessibilityRelation::AddTarget(int target_id
) {
92 target_ids_
.push_back(target_id
);
95 STDMETHODIMP
BrowserAccessibilityRelation::get_relationType(
96 BSTR
* relation_type
) {
100 if (!owner_
->instance_active())
103 *relation_type
= SysAllocString(type_
.c_str());
104 DCHECK(*relation_type
);
108 STDMETHODIMP
BrowserAccessibilityRelation::get_nTargets(long* n_targets
) {
112 if (!owner_
->instance_active())
115 *n_targets
= static_cast<long>(target_ids_
.size());
117 BrowserAccessibilityManager
* manager
= owner_
->manager();
118 for (long i
= *n_targets
- 1; i
>= 0; --i
) {
119 BrowserAccessibility
* result
= manager
->GetFromID(target_ids_
[i
]);
120 if (!result
|| !result
->instance_active()) {
128 STDMETHODIMP
BrowserAccessibilityRelation::get_target(long target_index
,
133 if (!owner_
->instance_active())
136 if (target_index
< 0 ||
137 target_index
>= static_cast<long>(target_ids_
.size())) {
141 BrowserAccessibilityManager
* manager
= owner_
->manager();
142 BrowserAccessibility
* result
=
143 manager
->GetFromID(target_ids_
[target_index
]);
144 if (!result
|| !result
->instance_active())
147 *target
= static_cast<IAccessible
*>(
148 result
->ToBrowserAccessibilityWin()->NewReference());
152 STDMETHODIMP
BrowserAccessibilityRelation::get_targets(long max_targets
,
155 if (!targets
|| !n_targets
)
158 if (!owner_
->instance_active())
161 long count
= static_cast<long>(target_ids_
.size());
162 if (count
> max_targets
)
169 for (long i
= 0; i
< count
; ++i
) {
170 HRESULT result
= get_target(i
, &targets
[i
]);
179 // BrowserAccessibilityWin::WinAttributes
182 BrowserAccessibilityWin::WinAttributes::WinAttributes()
189 BrowserAccessibilityWin::WinAttributes::~WinAttributes() {
193 // BrowserAccessibilityWin
197 BrowserAccessibility
* BrowserAccessibility::Create() {
198 ui::win::CreateATLModuleIfNeeded();
199 CComObject
<BrowserAccessibilityWin
>* instance
;
200 HRESULT hr
= CComObject
<BrowserAccessibilityWin
>::CreateInstance(&instance
);
201 DCHECK(SUCCEEDED(hr
));
202 return instance
->NewReference();
205 BrowserAccessibilityWin
* BrowserAccessibility::ToBrowserAccessibilityWin() {
206 return static_cast<BrowserAccessibilityWin
*>(this);
209 BrowserAccessibilityWin::BrowserAccessibilityWin()
210 : win_attributes_(new WinAttributes()),
211 previous_scroll_x_(0),
212 previous_scroll_y_(0) {
213 // Start unique IDs at -1 and decrement each time, because get_accChild
214 // uses positive IDs to enumerate children, so we use negative IDs to
215 // clearly distinguish between indices and unique IDs.
216 unique_id_win_
= next_unique_id_win_
;
217 if (next_unique_id_win_
==
218 base::win::kLastBrowserAccessibilityManagerAccessibilityId
) {
219 next_unique_id_win_
=
220 base::win::kFirstBrowserAccessibilityManagerAccessibilityId
;
222 next_unique_id_win_
--;
225 BrowserAccessibilityWin::~BrowserAccessibilityWin() {
226 for (size_t i
= 0; i
< relations_
.size(); ++i
)
227 relations_
[i
]->Release();
231 // IAccessible methods.
234 // * Always test for instance_active() first and return E_FAIL if it's false.
235 // * Always check for invalid arguments first, even if they're unused.
236 // * Return S_FALSE if the only output is a string argument and it's empty.
239 HRESULT
BrowserAccessibilityWin::accDoDefaultAction(VARIANT var_id
) {
240 if (!instance_active())
243 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
247 manager()->DoDefaultAction(*target
);
251 STDMETHODIMP
BrowserAccessibilityWin::accHitTest(LONG x_left
,
254 if (!instance_active())
260 gfx::Point
point(x_left
, y_top
);
261 if (!GetGlobalBoundsRect().Contains(point
)) {
262 // Return S_FALSE and VT_EMPTY when the outside the object's boundaries.
263 child
->vt
= VT_EMPTY
;
267 BrowserAccessibility
* result
= BrowserAccessibilityForPoint(point
);
268 if (result
== this) {
269 // Point is within this object.
271 child
->lVal
= CHILDID_SELF
;
273 child
->vt
= VT_DISPATCH
;
274 child
->pdispVal
= result
->ToBrowserAccessibilityWin()->NewReference();
279 STDMETHODIMP
BrowserAccessibilityWin::accLocation(LONG
* x_left
,
284 if (!instance_active())
287 if (!x_left
|| !y_top
|| !width
|| !height
)
290 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
294 gfx::Rect bounds
= target
->GetGlobalBoundsRect();
295 *x_left
= bounds
.x();
297 *width
= bounds
.width();
298 *height
= bounds
.height();
303 STDMETHODIMP
BrowserAccessibilityWin::accNavigate(LONG nav_dir
,
306 BrowserAccessibilityWin
* target
= GetTargetFromChildID(start
);
310 if ((nav_dir
== NAVDIR_LASTCHILD
|| nav_dir
== NAVDIR_FIRSTCHILD
) &&
311 start
.lVal
!= CHILDID_SELF
) {
312 // MSAA states that navigating to first/last child can only be from self.
316 uint32 child_count
= target
->PlatformChildCount();
318 BrowserAccessibility
* result
= NULL
;
324 // These directions are not implemented, matching Mozilla and IE.
326 case NAVDIR_FIRSTCHILD
:
328 result
= target
->PlatformGetChild(0);
330 case NAVDIR_LASTCHILD
:
332 result
= target
->PlatformGetChild(child_count
- 1);
335 result
= target
->GetNextSibling();
337 case NAVDIR_PREVIOUS
:
338 result
= target
->GetPreviousSibling();
347 end
->vt
= VT_DISPATCH
;
348 end
->pdispVal
= result
->ToBrowserAccessibilityWin()->NewReference();
352 STDMETHODIMP
BrowserAccessibilityWin::get_accChild(VARIANT var_child
,
353 IDispatch
** disp_child
) {
354 if (!instance_active())
362 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_child
);
366 (*disp_child
) = target
->NewReference();
370 STDMETHODIMP
BrowserAccessibilityWin::get_accChildCount(LONG
* child_count
) {
371 if (!instance_active())
377 *child_count
= PlatformChildCount();
382 STDMETHODIMP
BrowserAccessibilityWin::get_accDefaultAction(VARIANT var_id
,
384 if (!instance_active())
390 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
394 return target
->GetStringAttributeAsBstr(
395 ui::AX_ATTR_ACTION
, def_action
);
398 STDMETHODIMP
BrowserAccessibilityWin::get_accDescription(VARIANT var_id
,
400 if (!instance_active())
406 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
410 base::string16 description_str
= target
->description();
411 if (description_str
.empty())
414 *desc
= SysAllocString(description_str
.c_str());
420 STDMETHODIMP
BrowserAccessibilityWin::get_accFocus(VARIANT
* focus_child
) {
421 if (!instance_active())
427 BrowserAccessibilityWin
* focus
= static_cast<BrowserAccessibilityWin
*>(
428 manager()->GetFocus(this));
430 focus_child
->vt
= VT_I4
;
431 focus_child
->lVal
= CHILDID_SELF
;
432 } else if (focus
== NULL
) {
433 focus_child
->vt
= VT_EMPTY
;
435 focus_child
->vt
= VT_DISPATCH
;
436 focus_child
->pdispVal
= focus
->NewReference();
442 STDMETHODIMP
BrowserAccessibilityWin::get_accHelp(VARIANT var_id
, BSTR
* help
) {
443 if (!instance_active())
449 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
453 base::string16 help_str
= target
->help();
454 if (help_str
.empty())
457 *help
= SysAllocString(help_str
.c_str());
463 STDMETHODIMP
BrowserAccessibilityWin::get_accKeyboardShortcut(VARIANT var_id
,
465 if (!instance_active())
471 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
475 return target
->GetStringAttributeAsBstr(
476 ui::AX_ATTR_SHORTCUT
, acc_key
);
479 STDMETHODIMP
BrowserAccessibilityWin::get_accName(VARIANT var_id
, BSTR
* name
) {
480 if (!instance_active())
486 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
490 base::string16 name_str
= target
->name();
492 // If the name is empty, see if it's labeled by another element.
493 if (name_str
.empty()) {
495 if (target
->GetIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT
,
497 BrowserAccessibilityWin
* title_elem
=
498 manager()->GetFromID(title_elem_id
)->ToBrowserAccessibilityWin();
500 name_str
= title_elem
->GetNameRecursive();
504 if (name_str
.empty())
507 *name
= SysAllocString(name_str
.c_str());
513 STDMETHODIMP
BrowserAccessibilityWin::get_accParent(IDispatch
** disp_parent
) {
514 if (!instance_active())
520 IAccessible
* parent_obj
= GetParent()->ToBrowserAccessibilityWin();
521 if (parent_obj
== NULL
) {
522 // This happens if we're the root of the tree;
523 // return the IAccessible for the window.
525 manager()->ToBrowserAccessibilityManagerWin()->GetParentIAccessible();
526 // |parent| can only be NULL if the manager was created before the parent
527 // IAccessible was known and it wasn't subsequently set before a client
528 // requested it. This has been fixed. |parent| may also be NULL during
529 // destruction. Possible cases where this could occur include tabs being
530 // dragged to a new window, etc.
532 DVLOG(1) << "In Function: "
534 << ". Parent IAccessible interface is NULL. Returning failure";
538 parent_obj
->AddRef();
539 *disp_parent
= parent_obj
;
543 STDMETHODIMP
BrowserAccessibilityWin::get_accRole(VARIANT var_id
,
545 if (!instance_active())
551 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
555 if (!target
->role_name().empty()) {
557 role
->bstrVal
= SysAllocString(target
->role_name().c_str());
560 role
->lVal
= target
->ia_role();
565 STDMETHODIMP
BrowserAccessibilityWin::get_accState(VARIANT var_id
,
567 if (!instance_active())
573 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
578 state
->lVal
= target
->ia_state();
579 if (manager()->GetFocus(NULL
) == this)
580 state
->lVal
|= STATE_SYSTEM_FOCUSED
;
585 STDMETHODIMP
BrowserAccessibilityWin::get_accValue(VARIANT var_id
,
587 if (!instance_active())
593 BrowserAccessibilityWin
* target
= GetTargetFromChildID(var_id
);
597 if (target
->ia_role() == ROLE_SYSTEM_PROGRESSBAR
||
598 target
->ia_role() == ROLE_SYSTEM_SCROLLBAR
||
599 target
->ia_role() == ROLE_SYSTEM_SLIDER
) {
600 base::string16 value_text
= target
->GetValueText();
601 *value
= SysAllocString(value_text
.c_str());
606 // Expose color well value.
607 if (target
->ia2_role() == IA2_ROLE_COLOR_CHOOSER
) {
608 int r
= target
->GetIntAttribute(
609 ui::AX_ATTR_COLOR_VALUE_RED
);
610 int g
= target
->GetIntAttribute(
611 ui::AX_ATTR_COLOR_VALUE_GREEN
);
612 int b
= target
->GetIntAttribute(
613 ui::AX_ATTR_COLOR_VALUE_BLUE
);
614 base::string16 value_text
;
615 value_text
= base::IntToString16((r
* 100) / 255) + L
"% red " +
616 base::IntToString16((g
* 100) / 255) + L
"% green " +
617 base::IntToString16((b
* 100) / 255) + L
"% blue";
618 *value
= SysAllocString(value_text
.c_str());
623 *value
= SysAllocString(target
->value().c_str());
628 STDMETHODIMP
BrowserAccessibilityWin::get_accHelpTopic(BSTR
* help_file
,
634 STDMETHODIMP
BrowserAccessibilityWin::get_accSelection(VARIANT
* selected
) {
635 if (!instance_active())
638 if (GetRole() != ui::AX_ROLE_LIST_BOX
)
641 unsigned long selected_count
= 0;
642 for (size_t i
= 0; i
< InternalChildCount(); ++i
) {
643 if (InternalGetChild(i
)->HasState(ui::AX_STATE_SELECTED
))
647 if (selected_count
== 0) {
648 selected
->vt
= VT_EMPTY
;
652 if (selected_count
== 1) {
653 for (size_t i
= 0; i
< InternalChildCount(); ++i
) {
654 if (InternalGetChild(i
)->HasState(ui::AX_STATE_SELECTED
)) {
655 selected
->vt
= VT_DISPATCH
;
657 InternalGetChild(i
)->ToBrowserAccessibilityWin()->NewReference();
663 // Multiple items are selected.
664 base::win::EnumVariant
* enum_variant
=
665 new base::win::EnumVariant(selected_count
);
666 enum_variant
->AddRef();
667 unsigned long index
= 0;
668 for (size_t i
= 0; i
< InternalChildCount(); ++i
) {
669 if (InternalGetChild(i
)->HasState(ui::AX_STATE_SELECTED
)) {
670 enum_variant
->ItemAt(index
)->vt
= VT_DISPATCH
;
671 enum_variant
->ItemAt(index
)->pdispVal
=
672 InternalGetChild(i
)->ToBrowserAccessibilityWin()->NewReference();
676 selected
->vt
= VT_UNKNOWN
;
677 selected
->punkVal
= static_cast<IUnknown
*>(
678 static_cast<base::win::IUnknownImpl
*>(enum_variant
));
682 STDMETHODIMP
BrowserAccessibilityWin::accSelect(
683 LONG flags_sel
, VARIANT var_id
) {
684 if (!instance_active())
687 if (flags_sel
& SELFLAG_TAKEFOCUS
) {
688 manager()->SetFocus(this, true);
696 BrowserAccessibilityWin::put_accName(VARIANT var_id
, BSTR put_name
) {
700 BrowserAccessibilityWin::put_accValue(VARIANT var_id
, BSTR put_val
) {
705 // IAccessible2 methods.
708 STDMETHODIMP
BrowserAccessibilityWin::role(LONG
* role
) {
709 if (!instance_active())
720 STDMETHODIMP
BrowserAccessibilityWin::get_attributes(BSTR
* attributes
) {
721 if (!instance_active())
727 // The iaccessible2 attributes are a set of key-value pairs
728 // separated by semicolons, with a colon between the key and the value.
730 const std::vector
<base::string16
>& attributes_list
= ia2_attributes();
731 for (unsigned int i
= 0; i
< attributes_list
.size(); ++i
) {
732 str
+= attributes_list
[i
] + L
';';
738 *attributes
= SysAllocString(str
.c_str());
743 STDMETHODIMP
BrowserAccessibilityWin::get_states(AccessibleStates
* states
) {
744 if (!instance_active())
750 *states
= ia2_state();
755 STDMETHODIMP
BrowserAccessibilityWin::get_uniqueID(LONG
* unique_id
) {
756 if (!instance_active())
762 *unique_id
= unique_id_win_
;
766 STDMETHODIMP
BrowserAccessibilityWin::get_windowHandle(HWND
* window_handle
) {
767 if (!instance_active())
774 manager()->ToBrowserAccessibilityManagerWin()->GetParentHWND();
781 STDMETHODIMP
BrowserAccessibilityWin::get_indexInParent(LONG
* index_in_parent
) {
782 if (!instance_active())
785 if (!index_in_parent
)
788 *index_in_parent
= this->GetIndexInParent();
792 STDMETHODIMP
BrowserAccessibilityWin::get_nRelations(LONG
* n_relations
) {
793 if (!instance_active())
799 *n_relations
= relations_
.size();
803 STDMETHODIMP
BrowserAccessibilityWin::get_relation(
805 IAccessibleRelation
** relation
) {
806 if (!instance_active())
809 if (relation_index
< 0 ||
810 relation_index
>= static_cast<long>(relations_
.size())) {
817 relations_
[relation_index
]->AddRef();
818 *relation
= relations_
[relation_index
];
822 STDMETHODIMP
BrowserAccessibilityWin::get_relations(
824 IAccessibleRelation
** relations
,
826 if (!instance_active())
829 if (!relations
|| !n_relations
)
832 long count
= static_cast<long>(relations_
.size());
833 *n_relations
= count
;
837 for (long i
= 0; i
< count
; ++i
) {
838 relations_
[i
]->AddRef();
839 relations
[i
] = relations_
[i
];
845 STDMETHODIMP
BrowserAccessibilityWin::scrollTo(enum IA2ScrollType scroll_type
) {
846 if (!instance_active())
849 gfx::Rect r
= GetLocation();
850 switch(scroll_type
) {
851 case IA2_SCROLL_TYPE_TOP_LEFT
:
852 manager()->ScrollToMakeVisible(*this, gfx::Rect(r
.x(), r
.y(), 0, 0));
854 case IA2_SCROLL_TYPE_BOTTOM_RIGHT
:
855 manager()->ScrollToMakeVisible(
856 *this, gfx::Rect(r
.right(), r
.bottom(), 0, 0));
858 case IA2_SCROLL_TYPE_TOP_EDGE
:
859 manager()->ScrollToMakeVisible(
860 *this, gfx::Rect(r
.x(), r
.y(), r
.width(), 0));
862 case IA2_SCROLL_TYPE_BOTTOM_EDGE
:
863 manager()->ScrollToMakeVisible(
864 *this, gfx::Rect(r
.x(), r
.bottom(), r
.width(), 0));
866 case IA2_SCROLL_TYPE_LEFT_EDGE
:
867 manager()->ScrollToMakeVisible(
868 *this, gfx::Rect(r
.x(), r
.y(), 0, r
.height()));
870 case IA2_SCROLL_TYPE_RIGHT_EDGE
:
871 manager()->ScrollToMakeVisible(
872 *this, gfx::Rect(r
.right(), r
.y(), 0, r
.height()));
874 case IA2_SCROLL_TYPE_ANYWHERE
:
876 manager()->ScrollToMakeVisible(*this, r
);
880 manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
885 STDMETHODIMP
BrowserAccessibilityWin::scrollToPoint(
886 enum IA2CoordinateType coordinate_type
,
889 if (!instance_active())
892 gfx::Point
scroll_to(x
, y
);
894 if (coordinate_type
== IA2_COORDTYPE_SCREEN_RELATIVE
) {
895 scroll_to
-= manager()->GetViewBounds().OffsetFromOrigin();
896 } else if (coordinate_type
== IA2_COORDTYPE_PARENT_RELATIVE
) {
898 scroll_to
+= GetParent()->GetLocation().OffsetFromOrigin();
903 manager()->ScrollToPoint(*this, scroll_to
);
904 manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
909 STDMETHODIMP
BrowserAccessibilityWin::get_groupPosition(
911 LONG
* similar_items_in_group
,
912 LONG
* position_in_group
) {
913 if (!instance_active())
916 if (!group_level
|| !similar_items_in_group
|| !position_in_group
)
920 *similar_items_in_group
= GetIntAttribute(ui::AX_ATTR_SET_SIZE
);
921 *position_in_group
= GetIntAttribute(ui::AX_ATTR_POS_IN_SET
);
926 // IAccessibleEx methods not implemented.
929 STDMETHODIMP
BrowserAccessibilityWin::get_extendedRole(BSTR
* extended_role
) {
933 BrowserAccessibilityWin::get_localizedExtendedRole(
934 BSTR
* localized_extended_role
) {
938 BrowserAccessibilityWin::get_nExtendedStates(LONG
* n_extended_states
) {
942 BrowserAccessibilityWin::get_extendedStates(LONG max_extended_states
,
943 BSTR
** extended_states
,
944 LONG
* n_extended_states
) {
948 BrowserAccessibilityWin::get_localizedExtendedStates(
949 LONG max_localized_extended_states
,
950 BSTR
** localized_extended_states
,
951 LONG
* n_localized_extended_states
) {
954 STDMETHODIMP
BrowserAccessibilityWin::get_locale(IA2Locale
* locale
) {
959 // IAccessibleApplication methods.
962 STDMETHODIMP
BrowserAccessibilityWin::get_appName(BSTR
* app_name
) {
963 // No need to check |instance_active()| because this interface is
964 // global, and doesn't depend on any local state.
969 // GetProduct() returns a string like "Chrome/aa.bb.cc.dd", split out
970 // the part before the "/".
971 std::vector
<std::string
> product_components
;
972 base::SplitString(GetContentClient()->GetProduct(), '/', &product_components
);
973 DCHECK_EQ(2U, product_components
.size());
974 if (product_components
.size() != 2)
976 *app_name
= SysAllocString(base::UTF8ToUTF16(product_components
[0]).c_str());
978 return *app_name
? S_OK
: E_FAIL
;
981 STDMETHODIMP
BrowserAccessibilityWin::get_appVersion(BSTR
* app_version
) {
982 // No need to check |instance_active()| because this interface is
983 // global, and doesn't depend on any local state.
988 // GetProduct() returns a string like "Chrome/aa.bb.cc.dd", split out
989 // the part after the "/".
990 std::vector
<std::string
> product_components
;
991 base::SplitString(GetContentClient()->GetProduct(), '/', &product_components
);
992 DCHECK_EQ(2U, product_components
.size());
993 if (product_components
.size() != 2)
996 SysAllocString(base::UTF8ToUTF16(product_components
[1]).c_str());
997 DCHECK(*app_version
);
998 return *app_version
? S_OK
: E_FAIL
;
1001 STDMETHODIMP
BrowserAccessibilityWin::get_toolkitName(BSTR
* toolkit_name
) {
1002 // No need to check |instance_active()| because this interface is
1003 // global, and doesn't depend on any local state.
1006 return E_INVALIDARG
;
1008 // This is hard-coded; all products based on the Chromium engine
1009 // will have the same toolkit name, so that assistive technology can
1010 // detect any Chrome-based product.
1011 *toolkit_name
= SysAllocString(L
"Chrome");
1012 DCHECK(*toolkit_name
);
1013 return *toolkit_name
? S_OK
: E_FAIL
;
1016 STDMETHODIMP
BrowserAccessibilityWin::get_toolkitVersion(
1017 BSTR
* toolkit_version
) {
1018 // No need to check |instance_active()| because this interface is
1019 // global, and doesn't depend on any local state.
1021 if (!toolkit_version
)
1022 return E_INVALIDARG
;
1024 std::string user_agent
= GetContentClient()->GetUserAgent();
1025 *toolkit_version
= SysAllocString(base::UTF8ToUTF16(user_agent
).c_str());
1026 DCHECK(*toolkit_version
);
1027 return *toolkit_version
? S_OK
: E_FAIL
;
1031 // IAccessibleImage methods.
1034 STDMETHODIMP
BrowserAccessibilityWin::get_description(BSTR
* desc
) {
1035 if (!instance_active())
1039 return E_INVALIDARG
;
1041 if (description().empty())
1044 *desc
= SysAllocString(description().c_str());
1050 STDMETHODIMP
BrowserAccessibilityWin::get_imagePosition(
1051 enum IA2CoordinateType coordinate_type
,
1054 if (!instance_active())
1058 return E_INVALIDARG
;
1060 if (coordinate_type
== IA2_COORDTYPE_SCREEN_RELATIVE
) {
1062 manager()->ToBrowserAccessibilityManagerWin()->GetParentHWND();
1065 POINT top_left
= {0, 0};
1066 ::ClientToScreen(parent_hwnd
, &top_left
);
1067 *x
= GetLocation().x() + top_left
.x
;
1068 *y
= GetLocation().y() + top_left
.y
;
1069 } else if (coordinate_type
== IA2_COORDTYPE_PARENT_RELATIVE
) {
1070 *x
= GetLocation().x();
1071 *y
= GetLocation().y();
1073 *x
-= GetParent()->GetLocation().x();
1074 *y
-= GetParent()->GetLocation().y();
1077 return E_INVALIDARG
;
1083 STDMETHODIMP
BrowserAccessibilityWin::get_imageSize(LONG
* height
, LONG
* width
) {
1084 if (!instance_active())
1087 if (!height
|| !width
)
1088 return E_INVALIDARG
;
1090 *height
= GetLocation().height();
1091 *width
= GetLocation().width();
1096 // IAccessibleTable methods.
1099 STDMETHODIMP
BrowserAccessibilityWin::get_accessibleAt(
1102 IUnknown
** accessible
) {
1103 if (!instance_active())
1107 return E_INVALIDARG
;
1111 if (!GetIntAttribute(
1112 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1114 ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1120 if (row
< 0 || row
>= rows
|| column
< 0 || column
>= columns
)
1121 return E_INVALIDARG
;
1123 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1124 ui::AX_ATTR_CELL_IDS
);
1125 DCHECK_EQ(columns
* rows
, static_cast<int>(cell_ids
.size()));
1127 int cell_id
= cell_ids
[row
* columns
+ column
];
1128 BrowserAccessibilityWin
* cell
= GetFromID(cell_id
);
1130 *accessible
= static_cast<IAccessible
*>(cell
->NewReference());
1135 return E_INVALIDARG
;
1138 STDMETHODIMP
BrowserAccessibilityWin::get_caption(IUnknown
** accessible
) {
1139 if (!instance_active())
1143 return E_INVALIDARG
;
1145 // TODO(dmazzoni): implement
1149 STDMETHODIMP
BrowserAccessibilityWin::get_childIndex(long row
,
1152 if (!instance_active())
1156 return E_INVALIDARG
;
1160 if (!GetIntAttribute(
1161 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1163 ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1169 if (row
< 0 || row
>= rows
|| column
< 0 || column
>= columns
)
1170 return E_INVALIDARG
;
1172 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1173 ui::AX_ATTR_CELL_IDS
);
1174 const std::vector
<int32
>& unique_cell_ids
= GetIntListAttribute(
1175 ui::AX_ATTR_UNIQUE_CELL_IDS
);
1176 DCHECK_EQ(columns
* rows
, static_cast<int>(cell_ids
.size()));
1177 int cell_id
= cell_ids
[row
* columns
+ column
];
1178 for (size_t i
= 0; i
< unique_cell_ids
.size(); ++i
) {
1179 if (unique_cell_ids
[i
] == cell_id
) {
1180 *cell_index
= (long)i
;
1188 STDMETHODIMP
BrowserAccessibilityWin::get_columnDescription(long column
,
1189 BSTR
* description
) {
1190 if (!instance_active())
1194 return E_INVALIDARG
;
1198 if (!GetIntAttribute(
1199 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1200 !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1206 if (column
< 0 || column
>= columns
)
1207 return E_INVALIDARG
;
1209 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1210 ui::AX_ATTR_CELL_IDS
);
1211 for (int i
= 0; i
< rows
; ++i
) {
1212 int cell_id
= cell_ids
[i
* columns
+ column
];
1213 BrowserAccessibilityWin
* cell
= static_cast<BrowserAccessibilityWin
*>(
1214 manager()->GetFromID(cell_id
));
1215 if (cell
&& cell
->GetRole() == ui::AX_ROLE_COLUMN_HEADER
) {
1216 base::string16 cell_name
= cell
->GetString16Attribute(
1218 if (cell_name
.size() > 0) {
1219 *description
= SysAllocString(cell_name
.c_str());
1223 if (cell
->description().size() > 0) {
1224 *description
= SysAllocString(cell
->description().c_str());
1233 STDMETHODIMP
BrowserAccessibilityWin::get_columnExtentAt(
1236 long* n_columns_spanned
) {
1237 if (!instance_active())
1240 if (!n_columns_spanned
)
1241 return E_INVALIDARG
;
1245 if (!GetIntAttribute(
1246 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1247 !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1253 if (row
< 0 || row
>= rows
|| column
< 0 || column
>= columns
)
1254 return E_INVALIDARG
;
1256 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1257 ui::AX_ATTR_CELL_IDS
);
1258 int cell_id
= cell_ids
[row
* columns
+ column
];
1259 BrowserAccessibilityWin
* cell
= static_cast<BrowserAccessibilityWin
*>(
1260 manager()->GetFromID(cell_id
));
1263 cell
->GetIntAttribute(
1264 ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN
, &colspan
) &&
1266 *n_columns_spanned
= colspan
;
1273 STDMETHODIMP
BrowserAccessibilityWin::get_columnHeader(
1274 IAccessibleTable
** accessible_table
,
1275 long* starting_row_index
) {
1276 // TODO(dmazzoni): implement
1280 STDMETHODIMP
BrowserAccessibilityWin::get_columnIndex(long cell_index
,
1281 long* column_index
) {
1282 if (!instance_active())
1286 return E_INVALIDARG
;
1288 const std::vector
<int32
>& unique_cell_ids
= GetIntListAttribute(
1289 ui::AX_ATTR_UNIQUE_CELL_IDS
);
1290 int cell_id_count
= static_cast<int>(unique_cell_ids
.size());
1292 return E_INVALIDARG
;
1293 if (cell_index
>= cell_id_count
)
1296 int cell_id
= unique_cell_ids
[cell_index
];
1297 BrowserAccessibilityWin
* cell
=
1298 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1301 cell
->GetIntAttribute(
1302 ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &col_index
)) {
1303 *column_index
= col_index
;
1310 STDMETHODIMP
BrowserAccessibilityWin::get_nColumns(long* column_count
) {
1311 if (!instance_active())
1315 return E_INVALIDARG
;
1318 if (GetIntAttribute(
1319 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
)) {
1320 *column_count
= columns
;
1327 STDMETHODIMP
BrowserAccessibilityWin::get_nRows(long* row_count
) {
1328 if (!instance_active())
1332 return E_INVALIDARG
;
1335 if (GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
)) {
1343 STDMETHODIMP
BrowserAccessibilityWin::get_nSelectedChildren(long* cell_count
) {
1344 if (!instance_active())
1348 return E_INVALIDARG
;
1350 // TODO(dmazzoni): add support for selected cells/rows/columns in tables.
1355 STDMETHODIMP
BrowserAccessibilityWin::get_nSelectedColumns(long* column_count
) {
1356 if (!instance_active())
1360 return E_INVALIDARG
;
1366 STDMETHODIMP
BrowserAccessibilityWin::get_nSelectedRows(long* row_count
) {
1367 if (!instance_active())
1371 return E_INVALIDARG
;
1377 STDMETHODIMP
BrowserAccessibilityWin::get_rowDescription(long row
,
1378 BSTR
* description
) {
1379 if (!instance_active())
1383 return E_INVALIDARG
;
1387 if (!GetIntAttribute(
1388 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1389 !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1395 if (row
< 0 || row
>= rows
)
1396 return E_INVALIDARG
;
1398 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1399 ui::AX_ATTR_CELL_IDS
);
1400 for (int i
= 0; i
< columns
; ++i
) {
1401 int cell_id
= cell_ids
[row
* columns
+ i
];
1402 BrowserAccessibilityWin
* cell
=
1403 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1404 if (cell
&& cell
->GetRole() == ui::AX_ROLE_ROW_HEADER
) {
1405 base::string16 cell_name
= cell
->GetString16Attribute(
1407 if (cell_name
.size() > 0) {
1408 *description
= SysAllocString(cell_name
.c_str());
1412 if (cell
->description().size() > 0) {
1413 *description
= SysAllocString(cell
->description().c_str());
1422 STDMETHODIMP
BrowserAccessibilityWin::get_rowExtentAt(long row
,
1424 long* n_rows_spanned
) {
1425 if (!instance_active())
1428 if (!n_rows_spanned
)
1429 return E_INVALIDARG
;
1433 if (!GetIntAttribute(
1434 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1435 !GetIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
) ||
1441 if (row
< 0 || row
>= rows
|| column
< 0 || column
>= columns
)
1442 return E_INVALIDARG
;
1444 const std::vector
<int32
>& cell_ids
= GetIntListAttribute(
1445 ui::AX_ATTR_CELL_IDS
);
1446 int cell_id
= cell_ids
[row
* columns
+ column
];
1447 BrowserAccessibilityWin
* cell
=
1448 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1451 cell
->GetIntAttribute(
1452 ui::AX_ATTR_TABLE_CELL_ROW_SPAN
, &rowspan
) &&
1454 *n_rows_spanned
= rowspan
;
1461 STDMETHODIMP
BrowserAccessibilityWin::get_rowHeader(
1462 IAccessibleTable
** accessible_table
,
1463 long* starting_column_index
) {
1464 // TODO(dmazzoni): implement
1468 STDMETHODIMP
BrowserAccessibilityWin::get_rowIndex(long cell_index
,
1470 if (!instance_active())
1474 return E_INVALIDARG
;
1476 const std::vector
<int32
>& unique_cell_ids
= GetIntListAttribute(
1477 ui::AX_ATTR_UNIQUE_CELL_IDS
);
1478 int cell_id_count
= static_cast<int>(unique_cell_ids
.size());
1480 return E_INVALIDARG
;
1481 if (cell_index
>= cell_id_count
)
1484 int cell_id
= unique_cell_ids
[cell_index
];
1485 BrowserAccessibilityWin
* cell
=
1486 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1489 cell
->GetIntAttribute(
1490 ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &cell_row_index
)) {
1491 *row_index
= cell_row_index
;
1498 STDMETHODIMP
BrowserAccessibilityWin::get_selectedChildren(long max_children
,
1501 if (!instance_active())
1504 if (!children
|| !n_children
)
1505 return E_INVALIDARG
;
1507 // TODO(dmazzoni): Implement this.
1512 STDMETHODIMP
BrowserAccessibilityWin::get_selectedColumns(long max_columns
,
1515 if (!instance_active())
1518 if (!columns
|| !n_columns
)
1519 return E_INVALIDARG
;
1521 // TODO(dmazzoni): Implement this.
1526 STDMETHODIMP
BrowserAccessibilityWin::get_selectedRows(long max_rows
,
1529 if (!instance_active())
1532 if (!rows
|| !n_rows
)
1533 return E_INVALIDARG
;
1535 // TODO(dmazzoni): Implement this.
1540 STDMETHODIMP
BrowserAccessibilityWin::get_summary(IUnknown
** accessible
) {
1541 if (!instance_active())
1545 return E_INVALIDARG
;
1547 // TODO(dmazzoni): implement
1551 STDMETHODIMP
BrowserAccessibilityWin::get_isColumnSelected(
1553 boolean
* is_selected
) {
1554 if (!instance_active())
1558 return E_INVALIDARG
;
1560 // TODO(dmazzoni): Implement this.
1561 *is_selected
= false;
1565 STDMETHODIMP
BrowserAccessibilityWin::get_isRowSelected(long row
,
1566 boolean
* is_selected
) {
1567 if (!instance_active())
1571 return E_INVALIDARG
;
1573 // TODO(dmazzoni): Implement this.
1574 *is_selected
= false;
1578 STDMETHODIMP
BrowserAccessibilityWin::get_isSelected(long row
,
1580 boolean
* is_selected
) {
1581 if (!instance_active())
1585 return E_INVALIDARG
;
1587 // TODO(dmazzoni): Implement this.
1588 *is_selected
= false;
1592 STDMETHODIMP
BrowserAccessibilityWin::get_rowColumnExtentsAtIndex(
1597 long* column_extents
,
1598 boolean
* is_selected
) {
1599 if (!instance_active())
1602 if (!row
|| !column
|| !row_extents
|| !column_extents
|| !is_selected
)
1603 return E_INVALIDARG
;
1605 const std::vector
<int32
>& unique_cell_ids
= GetIntListAttribute(
1606 ui::AX_ATTR_UNIQUE_CELL_IDS
);
1607 int cell_id_count
= static_cast<int>(unique_cell_ids
.size());
1609 return E_INVALIDARG
;
1610 if (index
>= cell_id_count
)
1613 int cell_id
= unique_cell_ids
[index
];
1614 BrowserAccessibilityWin
* cell
=
1615 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1619 cell
->GetIntAttribute(
1620 ui::AX_ATTR_TABLE_CELL_ROW_SPAN
, &rowspan
) &&
1621 cell
->GetIntAttribute(
1622 ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN
, &colspan
) &&
1625 *row_extents
= rowspan
;
1626 *column_extents
= colspan
;
1633 STDMETHODIMP
BrowserAccessibilityWin::selectRow(long row
) {
1637 STDMETHODIMP
BrowserAccessibilityWin::selectColumn(long column
) {
1641 STDMETHODIMP
BrowserAccessibilityWin::unselectRow(long row
) {
1645 STDMETHODIMP
BrowserAccessibilityWin::unselectColumn(long column
) {
1650 BrowserAccessibilityWin::get_modelChange(IA2TableModelChange
* model_change
) {
1655 // IAccessibleTable2 methods.
1658 STDMETHODIMP
BrowserAccessibilityWin::get_cellAt(long row
,
1661 return get_accessibleAt(row
, column
, cell
);
1664 STDMETHODIMP
BrowserAccessibilityWin::get_nSelectedCells(long* cell_count
) {
1665 return get_nSelectedChildren(cell_count
);
1668 STDMETHODIMP
BrowserAccessibilityWin::get_selectedCells(
1670 long* n_selected_cells
) {
1671 if (!instance_active())
1674 if (!cells
|| !n_selected_cells
)
1675 return E_INVALIDARG
;
1677 // TODO(dmazzoni): Implement this.
1678 *n_selected_cells
= 0;
1682 STDMETHODIMP
BrowserAccessibilityWin::get_selectedColumns(long** columns
,
1684 if (!instance_active())
1687 if (!columns
|| !n_columns
)
1688 return E_INVALIDARG
;
1690 // TODO(dmazzoni): Implement this.
1695 STDMETHODIMP
BrowserAccessibilityWin::get_selectedRows(long** rows
,
1697 if (!instance_active())
1700 if (!rows
|| !n_rows
)
1701 return E_INVALIDARG
;
1703 // TODO(dmazzoni): Implement this.
1710 // IAccessibleTableCell methods.
1713 STDMETHODIMP
BrowserAccessibilityWin::get_columnExtent(
1714 long* n_columns_spanned
) {
1715 if (!instance_active())
1718 if (!n_columns_spanned
)
1719 return E_INVALIDARG
;
1722 if (GetIntAttribute(
1723 ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN
, &colspan
) &&
1725 *n_columns_spanned
= colspan
;
1732 STDMETHODIMP
BrowserAccessibilityWin::get_columnHeaderCells(
1733 IUnknown
*** cell_accessibles
,
1734 long* n_column_header_cells
) {
1735 if (!instance_active())
1738 if (!cell_accessibles
|| !n_column_header_cells
)
1739 return E_INVALIDARG
;
1741 *n_column_header_cells
= 0;
1744 if (!GetIntAttribute(
1745 ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &column
)) {
1749 BrowserAccessibility
* table
= GetParent();
1750 while (table
&& table
->GetRole() != ui::AX_ROLE_TABLE
)
1751 table
= table
->GetParent();
1759 if (!table
->GetIntAttribute(
1760 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1761 !table
->GetIntAttribute(
1762 ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
)) {
1765 if (columns
<= 0 || rows
<= 0 || column
< 0 || column
>= columns
)
1768 const std::vector
<int32
>& cell_ids
= table
->GetIntListAttribute(
1769 ui::AX_ATTR_CELL_IDS
);
1771 for (int i
= 0; i
< rows
; ++i
) {
1772 int cell_id
= cell_ids
[i
* columns
+ column
];
1773 BrowserAccessibilityWin
* cell
=
1774 manager()->GetFromID(cell_id
)->ToBrowserAccessibilityWin();
1775 if (cell
&& cell
->GetRole() == ui::AX_ROLE_COLUMN_HEADER
)
1776 (*n_column_header_cells
)++;
1779 *cell_accessibles
= static_cast<IUnknown
**>(CoTaskMemAlloc(
1780 (*n_column_header_cells
) * sizeof(cell_accessibles
[0])));
1782 for (int i
= 0; i
< rows
; ++i
) {
1783 int cell_id
= cell_ids
[i
* columns
+ column
];
1784 BrowserAccessibility
* cell
= manager()->GetFromID(cell_id
);
1785 if (cell
&& cell
->GetRole() == ui::AX_ROLE_COLUMN_HEADER
) {
1786 (*cell_accessibles
)[index
] = static_cast<IAccessible
*>(
1787 cell
->ToBrowserAccessibilityWin()->NewReference());
1795 STDMETHODIMP
BrowserAccessibilityWin::get_columnIndex(long* column_index
) {
1796 if (!instance_active())
1800 return E_INVALIDARG
;
1803 if (GetIntAttribute(
1804 ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &column
)) {
1805 *column_index
= column
;
1812 STDMETHODIMP
BrowserAccessibilityWin::get_rowExtent(long* n_rows_spanned
) {
1813 if (!instance_active())
1816 if (!n_rows_spanned
)
1817 return E_INVALIDARG
;
1820 if (GetIntAttribute(
1821 ui::AX_ATTR_TABLE_CELL_ROW_SPAN
, &rowspan
) &&
1823 *n_rows_spanned
= rowspan
;
1830 STDMETHODIMP
BrowserAccessibilityWin::get_rowHeaderCells(
1831 IUnknown
*** cell_accessibles
,
1832 long* n_row_header_cells
) {
1833 if (!instance_active())
1836 if (!cell_accessibles
|| !n_row_header_cells
)
1837 return E_INVALIDARG
;
1839 *n_row_header_cells
= 0;
1842 if (!GetIntAttribute(
1843 ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &row
)) {
1847 BrowserAccessibility
* table
= GetParent();
1848 while (table
&& table
->GetRole() != ui::AX_ROLE_TABLE
)
1849 table
= table
->GetParent();
1857 if (!table
->GetIntAttribute(
1858 ui::AX_ATTR_TABLE_COLUMN_COUNT
, &columns
) ||
1859 !table
->GetIntAttribute(
1860 ui::AX_ATTR_TABLE_ROW_COUNT
, &rows
)) {
1863 if (columns
<= 0 || rows
<= 0 || row
< 0 || row
>= rows
)
1866 const std::vector
<int32
>& cell_ids
= table
->GetIntListAttribute(
1867 ui::AX_ATTR_CELL_IDS
);
1869 for (int i
= 0; i
< columns
; ++i
) {
1870 int cell_id
= cell_ids
[row
* columns
+ i
];
1871 BrowserAccessibility
* cell
= manager()->GetFromID(cell_id
);
1872 if (cell
&& cell
->GetRole() == ui::AX_ROLE_ROW_HEADER
)
1873 (*n_row_header_cells
)++;
1876 *cell_accessibles
= static_cast<IUnknown
**>(CoTaskMemAlloc(
1877 (*n_row_header_cells
) * sizeof(cell_accessibles
[0])));
1879 for (int i
= 0; i
< columns
; ++i
) {
1880 int cell_id
= cell_ids
[row
* columns
+ i
];
1881 BrowserAccessibility
* cell
= manager()->GetFromID(cell_id
);
1882 if (cell
&& cell
->GetRole() == ui::AX_ROLE_ROW_HEADER
) {
1883 (*cell_accessibles
)[index
] = static_cast<IAccessible
*>(
1884 cell
->ToBrowserAccessibilityWin()->NewReference());
1892 STDMETHODIMP
BrowserAccessibilityWin::get_rowIndex(long* row_index
) {
1893 if (!instance_active())
1897 return E_INVALIDARG
;
1900 if (GetIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &row
)) {
1907 STDMETHODIMP
BrowserAccessibilityWin::get_isSelected(boolean
* is_selected
) {
1908 if (!instance_active())
1912 return E_INVALIDARG
;
1914 *is_selected
= false;
1918 STDMETHODIMP
BrowserAccessibilityWin::get_rowColumnExtents(
1922 long* column_extents
,
1923 boolean
* is_selected
) {
1924 if (!instance_active())
1932 return E_INVALIDARG
;
1939 if (GetIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &row
) &&
1941 ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &column
) &&
1943 ui::AX_ATTR_TABLE_CELL_ROW_SPAN
, &rowspan
) &&
1945 ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN
, &colspan
)) {
1947 *column_index
= column
;
1948 *row_extents
= rowspan
;
1949 *column_extents
= colspan
;
1950 *is_selected
= false;
1957 STDMETHODIMP
BrowserAccessibilityWin::get_table(IUnknown
** table
) {
1958 if (!instance_active())
1962 return E_INVALIDARG
;
1967 GetIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX
, &row
);
1968 GetIntAttribute(ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX
, &column
);
1970 BrowserAccessibility
* find_table
= GetParent();
1971 while (find_table
&& find_table
->GetRole() != ui::AX_ROLE_TABLE
)
1972 find_table
= find_table
->GetParent();
1978 *table
= static_cast<IAccessibleTable
*>(
1979 find_table
->ToBrowserAccessibilityWin()->NewReference());
1985 // IAccessibleText methods.
1988 STDMETHODIMP
BrowserAccessibilityWin::get_nCharacters(LONG
* n_characters
) {
1989 if (!instance_active())
1993 return E_INVALIDARG
;
1995 *n_characters
= TextForIAccessibleText().length();
1999 STDMETHODIMP
BrowserAccessibilityWin::get_caretOffset(LONG
* offset
) {
2000 if (!instance_active())
2004 return E_INVALIDARG
;
2006 // IA2 spec says that caret offset should be -1 if the object is not focused.
2007 if (manager()->GetFocus(this) != this) {
2013 if (IsEditableText()) {
2015 if (GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START
,
2017 *offset
= sel_start
;
2023 STDMETHODIMP
BrowserAccessibilityWin::get_characterExtents(
2025 enum IA2CoordinateType coordinate_type
,
2030 if (!instance_active())
2033 if (!out_x
|| !out_y
|| !out_width
|| !out_height
)
2034 return E_INVALIDARG
;
2036 const base::string16
& text_str
= TextForIAccessibleText();
2037 HandleSpecialTextOffset(text_str
, &offset
);
2039 if (offset
< 0 || offset
> static_cast<LONG
>(text_str
.size()))
2040 return E_INVALIDARG
;
2042 gfx::Rect character_bounds
;
2043 if (coordinate_type
== IA2_COORDTYPE_SCREEN_RELATIVE
) {
2044 character_bounds
= GetGlobalBoundsForRange(offset
, 1);
2045 } else if (coordinate_type
== IA2_COORDTYPE_PARENT_RELATIVE
) {
2046 character_bounds
= GetLocalBoundsForRange(offset
, 1);
2047 character_bounds
-= GetLocation().OffsetFromOrigin();
2049 return E_INVALIDARG
;
2052 *out_x
= character_bounds
.x();
2053 *out_y
= character_bounds
.y();
2054 *out_width
= character_bounds
.width();
2055 *out_height
= character_bounds
.height();
2060 STDMETHODIMP
BrowserAccessibilityWin::get_nSelections(LONG
* n_selections
) {
2061 if (!instance_active())
2065 return E_INVALIDARG
;
2068 if (IsEditableText()) {
2071 if (GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START
,
2073 GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END
, &sel_end
) &&
2074 sel_start
!= sel_end
)
2081 STDMETHODIMP
BrowserAccessibilityWin::get_selection(LONG selection_index
,
2084 if (!instance_active())
2087 if (!start_offset
|| !end_offset
|| selection_index
!= 0)
2088 return E_INVALIDARG
;
2090 LONG n_selections
= 0;
2091 if (FAILED(get_nSelections(&n_selections
)) || n_selections
< 1)
2092 return E_INVALIDARG
;
2096 if (IsEditableText()) {
2099 if (GetIntAttribute(
2100 ui::AX_ATTR_TEXT_SEL_START
, &sel_start
) &&
2101 GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END
, &sel_end
)) {
2102 *start_offset
= sel_start
;
2103 *end_offset
= sel_end
;
2110 STDMETHODIMP
BrowserAccessibilityWin::get_text(LONG start_offset
,
2113 if (!instance_active())
2117 return E_INVALIDARG
;
2119 const base::string16
& text_str
= TextForIAccessibleText();
2121 // Handle special text offsets.
2122 HandleSpecialTextOffset(text_str
, &start_offset
);
2123 HandleSpecialTextOffset(text_str
, &end_offset
);
2125 // The spec allows the arguments to be reversed.
2126 if (start_offset
> end_offset
) {
2127 LONG tmp
= start_offset
;
2128 start_offset
= end_offset
;
2132 // The spec does not allow the start or end offsets to be out or range;
2133 // we must return an error if so.
2134 LONG len
= text_str
.length();
2135 if (start_offset
< 0)
2136 return E_INVALIDARG
;
2137 if (end_offset
> len
)
2138 return E_INVALIDARG
;
2140 base::string16 substr
= text_str
.substr(start_offset
,
2141 end_offset
- start_offset
);
2145 *text
= SysAllocString(substr
.c_str());
2150 STDMETHODIMP
BrowserAccessibilityWin::get_textAtOffset(
2152 enum IA2TextBoundaryType boundary_type
,
2156 if (!instance_active())
2159 if (!start_offset
|| !end_offset
|| !text
)
2160 return E_INVALIDARG
;
2162 const base::string16
& text_str
= TextForIAccessibleText();
2163 HandleSpecialTextOffset(text_str
, &offset
);
2165 return E_INVALIDARG
;
2167 LONG text_len
= text_str
.length();
2168 if (offset
> text_len
)
2169 return E_INVALIDARG
;
2171 // The IAccessible2 spec says we don't have to implement the "sentence"
2172 // boundary type, we can just let the screenreader handle it.
2173 if (boundary_type
== IA2_TEXT_BOUNDARY_SENTENCE
) {
2180 // According to the IA2 Spec, only line boundaries should succeed when
2181 // the offset is one past the end of the text.
2182 if (offset
== text_len
&& boundary_type
!= IA2_TEXT_BOUNDARY_LINE
) {
2189 *start_offset
= FindBoundary(
2190 text_str
, boundary_type
, offset
, ui::BACKWARDS_DIRECTION
);
2191 *end_offset
= FindBoundary(
2192 text_str
, boundary_type
, offset
, ui::FORWARDS_DIRECTION
);
2193 return get_text(*start_offset
, *end_offset
, text
);
2196 STDMETHODIMP
BrowserAccessibilityWin::get_textBeforeOffset(
2198 enum IA2TextBoundaryType boundary_type
,
2202 if (!instance_active())
2205 if (!start_offset
|| !end_offset
|| !text
)
2206 return E_INVALIDARG
;
2208 // The IAccessible2 spec says we don't have to implement the "sentence"
2209 // boundary type, we can just let the screenreader handle it.
2210 if (boundary_type
== IA2_TEXT_BOUNDARY_SENTENCE
) {
2217 const base::string16
& text_str
= TextForIAccessibleText();
2219 *start_offset
= FindBoundary(
2220 text_str
, boundary_type
, offset
, ui::BACKWARDS_DIRECTION
);
2221 *end_offset
= offset
;
2222 return get_text(*start_offset
, *end_offset
, text
);
2225 STDMETHODIMP
BrowserAccessibilityWin::get_textAfterOffset(
2227 enum IA2TextBoundaryType boundary_type
,
2231 if (!instance_active())
2234 if (!start_offset
|| !end_offset
|| !text
)
2235 return E_INVALIDARG
;
2237 // The IAccessible2 spec says we don't have to implement the "sentence"
2238 // boundary type, we can just let the screenreader handle it.
2239 if (boundary_type
== IA2_TEXT_BOUNDARY_SENTENCE
) {
2246 const base::string16
& text_str
= TextForIAccessibleText();
2248 *start_offset
= offset
;
2249 *end_offset
= FindBoundary(
2250 text_str
, boundary_type
, offset
, ui::FORWARDS_DIRECTION
);
2251 return get_text(*start_offset
, *end_offset
, text
);
2254 STDMETHODIMP
BrowserAccessibilityWin::get_newText(IA2TextSegment
* new_text
) {
2255 if (!instance_active())
2259 return E_INVALIDARG
;
2261 if (!old_win_attributes_
)
2264 int start
, old_len
, new_len
;
2265 ComputeHypertextRemovedAndInserted(&start
, &old_len
, &new_len
);
2269 base::string16 substr
= hypertext().substr(start
, new_len
);
2270 new_text
->text
= SysAllocString(substr
.c_str());
2271 new_text
->start
= static_cast<long>(start
);
2272 new_text
->end
= static_cast<long>(start
+ new_len
);
2276 STDMETHODIMP
BrowserAccessibilityWin::get_oldText(IA2TextSegment
* old_text
) {
2277 if (!instance_active())
2281 return E_INVALIDARG
;
2283 if (!old_win_attributes_
)
2286 int start
, old_len
, new_len
;
2287 ComputeHypertextRemovedAndInserted(&start
, &old_len
, &new_len
);
2291 base::string16 old_hypertext
= old_win_attributes_
->hypertext
;
2292 base::string16 substr
= old_hypertext
.substr(start
, old_len
);
2293 old_text
->text
= SysAllocString(substr
.c_str());
2294 old_text
->start
= static_cast<long>(start
);
2295 old_text
->end
= static_cast<long>(start
+ old_len
);
2299 STDMETHODIMP
BrowserAccessibilityWin::get_offsetAtPoint(
2302 enum IA2CoordinateType coord_type
,
2304 if (!instance_active())
2308 return E_INVALIDARG
;
2310 // TODO(dmazzoni): implement this. We're returning S_OK for now so that
2311 // screen readers still return partially accurate results rather than
2312 // completely failing.
2317 STDMETHODIMP
BrowserAccessibilityWin::scrollSubstringTo(
2320 enum IA2ScrollType scroll_type
) {
2321 // TODO(dmazzoni): adjust this for the start and end index, too.
2322 return scrollTo(scroll_type
);
2325 STDMETHODIMP
BrowserAccessibilityWin::scrollSubstringToPoint(
2328 enum IA2CoordinateType coordinate_type
,
2330 // TODO(dmazzoni): adjust this for the start and end index, too.
2331 return scrollToPoint(coordinate_type
, x
, y
);
2334 STDMETHODIMP
BrowserAccessibilityWin::addSelection(LONG start_offset
,
2336 if (!instance_active())
2339 const base::string16
& text_str
= TextForIAccessibleText();
2340 HandleSpecialTextOffset(text_str
, &start_offset
);
2341 HandleSpecialTextOffset(text_str
, &end_offset
);
2343 manager()->SetTextSelection(*this, start_offset
, end_offset
);
2347 STDMETHODIMP
BrowserAccessibilityWin::removeSelection(LONG selection_index
) {
2348 if (!instance_active())
2351 if (selection_index
!= 0)
2352 return E_INVALIDARG
;
2354 manager()->SetTextSelection(*this, 0, 0);
2358 STDMETHODIMP
BrowserAccessibilityWin::setCaretOffset(LONG offset
) {
2359 if (!instance_active())
2362 const base::string16
& text_str
= TextForIAccessibleText();
2363 HandleSpecialTextOffset(text_str
, &offset
);
2364 manager()->SetTextSelection(*this, offset
, offset
);
2368 STDMETHODIMP
BrowserAccessibilityWin::setSelection(LONG selection_index
,
2371 if (!instance_active())
2374 if (selection_index
!= 0)
2375 return E_INVALIDARG
;
2377 const base::string16
& text_str
= TextForIAccessibleText();
2378 HandleSpecialTextOffset(text_str
, &start_offset
);
2379 HandleSpecialTextOffset(text_str
, &end_offset
);
2381 manager()->SetTextSelection(*this, start_offset
, end_offset
);
2386 // IAccessibleText methods not implemented.
2389 STDMETHODIMP
BrowserAccessibilityWin::get_attributes(LONG offset
,
2392 BSTR
* text_attributes
) {
2397 // IAccessibleHypertext methods.
2400 STDMETHODIMP
BrowserAccessibilityWin::get_nHyperlinks(long* hyperlink_count
) {
2401 if (!instance_active())
2404 if (!hyperlink_count
)
2405 return E_INVALIDARG
;
2407 *hyperlink_count
= hyperlink_offset_to_index().size();
2411 STDMETHODIMP
BrowserAccessibilityWin::get_hyperlink(
2413 IAccessibleHyperlink
** hyperlink
) {
2414 if (!instance_active())
2419 index
>= static_cast<long>(hyperlinks().size())) {
2420 return E_INVALIDARG
;
2423 int32 id
= hyperlinks()[index
];
2424 BrowserAccessibilityWin
* child
=
2425 manager()->GetFromID(id
)->ToBrowserAccessibilityWin();
2427 *hyperlink
= static_cast<IAccessibleHyperlink
*>(child
->NewReference());
2434 STDMETHODIMP
BrowserAccessibilityWin::get_hyperlinkIndex(
2436 long* hyperlink_index
) {
2437 if (!instance_active())
2440 if (!hyperlink_index
)
2441 return E_INVALIDARG
;
2443 *hyperlink_index
= -1;
2445 if (char_index
< 0 ||
2446 char_index
>= static_cast<long>(hypertext().size())) {
2447 return E_INVALIDARG
;
2450 std::map
<int32
, int32
>::iterator it
=
2451 hyperlink_offset_to_index().find(char_index
);
2452 if (it
== hyperlink_offset_to_index().end())
2455 *hyperlink_index
= it
->second
;
2460 // IAccessibleHyperlink not implemented.
2463 STDMETHODIMP
BrowserAccessibilityWin::get_anchor(long index
, VARIANT
* anchor
) {
2467 BrowserAccessibilityWin::get_anchorTarget(long index
, VARIANT
* anchor_target
) {
2470 STDMETHODIMP
BrowserAccessibilityWin::get_startIndex(long* index
) {
2473 STDMETHODIMP
BrowserAccessibilityWin::get_endIndex(long* index
) {
2476 STDMETHODIMP
BrowserAccessibilityWin::get_valid(boolean
* valid
) {
2481 // IAccessibleAction not implemented.
2484 STDMETHODIMP
BrowserAccessibilityWin::nActions(long* n_actions
) {
2487 STDMETHODIMP
BrowserAccessibilityWin::doAction(long action_index
) {
2491 BrowserAccessibilityWin::get_description(long action_index
, BSTR
* description
) {
2494 STDMETHODIMP
BrowserAccessibilityWin::get_keyBinding(long action_index
,
2495 long n_max_bindings
,
2496 BSTR
** key_bindings
,
2500 STDMETHODIMP
BrowserAccessibilityWin::get_name(long action_index
, BSTR
* name
) {
2504 BrowserAccessibilityWin::get_localizedName(long action_index
,
2505 BSTR
* localized_name
) {
2510 // IAccessibleValue methods.
2513 STDMETHODIMP
BrowserAccessibilityWin::get_currentValue(VARIANT
* value
) {
2514 if (!instance_active())
2518 return E_INVALIDARG
;
2521 if (GetFloatAttribute(
2522 ui::AX_ATTR_VALUE_FOR_RANGE
, &float_val
)) {
2524 value
->dblVal
= float_val
;
2528 value
->vt
= VT_EMPTY
;
2532 STDMETHODIMP
BrowserAccessibilityWin::get_minimumValue(VARIANT
* value
) {
2533 if (!instance_active())
2537 return E_INVALIDARG
;
2540 if (GetFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE
,
2543 value
->dblVal
= float_val
;
2547 value
->vt
= VT_EMPTY
;
2551 STDMETHODIMP
BrowserAccessibilityWin::get_maximumValue(VARIANT
* value
) {
2552 if (!instance_active())
2556 return E_INVALIDARG
;
2559 if (GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE
,
2562 value
->dblVal
= float_val
;
2566 value
->vt
= VT_EMPTY
;
2570 STDMETHODIMP
BrowserAccessibilityWin::setCurrentValue(VARIANT new_value
) {
2571 // TODO(dmazzoni): Implement this.
2576 // ISimpleDOMDocument methods.
2579 STDMETHODIMP
BrowserAccessibilityWin::get_URL(BSTR
* url
) {
2580 if (!instance_active())
2584 return E_INVALIDARG
;
2586 return GetStringAttributeAsBstr(ui::AX_ATTR_DOC_URL
, url
);
2589 STDMETHODIMP
BrowserAccessibilityWin::get_title(BSTR
* title
) {
2590 if (!instance_active())
2594 return E_INVALIDARG
;
2596 return GetStringAttributeAsBstr(ui::AX_ATTR_DOC_TITLE
, title
);
2599 STDMETHODIMP
BrowserAccessibilityWin::get_mimeType(BSTR
* mime_type
) {
2600 if (!instance_active())
2604 return E_INVALIDARG
;
2606 return GetStringAttributeAsBstr(
2607 ui::AX_ATTR_DOC_MIMETYPE
, mime_type
);
2610 STDMETHODIMP
BrowserAccessibilityWin::get_docType(BSTR
* doc_type
) {
2611 if (!instance_active())
2615 return E_INVALIDARG
;
2617 return GetStringAttributeAsBstr(
2618 ui::AX_ATTR_DOC_DOCTYPE
, doc_type
);
2622 BrowserAccessibilityWin::get_nameSpaceURIForID(short name_space_id
,
2623 BSTR
* name_space_uri
) {
2627 BrowserAccessibilityWin::put_alternateViewMediaTypes(
2628 BSTR
* comma_separated_media_types
) {
2633 // ISimpleDOMNode methods.
2636 STDMETHODIMP
BrowserAccessibilityWin::get_nodeInfo(
2638 short* name_space_id
,
2640 unsigned int* num_children
,
2641 unsigned int* unique_id
,
2642 unsigned short* node_type
) {
2643 if (!instance_active())
2646 if (!node_name
|| !name_space_id
|| !node_value
|| !num_children
||
2647 !unique_id
|| !node_type
) {
2648 return E_INVALIDARG
;
2652 if (GetString16Attribute(ui::AX_ATTR_HTML_TAG
, &tag
))
2653 *node_name
= SysAllocString(tag
.c_str());
2658 *node_value
= SysAllocString(value().c_str());
2659 *num_children
= PlatformChildCount();
2660 *unique_id
= unique_id_win_
;
2662 if (ia_role() == ROLE_SYSTEM_DOCUMENT
) {
2663 *node_type
= NODETYPE_DOCUMENT
;
2664 } else if (ia_role() == ROLE_SYSTEM_TEXT
&&
2665 ((ia2_state() & IA2_STATE_EDITABLE
) == 0)) {
2666 *node_type
= NODETYPE_TEXT
;
2668 *node_type
= NODETYPE_ELEMENT
;
2674 STDMETHODIMP
BrowserAccessibilityWin::get_attributes(
2675 unsigned short max_attribs
,
2677 short* name_space_id
,
2678 BSTR
* attrib_values
,
2679 unsigned short* num_attribs
) {
2680 if (!instance_active())
2683 if (!attrib_names
|| !name_space_id
|| !attrib_values
|| !num_attribs
)
2684 return E_INVALIDARG
;
2686 *num_attribs
= max_attribs
;
2687 if (*num_attribs
> GetHtmlAttributes().size())
2688 *num_attribs
= GetHtmlAttributes().size();
2690 for (unsigned short i
= 0; i
< *num_attribs
; ++i
) {
2691 attrib_names
[i
] = SysAllocString(
2692 base::UTF8ToUTF16(GetHtmlAttributes()[i
].first
).c_str());
2693 name_space_id
[i
] = 0;
2694 attrib_values
[i
] = SysAllocString(
2695 base::UTF8ToUTF16(GetHtmlAttributes()[i
].second
).c_str());
2700 STDMETHODIMP
BrowserAccessibilityWin::get_attributesForNames(
2701 unsigned short num_attribs
,
2703 short* name_space_id
,
2704 BSTR
* attrib_values
) {
2705 if (!instance_active())
2708 if (!attrib_names
|| !name_space_id
|| !attrib_values
)
2709 return E_INVALIDARG
;
2711 for (unsigned short i
= 0; i
< num_attribs
; ++i
) {
2712 name_space_id
[i
] = 0;
2714 std::string name
= base::UTF16ToUTF8((LPCWSTR
)attrib_names
[i
]);
2715 for (unsigned int j
= 0; j
< GetHtmlAttributes().size(); ++j
) {
2716 if (GetHtmlAttributes()[j
].first
== name
) {
2717 attrib_values
[i
] = SysAllocString(
2718 base::UTF8ToUTF16(GetHtmlAttributes()[j
].second
).c_str());
2724 attrib_values
[i
] = NULL
;
2730 STDMETHODIMP
BrowserAccessibilityWin::get_computedStyle(
2731 unsigned short max_style_properties
,
2732 boolean use_alternate_view
,
2733 BSTR
* style_properties
,
2735 unsigned short *num_style_properties
) {
2736 if (!instance_active())
2739 if (!style_properties
|| !style_values
)
2740 return E_INVALIDARG
;
2742 // We only cache a single style property for now: DISPLAY
2744 base::string16 display
;
2745 if (max_style_properties
== 0 ||
2746 !GetString16Attribute(ui::AX_ATTR_DISPLAY
, &display
)) {
2747 *num_style_properties
= 0;
2751 *num_style_properties
= 1;
2752 style_properties
[0] = SysAllocString(L
"display");
2753 style_values
[0] = SysAllocString(display
.c_str());
2758 STDMETHODIMP
BrowserAccessibilityWin::get_computedStyleForProperties(
2759 unsigned short num_style_properties
,
2760 boolean use_alternate_view
,
2761 BSTR
* style_properties
,
2762 BSTR
* style_values
) {
2763 if (!instance_active())
2766 if (!style_properties
|| !style_values
)
2767 return E_INVALIDARG
;
2769 // We only cache a single style property for now: DISPLAY
2771 for (unsigned short i
= 0; i
< num_style_properties
; ++i
) {
2772 base::string16 name
= (LPCWSTR
)style_properties
[i
];
2773 base::StringToLowerASCII(&name
);
2774 if (name
== L
"display") {
2775 base::string16 display
= GetString16Attribute(
2776 ui::AX_ATTR_DISPLAY
);
2777 style_values
[i
] = SysAllocString(display
.c_str());
2779 style_values
[i
] = NULL
;
2786 STDMETHODIMP
BrowserAccessibilityWin::scrollTo(boolean placeTopLeft
) {
2787 return scrollTo(placeTopLeft
?
2788 IA2_SCROLL_TYPE_TOP_LEFT
: IA2_SCROLL_TYPE_ANYWHERE
);
2791 STDMETHODIMP
BrowserAccessibilityWin::get_parentNode(ISimpleDOMNode
** node
) {
2792 if (!instance_active())
2796 return E_INVALIDARG
;
2798 *node
= GetParent()->ToBrowserAccessibilityWin()->NewReference();
2802 STDMETHODIMP
BrowserAccessibilityWin::get_firstChild(ISimpleDOMNode
** node
) {
2803 if (!instance_active())
2807 return E_INVALIDARG
;
2809 if (PlatformChildCount() == 0) {
2814 *node
= PlatformGetChild(0)->ToBrowserAccessibilityWin()->NewReference();
2818 STDMETHODIMP
BrowserAccessibilityWin::get_lastChild(ISimpleDOMNode
** node
) {
2819 if (!instance_active())
2823 return E_INVALIDARG
;
2825 if (PlatformChildCount() == 0) {
2830 *node
= PlatformGetChild(PlatformChildCount() - 1)
2831 ->ToBrowserAccessibilityWin()->NewReference();
2835 STDMETHODIMP
BrowserAccessibilityWin::get_previousSibling(
2836 ISimpleDOMNode
** node
) {
2837 if (!instance_active())
2841 return E_INVALIDARG
;
2843 if (!GetParent() || GetIndexInParent() <= 0) {
2848 *node
= GetParent()->InternalGetChild(GetIndexInParent() - 1)->
2849 ToBrowserAccessibilityWin()->NewReference();
2853 STDMETHODIMP
BrowserAccessibilityWin::get_nextSibling(ISimpleDOMNode
** node
) {
2854 if (!instance_active())
2858 return E_INVALIDARG
;
2861 GetIndexInParent() < 0 ||
2862 GetIndexInParent() >= static_cast<int>(
2863 GetParent()->InternalChildCount()) - 1) {
2868 *node
= GetParent()->InternalGetChild(GetIndexInParent() + 1)->
2869 ToBrowserAccessibilityWin()->NewReference();
2873 STDMETHODIMP
BrowserAccessibilityWin::get_childAt(
2874 unsigned int child_index
,
2875 ISimpleDOMNode
** node
) {
2876 if (!instance_active())
2880 return E_INVALIDARG
;
2882 if (child_index
>= PlatformChildCount())
2883 return E_INVALIDARG
;
2885 BrowserAccessibility
* child
= PlatformGetChild(child_index
);
2891 *node
= child
->ToBrowserAccessibilityWin()->NewReference();
2895 STDMETHODIMP
BrowserAccessibilityWin::get_innerHTML(BSTR
* innerHTML
) {
2900 BrowserAccessibilityWin::get_localInterface(void** local_interface
) {
2904 STDMETHODIMP
BrowserAccessibilityWin::get_language(BSTR
* language
) {
2909 // ISimpleDOMText methods.
2912 STDMETHODIMP
BrowserAccessibilityWin::get_domText(BSTR
* dom_text
) {
2913 if (!instance_active())
2917 return E_INVALIDARG
;
2919 return GetStringAttributeAsBstr(
2920 ui::AX_ATTR_NAME
, dom_text
);
2923 STDMETHODIMP
BrowserAccessibilityWin::get_clippedSubstringBounds(
2924 unsigned int start_index
,
2925 unsigned int end_index
,
2930 // TODO(dmazzoni): fully support this API by intersecting the
2931 // rect with the container's rect.
2932 return get_unclippedSubstringBounds(
2933 start_index
, end_index
, out_x
, out_y
, out_width
, out_height
);
2936 STDMETHODIMP
BrowserAccessibilityWin::get_unclippedSubstringBounds(
2937 unsigned int start_index
,
2938 unsigned int end_index
,
2943 if (!instance_active())
2946 if (!out_x
|| !out_y
|| !out_width
|| !out_height
)
2947 return E_INVALIDARG
;
2949 const base::string16
& text_str
= TextForIAccessibleText();
2950 if (start_index
> text_str
.size() ||
2951 end_index
> text_str
.size() ||
2952 start_index
> end_index
) {
2953 return E_INVALIDARG
;
2956 gfx::Rect bounds
= GetGlobalBoundsForRange(
2957 start_index
, end_index
- start_index
);
2958 *out_x
= bounds
.x();
2959 *out_y
= bounds
.y();
2960 *out_width
= bounds
.width();
2961 *out_height
= bounds
.height();
2965 STDMETHODIMP
BrowserAccessibilityWin::scrollToSubstring(
2966 unsigned int start_index
,
2967 unsigned int end_index
) {
2968 if (!instance_active())
2971 const base::string16
& text_str
= TextForIAccessibleText();
2972 if (start_index
> text_str
.size() ||
2973 end_index
> text_str
.size() ||
2974 start_index
> end_index
) {
2975 return E_INVALIDARG
;
2978 manager()->ScrollToMakeVisible(*this, GetLocalBoundsForRange(
2979 start_index
, end_index
- start_index
));
2980 manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this);
2985 STDMETHODIMP
BrowserAccessibilityWin::get_fontFamily(BSTR
* font_family
) {
2990 // IServiceProvider methods.
2993 STDMETHODIMP
BrowserAccessibilityWin::QueryService(REFGUID guidService
,
2996 if (!instance_active())
2999 // The system uses IAccessible APIs for many purposes, but only
3000 // assistive technology like screen readers uses IAccessible2.
3001 // Enable full accessibility support when IAccessible2 APIs are queried.
3002 if (riid
== IID_IAccessible2
)
3003 BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility();
3005 if (guidService
== GUID_IAccessibleContentDocument
) {
3006 // Special Mozilla extension: return the accessible for the root document.
3007 // Screen readers use this to distinguish between a document loaded event
3008 // on the root document vs on an iframe.
3009 return manager()->GetRoot()->ToBrowserAccessibilityWin()->QueryInterface(
3010 IID_IAccessible2
, object
);
3013 if (guidService
== IID_IAccessible
||
3014 guidService
== IID_IAccessible2
||
3015 guidService
== IID_IAccessibleAction
||
3016 guidService
== IID_IAccessibleApplication
||
3017 guidService
== IID_IAccessibleHyperlink
||
3018 guidService
== IID_IAccessibleHypertext
||
3019 guidService
== IID_IAccessibleImage
||
3020 guidService
== IID_IAccessibleTable
||
3021 guidService
== IID_IAccessibleTable2
||
3022 guidService
== IID_IAccessibleTableCell
||
3023 guidService
== IID_IAccessibleText
||
3024 guidService
== IID_IAccessibleValue
||
3025 guidService
== IID_ISimpleDOMDocument
||
3026 guidService
== IID_ISimpleDOMNode
||
3027 guidService
== IID_ISimpleDOMText
||
3028 guidService
== GUID_ISimpleDOM
) {
3029 return QueryInterface(riid
, object
);
3032 // We only support the IAccessibleEx interface on Windows 8 and above. This
3033 // is needed for the on-screen Keyboard to show up in metro mode, when the
3034 // user taps an editable portion on the page.
3035 // All methods in the IAccessibleEx interface are unimplemented.
3036 if (riid
== IID_IAccessibleEx
&&
3037 base::win::GetVersion() >= base::win::VERSION_WIN8
) {
3038 return QueryInterface(riid
, object
);
3046 BrowserAccessibilityWin::GetObjectForChild(long child_id
, IAccessibleEx
** ret
) {
3051 BrowserAccessibilityWin::GetIAccessiblePair(IAccessible
** acc
, long* child_id
) {
3055 STDMETHODIMP
BrowserAccessibilityWin::GetRuntimeId(SAFEARRAY
** runtime_id
) {
3060 BrowserAccessibilityWin::ConvertReturnedElement(
3061 IRawElementProviderSimple
* element
,
3062 IAccessibleEx
** acc
) {
3066 STDMETHODIMP
BrowserAccessibilityWin::GetPatternProvider(PATTERNID id
,
3067 IUnknown
** provider
) {
3068 DVLOG(1) << "In Function: "
3070 << " for pattern id: "
3072 if (id
== UIA_ValuePatternId
|| id
== UIA_TextPatternId
) {
3073 if (IsEditableText()) {
3074 DVLOG(1) << "Returning UIA text provider";
3075 base::win::UIATextProvider::CreateTextProvider(
3076 GetValueText(), true, provider
);
3083 STDMETHODIMP
BrowserAccessibilityWin::GetPropertyValue(PROPERTYID id
,
3085 DVLOG(1) << "In Function: "
3087 << " for property id: "
3089 V_VT(ret
) = VT_EMPTY
;
3090 if (id
== UIA_ControlTypePropertyId
) {
3091 if (IsEditableText()) {
3093 ret
->lVal
= UIA_EditControlTypeId
;
3094 DVLOG(1) << "Returning Edit control type";
3096 DVLOG(1) << "Returning empty control type";
3102 STDMETHODIMP
BrowserAccessibilityWin::get_ProviderOptions(
3103 enum ProviderOptions
* ret
) {
3107 STDMETHODIMP
BrowserAccessibilityWin::get_HostRawElementProvider(
3108 IRawElementProviderSimple
** provider
) {
3113 // CComObjectRootEx methods.
3117 HRESULT WINAPI
BrowserAccessibilityWin::InternalQueryInterface(
3119 const _ATL_INTMAP_ENTRY
* entries
,
3122 BrowserAccessibilityWin
* accessibility
=
3123 reinterpret_cast<BrowserAccessibilityWin
*>(this_ptr
);
3124 int32 ia_role
= accessibility
->ia_role();
3125 if (iid
== IID_IAccessibleImage
) {
3126 if (ia_role
!= ROLE_SYSTEM_GRAPHIC
) {
3128 return E_NOINTERFACE
;
3130 } else if (iid
== IID_IAccessibleTable
|| iid
== IID_IAccessibleTable2
) {
3131 if (ia_role
!= ROLE_SYSTEM_TABLE
) {
3133 return E_NOINTERFACE
;
3135 } else if (iid
== IID_IAccessibleTableCell
) {
3136 if (!accessibility
->IsCellOrTableHeaderRole()) {
3138 return E_NOINTERFACE
;
3140 } else if (iid
== IID_IAccessibleValue
) {
3141 if (ia_role
!= ROLE_SYSTEM_PROGRESSBAR
&&
3142 ia_role
!= ROLE_SYSTEM_SCROLLBAR
&&
3143 ia_role
!= ROLE_SYSTEM_SLIDER
) {
3145 return E_NOINTERFACE
;
3147 } else if (iid
== IID_ISimpleDOMDocument
) {
3148 if (ia_role
!= ROLE_SYSTEM_DOCUMENT
) {
3150 return E_NOINTERFACE
;
3154 return CComObjectRootBase::InternalQueryInterface(
3155 this_ptr
, entries
, iid
, object
);
3162 void BrowserAccessibilityWin::UpdateStep1ComputeWinAttributes() {
3163 // Swap win_attributes_ to old_win_attributes_, allowing us to see
3164 // exactly what changed and fire appropriate events. Note that
3165 // old_win_attributes_ is cleared at the end of UpdateStep3FireEvents.
3166 old_win_attributes_
.swap(win_attributes_
);
3167 win_attributes_
.reset(new WinAttributes());
3171 win_attributes_
->ia2_attributes
.clear();
3173 // Expose autocomplete attribute for combobox and textbox.
3174 StringAttributeToIA2(ui::AX_ATTR_AUTO_COMPLETE
, "autocomplete");
3176 // Expose the "display" and "tag" attributes.
3177 StringAttributeToIA2(ui::AX_ATTR_DISPLAY
, "display");
3178 StringAttributeToIA2(ui::AX_ATTR_DROPEFFECT
, "dropeffect");
3179 StringAttributeToIA2(ui::AX_ATTR_TEXT_INPUT_TYPE
, "text-input-type");
3180 StringAttributeToIA2(ui::AX_ATTR_HTML_TAG
, "tag");
3181 StringAttributeToIA2(ui::AX_ATTR_ROLE
, "xml-roles");
3183 // Expose "level" attribute for headings, trees, etc.
3184 IntAttributeToIA2(ui::AX_ATTR_HIERARCHICAL_LEVEL
, "level");
3186 // Expose the set size and position in set.
3187 IntAttributeToIA2(ui::AX_ATTR_SET_SIZE
, "setsize");
3188 IntAttributeToIA2(ui::AX_ATTR_POS_IN_SET
, "posinset");
3190 if (ia_role() == ROLE_SYSTEM_CHECKBUTTON
||
3191 ia_role() == ROLE_SYSTEM_RADIOBUTTON
||
3192 ia2_role() == IA2_ROLE_CHECK_MENU_ITEM
||
3193 ia2_role() == IA2_ROLE_RADIO_MENU_ITEM
||
3194 ia2_role() == IA2_ROLE_TOGGLE_BUTTON
) {
3195 win_attributes_
->ia2_attributes
.push_back(L
"checkable:true");
3198 // Expose live region attributes.
3199 StringAttributeToIA2(ui::AX_ATTR_LIVE_STATUS
, "live");
3200 StringAttributeToIA2(ui::AX_ATTR_LIVE_RELEVANT
, "relevant");
3201 BoolAttributeToIA2(ui::AX_ATTR_LIVE_ATOMIC
, "atomic");
3202 BoolAttributeToIA2(ui::AX_ATTR_LIVE_BUSY
, "busy");
3204 // Expose aria-grabbed attributes.
3205 BoolAttributeToIA2(ui::AX_ATTR_GRABBED
, "grabbed");
3207 // Expose container live region attributes.
3208 StringAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_STATUS
,
3210 StringAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_RELEVANT
,
3211 "container-relevant");
3212 BoolAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_ATOMIC
,
3213 "container-atomic");
3214 BoolAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_BUSY
,
3217 // Expose table cell index.
3218 if (IsCellOrTableHeaderRole()) {
3219 BrowserAccessibility
* table
= GetParent();
3220 while (table
&& table
->GetRole() != ui::AX_ROLE_TABLE
)
3221 table
= table
->GetParent();
3223 const std::vector
<int32
>& unique_cell_ids
= table
->GetIntListAttribute(
3224 ui::AX_ATTR_UNIQUE_CELL_IDS
);
3225 for (size_t i
= 0; i
< unique_cell_ids
.size(); ++i
) {
3226 if (unique_cell_ids
[i
] == GetId()) {
3227 win_attributes_
->ia2_attributes
.push_back(
3228 base::string16(L
"table-cell-index:") + base::IntToString16(i
));
3234 // Expose invalid state for form controls and elements with aria-invalid.
3236 if (GetIntAttribute(ui::AX_ATTR_INVALID_STATE
, &invalid_state
)) {
3237 // TODO(nektar): Handle the possibility of having multiple aria-invalid
3238 // attributes defined, e.g., "invalid:spelling,grammar".
3239 switch (invalid_state
) {
3240 case ui::AX_INVALID_STATE_FALSE
:
3241 win_attributes_
->ia2_attributes
.push_back(L
"invalid:false");
3243 case ui::AX_INVALID_STATE_TRUE
:
3244 win_attributes_
->ia2_attributes
.push_back(L
"invalid:true");
3246 case ui::AX_INVALID_STATE_SPELLING
:
3247 win_attributes_
->ia2_attributes
.push_back(L
"invalid:spelling");
3249 case ui::AX_INVALID_STATE_GRAMMAR
:
3250 win_attributes_
->ia2_attributes
.push_back(L
"invalid:grammar");
3252 case ui::AX_INVALID_STATE_OTHER
:
3254 base::string16 aria_invalid_value
;
3255 if (GetString16Attribute(ui::AX_ATTR_ARIA_INVALID_VALUE
,
3256 &aria_invalid_value
)) {
3257 win_attributes_
->ia2_attributes
.push_back(
3258 L
"invalid:" + aria_invalid_value
);
3260 // Set the attribute to L"true", since we cannot be more specific.
3261 win_attributes_
->ia2_attributes
.push_back(L
"invalid:true");
3270 // Expose row or column header sort direction.
3271 int32 sort_direction
;
3272 if ((ia_role() == ROLE_SYSTEM_COLUMNHEADER
||
3273 ia_role() == ROLE_SYSTEM_ROWHEADER
) &&
3274 GetIntAttribute(ui::AX_ATTR_SORT_DIRECTION
, &sort_direction
)) {
3275 switch (sort_direction
) {
3276 case ui::AX_SORT_DIRECTION_UNSORTED
:
3277 win_attributes_
->ia2_attributes
.push_back(L
"sort:none");
3279 case ui::AX_SORT_DIRECTION_ASCENDING
:
3280 win_attributes_
->ia2_attributes
.push_back(L
"sort:ascending");
3282 case ui::AX_SORT_DIRECTION_DESCENDING
:
3283 win_attributes_
->ia2_attributes
.push_back(L
"sort:descending");
3285 case ui::AX_SORT_DIRECTION_OTHER
:
3286 win_attributes_
->ia2_attributes
.push_back(L
"sort:other");
3293 // The calculation of the accessible name of an element has been
3294 // standardized in the HTML to Platform Accessibility APIs Implementation
3295 // Guide (http://www.w3.org/TR/html-aapi/). In order to return the
3296 // appropriate accessible name on Windows, we need to apply some logic
3297 // to the fields we get from WebKit.
3299 // TODO(dmazzoni): move most of this logic into WebKit.
3303 // name: the default name, e.g. inner text
3304 // title ui element: a reference to a <label> element on the same
3305 // page that labels this node.
3306 // description: accessible labels that override the default name:
3307 // aria-label or aria-labelledby or aria-describedby
3308 // help: the value of the "title" attribute
3310 // On Windows, the logic we apply lets some fields take precedence and
3311 // always returns the primary name in "name" and the secondary name,
3312 // if any, in "description".
3314 int title_elem_id
= GetIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT
);
3315 base::string16 name
= GetString16Attribute(ui::AX_ATTR_NAME
);
3316 base::string16 description
= GetString16Attribute(ui::AX_ATTR_DESCRIPTION
);
3317 base::string16 help
= GetString16Attribute(ui::AX_ATTR_HELP
);
3318 base::string16 value
= GetString16Attribute(ui::AX_ATTR_VALUE
);
3320 // WebKit annoyingly puts the title in the description if there's no other
3321 // description, which just confuses the rest of the logic. Put it back.
3322 // Now "help" is always the value of the "title" attribute, if present.
3323 base::string16 title_attr
;
3324 if (GetHtmlAttribute("title", &title_attr
) &&
3325 description
== title_attr
&&
3328 description
.clear();
3331 // Now implement the main logic: the descripion should become the name if
3332 // it's nonempty, and the help should become the description if
3333 // there's no description - or the name if there's no name or description.
3334 if (!description
.empty()) {
3336 description
.clear();
3338 if (!help
.empty() && description
.empty()) {
3342 if (!description
.empty() && name
.empty() && !title_elem_id
) {
3344 description
.clear();
3347 // If it's a text field, also consider the placeholder.
3348 base::string16 placeholder
;
3349 if (GetRole() == ui::AX_ROLE_TEXT_FIELD
&&
3350 HasState(ui::AX_STATE_FOCUSABLE
) &&
3351 GetHtmlAttribute("placeholder", &placeholder
)) {
3352 if (name
.empty() && !title_elem_id
) {
3354 } else if (description
.empty()) {
3355 description
= placeholder
;
3359 // On Windows, the value of a document should be its url.
3360 if (GetRole() == ui::AX_ROLE_ROOT_WEB_AREA
||
3361 GetRole() == ui::AX_ROLE_WEB_AREA
) {
3362 value
= GetString16Attribute(ui::AX_ATTR_DOC_URL
);
3365 // For certain roles (listbox option, static text, and list marker)
3366 // WebKit stores the main accessible text in the "value" - swap it so
3367 // that it's the "name".
3369 (GetRole() == ui::AX_ROLE_STATIC_TEXT
||
3370 GetRole() == ui::AX_ROLE_LIST_MARKER
||
3371 IsListBoxOptionOrMenuListOption())) {
3372 base::string16 tmp
= value
;
3377 // If this doesn't have a value and is linked then set its value to the url
3378 // attribute. This allows screen readers to read an empty link's destination.
3379 if (value
.empty() && (ia_state() & STATE_SYSTEM_LINKED
))
3380 value
= GetString16Attribute(ui::AX_ATTR_URL
);
3382 win_attributes_
->name
= name
;
3383 win_attributes_
->description
= description
;
3384 win_attributes_
->help
= help
;
3385 win_attributes_
->value
= value
;
3387 // Clear any old relationships between this node and other nodes.
3388 for (size_t i
= 0; i
< relations_
.size(); ++i
)
3389 relations_
[i
]->Release();
3392 // Handle title UI element.
3393 if (title_elem_id
) {
3394 // Add a labelled by relationship.
3395 CComObject
<BrowserAccessibilityRelation
>* relation
;
3396 HRESULT hr
= CComObject
<BrowserAccessibilityRelation
>::CreateInstance(
3398 DCHECK(SUCCEEDED(hr
));
3400 relation
->Initialize(this, IA2_RELATION_LABELLED_BY
);
3401 relation
->AddTarget(title_elem_id
);
3402 relations_
.push_back(relation
);
3405 // Expose slider value.
3406 if (ia_role() == ROLE_SYSTEM_PROGRESSBAR
||
3407 ia_role() == ROLE_SYSTEM_SCROLLBAR
||
3408 ia_role() == ROLE_SYSTEM_SLIDER
) {
3409 win_attributes_
->ia2_attributes
.push_back(L
"valuetext:" + GetValueText());
3412 // If this is a web area for a presentational iframe, give it a role of
3413 // something other than DOCUMENT so that the fact that it's a separate doc
3414 // is not exposed to AT.
3415 if (IsWebAreaForPresentationalIframe()) {
3416 win_attributes_
->ia_role
= ROLE_SYSTEM_GROUPING
;
3417 win_attributes_
->ia2_role
= ROLE_SYSTEM_GROUPING
;
3421 void BrowserAccessibilityWin::UpdateStep2ComputeHypertext() {
3422 // Construct the hypertext for this node, which contains the concatenation
3423 // of all of the static text of this node's children and an embedded object
3424 // character for all non-static-text children. Build up a map from the
3425 // character index of each embedded object character to the id of the
3426 // child object it points to.
3427 for (unsigned int i
= 0; i
< PlatformChildCount(); ++i
) {
3428 BrowserAccessibilityWin
* child
=
3429 PlatformGetChild(i
)->ToBrowserAccessibilityWin();
3430 if (child
->GetRole() == ui::AX_ROLE_STATIC_TEXT
) {
3431 win_attributes_
->hypertext
+= child
->name();
3433 int32 char_offset
= hypertext().size();
3434 int32 child_id
= child
->GetId();
3435 int32 index
= hyperlinks().size();
3436 win_attributes_
->hyperlink_offset_to_index
[char_offset
] = index
;
3437 win_attributes_
->hyperlinks
.push_back(child_id
);
3438 win_attributes_
->hypertext
+= kEmbeddedCharacter
;
3443 void BrowserAccessibilityWin::UpdateStep3FireEvents(bool is_subtree_creation
) {
3444 BrowserAccessibilityManagerWin
* manager
=
3445 this->manager()->ToBrowserAccessibilityManagerWin();
3447 // Fire an event when an alert first appears.
3448 if (ia_role() == ROLE_SYSTEM_ALERT
&&
3449 old_win_attributes_
->ia_role
!= ROLE_SYSTEM_ALERT
) {
3450 manager
->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT
, this);
3453 // Fire an event when a new subtree is created.
3454 if (is_subtree_creation
)
3455 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_SHOW
, this);
3457 // The rest of the events only fire on changes, not on new objects.
3458 if (old_win_attributes_
->ia_role
!= 0 ||
3459 !old_win_attributes_
->role_name
.empty()) {
3460 // Fire an event if the name, description, help, or value changes.
3461 if (name() != old_win_attributes_
->name
)
3462 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_NAMECHANGE
, this);
3463 if (description() != old_win_attributes_
->description
)
3464 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_DESCRIPTIONCHANGE
, this);
3465 if (help() != old_win_attributes_
->help
)
3466 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_HELPCHANGE
, this);
3467 if (value() != old_win_attributes_
->value
)
3468 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_VALUECHANGE
, this);
3469 if (ia_state() != old_win_attributes_
->ia_state
)
3470 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_STATECHANGE
, this);
3472 // Normally focus events are handled elsewhere, however
3473 // focus for managed descendants is platform-specific.
3474 // Fire a focus event if the focused descendant in a multi-select
3475 // list box changes.
3476 if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION
&&
3477 (ia_state() & STATE_SYSTEM_FOCUSABLE
) &&
3478 (ia_state() & STATE_SYSTEM_SELECTABLE
) &&
3479 (ia_state() & STATE_SYSTEM_FOCUSED
) &&
3480 !(old_win_attributes_
->ia_state
& STATE_SYSTEM_FOCUSED
)) {
3481 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_FOCUS
, this);
3484 // Handle selection being added or removed.
3485 bool is_selected_now
= (ia_state() & STATE_SYSTEM_SELECTED
) != 0;
3486 bool was_selected_before
=
3487 (old_win_attributes_
->ia_state
& STATE_SYSTEM_SELECTED
) != 0;
3488 if (is_selected_now
|| was_selected_before
) {
3489 bool multiselect
= false;
3490 if (GetParent() && GetParent()->HasState(ui::AX_STATE_MULTISELECTABLE
))
3494 // In a multi-select box, fire SELECTIONADD and SELECTIONREMOVE events.
3495 if (is_selected_now
&& !was_selected_before
) {
3496 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONADD
, this);
3497 } else if (!is_selected_now
&& was_selected_before
) {
3498 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONREMOVE
, this);
3500 } else if (is_selected_now
&& !was_selected_before
) {
3501 // In a single-select box, only fire SELECTION events.
3502 manager
->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTION
, this);
3506 // Fire an event if this container object has scrolled.
3509 if (GetIntAttribute(ui::AX_ATTR_SCROLL_X
, &sx
) &&
3510 GetIntAttribute(ui::AX_ATTR_SCROLL_Y
, &sy
)) {
3511 if (sx
!= previous_scroll_x_
|| sy
!= previous_scroll_y_
)
3512 manager
->MaybeCallNotifyWinEvent(EVENT_SYSTEM_SCROLLINGEND
, this);
3513 previous_scroll_x_
= sx
;
3514 previous_scroll_y_
= sy
;
3517 // Changing a static text node can affect the IAccessibleText hypertext
3518 // of the parent node, so force an update on the parent.
3519 BrowserAccessibilityWin
* parent
= GetParent()->ToBrowserAccessibilityWin();
3521 GetRole() == ui::AX_ROLE_STATIC_TEXT
&&
3522 name() != old_win_attributes_
->name
) {
3523 parent
->UpdateStep1ComputeWinAttributes();
3524 parent
->UpdateStep2ComputeHypertext();
3525 parent
->UpdateStep3FireEvents(false);
3528 // Fire hypertext-related events.
3529 int start
, old_len
, new_len
;
3530 ComputeHypertextRemovedAndInserted(&start
, &old_len
, &new_len
);
3532 // In-process screen readers may call IAccessibleText::get_oldText
3533 // in reaction to this event to retrieve the text that was removed.
3534 manager
->MaybeCallNotifyWinEvent(IA2_EVENT_TEXT_REMOVED
, this);
3537 // In-process screen readers may call IAccessibleText::get_newText
3538 // in reaction to this event to retrieve the text that was inserted.
3539 manager
->MaybeCallNotifyWinEvent(IA2_EVENT_TEXT_INSERTED
, this);
3543 old_win_attributes_
.reset(nullptr);
3546 void BrowserAccessibilityWin::OnSubtreeWillBeDeleted() {
3547 manager()->ToBrowserAccessibilityManagerWin()->MaybeCallNotifyWinEvent(
3548 EVENT_OBJECT_HIDE
, this);
3551 void BrowserAccessibilityWin::NativeAddReference() {
3555 void BrowserAccessibilityWin::NativeReleaseReference() {
3559 bool BrowserAccessibilityWin::IsNative() const {
3563 void BrowserAccessibilityWin::OnLocationChanged() {
3564 manager()->ToBrowserAccessibilityManagerWin()->MaybeCallNotifyWinEvent(
3565 EVENT_OBJECT_LOCATIONCHANGE
, this);
3568 BrowserAccessibilityWin
* BrowserAccessibilityWin::NewReference() {
3573 BrowserAccessibilityWin
* BrowserAccessibilityWin::GetTargetFromChildID(
3574 const VARIANT
& var_id
) {
3575 if (var_id
.vt
!= VT_I4
)
3578 LONG child_id
= var_id
.lVal
;
3579 if (child_id
== CHILDID_SELF
)
3582 if (child_id
>= 1 && child_id
<= static_cast<LONG
>(PlatformChildCount()))
3583 return PlatformGetChild(child_id
- 1)->ToBrowserAccessibilityWin();
3585 return manager()->ToBrowserAccessibilityManagerWin()->
3586 GetFromUniqueIdWin(child_id
);
3589 HRESULT
BrowserAccessibilityWin::GetStringAttributeAsBstr(
3590 ui::AXStringAttribute attribute
,
3594 if (!GetString16Attribute(attribute
, &str
))
3600 *value_bstr
= SysAllocString(str
.c_str());
3601 DCHECK(*value_bstr
);
3606 void BrowserAccessibilityWin::StringAttributeToIA2(
3607 ui::AXStringAttribute attribute
,
3608 const char* ia2_attr
) {
3609 base::string16 value
;
3610 if (GetString16Attribute(attribute
, &value
)) {
3611 win_attributes_
->ia2_attributes
.push_back(
3612 base::ASCIIToUTF16(ia2_attr
) + L
":" + value
);
3616 void BrowserAccessibilityWin::BoolAttributeToIA2(
3617 ui::AXBoolAttribute attribute
,
3618 const char* ia2_attr
) {
3620 if (GetBoolAttribute(attribute
, &value
)) {
3621 win_attributes_
->ia2_attributes
.push_back(
3622 (base::ASCIIToUTF16(ia2_attr
) + L
":") +
3623 (value
? L
"true" : L
"false"));
3627 void BrowserAccessibilityWin::IntAttributeToIA2(
3628 ui::AXIntAttribute attribute
,
3629 const char* ia2_attr
) {
3631 if (GetIntAttribute(attribute
, &value
)) {
3632 win_attributes_
->ia2_attributes
.push_back(
3633 base::ASCIIToUTF16(ia2_attr
) + L
":" +
3634 base::IntToString16(value
));
3638 base::string16
BrowserAccessibilityWin::GetNameRecursive() const {
3639 if (!name().empty()) {
3643 base::string16 result
;
3644 for (uint32 i
= 0; i
< PlatformChildCount(); ++i
) {
3645 result
+= PlatformGetChild(i
)->ToBrowserAccessibilityWin()->
3651 base::string16
BrowserAccessibilityWin::GetValueText() {
3653 base::string16 value
= this->value();
3655 if (value
.empty() &&
3656 GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE
, &fval
)) {
3657 value
= base::UTF8ToUTF16(base::DoubleToString(fval
));
3662 base::string16
BrowserAccessibilityWin::TextForIAccessibleText() {
3663 if (IsEditableText() || GetRole() == ui::AX_ROLE_MENU_LIST_OPTION
)
3665 return (GetRole() == ui::AX_ROLE_STATIC_TEXT
) ? name() : hypertext();
3668 bool BrowserAccessibilityWin::IsSameHypertextCharacter(size_t old_char_index
,
3669 size_t new_char_index
) {
3670 CHECK(old_win_attributes_
);
3672 // For anything other than the "embedded character", we just compare the
3673 // characters directly.
3674 base::char16 old_ch
= old_win_attributes_
->hypertext
[old_char_index
];
3675 base::char16 new_ch
= win_attributes_
->hypertext
[new_char_index
];
3676 if (old_ch
!= new_ch
)
3678 if (old_ch
== new_ch
&& new_ch
!= kEmbeddedCharacter
)
3681 // If it's an embedded character, they're only identical if the child id
3682 // the hyperlink points to is the same.
3683 std::map
<int32
, int32
>& old_offset_to_index
=
3684 old_win_attributes_
->hyperlink_offset_to_index
;
3685 std::vector
<int32
>& old_hyperlinks
= old_win_attributes_
->hyperlinks
;
3686 int32 old_hyperlinks_count
= static_cast<int32
>(old_hyperlinks
.size());
3687 std::map
<int32
, int32
>::iterator iter
;
3688 iter
= old_offset_to_index
.find(old_char_index
);
3689 int old_index
= (iter
!= old_offset_to_index
.end()) ? iter
->second
: -1;
3690 int old_child_id
= (old_index
>= 0 && old_index
< old_hyperlinks_count
) ?
3691 old_hyperlinks
[old_index
] : -1;
3693 std::map
<int32
, int32
>& new_offset_to_index
=
3694 win_attributes_
->hyperlink_offset_to_index
;
3695 std::vector
<int32
>& new_hyperlinks
= win_attributes_
->hyperlinks
;
3696 int32 new_hyperlinks_count
= static_cast<int32
>(new_hyperlinks
.size());
3697 iter
= new_offset_to_index
.find(new_char_index
);
3698 int new_index
= (iter
!= new_offset_to_index
.end()) ? iter
->second
: -1;
3699 int new_child_id
= (new_index
>= 0 && new_index
< new_hyperlinks_count
) ?
3700 new_hyperlinks
[new_index
] : -1;
3702 return old_child_id
== new_child_id
;
3705 void BrowserAccessibilityWin::ComputeHypertextRemovedAndInserted(
3706 int* start
, int* old_len
, int* new_len
) {
3707 CHECK(old_win_attributes_
);
3713 const base::string16
& old_text
= old_win_attributes_
->hypertext
;
3714 const base::string16
& new_text
= hypertext();
3716 size_t common_prefix
= 0;
3717 while (common_prefix
< old_text
.size() &&
3718 common_prefix
< new_text
.size() &&
3719 IsSameHypertextCharacter(common_prefix
, common_prefix
)) {
3723 size_t common_suffix
= 0;
3724 while (common_prefix
+ common_suffix
< old_text
.size() &&
3725 common_prefix
+ common_suffix
< new_text
.size() &&
3726 IsSameHypertextCharacter(
3727 old_text
.size() - common_suffix
- 1,
3728 new_text
.size() - common_suffix
- 1)) {
3732 *start
= common_prefix
;
3733 *old_len
= old_text
.size() - common_prefix
- common_suffix
;
3734 *new_len
= new_text
.size() - common_prefix
- common_suffix
;
3737 void BrowserAccessibilityWin::HandleSpecialTextOffset(
3738 const base::string16
& text
,
3740 if (*offset
== IA2_TEXT_OFFSET_LENGTH
)
3741 *offset
= static_cast<LONG
>(text
.size());
3742 else if (*offset
== IA2_TEXT_OFFSET_CARET
)
3743 get_caretOffset(offset
);
3746 ui::TextBoundaryType
BrowserAccessibilityWin::IA2TextBoundaryToTextBoundary(
3747 IA2TextBoundaryType ia2_boundary
) {
3748 switch(ia2_boundary
) {
3749 case IA2_TEXT_BOUNDARY_CHAR
:
3750 return ui::CHAR_BOUNDARY
;
3751 case IA2_TEXT_BOUNDARY_WORD
:
3752 return ui::WORD_BOUNDARY
;
3753 case IA2_TEXT_BOUNDARY_LINE
:
3754 return ui::LINE_BOUNDARY
;
3755 case IA2_TEXT_BOUNDARY_SENTENCE
:
3756 return ui::SENTENCE_BOUNDARY
;
3757 case IA2_TEXT_BOUNDARY_PARAGRAPH
:
3758 return ui::PARAGRAPH_BOUNDARY
;
3759 case IA2_TEXT_BOUNDARY_ALL
:
3760 return ui::ALL_BOUNDARY
;
3764 return ui::CHAR_BOUNDARY
;
3767 LONG
BrowserAccessibilityWin::FindBoundary(
3768 const base::string16
& text
,
3769 IA2TextBoundaryType ia2_boundary
,
3771 ui::TextBoundaryDirection direction
) {
3772 HandleSpecialTextOffset(text
, &start_offset
);
3773 if (ia2_boundary
== IA2_TEXT_BOUNDARY_WORD
&&
3774 GetRole() == ui::AX_ROLE_TEXT_FIELD
) {
3775 return GetWordStartBoundary(static_cast<int>(start_offset
), direction
);
3778 ui::TextBoundaryType boundary
= IA2TextBoundaryToTextBoundary(ia2_boundary
);
3779 const std::vector
<int32
>& line_breaks
= GetIntListAttribute(
3780 ui::AX_ATTR_LINE_BREAKS
);
3781 return ui::FindAccessibleTextBoundary(
3782 text
, line_breaks
, boundary
, start_offset
, direction
);
3785 BrowserAccessibilityWin
* BrowserAccessibilityWin::GetFromID(int32 id
) {
3786 return manager()->GetFromID(id
)->ToBrowserAccessibilityWin();
3789 bool BrowserAccessibilityWin::IsListBoxOptionOrMenuListOption() {
3793 int32 role
= GetRole();
3794 int32 parent_role
= GetParent()->GetRole();
3796 if (role
== ui::AX_ROLE_LIST_BOX_OPTION
&&
3797 parent_role
== ui::AX_ROLE_LIST_BOX
) {
3801 if (role
== ui::AX_ROLE_MENU_LIST_OPTION
&&
3802 parent_role
== ui::AX_ROLE_MENU_LIST_POPUP
) {
3809 void BrowserAccessibilityWin::InitRoleAndState() {
3812 base::string16 role_name
;
3814 int32 ia2_state
= IA2_STATE_OPAQUE
;
3816 if (HasState(ui::AX_STATE_BUSY
))
3817 ia_state
|= STATE_SYSTEM_BUSY
;
3818 if (HasState(ui::AX_STATE_CHECKED
))
3819 ia_state
|= STATE_SYSTEM_CHECKED
;
3820 if (HasState(ui::AX_STATE_COLLAPSED
))
3821 ia_state
|= STATE_SYSTEM_COLLAPSED
;
3822 if (HasState(ui::AX_STATE_EXPANDED
))
3823 ia_state
|= STATE_SYSTEM_EXPANDED
;
3824 if (HasState(ui::AX_STATE_FOCUSABLE
))
3825 ia_state
|= STATE_SYSTEM_FOCUSABLE
;
3826 if (HasState(ui::AX_STATE_HASPOPUP
))
3827 ia_state
|= STATE_SYSTEM_HASPOPUP
;
3828 if (HasState(ui::AX_STATE_INDETERMINATE
))
3829 ia_state
|= STATE_SYSTEM_INDETERMINATE
;
3830 if (HasIntAttribute(ui::AX_ATTR_INVALID_STATE
) &&
3831 GetIntAttribute(ui::AX_ATTR_INVALID_STATE
) != ui::AX_INVALID_STATE_FALSE
)
3832 ia2_state
|= IA2_STATE_INVALID_ENTRY
;
3833 if (HasState(ui::AX_STATE_INVISIBLE
))
3834 ia_state
|= STATE_SYSTEM_INVISIBLE
;
3835 if (HasState(ui::AX_STATE_LINKED
))
3836 ia_state
|= STATE_SYSTEM_LINKED
;
3837 if (HasState(ui::AX_STATE_MULTISELECTABLE
)) {
3838 ia_state
|= STATE_SYSTEM_EXTSELECTABLE
;
3839 ia_state
|= STATE_SYSTEM_MULTISELECTABLE
;
3841 // TODO(ctguil): Support STATE_SYSTEM_EXTSELECTABLE/accSelect.
3842 if (HasState(ui::AX_STATE_OFFSCREEN
))
3843 ia_state
|= STATE_SYSTEM_OFFSCREEN
;
3844 if (HasState(ui::AX_STATE_PRESSED
))
3845 ia_state
|= STATE_SYSTEM_PRESSED
;
3846 if (HasState(ui::AX_STATE_PROTECTED
))
3847 ia_state
|= STATE_SYSTEM_PROTECTED
;
3848 if (HasState(ui::AX_STATE_REQUIRED
))
3849 ia2_state
|= IA2_STATE_REQUIRED
;
3850 if (HasState(ui::AX_STATE_SELECTABLE
))
3851 ia_state
|= STATE_SYSTEM_SELECTABLE
;
3852 if (HasState(ui::AX_STATE_SELECTED
))
3853 ia_state
|= STATE_SYSTEM_SELECTED
;
3854 if (HasState(ui::AX_STATE_VISITED
))
3855 ia_state
|= STATE_SYSTEM_TRAVERSED
;
3856 if (!HasState(ui::AX_STATE_ENABLED
))
3857 ia_state
|= STATE_SYSTEM_UNAVAILABLE
;
3858 if (HasState(ui::AX_STATE_VERTICAL
))
3859 ia2_state
|= IA2_STATE_VERTICAL
;
3860 if (HasState(ui::AX_STATE_HORIZONTAL
))
3861 ia2_state
|= IA2_STATE_HORIZONTAL
;
3862 if (HasState(ui::AX_STATE_VISITED
))
3863 ia_state
|= STATE_SYSTEM_TRAVERSED
;
3865 // Expose whether or not the mouse is over an element, but suppress
3866 // this for tests because it can make the test results flaky depending
3867 // on the position of the mouse.
3868 BrowserAccessibilityStateImpl
* accessibility_state
=
3869 BrowserAccessibilityStateImpl::GetInstance();
3870 if (!accessibility_state
->disable_hot_tracking_for_testing()) {
3871 if (HasState(ui::AX_STATE_HOVERED
))
3872 ia_state
|= STATE_SYSTEM_HOTTRACKED
;
3875 // WebKit marks everything as readonly unless it's editable text, so if it's
3876 // not readonly, mark it as editable now. The final computation of the
3877 // READONLY state for MSAA is below, after the switch.
3878 if (!HasState(ui::AX_STATE_READ_ONLY
))
3879 ia2_state
|= IA2_STATE_EDITABLE
;
3881 if (GetBoolAttribute(ui::AX_ATTR_BUTTON_MIXED
))
3882 ia_state
|= STATE_SYSTEM_MIXED
;
3884 if (GetBoolAttribute(ui::AX_ATTR_CAN_SET_VALUE
))
3885 ia2_state
|= IA2_STATE_EDITABLE
;
3887 if (!GetStringAttribute(ui::AX_ATTR_AUTO_COMPLETE
).empty())
3888 ia2_state
|= IA2_STATE_SUPPORTS_AUTOCOMPLETION
;
3890 base::string16 html_tag
= GetString16Attribute(
3891 ui::AX_ATTR_HTML_TAG
);
3892 switch (GetRole()) {
3893 case ui::AX_ROLE_ALERT
:
3894 ia_role
= ROLE_SYSTEM_ALERT
;
3896 case ui::AX_ROLE_ALERT_DIALOG
:
3897 ia_role
= ROLE_SYSTEM_DIALOG
;
3899 case ui::AX_ROLE_APPLICATION
:
3900 ia_role
= ROLE_SYSTEM_APPLICATION
;
3902 case ui::AX_ROLE_ARTICLE
:
3903 ia_role
= ROLE_SYSTEM_DOCUMENT
;
3904 ia_state
|= STATE_SYSTEM_READONLY
;
3906 case ui::AX_ROLE_BANNER
:
3907 ia_role
= ROLE_SYSTEM_GROUPING
;
3908 ia2_role
= IA2_ROLE_HEADER
;
3910 case ui::AX_ROLE_BLOCKQUOTE
:
3911 role_name
= html_tag
;
3912 ia2_role
= IA2_ROLE_SECTION
;
3914 case ui::AX_ROLE_BUSY_INDICATOR
:
3915 ia_role
= ROLE_SYSTEM_ANIMATION
;
3916 ia_state
|= STATE_SYSTEM_READONLY
;
3918 case ui::AX_ROLE_BUTTON
:
3919 ia_role
= ROLE_SYSTEM_PUSHBUTTON
;
3921 case ui::AX_ROLE_CANVAS
:
3922 if (GetBoolAttribute(ui::AX_ATTR_CANVAS_HAS_FALLBACK
)) {
3923 role_name
= L
"canvas";
3924 ia2_role
= IA2_ROLE_CANVAS
;
3926 ia_role
= ROLE_SYSTEM_GRAPHIC
;
3929 case ui::AX_ROLE_CAPTION
:
3930 ia_role
= ROLE_SYSTEM_TEXT
;
3931 ia2_role
= IA2_ROLE_CAPTION
;
3933 case ui::AX_ROLE_CELL
:
3934 ia_role
= ROLE_SYSTEM_CELL
;
3936 case ui::AX_ROLE_CHECK_BOX
:
3937 ia_role
= ROLE_SYSTEM_CHECKBUTTON
;
3938 ia2_state
|= IA2_STATE_CHECKABLE
;
3940 case ui::AX_ROLE_COLOR_WELL
:
3941 ia_role
= ROLE_SYSTEM_TEXT
;
3942 ia2_role
= IA2_ROLE_COLOR_CHOOSER
;
3944 case ui::AX_ROLE_COLUMN
:
3945 ia_role
= ROLE_SYSTEM_COLUMN
;
3947 case ui::AX_ROLE_COLUMN_HEADER
:
3948 ia_role
= ROLE_SYSTEM_COLUMNHEADER
;
3950 case ui::AX_ROLE_COMBO_BOX
:
3951 ia_role
= ROLE_SYSTEM_COMBOBOX
;
3953 case ui::AX_ROLE_COMPLEMENTARY
:
3954 ia_role
= ROLE_SYSTEM_GROUPING
;
3955 ia2_role
= IA2_ROLE_NOTE
;
3957 case ui::AX_ROLE_CONTENT_INFO
:
3958 ia_role
= ROLE_SYSTEM_TEXT
;
3959 ia2_role
= IA2_ROLE_PARAGRAPH
;
3961 case ui::AX_ROLE_DATE
:
3962 case ui::AX_ROLE_DATE_TIME
:
3963 ia_role
= ROLE_SYSTEM_DROPLIST
;
3964 ia2_role
= IA2_ROLE_DATE_EDITOR
;
3966 case ui::AX_ROLE_DIV
:
3968 ia_role
= ROLE_SYSTEM_GROUPING
;
3969 ia2_role
= IA2_ROLE_SECTION
;
3971 case ui::AX_ROLE_DEFINITION
:
3972 role_name
= html_tag
;
3973 ia2_role
= IA2_ROLE_PARAGRAPH
;
3974 ia_state
|= STATE_SYSTEM_READONLY
;
3976 case ui::AX_ROLE_DESCRIPTION_LIST_DETAIL
:
3977 role_name
= html_tag
;
3978 ia_role
= ROLE_SYSTEM_TEXT
;
3979 ia2_role
= IA2_ROLE_PARAGRAPH
;
3981 case ui::AX_ROLE_DESCRIPTION_LIST
:
3982 role_name
= html_tag
;
3983 ia_role
= ROLE_SYSTEM_LIST
;
3984 ia_state
|= STATE_SYSTEM_READONLY
;
3986 case ui::AX_ROLE_DESCRIPTION_LIST_TERM
:
3987 ia_role
= ROLE_SYSTEM_LISTITEM
;
3988 ia_state
|= STATE_SYSTEM_READONLY
;
3990 case ui::AX_ROLE_DETAILS
:
3991 role_name
= html_tag
;
3992 ia_role
= ROLE_SYSTEM_GROUPING
;
3994 case ui::AX_ROLE_DIALOG
:
3995 ia_role
= ROLE_SYSTEM_DIALOG
;
3997 case ui::AX_ROLE_DISCLOSURE_TRIANGLE
:
3998 ia_role
= ROLE_SYSTEM_PUSHBUTTON
;
4000 case ui::AX_ROLE_DOCUMENT
:
4001 case ui::AX_ROLE_ROOT_WEB_AREA
:
4002 case ui::AX_ROLE_WEB_AREA
:
4003 ia_role
= ROLE_SYSTEM_DOCUMENT
;
4004 ia_state
|= STATE_SYSTEM_READONLY
;
4005 ia_state
|= STATE_SYSTEM_FOCUSABLE
;
4007 case ui::AX_ROLE_EMBEDDED_OBJECT
:
4008 ia_role
= ROLE_SYSTEM_CLIENT
;
4009 ia2_role
= IA2_ROLE_EMBEDDED_OBJECT
;
4011 case ui::AX_ROLE_FIGCAPTION
:
4012 role_name
= html_tag
;
4013 ia2_role
= IA2_ROLE_CAPTION
;
4015 case ui::AX_ROLE_FIGURE
:
4016 ia_role
= ROLE_SYSTEM_GROUPING
;
4018 case ui::AX_ROLE_FORM
:
4019 role_name
= L
"form";
4020 ia2_role
= IA2_ROLE_FORM
;
4022 case ui::AX_ROLE_FOOTER
:
4023 ia_role
= ROLE_SYSTEM_GROUPING
;
4024 ia2_role
= IA2_ROLE_FOOTER
;
4026 case ui::AX_ROLE_GRID
:
4027 ia_role
= ROLE_SYSTEM_TABLE
;
4028 ia_state
|= STATE_SYSTEM_READONLY
;
4030 case ui::AX_ROLE_GROUP
: {
4031 base::string16 aria_role
= GetString16Attribute(
4033 if (aria_role
== L
"group" || html_tag
== L
"fieldset") {
4034 ia_role
= ROLE_SYSTEM_GROUPING
;
4035 } else if (html_tag
== L
"li") {
4036 ia_role
= ROLE_SYSTEM_LISTITEM
;
4037 ia_state
|= STATE_SYSTEM_READONLY
;
4039 if (html_tag
.empty())
4042 role_name
= html_tag
;
4043 ia2_role
= IA2_ROLE_SECTION
;
4047 case ui::AX_ROLE_HEADING
:
4048 role_name
= html_tag
;
4049 ia2_role
= IA2_ROLE_HEADING
;
4051 case ui::AX_ROLE_IFRAME
:
4052 ia_role
= ROLE_SYSTEM_DOCUMENT
;
4053 ia2_role
= IA2_ROLE_INTERNAL_FRAME
;
4054 ia_state
= STATE_SYSTEM_READONLY
;
4056 case ui::AX_ROLE_IFRAME_PRESENTATIONAL
:
4057 ia_role
= ROLE_SYSTEM_GROUPING
;
4059 case ui::AX_ROLE_IMAGE
:
4060 ia_role
= ROLE_SYSTEM_GRAPHIC
;
4061 ia_state
|= STATE_SYSTEM_READONLY
;
4063 case ui::AX_ROLE_IMAGE_MAP
:
4064 role_name
= html_tag
;
4065 ia2_role
= IA2_ROLE_IMAGE_MAP
;
4066 ia_state
|= STATE_SYSTEM_READONLY
;
4068 case ui::AX_ROLE_IMAGE_MAP_LINK
:
4069 ia_role
= ROLE_SYSTEM_LINK
;
4070 ia_state
|= STATE_SYSTEM_LINKED
;
4071 ia_state
|= STATE_SYSTEM_READONLY
;
4073 case ui::AX_ROLE_LABEL_TEXT
:
4074 case ui::AX_ROLE_LEGEND
:
4075 ia_role
= ROLE_SYSTEM_TEXT
;
4076 ia2_role
= IA2_ROLE_LABEL
;
4078 case ui::AX_ROLE_LINK
:
4079 ia_role
= ROLE_SYSTEM_LINK
;
4080 ia_state
|= STATE_SYSTEM_LINKED
;
4082 case ui::AX_ROLE_LIST
:
4083 ia_role
= ROLE_SYSTEM_LIST
;
4084 ia_state
|= STATE_SYSTEM_READONLY
;
4086 case ui::AX_ROLE_LIST_BOX
:
4087 ia_role
= ROLE_SYSTEM_LIST
;
4089 case ui::AX_ROLE_LIST_BOX_OPTION
:
4090 ia_role
= ROLE_SYSTEM_LISTITEM
;
4091 if (ia_state
& STATE_SYSTEM_SELECTABLE
) {
4092 ia_state
|= STATE_SYSTEM_FOCUSABLE
;
4093 if (HasState(ui::AX_STATE_FOCUSED
))
4094 ia_state
|= STATE_SYSTEM_FOCUSED
;
4097 case ui::AX_ROLE_LIST_ITEM
:
4098 ia_role
= ROLE_SYSTEM_LISTITEM
;
4099 ia_state
|= STATE_SYSTEM_READONLY
;
4101 case ui::AX_ROLE_MAIN
:
4102 ia_role
= ROLE_SYSTEM_GROUPING
;
4103 ia2_role
= IA2_ROLE_PARAGRAPH
;
4105 case ui::AX_ROLE_MARQUEE
:
4106 ia_role
= ROLE_SYSTEM_ANIMATION
;
4108 case ui::AX_ROLE_MATH
:
4109 ia_role
= ROLE_SYSTEM_EQUATION
;
4111 case ui::AX_ROLE_MENU
:
4112 case ui::AX_ROLE_MENU_BUTTON
:
4113 ia_role
= ROLE_SYSTEM_MENUPOPUP
;
4115 case ui::AX_ROLE_MENU_BAR
:
4116 ia_role
= ROLE_SYSTEM_MENUBAR
;
4118 case ui::AX_ROLE_MENU_ITEM
:
4119 ia_role
= ROLE_SYSTEM_MENUITEM
;
4121 case ui::AX_ROLE_MENU_ITEM_CHECK_BOX
:
4122 ia_role
= ROLE_SYSTEM_MENUITEM
;
4123 ia2_role
= IA2_ROLE_CHECK_MENU_ITEM
;
4124 ia2_state
|= IA2_STATE_CHECKABLE
;
4126 case ui::AX_ROLE_MENU_ITEM_RADIO
:
4127 ia_role
= ROLE_SYSTEM_MENUITEM
;
4128 ia2_role
= IA2_ROLE_RADIO_MENU_ITEM
;
4130 case ui::AX_ROLE_MENU_LIST_POPUP
:
4131 ia_role
= ROLE_SYSTEM_LIST
;
4132 ia2_state
&= ~(IA2_STATE_EDITABLE
);
4134 case ui::AX_ROLE_MENU_LIST_OPTION
:
4135 ia_role
= ROLE_SYSTEM_LISTITEM
;
4136 ia2_state
&= ~(IA2_STATE_EDITABLE
);
4137 if (ia_state
& STATE_SYSTEM_SELECTABLE
) {
4138 ia_state
|= STATE_SYSTEM_FOCUSABLE
;
4139 if (HasState(ui::AX_STATE_FOCUSED
))
4140 ia_state
|= STATE_SYSTEM_FOCUSED
;
4143 case ui::AX_ROLE_METER
:
4144 role_name
= html_tag
;
4145 ia_role
= ROLE_SYSTEM_PROGRESSBAR
;
4147 case ui::AX_ROLE_NAVIGATION
:
4148 ia_role
= ROLE_SYSTEM_GROUPING
;
4149 ia2_role
= IA2_ROLE_SECTION
;
4151 case ui::AX_ROLE_NOTE
:
4152 ia_role
= ROLE_SYSTEM_GROUPING
;
4153 ia2_role
= IA2_ROLE_NOTE
;
4155 case ui::AX_ROLE_OUTLINE
:
4156 ia_role
= ROLE_SYSTEM_OUTLINE
;
4158 case ui::AX_ROLE_PARAGRAPH
:
4160 ia2_role
= IA2_ROLE_PARAGRAPH
;
4162 case ui::AX_ROLE_POP_UP_BUTTON
:
4163 if (html_tag
== L
"select") {
4164 ia_role
= ROLE_SYSTEM_COMBOBOX
;
4166 ia_role
= ROLE_SYSTEM_BUTTONMENU
;
4169 case ui::AX_ROLE_PRE
:
4170 role_name
= html_tag
;
4171 ia_role
= ROLE_SYSTEM_TEXT
;
4172 ia2_role
= IA2_ROLE_PARAGRAPH
;
4174 case ui::AX_ROLE_PROGRESS_INDICATOR
:
4175 ia_role
= ROLE_SYSTEM_PROGRESSBAR
;
4176 ia_state
|= STATE_SYSTEM_READONLY
;
4178 case ui::AX_ROLE_RADIO_BUTTON
:
4179 ia_role
= ROLE_SYSTEM_RADIOBUTTON
;
4180 ia2_state
= IA2_STATE_CHECKABLE
;
4182 case ui::AX_ROLE_RADIO_GROUP
:
4183 ia_role
= ROLE_SYSTEM_GROUPING
;
4185 case ui::AX_ROLE_REGION
:
4186 if (html_tag
== L
"section") {
4187 ia_role
= ROLE_SYSTEM_GROUPING
;
4188 ia2_role
= IA2_ROLE_SECTION
;
4190 ia_role
= ROLE_SYSTEM_PANE
;
4193 case ui::AX_ROLE_ROW
:
4194 ia_role
= ROLE_SYSTEM_ROW
;
4196 case ui::AX_ROLE_ROW_HEADER
:
4197 ia_role
= ROLE_SYSTEM_ROWHEADER
;
4199 case ui::AX_ROLE_RUBY
:
4200 ia_role
= ROLE_SYSTEM_TEXT
;
4201 ia2_role
= IA2_ROLE_TEXT_FRAME
;
4203 case ui::AX_ROLE_RULER
:
4204 ia_role
= ROLE_SYSTEM_CLIENT
;
4205 ia2_role
= IA2_ROLE_RULER
;
4206 ia_state
|= STATE_SYSTEM_READONLY
;
4208 case ui::AX_ROLE_SCROLL_AREA
:
4209 ia_role
= ROLE_SYSTEM_CLIENT
;
4210 ia2_role
= IA2_ROLE_SCROLL_PANE
;
4211 ia_state
|= STATE_SYSTEM_READONLY
;
4212 ia2_state
&= ~(IA2_STATE_EDITABLE
);
4214 case ui::AX_ROLE_SCROLL_BAR
:
4215 ia_role
= ROLE_SYSTEM_SCROLLBAR
;
4217 case ui::AX_ROLE_SEARCH
:
4218 ia_role
= ROLE_SYSTEM_GROUPING
;
4219 ia2_role
= IA2_ROLE_SECTION
;
4221 case ui::AX_ROLE_SLIDER
:
4222 ia_role
= ROLE_SYSTEM_SLIDER
;
4224 case ui::AX_ROLE_SPIN_BUTTON
:
4225 ia_role
= ROLE_SYSTEM_SPINBUTTON
;
4227 case ui::AX_ROLE_SPIN_BUTTON_PART
:
4228 ia_role
= ROLE_SYSTEM_PUSHBUTTON
;
4230 case ui::AX_ROLE_ANNOTATION
:
4231 case ui::AX_ROLE_LIST_MARKER
:
4232 case ui::AX_ROLE_STATIC_TEXT
:
4233 ia_role
= ROLE_SYSTEM_STATICTEXT
;
4235 case ui::AX_ROLE_STATUS
:
4236 ia_role
= ROLE_SYSTEM_STATUSBAR
;
4238 case ui::AX_ROLE_SPLITTER
:
4239 ia_role
= ROLE_SYSTEM_SEPARATOR
;
4241 case ui::AX_ROLE_SVG_ROOT
:
4242 ia_role
= ROLE_SYSTEM_GRAPHIC
;
4244 case ui::AX_ROLE_SWITCH
:
4245 role_name
= L
"switch";
4246 ia2_role
= IA2_ROLE_TOGGLE_BUTTON
;
4248 case ui::AX_ROLE_TAB
:
4249 ia_role
= ROLE_SYSTEM_PAGETAB
;
4251 case ui::AX_ROLE_TABLE
: {
4252 base::string16 aria_role
= GetString16Attribute(
4254 if (aria_role
== L
"treegrid") {
4255 ia_role
= ROLE_SYSTEM_OUTLINE
;
4257 ia_role
= ROLE_SYSTEM_TABLE
;
4261 case ui::AX_ROLE_TABLE_HEADER_CONTAINER
:
4262 ia_role
= ROLE_SYSTEM_GROUPING
;
4263 ia2_role
= IA2_ROLE_SECTION
;
4264 ia_state
|= STATE_SYSTEM_READONLY
;
4266 case ui::AX_ROLE_TAB_LIST
:
4267 ia_role
= ROLE_SYSTEM_PAGETABLIST
;
4269 case ui::AX_ROLE_TAB_PANEL
:
4270 ia_role
= ROLE_SYSTEM_PROPERTYPAGE
;
4272 case ui::AX_ROLE_TOGGLE_BUTTON
:
4273 ia_role
= ROLE_SYSTEM_PUSHBUTTON
;
4274 ia2_role
= IA2_ROLE_TOGGLE_BUTTON
;
4276 case ui::AX_ROLE_TEXT_FIELD
:
4277 case ui::AX_ROLE_SEARCH_BOX
:
4278 ia_role
= ROLE_SYSTEM_TEXT
;
4279 if (HasState(ui::AX_STATE_MULTILINE
))
4280 ia2_state
|= IA2_STATE_MULTI_LINE
;
4282 ia2_state
|= IA2_STATE_SINGLE_LINE
;
4283 ia2_state
|= IA2_STATE_EDITABLE
;
4284 ia2_state
|= IA2_STATE_SELECTABLE_TEXT
;
4286 case ui::AX_ROLE_TIME
:
4287 ia_role
= ROLE_SYSTEM_SPINBUTTON
;
4289 case ui::AX_ROLE_TIMER
:
4290 ia_role
= ROLE_SYSTEM_CLOCK
;
4291 ia_state
|= STATE_SYSTEM_READONLY
;
4293 case ui::AX_ROLE_TOOLBAR
:
4294 ia_role
= ROLE_SYSTEM_TOOLBAR
;
4295 ia_state
|= STATE_SYSTEM_READONLY
;
4297 case ui::AX_ROLE_TOOLTIP
:
4298 ia_role
= ROLE_SYSTEM_TOOLTIP
;
4299 ia_state
|= STATE_SYSTEM_READONLY
;
4301 case ui::AX_ROLE_TREE
:
4302 ia_role
= ROLE_SYSTEM_OUTLINE
;
4304 case ui::AX_ROLE_TREE_GRID
:
4305 ia_role
= ROLE_SYSTEM_OUTLINE
;
4307 case ui::AX_ROLE_TREE_ITEM
:
4308 ia_role
= ROLE_SYSTEM_OUTLINEITEM
;
4310 case ui::AX_ROLE_LINE_BREAK
:
4311 ia_role
= ROLE_SYSTEM_WHITESPACE
;
4313 case ui::AX_ROLE_WINDOW
:
4314 ia_role
= ROLE_SYSTEM_WINDOW
;
4317 // TODO(dmazzoni): figure out the proper MSAA role for all of these.
4318 case ui::AX_ROLE_DIRECTORY
:
4319 case ui::AX_ROLE_IGNORED
:
4320 case ui::AX_ROLE_LOG
:
4321 case ui::AX_ROLE_NONE
:
4322 case ui::AX_ROLE_PRESENTATIONAL
:
4323 case ui::AX_ROLE_SLIDER_THUMB
:
4325 ia_role
= ROLE_SYSTEM_CLIENT
;
4329 // Compute the final value of READONLY for MSAA.
4331 // We always set the READONLY state for elements that have the
4332 // aria-readonly attribute and for a few roles (in the switch above).
4333 // We clear the READONLY state on focusable controls and on a document.
4334 // Everything else, the majority of objects, do not have this state set.
4335 if (HasState(ui::AX_STATE_FOCUSABLE
) &&
4336 ia_role
!= ROLE_SYSTEM_DOCUMENT
) {
4337 ia_state
&= ~(STATE_SYSTEM_READONLY
);
4339 if (!HasState(ui::AX_STATE_READ_ONLY
))
4340 ia_state
&= ~(STATE_SYSTEM_READONLY
);
4341 if (GetBoolAttribute(ui::AX_ATTR_ARIA_READONLY
))
4342 ia_state
|= STATE_SYSTEM_READONLY
;
4344 // The role should always be set.
4345 DCHECK(!role_name
.empty() || ia_role
);
4347 // If we didn't explicitly set the IAccessible2 role, make it the same
4348 // as the MSAA role.
4352 win_attributes_
->ia_role
= ia_role
;
4353 win_attributes_
->ia_state
= ia_state
;
4354 win_attributes_
->role_name
= role_name
;
4355 win_attributes_
->ia2_role
= ia2_role
;
4356 win_attributes_
->ia2_state
= ia2_state
;
4359 } // namespace content