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

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

Issue 1435113003: Make use of new AX name calc in Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix ChromeVox and Automation API tests Created 5 years, 1 month 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 <algorithm> 10 #include <algorithm>
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 return S_OK; 449 return S_OK;
450 } 450 }
451 451
452 STDMETHODIMP BrowserAccessibilityWin::get_accHelp(VARIANT var_id, BSTR* help) { 452 STDMETHODIMP BrowserAccessibilityWin::get_accHelp(VARIANT var_id, BSTR* help) {
453 if (!instance_active()) 453 if (!instance_active())
454 return E_FAIL; 454 return E_FAIL;
455 455
456 if (!help) 456 if (!help)
457 return E_INVALIDARG; 457 return E_INVALIDARG;
458 458
459 BrowserAccessibilityWin* target = GetTargetFromChildID(var_id); 459 return S_FALSE;
460 if (!target)
461 return E_INVALIDARG;
462
463 base::string16 help_str = target->help();
464 if (help_str.empty())
465 return S_FALSE;
466
467 *help = SysAllocString(help_str.c_str());
468
469 DCHECK(*help);
470 return S_OK;
471 } 460 }
472 461
473 STDMETHODIMP BrowserAccessibilityWin::get_accKeyboardShortcut(VARIANT var_id, 462 STDMETHODIMP BrowserAccessibilityWin::get_accKeyboardShortcut(VARIANT var_id,
474 BSTR* acc_key) { 463 BSTR* acc_key) {
475 if (!instance_active()) 464 if (!instance_active())
476 return E_FAIL; 465 return E_FAIL;
477 466
478 if (!acc_key) 467 if (!acc_key)
479 return E_INVALIDARG; 468 return E_INVALIDARG;
480 469
(...skipping 10 matching lines...) Expand all
491 return E_FAIL; 480 return E_FAIL;
492 481
493 if (!name) 482 if (!name)
494 return E_INVALIDARG; 483 return E_INVALIDARG;
495 484
496 BrowserAccessibilityWin* target = GetTargetFromChildID(var_id); 485 BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
497 if (!target) 486 if (!target)
498 return E_INVALIDARG; 487 return E_INVALIDARG;
499 488
500 base::string16 name_str = target->name(); 489 base::string16 name_str = target->name();
501
502 // If the name is empty, see if it's labeled by another element.
503 if (name_str.empty()) {
504 int title_elem_id;
505 if (target->GetIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT,
506 &title_elem_id)) {
507 BrowserAccessibilityWin* title_elem =
508 manager()->GetFromID(title_elem_id)->ToBrowserAccessibilityWin();
509 if (title_elem)
510 name_str = title_elem->GetNameRecursive();
511 }
512 }
513
514 if (name_str.empty()) 490 if (name_str.empty())
515 return S_FALSE; 491 return S_FALSE;
516 492
517 *name = SysAllocString(name_str.c_str()); 493 *name = SysAllocString(name_str.c_str());
518 494
519 DCHECK(*name); 495 DCHECK(*name);
520 return S_OK; 496 return S_OK;
521 } 497 }
522 498
523 STDMETHODIMP BrowserAccessibilityWin::get_accParent(IDispatch** disp_parent) { 499 STDMETHODIMP BrowserAccessibilityWin::get_accParent(IDispatch** disp_parent) {
(...skipping 1614 matching lines...) Expand 10 before | Expand all | Expand 10 after
2138 // The spec does not allow the start or end offsets to be out or range; 2114 // The spec does not allow the start or end offsets to be out or range;
2139 // we must return an error if so. 2115 // we must return an error if so.
2140 LONG len = text_str.length(); 2116 LONG len = text_str.length();
2141 if (start_offset < 0) 2117 if (start_offset < 0)
2142 return E_INVALIDARG; 2118 return E_INVALIDARG;
2143 if (end_offset > len) 2119 if (end_offset > len)
2144 return E_INVALIDARG; 2120 return E_INVALIDARG;
2145 2121
2146 base::string16 substr = text_str.substr(start_offset, 2122 base::string16 substr = text_str.substr(start_offset,
2147 end_offset - start_offset); 2123 end_offset - start_offset);
2124
2148 if (substr.empty()) 2125 if (substr.empty())
2149 return S_FALSE; 2126 return S_FALSE;
2150 2127
2151 *text = SysAllocString(substr.c_str()); 2128 *text = SysAllocString(substr.c_str());
2152 DCHECK(*text); 2129 DCHECK(*text);
2153 return S_OK; 2130 return S_OK;
2154 } 2131 }
2155 2132
2156 STDMETHODIMP BrowserAccessibilityWin::get_textAtOffset( 2133 STDMETHODIMP BrowserAccessibilityWin::get_textAtOffset(
2157 LONG offset, 2134 LONG offset,
(...skipping 1239 matching lines...) Expand 10 before | Expand all | Expand 10 after
3397 win_attributes_->ia2_attributes.push_back(L"sort:descending"); 3374 win_attributes_->ia2_attributes.push_back(L"sort:descending");
3398 break; 3375 break;
3399 case ui::AX_SORT_DIRECTION_OTHER: 3376 case ui::AX_SORT_DIRECTION_OTHER:
3400 win_attributes_->ia2_attributes.push_back(L"sort:other"); 3377 win_attributes_->ia2_attributes.push_back(L"sort:other");
3401 break; 3378 break;
3402 default: 3379 default:
3403 NOTREACHED(); 3380 NOTREACHED();
3404 } 3381 }
3405 } 3382 }
3406 3383
3407 // The calculation of the accessible name of an element has been 3384 win_attributes_->name = GetString16Attribute(ui::AX_ATTR_NAME);
3408 // standardized in the HTML to Platform Accessibility APIs Implementation 3385 win_attributes_->description = GetString16Attribute(ui::AX_ATTR_DESCRIPTION);
3409 // Guide (http://www.w3.org/TR/html-aapi/). In order to return the
3410 // appropriate accessible name on Windows, we need to apply some logic
3411 // to the fields we get from WebKit.
3412 //
3413 // TODO(dmazzoni): move most of this logic into WebKit.
3414 //
3415 // WebKit gives us:
3416 //
3417 // name: the default name, e.g. inner text
3418 // title ui element: a reference to a <label> element on the same
3419 // page that labels this node.
3420 // description: accessible labels that override the default name:
3421 // aria-label or aria-labelledby or aria-describedby
3422 // help: the value of the "title" attribute
3423 //
3424 // On Windows, the logic we apply lets some fields take precedence and
3425 // always returns the primary name in "name" and the secondary name,
3426 // if any, in "description".
3427 3386
3428 int title_elem_id = GetIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT);
3429 base::string16 name = GetString16Attribute(ui::AX_ATTR_NAME);
3430 base::string16 description = GetString16Attribute(ui::AX_ATTR_DESCRIPTION);
3431 base::string16 help = GetString16Attribute(ui::AX_ATTR_HELP);
3432 base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE); 3387 base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE);
3433 3388
3434 // WebKit annoyingly puts the title in the description if there's no other
3435 // description, which just confuses the rest of the logic. Put it back.
3436 // Now "help" is always the value of the "title" attribute, if present.
3437 base::string16 title_attr;
3438 if (GetHtmlAttribute("title", &title_attr) &&
3439 description == title_attr &&
3440 help.empty()) {
3441 help = description;
3442 description.clear();
3443 }
3444
3445 // Now implement the main logic: the descripion should become the name if
aboxhall 2015/11/13 23:13:48 This is so great.
dmazzoni 2015/11/16 18:52:04 Yay for deleted code!
3446 // it's nonempty, and the help should become the description if
3447 // there's no description - or the name if there's no name or description.
3448 if (!description.empty()) {
3449 name = description;
3450 description.clear();
3451 }
3452 if (!help.empty() && description.empty()) {
3453 description = help;
3454 help.clear();
3455 }
3456 if (!description.empty() && name.empty() && !title_elem_id) {
3457 name = description;
3458 description.clear();
3459 }
3460
3461 // If it's a text field, also consider the placeholder.
3462 base::string16 placeholder;
3463 if (GetRole() == ui::AX_ROLE_TEXT_FIELD &&
3464 HasState(ui::AX_STATE_FOCUSABLE) &&
3465 GetHtmlAttribute("placeholder", &placeholder)) {
3466 if (name.empty() && !title_elem_id) {
3467 name = placeholder;
3468 } else if (description.empty()) {
3469 description = placeholder;
3470 }
3471 }
3472
3473 // On Windows, the value of a document should be its url. 3389 // On Windows, the value of a document should be its url.
3474 if (GetRole() == ui::AX_ROLE_ROOT_WEB_AREA || 3390 if (GetRole() == ui::AX_ROLE_ROOT_WEB_AREA ||
3475 GetRole() == ui::AX_ROLE_WEB_AREA) { 3391 GetRole() == ui::AX_ROLE_WEB_AREA) {
3476 value = base::UTF8ToUTF16(manager()->GetTreeData().url); 3392 value = base::UTF8ToUTF16(manager()->GetTreeData().url);
3477 } 3393 }
3478 3394
3479 // For certain roles (listbox option, static text, and list marker)
3480 // WebKit stores the main accessible text in the "value" - swap it so
3481 // that it's the "name".
3482 if (name.empty() &&
3483 (GetRole() == ui::AX_ROLE_STATIC_TEXT ||
3484 GetRole() == ui::AX_ROLE_LIST_MARKER ||
3485 IsListBoxOptionOrMenuListOption())) {
3486 base::string16 tmp = value;
3487 value = name;
3488 name = tmp;
3489 }
3490
3491 // If this doesn't have a value and is linked then set its value to the url 3395 // If this doesn't have a value and is linked then set its value to the url
3492 // attribute. This allows screen readers to read an empty link's destination. 3396 // attribute. This allows screen readers to read an empty link's destination.
3493 if (value.empty() && (ia_state() & STATE_SYSTEM_LINKED)) 3397 if (value.empty() && (ia_state() & STATE_SYSTEM_LINKED))
3494 value = GetString16Attribute(ui::AX_ATTR_URL); 3398 value = GetString16Attribute(ui::AX_ATTR_URL);
3495 3399
3496 win_attributes_->name = name;
3497 win_attributes_->description = description;
3498 win_attributes_->help = help;
3499 win_attributes_->value = value; 3400 win_attributes_->value = value;
3500 3401
3501 // Clear any old relationships between this node and other nodes. 3402 // Clear any old relationships between this node and other nodes.
3502 for (size_t i = 0; i < relations_.size(); ++i) 3403 for (size_t i = 0; i < relations_.size(); ++i)
3503 relations_[i]->Release(); 3404 relations_[i]->Release();
3504 relations_.clear(); 3405 relations_.clear();
3505 3406
3506 // Handle title UI element. 3407 // Handle title UI element.
3507 if (title_elem_id) { 3408 AddRelations(ui::AX_ATTR_CONTROLS_IDS, IA2_RELATION_CONTROLLER_FOR);
3508 // Add a labelled by relationship. 3409 AddRelations(ui::AX_ATTR_DESCRIBEDBY_IDS, IA2_RELATION_DESCRIBED_BY);
3509 CComObject<BrowserAccessibilityRelation>* relation; 3410 AddRelations(ui::AX_ATTR_FLOWTO_IDS, IA2_RELATION_FLOWS_TO);
3510 HRESULT hr = CComObject<BrowserAccessibilityRelation>::CreateInstance( 3411 AddRelations(ui::AX_ATTR_LABELLEDBY_IDS, IA2_RELATION_LABELLED_BY);
3511 &relation);
3512 DCHECK(SUCCEEDED(hr));
3513 relation->AddRef();
3514 relation->Initialize(this, IA2_RELATION_LABELLED_BY);
3515 relation->AddTarget(title_elem_id);
3516 relations_.push_back(relation);
3517 }
3518 3412
3519 UpdateRequiredAttributes(); 3413 UpdateRequiredAttributes();
3520 // If this is a web area for a presentational iframe, give it a role of 3414 // If this is a web area for a presentational iframe, give it a role of
3521 // something other than DOCUMENT so that the fact that it's a separate doc 3415 // something other than DOCUMENT so that the fact that it's a separate doc
3522 // is not exposed to AT. 3416 // is not exposed to AT.
3523 if (IsWebAreaForPresentationalIframe()) { 3417 if (IsWebAreaForPresentationalIframe()) {
3524 win_attributes_->ia_role = ROLE_SYSTEM_GROUPING; 3418 win_attributes_->ia_role = ROLE_SYSTEM_GROUPING;
3525 win_attributes_->ia2_role = ROLE_SYSTEM_GROUPING; 3419 win_attributes_->ia2_role = ROLE_SYSTEM_GROUPING;
3526 } 3420 }
3527 } 3421 }
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
3574 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SHOW, this); 3468 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SHOW, this);
3575 3469
3576 // The rest of the events only fire on changes, not on new objects. 3470 // The rest of the events only fire on changes, not on new objects.
3577 if (old_win_attributes_->ia_role != 0 || 3471 if (old_win_attributes_->ia_role != 0 ||
3578 !old_win_attributes_->role_name.empty()) { 3472 !old_win_attributes_->role_name.empty()) {
3579 // Fire an event if the name, description, help, or value changes. 3473 // Fire an event if the name, description, help, or value changes.
3580 if (name() != old_win_attributes_->name) 3474 if (name() != old_win_attributes_->name)
3581 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, this); 3475 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, this);
3582 if (description() != old_win_attributes_->description) 3476 if (description() != old_win_attributes_->description)
3583 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_DESCRIPTIONCHANGE, this); 3477 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_DESCRIPTIONCHANGE, this);
3584 if (help() != old_win_attributes_->help)
3585 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_HELPCHANGE, this);
3586 if (value() != old_win_attributes_->value) 3478 if (value() != old_win_attributes_->value)
3587 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_VALUECHANGE, this); 3479 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_VALUECHANGE, this);
3588 if (ia_state() != old_win_attributes_->ia_state) 3480 if (ia_state() != old_win_attributes_->ia_state)
3589 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_STATECHANGE, this); 3481 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_STATECHANGE, this);
3590 3482
3591 // Normally focus events are handled elsewhere, however 3483 // Normally focus events are handled elsewhere, however
3592 // focus for managed descendants is platform-specific. 3484 // focus for managed descendants is platform-specific.
3593 // Fire a focus event if the focused descendant in a multi-select 3485 // Fire a focus event if the focused descendant in a multi-select
3594 // list box changes. 3486 // list box changes.
3595 if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION && 3487 if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION &&
(...skipping 627 matching lines...) Expand 10 before | Expand all | Expand 10 after
4223 // Expose input-text type attribute. 4115 // Expose input-text type attribute.
4224 base::string16 type; 4116 base::string16 type;
4225 base::string16 html_tag = GetString16Attribute(ui::AX_ATTR_HTML_TAG); 4117 base::string16 html_tag = GetString16Attribute(ui::AX_ATTR_HTML_TAG);
4226 if (GetRole() == ui::AX_ROLE_TEXT_FIELD && html_tag == L"input" && 4118 if (GetRole() == ui::AX_ROLE_TEXT_FIELD && html_tag == L"input" &&
4227 GetHtmlAttribute("type", &type)) { 4119 GetHtmlAttribute("type", &type)) {
4228 SanitizeStringAttributeForIA2(type, &type); 4120 SanitizeStringAttributeForIA2(type, &type);
4229 win_attributes_->ia2_attributes.push_back(L"text-input-type:" + type); 4121 win_attributes_->ia2_attributes.push_back(L"text-input-type:" + type);
4230 } 4122 }
4231 } 4123 }
4232 4124
4125 void BrowserAccessibilityWin::AddRelations(
4126 ui::AXIntListAttribute src_attr,
4127 const base::string16& iaccessiblerelation_type) {
4128 if (!HasIntListAttribute(src_attr))
4129 return;
4130
4131 const std::vector<int32>& ids = GetIntListAttribute(src_attr);
4132 for (size_t i = 0; i < ids.size(); ++i) {
4133 CComObject<BrowserAccessibilityRelation>* relation;
4134 HRESULT hr = CComObject<BrowserAccessibilityRelation>::CreateInstance(
4135 &relation);
4136 DCHECK(SUCCEEDED(hr));
4137 relation->AddRef();
4138 relation->Initialize(this, iaccessiblerelation_type);
4139 relation->AddTarget(ids[i]);
4140 relations_.push_back(relation);
4141 }
4142 }
4143
4233 void BrowserAccessibilityWin::InitRoleAndState() { 4144 void BrowserAccessibilityWin::InitRoleAndState() {
4234 int32 ia_role = 0; 4145 int32 ia_role = 0;
4235 int32 ia_state = 0; 4146 int32 ia_state = 0;
4236 base::string16 role_name; 4147 base::string16 role_name;
4237 int32 ia2_role = 0; 4148 int32 ia2_role = 0;
4238 int32 ia2_state = IA2_STATE_OPAQUE; 4149 int32 ia2_state = IA2_STATE_OPAQUE;
4239 4150
4240 if (HasState(ui::AX_STATE_BUSY)) 4151 if (HasState(ui::AX_STATE_BUSY))
4241 ia_state |= STATE_SYSTEM_BUSY; 4152 ia_state |= STATE_SYSTEM_BUSY;
4242 if (HasState(ui::AX_STATE_CHECKED)) 4153 if (HasState(ui::AX_STATE_CHECKED))
(...skipping 536 matching lines...) Expand 10 before | Expand all | Expand 10 after
4779 ia2_role = ia_role; 4690 ia2_role = ia_role;
4780 4691
4781 win_attributes_->ia_role = ia_role; 4692 win_attributes_->ia_role = ia_role;
4782 win_attributes_->ia_state = ia_state; 4693 win_attributes_->ia_state = ia_state;
4783 win_attributes_->role_name = role_name; 4694 win_attributes_->role_name = role_name;
4784 win_attributes_->ia2_role = ia2_role; 4695 win_attributes_->ia2_role = ia2_role;
4785 win_attributes_->ia2_state = ia2_state; 4696 win_attributes_->ia2_state = ia2_state;
4786 } 4697 }
4787 4698
4788 } // namespace content 4699 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698