| 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 |