Chromium Code Reviews| 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/browser_accessibility_win.h" | 5 #include "chrome/browser/browser_accessibility_win.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/string_number_conversions.h" | |
| 8 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 9 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
| 10 #include "chrome/browser/browser_accessibility_manager_win.h" | 11 #include "chrome/browser/browser_accessibility_manager_win.h" |
| 11 #include "net/base/escape.h" | 12 #include "net/base/escape.h" |
| 12 | 13 |
| 13 using webkit_glue::WebAccessibility; | 14 using webkit_glue::WebAccessibility; |
| 14 | 15 |
| 15 BrowserAccessibility::BrowserAccessibility() | 16 BrowserAccessibility::BrowserAccessibility() |
| 16 : manager_(NULL), | 17 : manager_(NULL), |
| 17 parent_(NULL), | 18 parent_(NULL), |
| 18 child_id_(-1), | 19 child_id_(-1), |
| 19 index_in_parent_(-1), | 20 index_in_parent_(-1), |
| 20 renderer_id_(-1), | 21 renderer_id_(-1), |
| 21 instance_active_(false) { | 22 instance_active_(false) { |
| 22 } | 23 } |
| 23 | 24 |
| 24 BrowserAccessibility::~BrowserAccessibility() { | 25 BrowserAccessibility::~BrowserAccessibility() { |
| 25 InactivateTree(); | 26 InactivateTree(); |
| 26 } | 27 } |
| 27 | 28 |
| 28 void BrowserAccessibility::Initialize( | 29 void BrowserAccessibility::Initialize( |
| 29 BrowserAccessibilityManager* manager, | 30 BrowserAccessibilityManager* manager, |
| 30 BrowserAccessibility* parent, | 31 BrowserAccessibility* parent, |
| 31 LONG child_id, | 32 LONG child_id, |
| 32 LONG index_in_parent, | 33 LONG index_in_parent, |
| 33 const webkit_glue::WebAccessibility& src) { | 34 const webkit_glue::WebAccessibility& src) { |
| 34 DCHECK_EQ(children_.size(), 0U); | |
| 35 | |
| 36 manager_ = manager; | 35 manager_ = manager; |
| 37 parent_ = parent; | 36 parent_ = parent; |
| 38 child_id_ = child_id; | 37 child_id_ = child_id; |
| 39 index_in_parent_ = index_in_parent; | 38 index_in_parent_ = index_in_parent; |
| 40 | 39 |
| 41 renderer_id_ = src.id; | 40 renderer_id_ = src.id; |
| 42 name_ = src.name; | 41 name_ = src.name; |
| 43 value_ = src.value; | 42 value_ = src.value; |
| 44 attributes_ = src.attributes; | 43 attributes_ = src.attributes; |
| 45 html_attributes_ = src.html_attributes; | 44 html_attributes_ = src.html_attributes; |
| 46 location_ = src.location; | 45 location_ = src.location; |
| 46 src_role_ = src.role; | |
| 47 InitRoleAndState(src.role, src.state); | 47 InitRoleAndState(src.role, src.state); |
| 48 | 48 |
| 49 // Expose headings levels to NVDA with the "level" object attribute. | 49 // Expose headings levels to NVDA with the "level" object attribute. |
| 50 if (src.role == WebAccessibility::ROLE_HEADING && role_name_.size() == 2 && | 50 if (src.role == WebAccessibility::ROLE_HEADING && role_name_.size() == 2 && |
| 51 IsAsciiDigit(role_name_[1])) { | 51 IsAsciiDigit(role_name_[1])) { |
| 52 html_attributes_.push_back(std::make_pair(L"level", role_name_.substr(1))); | 52 html_attributes_.push_back(std::make_pair(L"level", role_name_.substr(1))); |
| 53 } | 53 } |
| 54 | 54 |
| 55 // If this object doesn't have a name but it does have a description, | 55 // If this object doesn't have a name but it does have a description, |
| 56 // use the description as its name - because some screen readers only | 56 // use the description as its name - because some screen readers only |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 99 } | 99 } |
| 100 | 100 |
| 101 BrowserAccessibility* BrowserAccessibility::GetParent() { | 101 BrowserAccessibility* BrowserAccessibility::GetParent() { |
| 102 return parent_; | 102 return parent_; |
| 103 } | 103 } |
| 104 | 104 |
| 105 uint32 BrowserAccessibility::GetChildCount() { | 105 uint32 BrowserAccessibility::GetChildCount() { |
| 106 return children_.size(); | 106 return children_.size(); |
| 107 } | 107 } |
| 108 | 108 |
| 109 BrowserAccessibility* BrowserAccessibility::GetChild(uint32 child_index) { | |
| 110 DCHECK(child_index >= 0 && child_index < children_.size()); | |
| 111 return children_[child_index]; | |
| 112 } | |
| 113 | |
| 109 BrowserAccessibility* BrowserAccessibility::GetPreviousSibling() { | 114 BrowserAccessibility* BrowserAccessibility::GetPreviousSibling() { |
| 110 if (parent_ && index_in_parent_ > 0) | 115 if (parent_ && index_in_parent_ > 0) |
| 111 return parent_->children_[index_in_parent_ - 1]; | 116 return parent_->children_[index_in_parent_ - 1]; |
| 112 | 117 |
| 113 return NULL; | 118 return NULL; |
| 114 } | 119 } |
| 115 | 120 |
| 116 BrowserAccessibility* BrowserAccessibility::GetNextSibling() { | 121 BrowserAccessibility* BrowserAccessibility::GetNextSibling() { |
| 117 if (parent_ && | 122 if (parent_ && |
| 118 index_in_parent_ >= 0 && | 123 index_in_parent_ >= 0 && |
| (...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 568 if (!instance_active_) | 573 if (!instance_active_) |
| 569 return E_FAIL; | 574 return E_FAIL; |
| 570 | 575 |
| 571 if (!desc) | 576 if (!desc) |
| 572 return E_INVALIDARG; | 577 return E_INVALIDARG; |
| 573 | 578 |
| 574 return GetAttributeAsBstr(WebAccessibility::ATTR_DESCRIPTION, desc); | 579 return GetAttributeAsBstr(WebAccessibility::ATTR_DESCRIPTION, desc); |
| 575 } | 580 } |
| 576 | 581 |
| 577 STDMETHODIMP BrowserAccessibility::get_imagePosition( | 582 STDMETHODIMP BrowserAccessibility::get_imagePosition( |
| 578 enum IA2CoordinateType coordinate_type, long* x, long* y) { | 583 enum IA2CoordinateType coordinate_type, LONG* x, LONG* y) { |
| 579 if (!instance_active_) | 584 if (!instance_active_) |
| 580 return E_FAIL; | 585 return E_FAIL; |
| 581 | 586 |
| 582 if (!x || !y) | 587 if (!x || !y) |
| 583 return E_INVALIDARG; | 588 return E_INVALIDARG; |
| 584 | 589 |
| 585 if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) { | 590 if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) { |
| 586 HWND parent_hwnd = manager_->GetParentHWND(); | 591 HWND parent_hwnd = manager_->GetParentHWND(); |
| 587 POINT top_left = {0, 0}; | 592 POINT top_left = {0, 0}; |
| 588 ::ClientToScreen(parent_hwnd, &top_left); | 593 ::ClientToScreen(parent_hwnd, &top_left); |
| 589 *x = location_.x + top_left.x; | 594 *x = location_.x + top_left.x; |
| 590 *y = location_.y + top_left.y; | 595 *y = location_.y + top_left.y; |
| 591 } else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) { | 596 } else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) { |
| 592 *x = location_.x; | 597 *x = location_.x; |
| 593 *y = location_.y; | 598 *y = location_.y; |
| 594 if (parent_) { | 599 if (parent_) { |
| 595 *x -= parent_->location_.x; | 600 *x -= parent_->location_.x; |
| 596 *y -= parent_->location_.y; | 601 *y -= parent_->location_.y; |
| 597 } | 602 } |
| 598 } else { | 603 } else { |
| 599 return E_INVALIDARG; | 604 return E_INVALIDARG; |
| 600 } | 605 } |
| 601 | 606 |
| 602 return S_OK; | 607 return S_OK; |
| 603 } | 608 } |
| 604 | 609 |
| 605 STDMETHODIMP BrowserAccessibility::get_imageSize(long* height, long* width) { | 610 STDMETHODIMP BrowserAccessibility::get_imageSize(LONG* height, LONG* width) { |
| 606 if (!instance_active_) | 611 if (!instance_active_) |
| 607 return E_FAIL; | 612 return E_FAIL; |
| 608 | 613 |
| 609 if (!height || !width) | 614 if (!height || !width) |
| 610 return E_INVALIDARG; | 615 return E_INVALIDARG; |
| 611 | 616 |
| 612 *height = location_.height; | 617 *height = location_.height; |
| 613 *width = location_.width; | 618 *width = location_.width; |
| 614 return S_OK; | 619 return S_OK; |
| 615 } | 620 } |
| 616 | 621 |
| 617 // | 622 // |
| 618 // IAccessibleText methods. | 623 // IAccessibleText methods. |
| 619 // | 624 // |
| 620 | 625 |
| 621 STDMETHODIMP BrowserAccessibility::get_nCharacters(long* n_characters) { | 626 STDMETHODIMP BrowserAccessibility::get_nCharacters(LONG* n_characters) { |
| 622 if (!instance_active_) | 627 if (!instance_active_) |
| 623 return E_FAIL; | 628 return E_FAIL; |
| 624 | 629 |
| 625 if (!n_characters) | 630 if (!n_characters) |
| 626 return E_INVALIDARG; | 631 return E_INVALIDARG; |
| 627 | 632 |
| 628 *n_characters = name_.length(); | 633 if (src_role_ == WebAccessibility::ROLE_TEXT_FIELD) { |
| 634 *n_characters = value_.length(); | |
| 635 } else { | |
| 636 *n_characters = name_.length(); | |
| 637 } | |
| 638 | |
| 629 return S_OK; | 639 return S_OK; |
| 630 } | 640 } |
| 631 | 641 |
| 632 STDMETHODIMP BrowserAccessibility::get_text( | 642 STDMETHODIMP BrowserAccessibility::get_text( |
| 633 long start_offset, long end_offset, BSTR* text) { | 643 LONG start_offset, LONG end_offset, BSTR* text) { |
| 634 if (!instance_active_) | 644 if (!instance_active_) |
| 635 return E_FAIL; | 645 return E_FAIL; |
| 636 | 646 |
| 637 if (!text) | 647 if (!text) |
| 638 return E_INVALIDARG; | 648 return E_INVALIDARG; |
| 639 | 649 |
| 640 long len = name_.length(); | 650 string16 text_str; |
|
Chris Guillory
2010/10/01 18:06:43
Can we use a reference here.
| |
| 651 if (src_role_ == WebAccessibility::ROLE_TEXT_FIELD) { | |
| 652 text_str = value_; | |
| 653 } else { | |
| 654 text_str = name_; | |
| 655 } | |
| 656 | |
| 657 // The spec allows the arguments to be reversed. | |
| 658 if (start_offset > end_offset) { | |
| 659 LONG tmp = start_offset; | |
| 660 start_offset = end_offset; | |
| 661 end_offset = tmp; | |
| 662 } | |
| 663 | |
| 664 // The spec does not allow the start or end offsets to be out or range; | |
| 665 // we must return an error if so. | |
| 666 LONG len = text_str.length(); | |
| 641 if (start_offset < 0) | 667 if (start_offset < 0) |
| 642 start_offset = 0; | 668 return E_INVALIDARG; |
| 643 if (end_offset > len) | 669 if (end_offset > len) |
| 644 end_offset = len; | 670 return E_INVALIDARG; |
| 645 | 671 |
| 646 string16 substr = name_.substr(start_offset, end_offset - start_offset); | 672 string16 substr = text_str.substr(start_offset, end_offset - start_offset); |
| 647 if (substr.empty()) | 673 if (substr.empty()) |
| 648 return S_FALSE; | 674 return S_FALSE; |
| 649 | 675 |
| 650 *text = SysAllocString(substr.c_str()); | 676 *text = SysAllocString(substr.c_str()); |
| 651 DCHECK(*text); | 677 DCHECK(*text); |
| 652 return S_OK; | 678 return S_OK; |
| 653 } | 679 } |
| 654 | 680 |
| 655 STDMETHODIMP BrowserAccessibility::get_caretOffset(long* offset) { | 681 STDMETHODIMP BrowserAccessibility::get_caretOffset(LONG* offset) { |
| 656 if (!instance_active_) | 682 if (!instance_active_) |
| 657 return E_FAIL; | 683 return E_FAIL; |
| 658 | 684 |
| 659 if (!offset) | 685 if (!offset) |
| 660 return E_INVALIDARG; | 686 return E_INVALIDARG; |
| 661 | 687 |
| 662 *offset = 0; | 688 if (src_role_ == WebAccessibility::ROLE_TEXT_FIELD) { |
| 689 int sel_start = 0; | |
| 690 if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start)) { | |
| 691 *offset = sel_start; | |
| 692 } else { | |
| 693 *offset = 0; | |
| 694 } | |
| 695 } else { | |
| 696 *offset = 0; | |
| 697 } | |
| 698 | |
| 699 return S_OK; | |
| 700 } | |
| 701 | |
| 702 STDMETHODIMP BrowserAccessibility::get_nSelections(LONG* n_selections) { | |
| 703 if (!instance_active_) | |
| 704 return E_FAIL; | |
| 705 | |
| 706 if (!n_selections) | |
| 707 return E_INVALIDARG; | |
| 708 | |
| 709 if (src_role_ == WebAccessibility::ROLE_TEXT_FIELD) { | |
| 710 int sel_start = 0; | |
| 711 int sel_end = 0; | |
| 712 if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start) && | |
| 713 GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_END, &sel_end) && | |
| 714 sel_start != sel_end) { | |
| 715 *n_selections = 1; | |
| 716 } else { | |
| 717 *n_selections = 0; | |
| 718 } | |
| 719 } else { | |
| 720 *n_selections = 0; | |
| 721 } | |
| 722 | |
| 723 return S_OK; | |
| 724 } | |
| 725 | |
| 726 STDMETHODIMP BrowserAccessibility::get_selection(LONG selection_index, | |
| 727 LONG* start_offset, | |
| 728 LONG* end_offset) { | |
| 729 if (!instance_active_) | |
| 730 return E_FAIL; | |
| 731 | |
| 732 if (!start_offset || !end_offset || selection_index != 0) | |
| 733 return E_INVALIDARG; | |
| 734 | |
| 735 if (src_role_ == WebAccessibility::ROLE_TEXT_FIELD) { | |
| 736 int sel_start = 0; | |
| 737 int sel_end = 0; | |
| 738 if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start) && | |
| 739 GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_END, &sel_end)) { | |
| 740 *start_offset = sel_start; | |
| 741 *end_offset = sel_end; | |
| 742 } else { | |
| 743 *start_offset = 0; | |
| 744 *end_offset = 0; | |
| 745 } | |
| 746 } else { | |
| 747 *start_offset = 0; | |
| 748 *end_offset = 0; | |
| 749 } | |
| 750 | |
| 663 return S_OK; | 751 return S_OK; |
| 664 } | 752 } |
| 665 | 753 |
| 666 // | 754 // |
| 667 // ISimpleDOMDocument methods. | 755 // ISimpleDOMDocument methods. |
| 668 // | 756 // |
| 669 | 757 |
| 670 STDMETHODIMP BrowserAccessibility::get_URL(BSTR* url) { | 758 STDMETHODIMP BrowserAccessibility::get_URL(BSTR* url) { |
| 671 if (!instance_active_) | 759 if (!instance_active_) |
| 672 return E_FAIL; | 760 return E_FAIL; |
| (...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1004 // | 1092 // |
| 1005 // CComObjectRootEx methods. | 1093 // CComObjectRootEx methods. |
| 1006 // | 1094 // |
| 1007 | 1095 |
| 1008 HRESULT WINAPI BrowserAccessibility::InternalQueryInterface( | 1096 HRESULT WINAPI BrowserAccessibility::InternalQueryInterface( |
| 1009 void* this_ptr, | 1097 void* this_ptr, |
| 1010 const _ATL_INTMAP_ENTRY* entries, | 1098 const _ATL_INTMAP_ENTRY* entries, |
| 1011 REFIID iid, | 1099 REFIID iid, |
| 1012 void** object) { | 1100 void** object) { |
| 1013 if (iid == IID_IAccessibleText) { | 1101 if (iid == IID_IAccessibleText) { |
| 1014 if (role_ != ROLE_SYSTEM_LINK) { | 1102 if (role_ != ROLE_SYSTEM_LINK && role_ != ROLE_SYSTEM_TEXT) { |
| 1015 *object = NULL; | 1103 *object = NULL; |
| 1016 return E_NOINTERFACE; | 1104 return E_NOINTERFACE; |
| 1017 } | 1105 } |
| 1018 } else if (iid == IID_IAccessibleImage) { | 1106 } else if (iid == IID_IAccessibleImage) { |
| 1019 if (role_ != ROLE_SYSTEM_GRAPHIC) { | 1107 if (role_ != ROLE_SYSTEM_GRAPHIC) { |
| 1020 *object = NULL; | 1108 *object = NULL; |
| 1021 return E_NOINTERFACE; | 1109 return E_NOINTERFACE; |
| 1022 } | 1110 } |
| 1023 } else if (iid == IID_ISimpleDOMDocument) { | 1111 } else if (iid == IID_ISimpleDOMDocument) { |
| 1024 if (role_ != ROLE_SYSTEM_DOCUMENT) { | 1112 if (role_ != ROLE_SYSTEM_DOCUMENT) { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1074 | 1162 |
| 1075 if (str.empty()) | 1163 if (str.empty()) |
| 1076 return S_FALSE; | 1164 return S_FALSE; |
| 1077 | 1165 |
| 1078 *value_bstr = SysAllocString(str.c_str()); | 1166 *value_bstr = SysAllocString(str.c_str()); |
| 1079 DCHECK(*value_bstr); | 1167 DCHECK(*value_bstr); |
| 1080 | 1168 |
| 1081 return S_OK; | 1169 return S_OK; |
| 1082 } | 1170 } |
| 1083 | 1171 |
| 1084 string16 BrowserAccessibility::Escape(string16 str) { | 1172 bool BrowserAccessibility::GetAttributeAsInt( |
| 1085 return UTF8ToUTF16(EscapeNonASCII(UTF16ToUTF8(str))); | 1173 WebAccessibility::Attribute attribute, int* value_int) { |
| 1174 string16 value_str; | |
| 1175 | |
| 1176 if (!GetAttribute(attribute, &value_str)) | |
| 1177 return false; | |
| 1178 | |
| 1179 if (!base::StringToInt(value_str, value_int)) | |
| 1180 return false; | |
| 1181 | |
| 1182 return true; | |
| 1086 } | 1183 } |
| 1087 | 1184 |
| 1088 void BrowserAccessibility::InitRoleAndState(LONG web_role, | 1185 string16 BrowserAccessibility::Escape(string16 str) { |
| 1089 LONG web_state) { | 1186 return EscapeQueryParamValueUTF8(str, false); |
| 1187 } | |
| 1188 | |
| 1189 void BrowserAccessibility::InitRoleAndState(LONG web_role, LONG web_state) { | |
| 1090 state_ = 0; | 1190 state_ = 0; |
| 1091 ia2_state_ = IA2_STATE_OPAQUE; | 1191 ia2_state_ = IA2_STATE_OPAQUE; |
| 1092 | 1192 |
| 1093 if ((web_state >> WebAccessibility::STATE_CHECKED) & 1) | 1193 if ((web_state >> WebAccessibility::STATE_CHECKED) & 1) |
| 1094 state_ |= STATE_SYSTEM_CHECKED; | 1194 state_ |= STATE_SYSTEM_CHECKED; |
| 1095 if ((web_state >> WebAccessibility::STATE_COLLAPSED) & 1) | 1195 if ((web_state >> WebAccessibility::STATE_COLLAPSED) & 1) |
| 1096 state_ |= STATE_SYSTEM_COLLAPSED; | 1196 state_ |= STATE_SYSTEM_COLLAPSED; |
| 1097 if ((web_state >> WebAccessibility::STATE_EXPANDED) & 1) | 1197 if ((web_state >> WebAccessibility::STATE_EXPANDED) & 1) |
| 1098 state_ |= STATE_SYSTEM_EXPANDED; | 1198 state_ |= STATE_SYSTEM_EXPANDED; |
| 1099 if ((web_state >> WebAccessibility::STATE_FOCUSABLE) & 1) | 1199 if ((web_state >> WebAccessibility::STATE_FOCUSABLE) & 1) |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1377 } | 1477 } |
| 1378 | 1478 |
| 1379 // The role should always be set. | 1479 // The role should always be set. |
| 1380 DCHECK(!role_name_.empty() || role_); | 1480 DCHECK(!role_name_.empty() || role_); |
| 1381 | 1481 |
| 1382 // If we didn't explicitly set the IAccessible2 role, make it the same | 1482 // If we didn't explicitly set the IAccessible2 role, make it the same |
| 1383 // as the MSAA role. | 1483 // as the MSAA role. |
| 1384 if (!ia2_role_) | 1484 if (!ia2_role_) |
| 1385 ia2_role_ = role_; | 1485 ia2_role_ = role_; |
| 1386 } | 1486 } |
| OLD | NEW |