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

Side by Side Diff: ui/accessibility/platform/ax_platform_node_win.cc

Issue 2975413002: Move ia2_attributes handling to AXPlatformNodeWin. (Closed)
Patch Set: Suggestions from dmazzoni Created 3 years, 5 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
« no previous file with comments | « ui/accessibility/platform/ax_platform_node_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 <atlbase.h> 5 #include <atlbase.h>
6 #include <atlcom.h> 6 #include <atlcom.h>
7 #include <limits.h> 7 #include <limits.h>
8 #include <oleacc.h> 8 #include <oleacc.h>
9 #include <stdint.h> 9 #include <stdint.h>
10 10
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 // 197 //
198 // AXPlatformNodeWin 198 // AXPlatformNodeWin
199 // 199 //
200 200
201 AXPlatformNodeWin::AXPlatformNodeWin() { 201 AXPlatformNodeWin::AXPlatformNodeWin() {
202 } 202 }
203 203
204 AXPlatformNodeWin::~AXPlatformNodeWin() { 204 AXPlatformNodeWin::~AXPlatformNodeWin() {
205 } 205 }
206 206
207 // Static
208 void AXPlatformNodeWin::SanitizeStringAttributeForIA2(
209 const base::string16& input,
210 base::string16* output) {
211 DCHECK(output);
212 // According to the IA2 Spec, these characters need to be escaped with a
213 // backslash: backslash, colon, comma, equals and semicolon.
214 // Note that backslash must be replaced first.
215 base::ReplaceChars(input, L"\\", L"\\\\", output);
216 base::ReplaceChars(*output, L":", L"\\:", output);
217 base::ReplaceChars(*output, L",", L"\\,", output);
218 base::ReplaceChars(*output, L"=", L"\\=", output);
219 base::ReplaceChars(*output, L";", L"\\;", output);
220 }
221
222 void AXPlatformNodeWin::StringAttributeToIA2(
223 std::vector<base::string16>& attributes,
224 ui::AXStringAttribute attribute,
225 const char* ia2_attr) {
226 base::string16 value;
227 if (GetString16Attribute(attribute, &value)) {
228 SanitizeStringAttributeForIA2(value, &value);
229 attributes.push_back(base::ASCIIToUTF16(ia2_attr) + L":" + value);
230 }
231 }
232
233 void AXPlatformNodeWin::BoolAttributeToIA2(
234 std::vector<base::string16>& attributes,
235 ui::AXBoolAttribute attribute,
236 const char* ia2_attr) {
237 bool value;
238 if (GetBoolAttribute(attribute, &value)) {
239 attributes.push_back((base::ASCIIToUTF16(ia2_attr) + L":") +
240 (value ? L"true" : L"false"));
241 }
242 }
243
244 void AXPlatformNodeWin::IntAttributeToIA2(
245 std::vector<base::string16>& attributes,
246 ui::AXIntAttribute attribute,
247 const char* ia2_attr) {
248 int value;
249 if (GetIntAttribute(attribute, &value)) {
250 attributes.push_back(base::ASCIIToUTF16(ia2_attr) + L":" +
251 base::IntToString16(value));
252 }
253 }
254
207 // 255 //
208 // AXPlatformNodeBase implementation. 256 // AXPlatformNodeBase implementation.
209 // 257 //
210 258
211 void AXPlatformNodeWin::Dispose() { 259 void AXPlatformNodeWin::Dispose() {
212 Release(); 260 Release();
213 } 261 }
214 262
215 void AXPlatformNodeWin::Destroy() { 263 void AXPlatformNodeWin::Destroy() {
216 RemoveAlertTarget(); 264 RemoveAlertTarget();
(...skipping 574 matching lines...) Expand 10 before | Expand all | Expand 10 after
791 return E_NOTIMPL; 839 return E_NOTIMPL;
792 } 840 }
793 841
794 // 842 //
795 // IAccessible2 implementation. 843 // IAccessible2 implementation.
796 // 844 //
797 845
798 STDMETHODIMP AXPlatformNodeWin::role(LONG* role) { 846 STDMETHODIMP AXPlatformNodeWin::role(LONG* role) {
799 COM_OBJECT_VALIDATE_1_ARG(role); 847 COM_OBJECT_VALIDATE_1_ARG(role);
800 848
801 *role = IA2Role(); 849 *role = ComputeIA2Role();
802 // If we didn't explicitly set the IAccessible2 role, make it the same 850 // If we didn't explicitly set the IAccessible2 role, make it the same
803 // as the MSAA role. 851 // as the MSAA role.
804 if (!*role) 852 if (!*role)
805 *role = MSAARole(); 853 *role = MSAARole();
806 return S_OK; 854 return S_OK;
807 } 855 }
808 856
809 STDMETHODIMP AXPlatformNodeWin::get_states(AccessibleStates* states) { 857 STDMETHODIMP AXPlatformNodeWin::get_states(AccessibleStates* states) {
810 COM_OBJECT_VALIDATE_1_ARG(states); 858 COM_OBJECT_VALIDATE_1_ARG(states);
811 *states = IA2State(); 859 *states = ComputeIA2State();
812 return S_OK; 860 return S_OK;
813 } 861 }
814 862
815 STDMETHODIMP AXPlatformNodeWin::get_uniqueID(LONG* unique_id) { 863 STDMETHODIMP AXPlatformNodeWin::get_uniqueID(LONG* unique_id) {
816 COM_OBJECT_VALIDATE_1_ARG(unique_id); 864 COM_OBJECT_VALIDATE_1_ARG(unique_id);
817 *unique_id = -unique_id_; 865 *unique_id = -unique_id_;
818 return S_OK; 866 return S_OK;
819 } 867 }
820 868
821 STDMETHODIMP AXPlatformNodeWin::get_windowHandle(HWND* window_handle) { 869 STDMETHODIMP AXPlatformNodeWin::get_windowHandle(HWND* window_handle) {
(...skipping 1391 matching lines...) Expand 10 before | Expand all | Expand 10 after
2213 return false; 2261 return false;
2214 } 2262 }
2215 2263
2216 auto* parent = FromNativeViewAccessible(GetParent()); 2264 auto* parent = FromNativeViewAccessible(GetParent());
2217 if (!parent) 2265 if (!parent)
2218 return false; 2266 return false;
2219 2267
2220 return parent->GetData().role == ui::AX_ROLE_IFRAME_PRESENTATIONAL; 2268 return parent->GetData().role == ui::AX_ROLE_IFRAME_PRESENTATIONAL;
2221 } 2269 }
2222 2270
2223 int32_t AXPlatformNodeWin::IA2State() { 2271 int32_t AXPlatformNodeWin::ComputeIA2State() {
2224 const AXNodeData& data = GetData(); 2272 const AXNodeData& data = GetData();
2225 2273
2226 int32_t ia2_state = IA2_STATE_OPAQUE; 2274 int32_t ia2_state = IA2_STATE_OPAQUE;
2227 2275
2228 const auto checked_state = static_cast<ui::AXCheckedState>( 2276 const auto checked_state = static_cast<ui::AXCheckedState>(
2229 GetIntAttribute(ui::AX_ATTR_CHECKED_STATE)); 2277 GetIntAttribute(ui::AX_ATTR_CHECKED_STATE));
2230 if (checked_state) { 2278 if (checked_state) {
2231 ia2_state |= IA2_STATE_CHECKABLE; 2279 ia2_state |= IA2_STATE_CHECKABLE;
2232 } 2280 }
2233 2281
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
2281 ia2_state |= IA2_STATE_SINGLE_LINE; 2329 ia2_state |= IA2_STATE_SINGLE_LINE;
2282 } 2330 }
2283 ia2_state |= IA2_STATE_SELECTABLE_TEXT; 2331 ia2_state |= IA2_STATE_SELECTABLE_TEXT;
2284 break; 2332 break;
2285 default: 2333 default:
2286 break; 2334 break;
2287 } 2335 }
2288 return ia2_state; 2336 return ia2_state;
2289 } 2337 }
2290 2338
2291 // IA2Role() only returns a role if the MSAA role doesn't suffice, 2339 // ComputeIA2Role() only returns a role if the MSAA role doesn't suffice,
2292 // otherwise this method returns 0. See AXPlatformNodeWin::role(). 2340 // otherwise this method returns 0. See AXPlatformNodeWin::role().
2293 int32_t AXPlatformNodeWin::IA2Role() { 2341 int32_t AXPlatformNodeWin::ComputeIA2Role() {
2294 // If this is a web area for a presentational iframe, give it a role of 2342 // If this is a web area for a presentational iframe, give it a role of
2295 // something other than DOCUMENT so that the fact that it's a separate doc 2343 // something other than DOCUMENT so that the fact that it's a separate doc
2296 // is not exposed to AT. 2344 // is not exposed to AT.
2297 if (IsWebAreaForPresentationalIframe()) { 2345 if (IsWebAreaForPresentationalIframe()) {
2298 return ROLE_SYSTEM_GROUPING; 2346 return ROLE_SYSTEM_GROUPING;
2299 } 2347 }
2300 2348
2301 int32_t ia2_role = 0; 2349 int32_t ia2_role = 0;
2302 2350
2303 switch (GetData().role) { 2351 switch (GetData().role) {
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
2419 case ui::AX_ROLE_ABBR: 2467 case ui::AX_ROLE_ABBR:
2420 case ui::AX_ROLE_TIME: 2468 case ui::AX_ROLE_TIME:
2421 ia2_role = IA2_ROLE_TEXT_FRAME; 2469 ia2_role = IA2_ROLE_TEXT_FRAME;
2422 break; 2470 break;
2423 default: 2471 default:
2424 break; 2472 break;
2425 } 2473 }
2426 return ia2_role; 2474 return ia2_role;
2427 } 2475 }
2428 2476
2477 std::vector<base::string16> AXPlatformNodeWin::ComputeIA2Attributes() {
2478 std::vector<base::string16> result;
2479 // Expose some HTLM and ARIA attributes in the IAccessible2 attributes string.
2480 // "display", "tag", and "xml-roles" have somewhat unusual names for
2481 // historical reasons. Aside from that virtually every ARIA attribute
2482 // is exposed in a really straightforward way, i.e. "aria-foo" is exposed
2483 // as "foo".
2484 StringAttributeToIA2(result, ui::AX_ATTR_DISPLAY, "display");
2485 StringAttributeToIA2(result, ui::AX_ATTR_HTML_TAG, "tag");
2486 StringAttributeToIA2(result, ui::AX_ATTR_ROLE, "xml-roles");
2487 StringAttributeToIA2(result, ui::AX_ATTR_PLACEHOLDER, "placeholder");
2488
2489 StringAttributeToIA2(result, ui::AX_ATTR_AUTO_COMPLETE, "autocomplete");
2490 StringAttributeToIA2(result, ui::AX_ATTR_ROLE_DESCRIPTION, "roledescription");
2491 StringAttributeToIA2(result, ui::AX_ATTR_KEY_SHORTCUTS, "keyshortcuts");
2492
2493 IntAttributeToIA2(result, ui::AX_ATTR_HIERARCHICAL_LEVEL, "level");
2494 IntAttributeToIA2(result, ui::AX_ATTR_SET_SIZE, "setsize");
2495 IntAttributeToIA2(result, ui::AX_ATTR_POS_IN_SET, "posinset");
2496
2497 if (HasIntAttribute(ui::AX_ATTR_CHECKED_STATE))
2498 result.push_back(L"checkable:true");
2499
2500 // Expose live region attributes.
2501 StringAttributeToIA2(result, ui::AX_ATTR_LIVE_STATUS, "live");
2502 StringAttributeToIA2(result, ui::AX_ATTR_LIVE_RELEVANT, "relevant");
2503 BoolAttributeToIA2(result, ui::AX_ATTR_LIVE_ATOMIC, "atomic");
2504 BoolAttributeToIA2(result, ui::AX_ATTR_LIVE_BUSY, "busy");
2505
2506 // Expose container live region attributes.
2507 StringAttributeToIA2(result, ui::AX_ATTR_CONTAINER_LIVE_STATUS,
2508 "container-live");
2509 StringAttributeToIA2(result, ui::AX_ATTR_CONTAINER_LIVE_RELEVANT,
2510 "container-relevant");
2511 BoolAttributeToIA2(result, ui::AX_ATTR_CONTAINER_LIVE_ATOMIC,
2512 "container-atomic");
2513 BoolAttributeToIA2(result, ui::AX_ATTR_CONTAINER_LIVE_BUSY, "container-busy");
2514
2515 // Expose the non-standard explicit-name IA2 attribute.
2516 int name_from;
2517 if (GetIntAttribute(ui::AX_ATTR_NAME_FROM, &name_from) &&
2518 name_from != ui::AX_NAME_FROM_CONTENTS) {
2519 result.push_back(L"explicit-name:true");
2520 }
2521
2522 // Expose the aria-current attribute.
2523 int32_t aria_current_state;
2524 if (GetIntAttribute(ui::AX_ATTR_ARIA_CURRENT_STATE, &aria_current_state)) {
2525 switch (static_cast<ui::AXAriaCurrentState>(aria_current_state)) {
2526 case ui::AX_ARIA_CURRENT_STATE_NONE:
2527 break;
2528 case ui::AX_ARIA_CURRENT_STATE_FALSE:
2529 result.push_back(L"current:false");
2530 break;
2531 case ui::AX_ARIA_CURRENT_STATE_TRUE:
2532 result.push_back(L"current:true");
2533 break;
2534 case ui::AX_ARIA_CURRENT_STATE_PAGE:
2535 result.push_back(L"current:page");
2536 break;
2537 case ui::AX_ARIA_CURRENT_STATE_STEP:
2538 result.push_back(L"current:step");
2539 break;
2540 case ui::AX_ARIA_CURRENT_STATE_LOCATION:
2541 result.push_back(L"current:location");
2542 break;
2543 case ui::AX_ARIA_CURRENT_STATE_DATE:
2544 result.push_back(L"current:date");
2545 break;
2546 case ui::AX_ARIA_CURRENT_STATE_TIME:
2547 result.push_back(L"current:time");
2548 break;
2549 }
2550 }
2551
2552 // Expose table cell index.
2553 if (ui::IsCellOrTableHeaderRole(GetData().role)) {
2554 AXPlatformNodeBase* table = FromNativeViewAccessible(GetParent());
2555
2556 while (table && !ui::IsTableLikeRole(table->GetData().role))
2557 table = FromNativeViewAccessible(table->GetParent());
2558
2559 if (table) {
2560 const std::vector<int32_t>& unique_cell_ids =
2561 table->GetIntListAttribute(ui::AX_ATTR_UNIQUE_CELL_IDS);
2562 for (size_t i = 0; i < unique_cell_ids.size(); ++i) {
2563 if (unique_cell_ids[i] == GetData().id) {
2564 result.push_back(base::string16(L"table-cell-index:") +
2565 base::IntToString16(static_cast<int>(i)));
2566 }
2567 }
2568 }
2569 }
2570
2571 // Expose aria-colcount and aria-rowcount in a table, grid or treegrid.
2572 if (ui::IsTableLikeRole(GetData().role)) {
2573 IntAttributeToIA2(result, ui::AX_ATTR_ARIA_COLUMN_COUNT, "colcount");
2574 IntAttributeToIA2(result, ui::AX_ATTR_ARIA_ROW_COUNT, "rowcount");
2575 }
2576
2577 // Expose aria-colindex and aria-rowindex in a cell or row.
2578 if (ui::IsCellOrTableHeaderRole(GetData().role) ||
2579 GetData().role == ui::AX_ROLE_ROW) {
2580 if (GetData().role != ui::AX_ROLE_ROW)
2581 IntAttributeToIA2(result, ui::AX_ATTR_ARIA_CELL_COLUMN_INDEX, "colindex");
2582 IntAttributeToIA2(result, ui::AX_ATTR_ARIA_CELL_ROW_INDEX, "rowindex");
2583 }
2584
2585 // Expose row or column header sort direction.
2586 int32_t sort_direction;
2587 if ((MSAARole() == ROLE_SYSTEM_COLUMNHEADER ||
2588 MSAARole() == ROLE_SYSTEM_ROWHEADER) &&
2589 GetIntAttribute(ui::AX_ATTR_SORT_DIRECTION, &sort_direction)) {
2590 switch (static_cast<ui::AXSortDirection>(sort_direction)) {
2591 case ui::AX_SORT_DIRECTION_NONE:
2592 break;
2593 case ui::AX_SORT_DIRECTION_UNSORTED:
2594 result.push_back(L"sort:none");
2595 break;
2596 case ui::AX_SORT_DIRECTION_ASCENDING:
2597 result.push_back(L"sort:ascending");
2598 break;
2599 case ui::AX_SORT_DIRECTION_DESCENDING:
2600 result.push_back(L"sort:descending");
2601 break;
2602 case ui::AX_SORT_DIRECTION_OTHER:
2603 result.push_back(L"sort:other");
2604 break;
2605 }
2606 }
2607
2608 if (ui::IsCellOrTableHeaderRole(GetData().role)) {
2609 // Expose colspan attribute.
2610 base::string16 colspan;
2611 if (GetData().GetHtmlAttribute("aria-colspan", &colspan)) {
2612 SanitizeStringAttributeForIA2(colspan, &colspan);
2613 result.push_back(L"colspan:" + colspan);
2614 }
2615 // Expose rowspan attribute.
2616 base::string16 rowspan;
2617 if (GetData().GetHtmlAttribute("aria-rowspan", &rowspan)) {
2618 SanitizeStringAttributeForIA2(rowspan, &rowspan);
2619 result.push_back(L"rowspan:" + rowspan);
2620 }
2621 }
2622
2623 // Expose slider value.
2624 if (IsRangeValueSupported()) {
2625 base::string16 value = GetRangeValueText();
2626 SanitizeStringAttributeForIA2(value, &value);
2627 result.push_back(L"valuetext:" + value);
2628 }
2629
2630 // Expose dropeffect attribute.
2631 base::string16 drop_effect;
2632 if (GetData().GetHtmlAttribute("aria-dropeffect", &drop_effect)) {
2633 SanitizeStringAttributeForIA2(drop_effect, &drop_effect);
2634 result.push_back(L"dropeffect:" + drop_effect);
2635 }
2636
2637 // Expose grabbed attribute.
2638 base::string16 grabbed;
2639 if (GetData().GetHtmlAttribute("aria-grabbed", &grabbed)) {
2640 SanitizeStringAttributeForIA2(grabbed, &grabbed);
2641 result.push_back(L"grabbed:" + grabbed);
2642 }
2643
2644 // Expose class attribute.
2645 base::string16 class_attr;
2646 if (GetData().GetHtmlAttribute("class", &class_attr)) {
2647 SanitizeStringAttributeForIA2(class_attr, &class_attr);
2648 result.push_back(L"class:" + class_attr);
2649 }
2650
2651 // Expose datetime attribute.
2652 base::string16 datetime;
2653 if (GetData().role == ui::AX_ROLE_TIME &&
2654 GetData().GetHtmlAttribute("datetime", &datetime)) {
2655 SanitizeStringAttributeForIA2(datetime, &datetime);
2656 result.push_back(L"datetime:" + datetime);
2657 }
2658
2659 // Expose id attribute.
2660 base::string16 id;
2661 if (GetData().GetHtmlAttribute("id", &id)) {
2662 SanitizeStringAttributeForIA2(id, &id);
2663 result.push_back(L"id:" + id);
2664 }
2665
2666 // Expose src attribute.
2667 base::string16 src;
2668 if (GetData().role == ui::AX_ROLE_IMAGE &&
2669 GetData().GetHtmlAttribute("src", &src)) {
2670 SanitizeStringAttributeForIA2(src, &src);
2671 result.push_back(L"src:" + src);
2672 }
2673
2674 // Expose input-text type attribute.
2675 base::string16 type;
2676 base::string16 html_tag = GetString16Attribute(ui::AX_ATTR_HTML_TAG);
2677 if (IsSimpleTextControl() && html_tag == L"input" &&
2678 GetData().GetHtmlAttribute("type", &type)) {
2679 SanitizeStringAttributeForIA2(type, &type);
2680 result.push_back(L"text-input-type:" + type);
2681 }
2682
2683 return result;
2684 }
2685
2429 bool AXPlatformNodeWin::ShouldNodeHaveReadonlyState( 2686 bool AXPlatformNodeWin::ShouldNodeHaveReadonlyState(
2430 const AXNodeData& data) const { 2687 const AXNodeData& data) const {
2431 if (data.GetBoolAttribute(ui::AX_ATTR_ARIA_READONLY)) 2688 if (data.GetBoolAttribute(ui::AX_ATTR_ARIA_READONLY))
2432 return true; 2689 return true;
2433 2690
2434 if (!data.HasState(ui::AX_STATE_READ_ONLY)) 2691 if (!data.HasState(ui::AX_STATE_READ_ONLY))
2435 return false; 2692 return false;
2436 2693
2437 switch (data.role) { 2694 switch (data.role) {
2438 case ui::AX_ROLE_ARTICLE: 2695 case ui::AX_ROLE_ARTICLE:
(...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after
2760 if (container && container->GetData().role == ui::AX_ROLE_GROUP) 3017 if (container && container->GetData().role == ui::AX_ROLE_GROUP)
2761 container = FromNativeViewAccessible(container->GetParent()); 3018 container = FromNativeViewAccessible(container->GetParent());
2762 3019
2763 if (!container) 3020 if (!container)
2764 return false; 3021 return false;
2765 3022
2766 return container->GetData().role == ui::AX_ROLE_TREE_GRID; 3023 return container->GetData().role == ui::AX_ROLE_TREE_GRID;
2767 } 3024 }
2768 3025
2769 } // namespace ui 3026 } // namespace ui
OLDNEW
« no previous file with comments | « ui/accessibility/platform/ax_platform_node_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698