Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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(ui::AXStringAttribute attribute, | |
| 223 const char* ia2_attr) { | |
| 224 base::string16 value; | |
| 225 if (GetString16Attribute(attribute, &value)) { | |
| 226 SanitizeStringAttributeForIA2(value, &value); | |
| 227 ia2_attributes_.push_back(base::ASCIIToUTF16(ia2_attr) + L":" + value); | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 void AXPlatformNodeWin::BoolAttributeToIA2(ui::AXBoolAttribute attribute, | |
| 232 const char* ia2_attr) { | |
| 233 bool value; | |
| 234 if (GetBoolAttribute(attribute, &value)) { | |
| 235 ia2_attributes_.push_back((base::ASCIIToUTF16(ia2_attr) + L":") + | |
| 236 (value ? L"true" : L"false")); | |
| 237 } | |
| 238 } | |
| 239 | |
| 240 void AXPlatformNodeWin::IntAttributeToIA2(ui::AXIntAttribute attribute, | |
| 241 const char* ia2_attr) { | |
| 242 int value; | |
| 243 if (GetIntAttribute(attribute, &value)) { | |
| 244 ia2_attributes_.push_back(base::ASCIIToUTF16(ia2_attr) + L":" + | |
| 245 base::IntToString16(value)); | |
| 246 } | |
| 247 } | |
| 248 | |
| 207 // | 249 // |
| 208 // AXPlatformNodeBase implementation. | 250 // AXPlatformNodeBase implementation. |
| 209 // | 251 // |
| 210 | 252 |
| 211 void AXPlatformNodeWin::Dispose() { | 253 void AXPlatformNodeWin::Dispose() { |
| 212 Release(); | 254 Release(); |
| 213 } | 255 } |
| 214 | 256 |
| 215 void AXPlatformNodeWin::Destroy() { | 257 void AXPlatformNodeWin::Destroy() { |
| 216 RemoveAlertTarget(); | 258 RemoveAlertTarget(); |
| (...skipping 2202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2419 case ui::AX_ROLE_ABBR: | 2461 case ui::AX_ROLE_ABBR: |
| 2420 case ui::AX_ROLE_TIME: | 2462 case ui::AX_ROLE_TIME: |
| 2421 ia2_role = IA2_ROLE_TEXT_FRAME; | 2463 ia2_role = IA2_ROLE_TEXT_FRAME; |
| 2422 break; | 2464 break; |
| 2423 default: | 2465 default: |
| 2424 break; | 2466 break; |
| 2425 } | 2467 } |
| 2426 return ia2_role; | 2468 return ia2_role; |
| 2427 } | 2469 } |
| 2428 | 2470 |
| 2471 std::vector<base::string16> AXPlatformNodeWin::IA2Attributes() { | |
| 2472 // maybe use a cache? | |
| 2473 ia2_attributes_.clear(); | |
|
dmazzoni
2017/07/17 08:27:18
It doesn't seem to make sense to store ia2_attribu
dougt
2017/07/17 19:28:27
Done.
| |
| 2474 | |
| 2475 // Expose some HTLM and ARIA attributes in the IAccessible2 attributes string. | |
| 2476 // "display", "tag", and "xml-roles" have somewhat unusual names for | |
| 2477 // historical reasons. Aside from that virtually every ARIA attribute | |
| 2478 // is exposed in a really straightforward way, i.e. "aria-foo" is exposed | |
| 2479 // as "foo". | |
| 2480 StringAttributeToIA2(ui::AX_ATTR_DISPLAY, "display"); | |
| 2481 StringAttributeToIA2(ui::AX_ATTR_HTML_TAG, "tag"); | |
| 2482 StringAttributeToIA2(ui::AX_ATTR_ROLE, "xml-roles"); | |
| 2483 StringAttributeToIA2(ui::AX_ATTR_PLACEHOLDER, "placeholder"); | |
| 2484 | |
| 2485 StringAttributeToIA2(ui::AX_ATTR_AUTO_COMPLETE, "autocomplete"); | |
| 2486 StringAttributeToIA2(ui::AX_ATTR_ROLE_DESCRIPTION, "roledescription"); | |
| 2487 StringAttributeToIA2(ui::AX_ATTR_KEY_SHORTCUTS, "keyshortcuts"); | |
| 2488 | |
| 2489 IntAttributeToIA2(ui::AX_ATTR_HIERARCHICAL_LEVEL, "level"); | |
| 2490 IntAttributeToIA2(ui::AX_ATTR_SET_SIZE, "setsize"); | |
| 2491 IntAttributeToIA2(ui::AX_ATTR_POS_IN_SET, "posinset"); | |
| 2492 | |
| 2493 if (HasIntAttribute(ui::AX_ATTR_CHECKED_STATE)) | |
| 2494 ia2_attributes_.push_back(L"checkable:true"); | |
| 2495 | |
| 2496 // Expose live region attributes. | |
| 2497 StringAttributeToIA2(ui::AX_ATTR_LIVE_STATUS, "live"); | |
| 2498 StringAttributeToIA2(ui::AX_ATTR_LIVE_RELEVANT, "relevant"); | |
| 2499 BoolAttributeToIA2(ui::AX_ATTR_LIVE_ATOMIC, "atomic"); | |
| 2500 BoolAttributeToIA2(ui::AX_ATTR_LIVE_BUSY, "busy"); | |
| 2501 | |
| 2502 // Expose container live region attributes. | |
| 2503 StringAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_STATUS, "container-live"); | |
| 2504 StringAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_RELEVANT, | |
| 2505 "container-relevant"); | |
| 2506 BoolAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_ATOMIC, "container-atomic"); | |
| 2507 BoolAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_BUSY, "container-busy"); | |
| 2508 | |
| 2509 // Expose the non-standard explicit-name IA2 attribute. | |
| 2510 int name_from; | |
| 2511 if (GetIntAttribute(ui::AX_ATTR_NAME_FROM, &name_from) && | |
| 2512 name_from != ui::AX_NAME_FROM_CONTENTS) { | |
| 2513 ia2_attributes_.push_back(L"explicit-name:true"); | |
| 2514 } | |
| 2515 | |
| 2516 // Expose the aria-current attribute. | |
| 2517 int32_t aria_current_state; | |
| 2518 if (GetIntAttribute(ui::AX_ATTR_ARIA_CURRENT_STATE, &aria_current_state)) { | |
| 2519 switch (static_cast<ui::AXAriaCurrentState>(aria_current_state)) { | |
| 2520 case ui::AX_ARIA_CURRENT_STATE_NONE: | |
| 2521 break; | |
| 2522 case ui::AX_ARIA_CURRENT_STATE_FALSE: | |
| 2523 ia2_attributes_.push_back(L"current:false"); | |
| 2524 break; | |
| 2525 case ui::AX_ARIA_CURRENT_STATE_TRUE: | |
| 2526 ia2_attributes_.push_back(L"current:true"); | |
| 2527 break; | |
| 2528 case ui::AX_ARIA_CURRENT_STATE_PAGE: | |
| 2529 ia2_attributes_.push_back(L"current:page"); | |
| 2530 break; | |
| 2531 case ui::AX_ARIA_CURRENT_STATE_STEP: | |
| 2532 ia2_attributes_.push_back(L"current:step"); | |
| 2533 break; | |
| 2534 case ui::AX_ARIA_CURRENT_STATE_LOCATION: | |
| 2535 ia2_attributes_.push_back(L"current:location"); | |
| 2536 break; | |
| 2537 case ui::AX_ARIA_CURRENT_STATE_DATE: | |
| 2538 ia2_attributes_.push_back(L"current:date"); | |
| 2539 break; | |
| 2540 case ui::AX_ARIA_CURRENT_STATE_TIME: | |
| 2541 ia2_attributes_.push_back(L"current:time"); | |
| 2542 break; | |
| 2543 } | |
| 2544 } | |
| 2545 | |
| 2546 // Expose table cell index. | |
| 2547 if (ui::IsCellOrTableHeaderRole(GetData().role)) { | |
| 2548 AXPlatformNodeBase* table = FromNativeViewAccessible(GetParent()); | |
| 2549 | |
| 2550 while (table && !ui::IsTableLikeRole(table->GetData().role)) | |
| 2551 table = FromNativeViewAccessible(table->GetParent()); | |
| 2552 | |
| 2553 if (table) { | |
| 2554 const std::vector<int32_t>& unique_cell_ids = | |
| 2555 table->GetIntListAttribute(ui::AX_ATTR_UNIQUE_CELL_IDS); | |
| 2556 for (size_t i = 0; i < unique_cell_ids.size(); ++i) { | |
| 2557 if (unique_cell_ids[i] == GetData().id) { | |
| 2558 ia2_attributes_.push_back(base::string16(L"table-cell-index:") + | |
| 2559 base::IntToString16(static_cast<int>(i))); | |
| 2560 } | |
| 2561 } | |
| 2562 } | |
| 2563 } | |
| 2564 | |
| 2565 // Expose aria-colcount and aria-rowcount in a table, grid or treegrid. | |
| 2566 if (ui::IsTableLikeRole(GetData().role)) { | |
| 2567 IntAttributeToIA2(ui::AX_ATTR_ARIA_COLUMN_COUNT, "colcount"); | |
| 2568 IntAttributeToIA2(ui::AX_ATTR_ARIA_ROW_COUNT, "rowcount"); | |
| 2569 } | |
| 2570 | |
| 2571 // Expose aria-colindex and aria-rowindex in a cell or row. | |
| 2572 if (ui::IsCellOrTableHeaderRole(GetData().role) || | |
| 2573 GetData().role == ui::AX_ROLE_ROW) { | |
| 2574 if (GetData().role != ui::AX_ROLE_ROW) | |
| 2575 IntAttributeToIA2(ui::AX_ATTR_ARIA_CELL_COLUMN_INDEX, "colindex"); | |
| 2576 IntAttributeToIA2(ui::AX_ATTR_ARIA_CELL_ROW_INDEX, "rowindex"); | |
| 2577 } | |
| 2578 | |
| 2579 // Expose row or column header sort direction. | |
| 2580 int32_t sort_direction; | |
| 2581 if ((MSAARole() == ROLE_SYSTEM_COLUMNHEADER || | |
| 2582 MSAARole() == ROLE_SYSTEM_ROWHEADER) && | |
| 2583 GetIntAttribute(ui::AX_ATTR_SORT_DIRECTION, &sort_direction)) { | |
| 2584 switch (static_cast<ui::AXSortDirection>(sort_direction)) { | |
| 2585 case ui::AX_SORT_DIRECTION_NONE: | |
| 2586 break; | |
| 2587 case ui::AX_SORT_DIRECTION_UNSORTED: | |
| 2588 ia2_attributes_.push_back(L"sort:none"); | |
| 2589 break; | |
| 2590 case ui::AX_SORT_DIRECTION_ASCENDING: | |
| 2591 ia2_attributes_.push_back(L"sort:ascending"); | |
| 2592 break; | |
| 2593 case ui::AX_SORT_DIRECTION_DESCENDING: | |
| 2594 ia2_attributes_.push_back(L"sort:descending"); | |
| 2595 break; | |
| 2596 case ui::AX_SORT_DIRECTION_OTHER: | |
| 2597 ia2_attributes_.push_back(L"sort:other"); | |
| 2598 break; | |
| 2599 } | |
| 2600 } | |
| 2601 | |
| 2602 if (ui::IsCellOrTableHeaderRole(GetData().role)) { | |
| 2603 // Expose colspan attribute. | |
| 2604 base::string16 colspan; | |
| 2605 if (GetData().GetHtmlAttribute("aria-colspan", &colspan)) { | |
| 2606 SanitizeStringAttributeForIA2(colspan, &colspan); | |
| 2607 ia2_attributes_.push_back(L"colspan:" + colspan); | |
| 2608 } | |
| 2609 // Expose rowspan attribute. | |
| 2610 base::string16 rowspan; | |
| 2611 if (GetData().GetHtmlAttribute("aria-rowspan", &rowspan)) { | |
| 2612 SanitizeStringAttributeForIA2(rowspan, &rowspan); | |
| 2613 ia2_attributes_.push_back(L"rowspan:" + rowspan); | |
| 2614 } | |
| 2615 } | |
| 2616 | |
| 2617 // Expose slider value. | |
| 2618 if (IsRangeValueSupported()) { | |
| 2619 base::string16 value = GetRangeValueText(); | |
| 2620 SanitizeStringAttributeForIA2(value, &value); | |
| 2621 ia2_attributes_.push_back(L"valuetext:" + value); | |
| 2622 } | |
| 2623 | |
| 2624 // Expose dropeffect attribute. | |
| 2625 base::string16 drop_effect; | |
| 2626 if (GetData().GetHtmlAttribute("aria-dropeffect", &drop_effect)) { | |
| 2627 SanitizeStringAttributeForIA2(drop_effect, &drop_effect); | |
| 2628 ia2_attributes_.push_back(L"dropeffect:" + drop_effect); | |
| 2629 } | |
| 2630 | |
| 2631 // Expose grabbed attribute. | |
| 2632 base::string16 grabbed; | |
| 2633 if (GetData().GetHtmlAttribute("aria-grabbed", &grabbed)) { | |
| 2634 SanitizeStringAttributeForIA2(grabbed, &grabbed); | |
| 2635 ia2_attributes_.push_back(L"grabbed:" + grabbed); | |
| 2636 } | |
| 2637 | |
| 2638 // Expose class attribute. | |
| 2639 base::string16 class_attr; | |
| 2640 if (GetData().GetHtmlAttribute("class", &class_attr)) { | |
| 2641 SanitizeStringAttributeForIA2(class_attr, &class_attr); | |
| 2642 ia2_attributes_.push_back(L"class:" + class_attr); | |
| 2643 } | |
| 2644 | |
| 2645 // Expose datetime attribute. | |
| 2646 base::string16 datetime; | |
| 2647 if (GetData().role == ui::AX_ROLE_TIME && | |
| 2648 GetData().GetHtmlAttribute("datetime", &datetime)) { | |
| 2649 SanitizeStringAttributeForIA2(datetime, &datetime); | |
| 2650 ia2_attributes_.push_back(L"datetime:" + datetime); | |
| 2651 } | |
| 2652 | |
| 2653 // Expose id attribute. | |
| 2654 base::string16 id; | |
| 2655 if (GetData().GetHtmlAttribute("id", &id)) { | |
| 2656 SanitizeStringAttributeForIA2(id, &id); | |
| 2657 ia2_attributes_.push_back(L"id:" + id); | |
| 2658 } | |
| 2659 | |
| 2660 // Expose src attribute. | |
| 2661 base::string16 src; | |
| 2662 if (GetData().role == ui::AX_ROLE_IMAGE && | |
| 2663 GetData().GetHtmlAttribute("src", &src)) { | |
| 2664 SanitizeStringAttributeForIA2(src, &src); | |
| 2665 ia2_attributes_.push_back(L"src:" + src); | |
| 2666 } | |
| 2667 | |
| 2668 // Expose input-text type attribute. | |
| 2669 base::string16 type; | |
| 2670 base::string16 html_tag = GetString16Attribute(ui::AX_ATTR_HTML_TAG); | |
| 2671 if (IsSimpleTextControl() && html_tag == L"input" && | |
| 2672 GetData().GetHtmlAttribute("type", &type)) { | |
| 2673 SanitizeStringAttributeForIA2(type, &type); | |
| 2674 ia2_attributes_.push_back(L"text-input-type:" + type); | |
| 2675 } | |
| 2676 | |
| 2677 return ia2_attributes_; | |
| 2678 } | |
| 2679 | |
| 2429 bool AXPlatformNodeWin::ShouldNodeHaveReadonlyState( | 2680 bool AXPlatformNodeWin::ShouldNodeHaveReadonlyState( |
| 2430 const AXNodeData& data) const { | 2681 const AXNodeData& data) const { |
| 2431 if (data.GetBoolAttribute(ui::AX_ATTR_ARIA_READONLY)) | 2682 if (data.GetBoolAttribute(ui::AX_ATTR_ARIA_READONLY)) |
| 2432 return true; | 2683 return true; |
| 2433 | 2684 |
| 2434 if (!data.HasState(ui::AX_STATE_READ_ONLY)) | 2685 if (!data.HasState(ui::AX_STATE_READ_ONLY)) |
| 2435 return false; | 2686 return false; |
| 2436 | 2687 |
| 2437 switch (data.role) { | 2688 switch (data.role) { |
| 2438 case ui::AX_ROLE_ARTICLE: | 2689 case ui::AX_ROLE_ARTICLE: |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2760 if (container && container->GetData().role == ui::AX_ROLE_GROUP) | 3011 if (container && container->GetData().role == ui::AX_ROLE_GROUP) |
| 2761 container = FromNativeViewAccessible(container->GetParent()); | 3012 container = FromNativeViewAccessible(container->GetParent()); |
| 2762 | 3013 |
| 2763 if (!container) | 3014 if (!container) |
| 2764 return false; | 3015 return false; |
| 2765 | 3016 |
| 2766 return container->GetData().role == ui::AX_ROLE_TREE_GRID; | 3017 return container->GetData().role == ui::AX_ROLE_TREE_GRID; |
| 2767 } | 3018 } |
| 2768 | 3019 |
| 2769 } // namespace ui | 3020 } // namespace ui |
| OLD | NEW |