Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(292)

Side by Side Diff: content/browser/accessibility/browser_accessibility_win.cc

Issue 1057083002: Fix menu list and list box screen reader accessibility. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix on Mac too Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/accessibility/browser_accessibility_win.h" 5 #include "content/browser/accessibility/browser_accessibility_win.h"
6 6
7 #include <UIAutomationClient.h> 7 #include <UIAutomationClient.h>
8 #include <UIAutomationCoreApi.h> 8 #include <UIAutomationCoreApi.h>
9 9
10 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_number_conversions.h"
(...skipping 885 matching lines...) Expand 10 before | Expand all | Expand 10 after
896 STDMETHODIMP BrowserAccessibilityWin::get_groupPosition( 896 STDMETHODIMP BrowserAccessibilityWin::get_groupPosition(
897 LONG* group_level, 897 LONG* group_level,
898 LONG* similar_items_in_group, 898 LONG* similar_items_in_group,
899 LONG* position_in_group) { 899 LONG* position_in_group) {
900 if (!instance_active()) 900 if (!instance_active())
901 return E_FAIL; 901 return E_FAIL;
902 902
903 if (!group_level || !similar_items_in_group || !position_in_group) 903 if (!group_level || !similar_items_in_group || !position_in_group)
904 return E_INVALIDARG; 904 return E_INVALIDARG;
905 905
906 if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION && 906 if (IsListBoxOptionOrMenuListOption()) {
907 GetParent() &&
908 GetParent()->GetRole() == ui::AX_ROLE_LIST_BOX) {
909 *group_level = 0; 907 *group_level = 0;
910 *similar_items_in_group = GetParent()->PlatformChildCount(); 908 *similar_items_in_group = GetParent()->PlatformChildCount();
911 *position_in_group = GetIndexInParent() + 1; 909 *position_in_group = GetIndexInParent() + 1;
912 return S_OK; 910 return S_OK;
913 } 911 }
914 912
915 return E_NOTIMPL; 913 return E_NOTIMPL;
916 } 914 }
917 915
918 // 916 //
(...skipping 2070 matching lines...) Expand 10 before | Expand all | Expand 10 after
2989 StringAttributeToIA2(ui::AX_ATTR_DISPLAY, "display"); 2987 StringAttributeToIA2(ui::AX_ATTR_DISPLAY, "display");
2990 StringAttributeToIA2(ui::AX_ATTR_DROPEFFECT, "dropeffect"); 2988 StringAttributeToIA2(ui::AX_ATTR_DROPEFFECT, "dropeffect");
2991 StringAttributeToIA2(ui::AX_ATTR_TEXT_INPUT_TYPE, "text-input-type"); 2989 StringAttributeToIA2(ui::AX_ATTR_TEXT_INPUT_TYPE, "text-input-type");
2992 StringAttributeToIA2(ui::AX_ATTR_HTML_TAG, "tag"); 2990 StringAttributeToIA2(ui::AX_ATTR_HTML_TAG, "tag");
2993 StringAttributeToIA2(ui::AX_ATTR_ROLE, "xml-roles"); 2991 StringAttributeToIA2(ui::AX_ATTR_ROLE, "xml-roles");
2994 2992
2995 // Expose "level" attribute for headings, trees, etc. 2993 // Expose "level" attribute for headings, trees, etc.
2996 IntAttributeToIA2(ui::AX_ATTR_HIERARCHICAL_LEVEL, "level"); 2994 IntAttributeToIA2(ui::AX_ATTR_HIERARCHICAL_LEVEL, "level");
2997 2995
2998 // Expose the set size and position in set for listbox options. 2996 // Expose the set size and position in set for listbox options.
2999 if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION && 2997 if (IsListBoxOptionOrMenuListOption()) {
3000 GetParent() &&
3001 GetParent()->GetRole() == ui::AX_ROLE_LIST_BOX) {
3002 win_attributes_->ia2_attributes.push_back( 2998 win_attributes_->ia2_attributes.push_back(
3003 L"setsize:" + base::IntToString16(GetParent()->PlatformChildCount())); 2999 L"setsize:" + base::IntToString16(GetParent()->PlatformChildCount()));
3004 win_attributes_->ia2_attributes.push_back( 3000 win_attributes_->ia2_attributes.push_back(
3005 L"setsize:" + base::IntToString16(GetIndexInParent() + 1)); 3001 L"posinset:" + base::IntToString16(GetIndexInParent() + 1));
3002 win_attributes_->ia2_attributes.push_back(
3003 L"tag:option");
3006 } 3004 }
3007 3005
3008 if (ia_role() == ROLE_SYSTEM_CHECKBUTTON || 3006 if (ia_role() == ROLE_SYSTEM_CHECKBUTTON ||
3009 ia_role() == ROLE_SYSTEM_RADIOBUTTON || 3007 ia_role() == ROLE_SYSTEM_RADIOBUTTON ||
3010 ia2_role() == IA2_ROLE_CHECK_MENU_ITEM || 3008 ia2_role() == IA2_ROLE_CHECK_MENU_ITEM ||
3011 ia2_role() == IA2_ROLE_RADIO_MENU_ITEM || 3009 ia2_role() == IA2_ROLE_RADIO_MENU_ITEM ||
3012 ia2_role() == IA2_ROLE_TOGGLE_BUTTON) { 3010 ia2_role() == IA2_ROLE_TOGGLE_BUTTON) {
3013 win_attributes_->ia2_attributes.push_back(L"checkable:true"); 3011 win_attributes_->ia2_attributes.push_back(L"checkable:true");
3014 } 3012 }
3015 3013
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
3177 // On Windows, the value of a document should be its url. 3175 // On Windows, the value of a document should be its url.
3178 if (GetRole() == ui::AX_ROLE_ROOT_WEB_AREA || 3176 if (GetRole() == ui::AX_ROLE_ROOT_WEB_AREA ||
3179 GetRole() == ui::AX_ROLE_WEB_AREA) { 3177 GetRole() == ui::AX_ROLE_WEB_AREA) {
3180 value = GetString16Attribute(ui::AX_ATTR_DOC_URL); 3178 value = GetString16Attribute(ui::AX_ATTR_DOC_URL);
3181 } 3179 }
3182 3180
3183 // For certain roles (listbox option, static text, and list marker) 3181 // For certain roles (listbox option, static text, and list marker)
3184 // WebKit stores the main accessible text in the "value" - swap it so 3182 // WebKit stores the main accessible text in the "value" - swap it so
3185 // that it's the "name". 3183 // that it's the "name".
3186 if (name.empty() && 3184 if (name.empty() &&
3187 (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION || 3185 (GetRole() == ui::AX_ROLE_STATIC_TEXT ||
3188 GetRole() == ui::AX_ROLE_STATIC_TEXT || 3186 GetRole() == ui::AX_ROLE_LIST_MARKER ||
3189 GetRole() == ui::AX_ROLE_LIST_MARKER)) { 3187 IsListBoxOptionOrMenuListOption())) {
3190 base::string16 tmp = value; 3188 base::string16 tmp = value;
3191 value = name; 3189 value = name;
3192 name = tmp; 3190 name = tmp;
3193 } 3191 }
3194 3192
3195 // If this doesn't have a value and is linked then set its value to the url 3193 // If this doesn't have a value and is linked then set its value to the url
3196 // attribute. This allows screen readers to read an empty link's destination. 3194 // attribute. This allows screen readers to read an empty link's destination.
3197 if (value.empty() && (ia_state() & STATE_SYSTEM_LINKED)) 3195 if (value.empty() && (ia_state() & STATE_SYSTEM_LINKED))
3198 value = GetString16Attribute(ui::AX_ATTR_URL); 3196 value = GetString16Attribute(ui::AX_ATTR_URL);
3199 3197
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
3296 (ia_state() & STATE_SYSTEM_SELECTABLE) && 3294 (ia_state() & STATE_SYSTEM_SELECTABLE) &&
3297 (ia_state() & STATE_SYSTEM_FOCUSED) && 3295 (ia_state() & STATE_SYSTEM_FOCUSED) &&
3298 !(old_win_attributes_->ia_state & STATE_SYSTEM_FOCUSED)) { 3296 !(old_win_attributes_->ia_state & STATE_SYSTEM_FOCUSED)) {
3299 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_FOCUS, this); 3297 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_FOCUS, this);
3300 } 3298 }
3301 3299
3302 // Handle selection being added or removed. 3300 // Handle selection being added or removed.
3303 bool is_selected_now = (ia_state() & STATE_SYSTEM_SELECTED) != 0; 3301 bool is_selected_now = (ia_state() & STATE_SYSTEM_SELECTED) != 0;
3304 bool was_selected_before = 3302 bool was_selected_before =
3305 (old_win_attributes_->ia_state & STATE_SYSTEM_SELECTED) != 0; 3303 (old_win_attributes_->ia_state & STATE_SYSTEM_SELECTED) != 0;
3306 if (is_selected_now && !was_selected_before) { 3304 if (is_selected_now || was_selected_before) {
3307 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONADD, this); 3305 bool multiselect = false;
3308 } else if (!is_selected_now && was_selected_before) { 3306 if (GetParent() && GetParent()->HasState(ui::AX_STATE_MULTISELECTABLE))
3309 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONREMOVE, this); 3307 multiselect = true;
3308
3309 if (multiselect) {
je_julie(Not used) 2015/04/06 10:31:48 Do we need this variable? it doesn't seem to be us
3310 // In a multi-select box, fire SELECTIONADD and SELECTIONREMOVE events.
3311 if (is_selected_now && !was_selected_before) {
3312 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONADD, this);
3313 } else if (!is_selected_now && was_selected_before) {
3314 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONREMOVE, this);
3315 }
3316 } else if (is_selected_now && !was_selected_before) {
3317 // In a single-select box, only fire SELECTION events.
3318 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTION, this);
3319 }
3310 } 3320 }
3311 3321
3312 // Fire an event if this container object has scrolled. 3322 // Fire an event if this container object has scrolled.
3313 int sx = 0; 3323 int sx = 0;
3314 int sy = 0; 3324 int sy = 0;
3315 if (GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) && 3325 if (GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
3316 GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) { 3326 GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
3317 if (sx != previous_scroll_x_ || sy != previous_scroll_y_) 3327 if (sx != previous_scroll_x_ || sy != previous_scroll_y_)
3318 manager->MaybeCallNotifyWinEvent(EVENT_SYSTEM_SCROLLINGEND, this); 3328 manager->MaybeCallNotifyWinEvent(EVENT_SYSTEM_SCROLLINGEND, this);
3319 previous_scroll_x_ = sx; 3329 previous_scroll_x_ = sx;
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
3459 base::string16 value = this->value(); 3469 base::string16 value = this->value();
3460 3470
3461 if (value.empty() && 3471 if (value.empty() &&
3462 GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, &fval)) { 3472 GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, &fval)) {
3463 value = base::UTF8ToUTF16(base::DoubleToString(fval)); 3473 value = base::UTF8ToUTF16(base::DoubleToString(fval));
3464 } 3474 }
3465 return value; 3475 return value;
3466 } 3476 }
3467 3477
3468 base::string16 BrowserAccessibilityWin::TextForIAccessibleText() { 3478 base::string16 BrowserAccessibilityWin::TextForIAccessibleText() {
3469 if (IsEditableText()) 3479 if (IsEditableText() || GetRole() == ui::AX_ROLE_MENU_LIST_OPTION)
3470 return value(); 3480 return value();
3471 return (GetRole() == ui::AX_ROLE_STATIC_TEXT) ? name() : hypertext(); 3481 return (GetRole() == ui::AX_ROLE_STATIC_TEXT) ? name() : hypertext();
3472 } 3482 }
3473 3483
3474 bool BrowserAccessibilityWin::IsSameHypertextCharacter(size_t old_char_index, 3484 bool BrowserAccessibilityWin::IsSameHypertextCharacter(size_t old_char_index,
3475 size_t new_char_index) { 3485 size_t new_char_index) {
3476 CHECK(old_win_attributes_); 3486 CHECK(old_win_attributes_);
3477 3487
3478 // For anything other than the "embedded character", we just compare the 3488 // For anything other than the "embedded character", we just compare the
3479 // characters directly. 3489 // characters directly.
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
3585 const std::vector<int32>& line_breaks = GetIntListAttribute( 3595 const std::vector<int32>& line_breaks = GetIntListAttribute(
3586 ui::AX_ATTR_LINE_BREAKS); 3596 ui::AX_ATTR_LINE_BREAKS);
3587 return ui::FindAccessibleTextBoundary( 3597 return ui::FindAccessibleTextBoundary(
3588 text, line_breaks, boundary, start_offset, direction); 3598 text, line_breaks, boundary, start_offset, direction);
3589 } 3599 }
3590 3600
3591 BrowserAccessibilityWin* BrowserAccessibilityWin::GetFromID(int32 id) { 3601 BrowserAccessibilityWin* BrowserAccessibilityWin::GetFromID(int32 id) {
3592 return manager()->GetFromID(id)->ToBrowserAccessibilityWin(); 3602 return manager()->GetFromID(id)->ToBrowserAccessibilityWin();
3593 } 3603 }
3594 3604
3605 bool BrowserAccessibilityWin::IsListBoxOptionOrMenuListOption() {
3606 if (!GetParent())
3607 return false;
3608
3609 int32 role = GetRole();
3610 int32 parent_role = GetParent()->GetRole();
3611
3612 if (role == ui::AX_ROLE_LIST_BOX_OPTION &&
3613 parent_role == ui::AX_ROLE_LIST_BOX) {
3614 return true;
3615 }
3616
3617 if (role == ui::AX_ROLE_MENU_LIST_OPTION &&
3618 parent_role == ui::AX_ROLE_MENU_LIST_POPUP) {
3619 return true;
3620 }
3621
3622 return false;
3623 }
3624
3595 void BrowserAccessibilityWin::InitRoleAndState() { 3625 void BrowserAccessibilityWin::InitRoleAndState() {
3596 int32 ia_role = 0; 3626 int32 ia_role = 0;
3597 int32 ia_state = 0; 3627 int32 ia_state = 0;
3598 base::string16 role_name; 3628 base::string16 role_name;
3599 int32 ia2_role = 0; 3629 int32 ia2_role = 0;
3600 int32 ia2_state = IA2_STATE_OPAQUE; 3630 int32 ia2_state = IA2_STATE_OPAQUE;
3601 3631
3602 if (HasState(ui::AX_STATE_BUSY)) 3632 if (HasState(ui::AX_STATE_BUSY))
3603 ia_state |= STATE_SYSTEM_BUSY; 3633 ia_state |= STATE_SYSTEM_BUSY;
3604 if (HasState(ui::AX_STATE_CHECKED)) 3634 if (HasState(ui::AX_STATE_CHECKED))
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after
3907 case ui::AX_ROLE_MENU_ITEM_CHECK_BOX: 3937 case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
3908 ia_role = ROLE_SYSTEM_MENUITEM; 3938 ia_role = ROLE_SYSTEM_MENUITEM;
3909 ia2_role = IA2_ROLE_CHECK_MENU_ITEM; 3939 ia2_role = IA2_ROLE_CHECK_MENU_ITEM;
3910 ia2_state |= IA2_STATE_CHECKABLE; 3940 ia2_state |= IA2_STATE_CHECKABLE;
3911 break; 3941 break;
3912 case ui::AX_ROLE_MENU_ITEM_RADIO: 3942 case ui::AX_ROLE_MENU_ITEM_RADIO:
3913 ia_role = ROLE_SYSTEM_MENUITEM; 3943 ia_role = ROLE_SYSTEM_MENUITEM;
3914 ia2_role = IA2_ROLE_RADIO_MENU_ITEM; 3944 ia2_role = IA2_ROLE_RADIO_MENU_ITEM;
3915 break; 3945 break;
3916 case ui::AX_ROLE_MENU_LIST_POPUP: 3946 case ui::AX_ROLE_MENU_LIST_POPUP:
3917 ia_role = ROLE_SYSTEM_CLIENT; 3947 ia_role = ROLE_SYSTEM_LIST;
3948 ia2_state &= ~(IA2_STATE_EDITABLE);
3918 break; 3949 break;
3919 case ui::AX_ROLE_MENU_LIST_OPTION: 3950 case ui::AX_ROLE_MENU_LIST_OPTION:
3920 ia_role = ROLE_SYSTEM_LISTITEM; 3951 ia_role = ROLE_SYSTEM_LISTITEM;
3952 ia2_state &= ~(IA2_STATE_EDITABLE);
3921 if (ia_state & STATE_SYSTEM_SELECTABLE) { 3953 if (ia_state & STATE_SYSTEM_SELECTABLE) {
3922 ia_state |= STATE_SYSTEM_FOCUSABLE; 3954 ia_state |= STATE_SYSTEM_FOCUSABLE;
3923 if (HasState(ui::AX_STATE_FOCUSED)) 3955 if (HasState(ui::AX_STATE_FOCUSED))
3924 ia_state |= STATE_SYSTEM_FOCUSED; 3956 ia_state |= STATE_SYSTEM_FOCUSED;
3925 } 3957 }
3926 break; 3958 break;
3927 case ui::AX_ROLE_METER: 3959 case ui::AX_ROLE_METER:
3928 role_name = html_tag; 3960 role_name = html_tag;
3929 ia_role = ROLE_SYSTEM_PROGRESSBAR; 3961 ia_role = ROLE_SYSTEM_PROGRESSBAR;
3930 break; 3962 break;
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
4137 ia2_role = ia_role; 4169 ia2_role = ia_role;
4138 4170
4139 win_attributes_->ia_role = ia_role; 4171 win_attributes_->ia_role = ia_role;
4140 win_attributes_->ia_state = ia_state; 4172 win_attributes_->ia_state = ia_state;
4141 win_attributes_->role_name = role_name; 4173 win_attributes_->role_name = role_name;
4142 win_attributes_->ia2_role = ia2_role; 4174 win_attributes_->ia2_role = ia2_role;
4143 win_attributes_->ia2_state = ia2_state; 4175 win_attributes_->ia2_state = ia2_state;
4144 } 4176 }
4145 4177
4146 } // namespace content 4178 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698