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 |