| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "content/browser/accessibility/browser_accessibility_win.h" | 5 #include "content/browser/accessibility/browser_accessibility_win.h" |
| 6 | 6 |
| 7 #include <UIAutomationClient.h> | 7 #include <UIAutomationClient.h> |
| 8 #include <UIAutomationCoreApi.h> | 8 #include <UIAutomationCoreApi.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 200 | 200 |
| 201 // static | 201 // static |
| 202 BrowserAccessibility* BrowserAccessibility::Create() { | 202 BrowserAccessibility* BrowserAccessibility::Create() { |
| 203 ui::win::CreateATLModuleIfNeeded(); | 203 ui::win::CreateATLModuleIfNeeded(); |
| 204 CComObject<BrowserAccessibilityWin>* instance; | 204 CComObject<BrowserAccessibilityWin>* instance; |
| 205 HRESULT hr = CComObject<BrowserAccessibilityWin>::CreateInstance(&instance); | 205 HRESULT hr = CComObject<BrowserAccessibilityWin>::CreateInstance(&instance); |
| 206 DCHECK(SUCCEEDED(hr)); | 206 DCHECK(SUCCEEDED(hr)); |
| 207 return instance->NewReference(); | 207 return instance->NewReference(); |
| 208 } | 208 } |
| 209 | 209 |
| 210 const BrowserAccessibilityWin* BrowserAccessibility::ToBrowserAccessibilityWin() | |
| 211 const { | |
| 212 return static_cast<const BrowserAccessibilityWin*>(this); | |
| 213 } | |
| 214 | |
| 215 BrowserAccessibilityWin* BrowserAccessibility::ToBrowserAccessibilityWin() { | 210 BrowserAccessibilityWin* BrowserAccessibility::ToBrowserAccessibilityWin() { |
| 216 return static_cast<BrowserAccessibilityWin*>(this); | 211 return static_cast<BrowserAccessibilityWin*>(this); |
| 217 } | 212 } |
| 218 | 213 |
| 219 BrowserAccessibilityWin::BrowserAccessibilityWin() | 214 BrowserAccessibilityWin::BrowserAccessibilityWin() |
| 220 : win_attributes_(new WinAttributes()), | 215 : win_attributes_(new WinAttributes()), |
| 221 previous_scroll_x_(0), | 216 previous_scroll_x_(0), |
| 222 previous_scroll_y_(0) { | 217 previous_scroll_y_(0) { |
| 223 // Start unique IDs at -1 and decrement each time, because get_accChild | 218 // Start unique IDs at -1 and decrement each time, because get_accChild |
| 224 // uses positive IDs to enumerate children, so we use negative IDs to | 219 // uses positive IDs to enumerate children, so we use negative IDs to |
| (...skipping 1783 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2008 | 2003 |
| 2009 STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) { | 2004 STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) { |
| 2010 if (!instance_active()) | 2005 if (!instance_active()) |
| 2011 return E_FAIL; | 2006 return E_FAIL; |
| 2012 | 2007 |
| 2013 if (!offset) | 2008 if (!offset) |
| 2014 return E_INVALIDARG; | 2009 return E_INVALIDARG; |
| 2015 | 2010 |
| 2016 int selection_start, selection_end; | 2011 int selection_start, selection_end; |
| 2017 GetSelectionOffsets(&selection_start, &selection_end); | 2012 GetSelectionOffsets(&selection_start, &selection_end); |
| 2018 // The caret is always at the end of the selection, if a selection exists. | 2013 *offset = selection_start; |
| 2019 *offset = selection_end; | 2014 if (selection_start < 0) |
| 2020 if (*offset < 0) | |
| 2021 return S_FALSE; | 2015 return S_FALSE; |
| 2022 | 2016 |
| 2023 return S_OK; | 2017 return S_OK; |
| 2024 } | 2018 } |
| 2025 | 2019 |
| 2026 STDMETHODIMP BrowserAccessibilityWin::get_characterExtents( | 2020 STDMETHODIMP BrowserAccessibilityWin::get_characterExtents( |
| 2027 LONG offset, | 2021 LONG offset, |
| 2028 enum IA2CoordinateType coordinate_type, | 2022 enum IA2CoordinateType coordinate_type, |
| 2029 LONG* out_x, | 2023 LONG* out_x, |
| 2030 LONG* out_y, | 2024 LONG* out_y, |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2064 if (!instance_active()) | 2058 if (!instance_active()) |
| 2065 return E_FAIL; | 2059 return E_FAIL; |
| 2066 | 2060 |
| 2067 if (!n_selections) | 2061 if (!n_selections) |
| 2068 return E_INVALIDARG; | 2062 return E_INVALIDARG; |
| 2069 | 2063 |
| 2070 *n_selections = 0; | 2064 *n_selections = 0; |
| 2071 int selection_start, selection_end; | 2065 int selection_start, selection_end; |
| 2072 GetSelectionOffsets(&selection_start, &selection_end); | 2066 GetSelectionOffsets(&selection_start, &selection_end); |
| 2073 if (selection_start >= 0 && selection_end >= 0 && | 2067 if (selection_start >= 0 && selection_end >= 0 && |
| 2074 selection_start != selection_end) { | 2068 selection_start != selection_end) |
| 2075 *n_selections = 1; | 2069 *n_selections = 1; |
| 2076 } | |
| 2077 | 2070 |
| 2078 return S_OK; | 2071 return S_OK; |
| 2079 } | 2072 } |
| 2080 | 2073 |
| 2081 STDMETHODIMP BrowserAccessibilityWin::get_selection(LONG selection_index, | 2074 STDMETHODIMP BrowserAccessibilityWin::get_selection(LONG selection_index, |
| 2082 LONG* start_offset, | 2075 LONG* start_offset, |
| 2083 LONG* end_offset) { | 2076 LONG* end_offset) { |
| 2084 if (!instance_active()) | 2077 if (!instance_active()) |
| 2085 return E_FAIL; | 2078 return E_FAIL; |
| 2086 | 2079 |
| 2087 if (!start_offset || !end_offset || selection_index != 0) | 2080 if (!start_offset || !end_offset || selection_index != 0) |
| 2088 return E_INVALIDARG; | 2081 return E_INVALIDARG; |
| 2089 | 2082 |
| 2090 LONG n_selections = 0; | 2083 LONG n_selections = 0; |
| 2091 if (FAILED(get_nSelections(&n_selections)) || n_selections < 1) | 2084 if (FAILED(get_nSelections(&n_selections)) || n_selections < 1) |
| 2092 return E_INVALIDARG; | 2085 return E_INVALIDARG; |
| 2093 | 2086 |
| 2094 *start_offset = 0; | 2087 *start_offset = 0; |
| 2095 *end_offset = 0; | 2088 *end_offset = 0; |
| 2096 int selection_start, selection_end; | 2089 int selection_start, selection_end; |
| 2097 GetSelectionOffsets(&selection_start, &selection_end); | 2090 GetSelectionOffsets(&selection_start, &selection_end); |
| 2098 if (selection_start >= 0 && selection_end >= 0) { | 2091 if (selection_start >= 0 && selection_end >= 0) { |
| 2099 // We should ignore the direction of the selection when exposing start and | |
| 2100 // end offsets. According to the IA2 Spec the end offset is always increased | |
| 2101 // by one past the end of the selection. This wouldn't make sense if | |
| 2102 // end < start. | |
| 2103 if (selection_end < selection_start) | |
| 2104 std::swap(selection_start, selection_end); | |
| 2105 | |
| 2106 *start_offset = selection_start; | 2092 *start_offset = selection_start; |
| 2107 *end_offset = selection_end; | 2093 *end_offset = selection_end; |
| 2108 } | 2094 } |
| 2109 | 2095 |
| 2110 return S_OK; | 2096 return S_OK; |
| 2111 } | 2097 } |
| 2112 | 2098 |
| 2113 STDMETHODIMP BrowserAccessibilityWin::get_text(LONG start_offset, | 2099 STDMETHODIMP BrowserAccessibilityWin::get_text(LONG start_offset, |
| 2114 LONG end_offset, | 2100 LONG end_offset, |
| 2115 BSTR* text) { | 2101 BSTR* text) { |
| (...skipping 1539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3655 int value; | 3641 int value; |
| 3656 if (GetIntAttribute(attribute, &value)) { | 3642 if (GetIntAttribute(attribute, &value)) { |
| 3657 win_attributes_->ia2_attributes.push_back( | 3643 win_attributes_->ia2_attributes.push_back( |
| 3658 base::ASCIIToUTF16(ia2_attr) + L":" + | 3644 base::ASCIIToUTF16(ia2_attr) + L":" + |
| 3659 base::IntToString16(value)); | 3645 base::IntToString16(value)); |
| 3660 } | 3646 } |
| 3661 } | 3647 } |
| 3662 | 3648 |
| 3663 int32 BrowserAccessibilityWin::GetHyperlinkIndexFromChild( | 3649 int32 BrowserAccessibilityWin::GetHyperlinkIndexFromChild( |
| 3664 const BrowserAccessibilityWin& child) const { | 3650 const BrowserAccessibilityWin& child) const { |
| 3665 if (hyperlinks().empty()) | |
| 3666 return -1; | |
| 3667 | |
| 3668 auto iterator = std::find( | 3651 auto iterator = std::find( |
| 3669 hyperlinks().begin(), hyperlinks().end(), child.GetId()); | 3652 hyperlinks().begin(), hyperlinks().end(), child.GetId()); |
| 3670 if (iterator == hyperlinks().end()) | 3653 if (iterator == hyperlinks().end()) |
| 3671 return -1; | 3654 return -1; |
| 3672 | 3655 |
| 3673 return static_cast<int32>(iterator - hyperlinks().begin()); | 3656 return static_cast<int32>(iterator - hyperlinks().begin()); |
| 3674 } | 3657 } |
| 3675 | 3658 |
| 3676 int32 BrowserAccessibilityWin::GetHypertextOffsetFromHyperlinkIndex( | 3659 int32 BrowserAccessibilityWin::GetHypertextOffsetFromHyperlinkIndex( |
| 3677 int32 hyperlink_index) const { | 3660 int32 hyperlink_index) const { |
| 3678 for (auto& offset_index : hyperlink_offset_to_index()) { | 3661 auto& offsets_map = hyperlink_offset_to_index(); |
| 3662 for (auto& offset_index : offsets_map) { |
| 3679 if (offset_index.second == hyperlink_index) | 3663 if (offset_index.second == hyperlink_index) |
| 3680 return offset_index.first; | 3664 return offset_index.first; |
| 3681 } | 3665 } |
| 3682 | 3666 |
| 3683 return -1; | 3667 return -1; |
| 3684 } | 3668 } |
| 3685 | 3669 |
| 3686 int32 BrowserAccessibilityWin::GetHypertextOffsetFromChild( | 3670 int32 BrowserAccessibilityWin::GetHypertextOffsetFromChild( |
| 3687 const BrowserAccessibilityWin& child) const { | 3671 const BrowserAccessibilityWin& child) const { |
| 3688 int32 hyperlink_index = GetHyperlinkIndexFromChild(child); | 3672 int32 hyperlink_index = GetHyperlinkIndexFromChild(child); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3699 while (parent_object && parent_object != this) { | 3683 while (parent_object && parent_object != this) { |
| 3700 current_object = parent_object; | 3684 current_object = parent_object; |
| 3701 parent_object = current_object->GetParent()->ToBrowserAccessibilityWin(); | 3685 parent_object = current_object->GetParent()->ToBrowserAccessibilityWin(); |
| 3702 } | 3686 } |
| 3703 if (!parent_object) | 3687 if (!parent_object) |
| 3704 return -1; | 3688 return -1; |
| 3705 | 3689 |
| 3706 return parent_object->GetHypertextOffsetFromChild(*current_object); | 3690 return parent_object->GetHypertextOffsetFromChild(*current_object); |
| 3707 } | 3691 } |
| 3708 | 3692 |
| 3709 int BrowserAccessibilityWin::GetHypertextOffsetFromEndpoint( | |
| 3710 const BrowserAccessibilityWin& endpoint_object, | |
| 3711 int endpoint_offset) const { | |
| 3712 // There are three cases: | |
| 3713 // 1. Either the selection endpoint is inside this object or is an ancestor of | |
| 3714 // of this object. endpoint_offset should be returned. | |
| 3715 // 2. The selection endpoint is a pure descendant of this object. The offset | |
| 3716 // of the embedded object character corresponding to the subtree in which | |
| 3717 // the endpoint is located should be returned. | |
| 3718 // 3. The selection endpoint is in a completely different part of the tree. | |
| 3719 // Either 0 or text_length should be returned depending on the direction that | |
| 3720 // one needs to travel to find the endpoint. | |
| 3721 | |
| 3722 // Case 1. | |
| 3723 // | |
| 3724 // IsDescendantOf includes the case when endpoint_object == this. | |
| 3725 if (IsDescendantOf(&endpoint_object) || | |
| 3726 // Handle the case when the endpoint is a direct text-only child. | |
| 3727 // The selection offset should still be valid on the parent. | |
| 3728 (endpoint_object.IsTextOnlyObject() && | |
| 3729 endpoint_object.GetParent() == this)) { | |
| 3730 return endpoint_offset; | |
| 3731 } | |
| 3732 | |
| 3733 const BrowserAccessibility* common_parent = this; | |
| 3734 while (common_parent && !endpoint_object.IsDescendantOf(common_parent)) { | |
| 3735 common_parent = common_parent->GetParent(); | |
| 3736 } | |
| 3737 if (!common_parent) | |
| 3738 return -1; | |
| 3739 | |
| 3740 auto common_parent_win = common_parent->ToBrowserAccessibilityWin(); | |
| 3741 // Text only objects must have a parent. | |
| 3742 DCHECK(!IsTextOnlyObject() || GetParent()); | |
| 3743 DCHECK(!endpoint_object.IsTextOnlyObject() || endpoint_object.GetParent()); | |
| 3744 // Text only objects that are direct descendants should behave as if they | |
| 3745 // are part of their parent when computing hyperlink offsets. | |
| 3746 const BrowserAccessibilityWin* nearest_non_text_ancestor = | |
| 3747 IsTextOnlyObject() ? GetParent()->ToBrowserAccessibilityWin() : this; | |
| 3748 const BrowserAccessibilityWin& nearest_non_text_endpoint = | |
| 3749 endpoint_object.IsTextOnlyObject() | |
| 3750 ? *(endpoint_object.GetParent()->ToBrowserAccessibilityWin()) | |
| 3751 : endpoint_object; | |
| 3752 | |
| 3753 // Case 2. | |
| 3754 // | |
| 3755 // We already checked in case 1 if our endpoint is inside this object. | |
| 3756 // We can safely assume that it is a descendant or in a completely different | |
| 3757 // part of the tree. | |
| 3758 if (common_parent_win == nearest_non_text_ancestor) { | |
| 3759 return nearest_non_text_ancestor->GetHypertextOffsetFromDescendant( | |
| 3760 nearest_non_text_endpoint); | |
| 3761 } | |
| 3762 | |
| 3763 // Case 3. | |
| 3764 // | |
| 3765 // We can safely assume that the endpoint is in another part of the tree or | |
| 3766 // at common parent, and that this object is a descendant of common parent. | |
| 3767 int current_offset = | |
| 3768 static_cast<int>(common_parent_win->GetHypertextOffsetFromDescendant( | |
| 3769 *nearest_non_text_ancestor)); | |
| 3770 DCHECK_GE(current_offset, 0); | |
| 3771 if (common_parent_win != &nearest_non_text_endpoint) { | |
| 3772 endpoint_offset = | |
| 3773 static_cast<int>(common_parent_win->GetHypertextOffsetFromDescendant( | |
| 3774 nearest_non_text_endpoint)); | |
| 3775 DCHECK_GE(endpoint_offset, 0); | |
| 3776 } | |
| 3777 | |
| 3778 if (endpoint_offset < current_offset) | |
| 3779 return 0; | |
| 3780 if (endpoint_offset > current_offset) | |
| 3781 return TextForIAccessibleText().length(); | |
| 3782 | |
| 3783 NOTREACHED(); | |
| 3784 return -1; | |
| 3785 } | |
| 3786 | |
| 3787 int BrowserAccessibilityWin::GetSelectionAnchor() const { | 3693 int BrowserAccessibilityWin::GetSelectionAnchor() const { |
| 3788 BrowserAccessibility* root = manager()->GetRoot(); | 3694 BrowserAccessibility* root = manager()->GetRoot(); |
| 3789 int32 anchor_id; | 3695 int32 anchor_id; |
| 3790 if (!root || !root->GetIntAttribute(ui::AX_ATTR_ANCHOR_OBJECT_ID, &anchor_id)) | 3696 if (!root || !root->GetIntAttribute(ui::AX_ATTR_ANCHOR_OBJECT_ID, &anchor_id)) |
| 3791 return -1; | 3697 return -1; |
| 3792 | 3698 |
| 3793 BrowserAccessibilityWin* anchor_object = manager()->GetFromID( | 3699 BrowserAccessibilityWin* anchor_object = manager()->GetFromID( |
| 3794 anchor_id)->ToBrowserAccessibilityWin(); | 3700 anchor_id)->ToBrowserAccessibilityWin(); |
| 3795 if (!anchor_object) | 3701 if (!anchor_object) |
| 3796 return -1; | 3702 return -1; |
| 3797 | 3703 |
| 3798 int anchor_offset; | 3704 // Includes the case when anchor_object == this. |
| 3799 if (!root->GetIntAttribute(ui::AX_ATTR_ANCHOR_OFFSET, &anchor_offset)) | 3705 if (IsDescendantOf(anchor_object) || |
| 3800 return -1; | 3706 // Text only objects that are direct descendants should behave as if they |
| 3707 // are part of this object when computing hypertext. |
| 3708 (anchor_object->GetParent() == this && |
| 3709 anchor_object->IsTextOnlyObject())) { |
| 3710 int anchor_offset; |
| 3711 if (!root->GetIntAttribute(ui::AX_ATTR_ANCHOR_OFFSET, &anchor_offset)) |
| 3712 return -1; |
| 3801 | 3713 |
| 3802 return GetHypertextOffsetFromEndpoint(*anchor_object, anchor_offset); | 3714 return anchor_offset; |
| 3715 } |
| 3716 |
| 3717 if (anchor_object->IsDescendantOf(this)) |
| 3718 return GetHypertextOffsetFromDescendant(*anchor_object); |
| 3719 |
| 3720 return -1; |
| 3803 } | 3721 } |
| 3804 | 3722 |
| 3805 int BrowserAccessibilityWin::GetSelectionFocus() const { | 3723 int BrowserAccessibilityWin::GetSelectionFocus() const { |
| 3806 BrowserAccessibility* root = manager()->GetRoot(); | 3724 BrowserAccessibility* root = manager()->GetRoot(); |
| 3807 int32 focus_id; | 3725 int32 focus_id; |
| 3808 if (!root || !root->GetIntAttribute(ui::AX_ATTR_FOCUS_OBJECT_ID, &focus_id)) | 3726 if (!root || !root->GetIntAttribute(ui::AX_ATTR_FOCUS_OBJECT_ID, &focus_id)) |
| 3809 return -1; | 3727 return -1; |
| 3810 | 3728 |
| 3811 BrowserAccessibilityWin* focus_object = manager()->GetFromID( | 3729 BrowserAccessibilityWin* focus_object = manager()->GetFromID( |
| 3812 focus_id)->ToBrowserAccessibilityWin(); | 3730 focus_id)->ToBrowserAccessibilityWin(); |
| 3813 if (!focus_object) | 3731 if (!focus_object) |
| 3814 return -1; | 3732 return -1; |
| 3815 | 3733 |
| 3816 int focus_offset; | 3734 // Includes the case when focus_object == this. |
| 3817 if (!root->GetIntAttribute(ui::AX_ATTR_FOCUS_OFFSET, &focus_offset)) | 3735 if (IsDescendantOf(focus_object) || |
| 3818 return -1; | 3736 // Text only objects that are direct descendants should behave as if they |
| 3737 // are part of this object when computing hypertext. |
| 3738 (focus_object->GetParent() == this && focus_object->IsTextOnlyObject())) { |
| 3739 int focus_offset; |
| 3740 if (!root->GetIntAttribute(ui::AX_ATTR_FOCUS_OFFSET, &focus_offset)) |
| 3741 return -1; |
| 3819 | 3742 |
| 3820 return GetHypertextOffsetFromEndpoint(*focus_object, focus_offset); | 3743 return focus_offset; |
| 3744 } |
| 3745 |
| 3746 if (focus_object->IsDescendantOf(this)) |
| 3747 return GetHypertextOffsetFromDescendant(*focus_object); |
| 3748 |
| 3749 return -1; |
| 3821 } | 3750 } |
| 3822 | 3751 |
| 3823 void BrowserAccessibilityWin::GetSelectionOffsets( | 3752 void BrowserAccessibilityWin::GetSelectionOffsets( |
| 3824 int* selection_start, int* selection_end) const { | 3753 int* selection_start, int* selection_end) const { |
| 3825 DCHECK(selection_start && selection_end); | 3754 DCHECK(selection_start && selection_end); |
| 3826 | 3755 |
| 3827 if (IsEditableText() && !HasState(ui::AX_STATE_RICHLY_EDITABLE) && | 3756 if (IsEditableText() && !HasState(ui::AX_STATE_RICHLY_EDITABLE) && |
| 3828 GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START, selection_start) && | 3757 GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START, selection_start) && |
| 3829 GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END, selection_end)) { | 3758 GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END, selection_end)) { |
| 3830 return; | 3759 return; |
| 3831 } | 3760 } |
| 3832 | 3761 |
| 3833 *selection_start = GetSelectionAnchor(); | 3762 *selection_start = GetSelectionAnchor(); |
| 3834 *selection_end = GetSelectionFocus(); | 3763 *selection_end = GetSelectionFocus(); |
| 3835 if (*selection_start < 0 || *selection_end < 0) | 3764 if (*selection_start < 0 || *selection_end < 0) |
| 3836 return; | 3765 return; |
| 3837 | 3766 |
| 3838 // If the selection is collapsed or if it only spans one character, return the | 3767 if (*selection_end < *selection_start) |
| 3839 // selection offsets only if the caret is active on this object or any of its | 3768 std::swap(*selection_start, *selection_end); |
| 3840 // children. | |
| 3841 // The focus object indicates the caret position. | |
| 3842 if (*selection_start == *selection_end) { | |
| 3843 BrowserAccessibility* root = manager()->GetRoot(); | |
| 3844 int32 focus_id; | |
| 3845 if (!root || !root->GetIntAttribute(ui::AX_ATTR_FOCUS_OBJECT_ID, &focus_id)) | |
| 3846 return; | |
| 3847 | 3769 |
| 3848 BrowserAccessibilityWin* focus_object = | 3770 // IA2 Spec says that the end of the selection should be after the last |
| 3849 manager()->GetFromID(focus_id)->ToBrowserAccessibilityWin(); | 3771 // embedded object character that is part of the selection, if there is one. |
| 3850 if (!focus_object) | 3772 if (hyperlink_offset_to_index().find(*selection_end) != |
| 3851 return; | 3773 hyperlink_offset_to_index().end()) { |
| 3852 | 3774 ++(*selection_end); |
| 3853 if (!focus_object->IsDescendantOf(this) && | |
| 3854 !(IsTextOnlyObject() && GetParent() == focus_object)) { | |
| 3855 *selection_start = -1; | |
| 3856 *selection_end = -1; | |
| 3857 return; | |
| 3858 } | |
| 3859 } | 3775 } |
| 3860 | |
| 3861 // The IA2 Spec says that if the largest of the two offsets falls on an | |
| 3862 // embedded object character and if there is a selection in that embedded | |
| 3863 // object, it should be incremented by one so that it points after the | |
| 3864 // embedded object character. | |
| 3865 // This is a signal to AT software that the embedded object is also part of | |
| 3866 // the selection. | |
| 3867 int* largest_offset = | |
| 3868 (*selection_start <= *selection_end) ? selection_end : selection_start; | |
| 3869 auto current_object = const_cast<BrowserAccessibilityWin*>(this); | |
| 3870 LONG hyperlink_index; | |
| 3871 HRESULT hr = | |
| 3872 current_object->get_hyperlinkIndex(*largest_offset, &hyperlink_index); | |
| 3873 if (hr != S_OK) | |
| 3874 return; | |
| 3875 | |
| 3876 DCHECK_GE(hyperlink_index, 0); | |
| 3877 base::win::ScopedComPtr<IAccessibleHyperlink> hyperlink; | |
| 3878 hr = current_object->get_hyperlink(hyperlink_index, hyperlink.Receive()); | |
| 3879 DCHECK(SUCCEEDED(hr)); | |
| 3880 base::win::ScopedComPtr<IAccessibleText> hyperlink_text; | |
| 3881 hr = hyperlink.QueryInterface(hyperlink_text.Receive()); | |
| 3882 DCHECK(SUCCEEDED(hr)); | |
| 3883 LONG n_selections = 0; | |
| 3884 hr = hyperlink_text->get_nSelections(&n_selections); | |
| 3885 DCHECK(SUCCEEDED(hr)); | |
| 3886 if (n_selections > 0) | |
| 3887 ++(*largest_offset); | |
| 3888 } | 3776 } |
| 3889 | 3777 |
| 3890 base::string16 BrowserAccessibilityWin::GetNameRecursive() const { | 3778 base::string16 BrowserAccessibilityWin::GetNameRecursive() const { |
| 3891 if (!name().empty()) { | 3779 if (!name().empty()) { |
| 3892 return name(); | 3780 return name(); |
| 3893 } | 3781 } |
| 3894 | 3782 |
| 3895 base::string16 result; | 3783 base::string16 result; |
| 3896 for (uint32 i = 0; i < PlatformChildCount(); ++i) { | 3784 for (uint32 i = 0; i < PlatformChildCount(); ++i) { |
| 3897 result += PlatformGetChild(i)->ToBrowserAccessibilityWin()-> | 3785 result += PlatformGetChild(i)->ToBrowserAccessibilityWin()-> |
| 3898 GetNameRecursive(); | 3786 GetNameRecursive(); |
| 3899 } | 3787 } |
| 3900 return result; | 3788 return result; |
| 3901 } | 3789 } |
| 3902 | 3790 |
| 3903 base::string16 BrowserAccessibilityWin::GetValueText() { | 3791 base::string16 BrowserAccessibilityWin::GetValueText() { |
| 3904 float fval; | 3792 float fval; |
| 3905 base::string16 value = this->value(); | 3793 base::string16 value = this->value(); |
| 3906 | 3794 |
| 3907 if (value.empty() && | 3795 if (value.empty() && |
| 3908 GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, &fval)) { | 3796 GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, &fval)) { |
| 3909 value = base::UTF8ToUTF16(base::DoubleToString(fval)); | 3797 value = base::UTF8ToUTF16(base::DoubleToString(fval)); |
| 3910 } | 3798 } |
| 3911 return value; | 3799 return value; |
| 3912 } | 3800 } |
| 3913 | 3801 |
| 3914 base::string16 BrowserAccessibilityWin::TextForIAccessibleText() const { | 3802 base::string16 BrowserAccessibilityWin::TextForIAccessibleText() { |
| 3915 switch (GetRole()) { | 3803 switch (GetRole()) { |
| 3916 case ui::AX_ROLE_TEXT_FIELD: | 3804 case ui::AX_ROLE_TEXT_FIELD: |
| 3917 case ui::AX_ROLE_MENU_LIST_OPTION: | 3805 case ui::AX_ROLE_MENU_LIST_OPTION: |
| 3918 return value(); | 3806 return value(); |
| 3919 default: | 3807 default: |
| 3920 return hypertext(); | 3808 return hypertext(); |
| 3921 } | 3809 } |
| 3922 } | 3810 } |
| 3923 | 3811 |
| 3924 bool BrowserAccessibilityWin::IsSameHypertextCharacter(size_t old_char_index, | 3812 bool BrowserAccessibilityWin::IsSameHypertextCharacter(size_t old_char_index, |
| (...skipping 686 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4611 ia2_role = ia_role; | 4499 ia2_role = ia_role; |
| 4612 | 4500 |
| 4613 win_attributes_->ia_role = ia_role; | 4501 win_attributes_->ia_role = ia_role; |
| 4614 win_attributes_->ia_state = ia_state; | 4502 win_attributes_->ia_state = ia_state; |
| 4615 win_attributes_->role_name = role_name; | 4503 win_attributes_->role_name = role_name; |
| 4616 win_attributes_->ia2_role = ia2_role; | 4504 win_attributes_->ia2_role = ia2_role; |
| 4617 win_attributes_->ia2_state = ia2_state; | 4505 win_attributes_->ia2_state = ia2_state; |
| 4618 } | 4506 } |
| 4619 | 4507 |
| 4620 } // namespace content | 4508 } // namespace content |
| OLD | NEW |