OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "chrome/browser/accessibility/browser_accessibility_win.h" | 5 #include "chrome/browser/accessibility/browser_accessibility_win.h" |
6 | 6 |
7 #include "base/string_number_conversions.h" | 7 #include "base/string_number_conversions.h" |
8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
9 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
10 #include "chrome/browser/accessibility/browser_accessibility_manager_win.h" | 10 #include "chrome/browser/accessibility/browser_accessibility_manager_win.h" |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
47 | 47 |
48 BrowserAccessibilityWin* target = GetTargetFromChildID(var_id); | 48 BrowserAccessibilityWin* target = GetTargetFromChildID(var_id); |
49 if (!target) | 49 if (!target) |
50 return E_INVALIDARG; | 50 return E_INVALIDARG; |
51 | 51 |
52 manager_->DoDefaultAction(*target); | 52 manager_->DoDefaultAction(*target); |
53 return S_OK; | 53 return S_OK; |
54 } | 54 } |
55 | 55 |
56 STDMETHODIMP BrowserAccessibilityWin::accHitTest(LONG x_left, LONG y_top, | 56 STDMETHODIMP BrowserAccessibilityWin::accHitTest(LONG x_left, LONG y_top, |
57 VARIANT* child) { | 57 VARIANT* child) { |
58 if (!instance_active_) | 58 if (!instance_active_) |
59 return E_FAIL; | 59 return E_FAIL; |
60 | 60 |
61 if (!child) | 61 if (!child) |
62 return E_INVALIDARG; | 62 return E_INVALIDARG; |
63 | 63 |
64 return E_NOTIMPL; | 64 return E_NOTIMPL; |
65 } | 65 } |
66 | 66 |
67 STDMETHODIMP BrowserAccessibilityWin::accLocation(LONG* x_left, LONG* y_top, | 67 STDMETHODIMP BrowserAccessibilityWin::accLocation(LONG* x_left, LONG* y_top, |
68 LONG* width, LONG* height, | 68 LONG* width, LONG* height, |
69 VARIANT var_id) { | 69 VARIANT var_id) { |
70 if (!instance_active_) | 70 if (!instance_active_) |
71 return E_FAIL; | 71 return E_FAIL; |
72 | 72 |
73 if (!x_left || !y_top || !width || !height) | 73 if (!x_left || !y_top || !width || !height) |
74 return E_INVALIDARG; | 74 return E_INVALIDARG; |
75 | 75 |
76 BrowserAccessibilityWin* target = GetTargetFromChildID(var_id); | 76 BrowserAccessibilityWin* target = GetTargetFromChildID(var_id); |
77 if (!target) | 77 if (!target) |
78 return E_INVALIDARG; | 78 return E_INVALIDARG; |
79 | 79 |
(...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
527 | 527 |
528 if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { | 528 if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { |
529 *n_characters = value_.length(); | 529 *n_characters = value_.length(); |
530 } else { | 530 } else { |
531 *n_characters = name_.length(); | 531 *n_characters = name_.length(); |
532 } | 532 } |
533 | 533 |
534 return S_OK; | 534 return S_OK; |
535 } | 535 } |
536 | 536 |
537 STDMETHODIMP BrowserAccessibilityWin::get_text( | |
538 LONG start_offset, LONG end_offset, BSTR* text) { | |
539 if (!instance_active_) | |
540 return E_FAIL; | |
541 | |
542 if (!text) | |
543 return E_INVALIDARG; | |
544 | |
545 string16 text_str; | |
546 if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { | |
547 text_str = value_; | |
548 } else { | |
549 text_str = name_; | |
550 } | |
551 | |
552 // The spec allows the arguments to be reversed. | |
553 if (start_offset > end_offset) { | |
554 LONG tmp = start_offset; | |
555 start_offset = end_offset; | |
556 end_offset = tmp; | |
557 } | |
558 | |
559 // The spec does not allow the start or end offsets to be out or range; | |
560 // we must return an error if so. | |
561 LONG len = text_str.length(); | |
562 if (start_offset < 0) | |
563 return E_INVALIDARG; | |
564 if (end_offset > len) | |
565 return E_INVALIDARG; | |
566 | |
567 string16 substr = text_str.substr(start_offset, end_offset - start_offset); | |
568 if (substr.empty()) | |
569 return S_FALSE; | |
570 | |
571 *text = SysAllocString(substr.c_str()); | |
572 DCHECK(*text); | |
573 return S_OK; | |
574 } | |
575 | |
576 STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) { | 537 STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) { |
577 if (!instance_active_) | 538 if (!instance_active_) |
578 return E_FAIL; | 539 return E_FAIL; |
579 | 540 |
580 if (!offset) | 541 if (!offset) |
581 return E_INVALIDARG; | 542 return E_INVALIDARG; |
582 | 543 |
583 if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { | 544 if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { |
584 int sel_start = 0; | 545 int sel_start = 0; |
585 if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start)) { | 546 if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start)) { |
586 *offset = sel_start; | 547 *offset = sel_start; |
587 } else { | 548 } else { |
588 *offset = 0; | 549 *offset = 0; |
589 } | 550 } |
590 } else { | 551 } else { |
591 *offset = 0; | 552 *offset = 0; |
592 } | 553 } |
593 | 554 |
594 return S_OK; | 555 return S_OK; |
595 } | 556 } |
596 | 557 |
597 STDMETHODIMP BrowserAccessibilityWin::get_nSelections(LONG* n_selections) { | 558 STDMETHODIMP BrowserAccessibilityWin::get_nSelections(LONG* n_selections) { |
598 if (!instance_active_) | 559 if (!instance_active_) |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
639 *end_offset = 0; | 600 *end_offset = 0; |
640 } | 601 } |
641 } else { | 602 } else { |
642 *start_offset = 0; | 603 *start_offset = 0; |
643 *end_offset = 0; | 604 *end_offset = 0; |
644 } | 605 } |
645 | 606 |
646 return S_OK; | 607 return S_OK; |
647 } | 608 } |
648 | 609 |
| 610 STDMETHODIMP BrowserAccessibilityWin::get_text( |
| 611 LONG start_offset, LONG end_offset, BSTR* text) { |
| 612 if (!instance_active_) |
| 613 return E_FAIL; |
| 614 |
| 615 if (!text) |
| 616 return E_INVALIDARG; |
| 617 |
| 618 const string16& text_str = TextForIAccessibleText(); |
| 619 |
| 620 // The spec allows the arguments to be reversed. |
| 621 if (start_offset > end_offset) { |
| 622 LONG tmp = start_offset; |
| 623 start_offset = end_offset; |
| 624 end_offset = tmp; |
| 625 } |
| 626 |
| 627 // The spec does not allow the start or end offsets to be out or range; |
| 628 // we must return an error if so. |
| 629 LONG len = text_str.length(); |
| 630 if (start_offset < 0) |
| 631 return E_INVALIDARG; |
| 632 if (end_offset > len) |
| 633 return E_INVALIDARG; |
| 634 |
| 635 string16 substr = text_str.substr(start_offset, end_offset - start_offset); |
| 636 if (substr.empty()) |
| 637 return S_FALSE; |
| 638 |
| 639 *text = SysAllocString(substr.c_str()); |
| 640 DCHECK(*text); |
| 641 return S_OK; |
| 642 } |
| 643 |
| 644 STDMETHODIMP BrowserAccessibilityWin::get_textAtOffset( |
| 645 LONG offset, |
| 646 enum IA2TextBoundaryType boundary_type, |
| 647 LONG* start_offset, LONG* end_offset, |
| 648 BSTR* text) { |
| 649 if (!instance_active_) |
| 650 return E_FAIL; |
| 651 |
| 652 if (!start_offset || !end_offset || !text) |
| 653 return E_INVALIDARG; |
| 654 |
| 655 // The IAccessible2 spec says we don't have to implement the "sentence" |
| 656 // boundary type, we can just let the screenreader handle it. |
| 657 if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) { |
| 658 *start_offset = 0; |
| 659 *end_offset = 0; |
| 660 *text = NULL; |
| 661 return S_FALSE; |
| 662 } |
| 663 |
| 664 const string16& text_str = TextForIAccessibleText(); |
| 665 |
| 666 *start_offset = FindBoundary(text_str, boundary_type, offset, -1); |
| 667 *end_offset = FindBoundary(text_str, boundary_type, offset, 1); |
| 668 return get_text(*start_offset, *end_offset, text); |
| 669 } |
| 670 |
| 671 STDMETHODIMP BrowserAccessibilityWin::get_textBeforeOffset( |
| 672 LONG offset, |
| 673 enum IA2TextBoundaryType boundary_type, |
| 674 LONG* start_offset, LONG* end_offset, |
| 675 BSTR* text) { |
| 676 if (!instance_active_) |
| 677 return E_FAIL; |
| 678 |
| 679 if (!start_offset || !end_offset || !text) |
| 680 return E_INVALIDARG; |
| 681 |
| 682 // The IAccessible2 spec says we don't have to implement the "sentence" |
| 683 // boundary type, we can just let the screenreader handle it. |
| 684 if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) { |
| 685 *start_offset = 0; |
| 686 *end_offset = 0; |
| 687 *text = NULL; |
| 688 return S_FALSE; |
| 689 } |
| 690 |
| 691 const string16& text_str = TextForIAccessibleText(); |
| 692 |
| 693 *start_offset = FindBoundary(text_str, boundary_type, offset, -1); |
| 694 *end_offset = offset; |
| 695 return get_text(*start_offset, *end_offset, text); |
| 696 } |
| 697 |
| 698 STDMETHODIMP BrowserAccessibilityWin::get_textAfterOffset( |
| 699 LONG offset, |
| 700 enum IA2TextBoundaryType boundary_type, |
| 701 LONG* start_offset, LONG* end_offset, |
| 702 BSTR* text) { |
| 703 if (!instance_active_) |
| 704 return E_FAIL; |
| 705 |
| 706 if (!start_offset || !end_offset || !text) |
| 707 return E_INVALIDARG; |
| 708 |
| 709 // The IAccessible2 spec says we don't have to implement the "sentence" |
| 710 // boundary type, we can just let the screenreader handle it. |
| 711 if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) { |
| 712 *start_offset = 0; |
| 713 *end_offset = 0; |
| 714 *text = NULL; |
| 715 return S_FALSE; |
| 716 } |
| 717 |
| 718 const string16& text_str = TextForIAccessibleText(); |
| 719 |
| 720 *start_offset = offset; |
| 721 *end_offset = FindBoundary(text_str, boundary_type, offset, 1); |
| 722 return get_text(*start_offset, *end_offset, text); |
| 723 } |
| 724 |
649 // | 725 // |
650 // ISimpleDOMDocument methods. | 726 // ISimpleDOMDocument methods. |
651 // | 727 // |
652 | 728 |
653 STDMETHODIMP BrowserAccessibilityWin::get_URL(BSTR* url) { | 729 STDMETHODIMP BrowserAccessibilityWin::get_URL(BSTR* url) { |
654 if (!instance_active_) | 730 if (!instance_active_) |
655 return E_FAIL; | 731 return E_FAIL; |
656 | 732 |
657 if (!url) | 733 if (!url) |
658 return E_INVALIDARG; | 734 return E_INVALIDARG; |
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1122 if (!base::StringToInt(value_str, value_int)) | 1198 if (!base::StringToInt(value_str, value_int)) |
1123 return false; | 1199 return false; |
1124 | 1200 |
1125 return true; | 1201 return true; |
1126 } | 1202 } |
1127 | 1203 |
1128 string16 BrowserAccessibilityWin::Escape(string16 str) { | 1204 string16 BrowserAccessibilityWin::Escape(string16 str) { |
1129 return EscapeQueryParamValueUTF8(str, false); | 1205 return EscapeQueryParamValueUTF8(str, false); |
1130 } | 1206 } |
1131 | 1207 |
| 1208 const string16& BrowserAccessibilityWin::TextForIAccessibleText() { |
| 1209 if (role_ == WebAccessibility::ROLE_TEXT_FIELD) { |
| 1210 return value_; |
| 1211 } else { |
| 1212 return name_; |
| 1213 } |
| 1214 } |
| 1215 |
| 1216 LONG BrowserAccessibilityWin::FindBoundary( |
| 1217 const string16& text, |
| 1218 IA2TextBoundaryType boundary, |
| 1219 LONG start_offset, |
| 1220 LONG direction) { |
| 1221 LONG text_size = static_cast<LONG>(text.size()); |
| 1222 DCHECK(start_offset >= 0 && start_offset <= text_size); |
| 1223 DCHECK(direction == 1 || direction == -1); |
| 1224 |
| 1225 if (boundary == IA2_TEXT_BOUNDARY_CHAR) { |
| 1226 if (direction == 1 && start_offset < text_size) |
| 1227 return start_offset + 1; |
| 1228 else |
| 1229 return start_offset; |
| 1230 } |
| 1231 |
| 1232 LONG result = start_offset; |
| 1233 for (;;) { |
| 1234 LONG pos; |
| 1235 if (direction == 1) { |
| 1236 if (result >= text_size) |
| 1237 return text_size; |
| 1238 pos = result; |
| 1239 } else { |
| 1240 if (result <= 0) |
| 1241 return 0; |
| 1242 pos = result - 1; |
| 1243 } |
| 1244 |
| 1245 switch (boundary) { |
| 1246 case IA2_TEXT_BOUNDARY_WORD: |
| 1247 if (IsWhitespace(text[pos])) |
| 1248 return result; |
| 1249 break; |
| 1250 case IA2_TEXT_BOUNDARY_LINE: |
| 1251 case IA2_TEXT_BOUNDARY_PARAGRAPH: |
| 1252 if (text[pos] == '\n') |
| 1253 return result; |
| 1254 case IA2_TEXT_BOUNDARY_SENTENCE: |
| 1255 // Note that we don't actually have to implement sentence support; |
| 1256 // currently IAccessibleText functions return S_FALSE so that |
| 1257 // screenreaders will handle it on their own. |
| 1258 if ((text[pos] == '.' || text[pos] == '!' || text[pos] == '?') && |
| 1259 (pos == text_size - 1 || IsWhitespace(text[pos + 1]))) { |
| 1260 return result; |
| 1261 } |
| 1262 case IA2_TEXT_BOUNDARY_ALL: |
| 1263 default: |
| 1264 break; |
| 1265 } |
| 1266 |
| 1267 if (direction > 0) { |
| 1268 result++; |
| 1269 } else if (direction < 0) { |
| 1270 result--; |
| 1271 } else { |
| 1272 NOTREACHED(); |
| 1273 return result; |
| 1274 } |
| 1275 } |
| 1276 } |
| 1277 |
1132 void BrowserAccessibilityWin::InitRoleAndState() { | 1278 void BrowserAccessibilityWin::InitRoleAndState() { |
1133 ia_state_ = 0; | 1279 ia_state_ = 0; |
1134 ia2_state_ = IA2_STATE_OPAQUE; | 1280 ia2_state_ = IA2_STATE_OPAQUE; |
1135 | 1281 |
1136 if ((state_ >> WebAccessibility::STATE_CHECKED) & 1) | 1282 if ((state_ >> WebAccessibility::STATE_CHECKED) & 1) |
1137 ia_state_ |= STATE_SYSTEM_CHECKED; | 1283 ia_state_ |= STATE_SYSTEM_CHECKED; |
1138 if ((state_ >> WebAccessibility::STATE_COLLAPSED) & 1) | 1284 if ((state_ >> WebAccessibility::STATE_COLLAPSED) & 1) |
1139 ia_state_|= STATE_SYSTEM_COLLAPSED; | 1285 ia_state_|= STATE_SYSTEM_COLLAPSED; |
1140 if ((state_ >> WebAccessibility::STATE_EXPANDED) & 1) | 1286 if ((state_ >> WebAccessibility::STATE_EXPANDED) & 1) |
1141 ia_state_|= STATE_SYSTEM_EXPANDED; | 1287 ia_state_|= STATE_SYSTEM_EXPANDED; |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1420 } | 1566 } |
1421 | 1567 |
1422 // The role should always be set. | 1568 // The role should always be set. |
1423 DCHECK(!role_name_.empty() || ia_role_); | 1569 DCHECK(!role_name_.empty() || ia_role_); |
1424 | 1570 |
1425 // If we didn't explicitly set the IAccessible2 role, make it the same | 1571 // If we didn't explicitly set the IAccessible2 role, make it the same |
1426 // as the MSAA role. | 1572 // as the MSAA role. |
1427 if (!ia2_role_) | 1573 if (!ia2_role_) |
1428 ia2_role_ = ia_role_; | 1574 ia2_role_ = ia_role_; |
1429 } | 1575 } |
OLD | NEW |