Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(290)

Side by Side Diff: content/browser/accessibility/browser_accessibility_win.cc

Issue 1195223006: Reports the position of the caret and current selection in content editables. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Added unit tests. Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 #include <algorithm>
dmazzoni 2015/07/16 19:50:23 Nit: don't group this with the Microsoft includes,
9 10
10 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_split.h" 12 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h" 13 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h" 14 #include "base/strings/utf_string_conversions.h"
14 #include "base/win/enum_variant.h" 15 #include "base/win/enum_variant.h"
15 #include "base/win/scoped_comptr.h" 16 #include "base/win/scoped_comptr.h"
16 #include "base/win/windows_version.h" 17 #include "base/win/windows_version.h"
17 #include "content/browser/accessibility/browser_accessibility_manager_win.h" 18 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
18 #include "content/browser/accessibility/browser_accessibility_state_impl.h" 19 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
(...skipping 1978 matching lines...) Expand 10 before | Expand all | Expand 10 after
1997 return S_OK; 1998 return S_OK;
1998 } 1999 }
1999 2000
2000 STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) { 2001 STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) {
2001 if (!instance_active()) 2002 if (!instance_active())
2002 return E_FAIL; 2003 return E_FAIL;
2003 2004
2004 if (!offset) 2005 if (!offset)
2005 return E_INVALIDARG; 2006 return E_INVALIDARG;
2006 2007
2007 // IA2 spec says that caret offset should be -1 if the object is not focused. 2008 int selection_start, selection_end;
2008 if (manager()->GetFocus(this) != this) { 2009 GetSelectionOffsets(&selection_start, &selection_end);
dmazzoni 2015/07/16 19:50:23 Are you 100% sure that this change isn't going to
2009 *offset = -1; 2010 *offset = selection_start;
2011 if (selection_start < 0)
2010 return S_FALSE; 2012 return S_FALSE;
2011 }
2012
2013 *offset = 0;
2014 if (IsEditableText()) {
2015 int sel_start = 0;
2016 if (GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START,
2017 &sel_start))
2018 *offset = sel_start;
2019 }
2020 2013
2021 return S_OK; 2014 return S_OK;
2022 } 2015 }
2023 2016
2024 STDMETHODIMP BrowserAccessibilityWin::get_characterExtents( 2017 STDMETHODIMP BrowserAccessibilityWin::get_characterExtents(
2025 LONG offset, 2018 LONG offset,
2026 enum IA2CoordinateType coordinate_type, 2019 enum IA2CoordinateType coordinate_type,
2027 LONG* out_x, 2020 LONG* out_x,
2028 LONG* out_y, 2021 LONG* out_y,
2029 LONG* out_width, 2022 LONG* out_width,
(...skipping 29 matching lines...) Expand all
2059 } 2052 }
2060 2053
2061 STDMETHODIMP BrowserAccessibilityWin::get_nSelections(LONG* n_selections) { 2054 STDMETHODIMP BrowserAccessibilityWin::get_nSelections(LONG* n_selections) {
2062 if (!instance_active()) 2055 if (!instance_active())
2063 return E_FAIL; 2056 return E_FAIL;
2064 2057
2065 if (!n_selections) 2058 if (!n_selections)
2066 return E_INVALIDARG; 2059 return E_INVALIDARG;
2067 2060
2068 *n_selections = 0; 2061 *n_selections = 0;
2069 if (IsEditableText()) { 2062 int selection_start, selection_end;
2070 int sel_start = 0; 2063 GetSelectionOffsets(&selection_start, &selection_end);
2071 int sel_end = 0; 2064 if (selection_start >= 0 && selection_end >= 0 &&
2072 if (GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START, 2065 selection_start != selection_end)
2073 &sel_start) && 2066 *n_selections = 1;
2074 GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END, &sel_end) &&
2075 sel_start != sel_end)
2076 *n_selections = 1;
2077 }
2078 2067
2079 return S_OK; 2068 return S_OK;
2080 } 2069 }
2081 2070
2082 STDMETHODIMP BrowserAccessibilityWin::get_selection(LONG selection_index, 2071 STDMETHODIMP BrowserAccessibilityWin::get_selection(LONG selection_index,
2083 LONG* start_offset, 2072 LONG* start_offset,
2084 LONG* end_offset) { 2073 LONG* end_offset) {
2085 if (!instance_active()) 2074 if (!instance_active())
2086 return E_FAIL; 2075 return E_FAIL;
2087 2076
2088 if (!start_offset || !end_offset || selection_index != 0) 2077 if (!start_offset || !end_offset || selection_index != 0)
2089 return E_INVALIDARG; 2078 return E_INVALIDARG;
2090 2079
2091 LONG n_selections = 0; 2080 LONG n_selections = 0;
2092 if (FAILED(get_nSelections(&n_selections)) || n_selections < 1) 2081 if (FAILED(get_nSelections(&n_selections)) || n_selections < 1)
2093 return E_INVALIDARG; 2082 return E_INVALIDARG;
2094 2083
2095 *start_offset = 0; 2084 *start_offset = 0;
2096 *end_offset = 0; 2085 *end_offset = 0;
2097 if (IsEditableText()) { 2086 int selection_start, selection_end;
2098 int sel_start = 0; 2087 GetSelectionOffsets(&selection_start, &selection_end);
2099 int sel_end = 0; 2088 if (selection_start >= 0 && selection_end >= 0) {
2100 if (GetIntAttribute( 2089 *start_offset = selection_start;
2101 ui::AX_ATTR_TEXT_SEL_START, &sel_start) && 2090 *end_offset = selection_end;
2102 GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END, &sel_end)) {
2103 *start_offset = sel_start;
2104 *end_offset = sel_end;
2105 }
2106 } 2091 }
2107 2092
2108 return S_OK; 2093 return S_OK;
2109 } 2094 }
2110 2095
2111 STDMETHODIMP BrowserAccessibilityWin::get_text(LONG start_offset, 2096 STDMETHODIMP BrowserAccessibilityWin::get_text(LONG start_offset,
2112 LONG end_offset, 2097 LONG end_offset,
2113 BSTR* text) { 2098 BSTR* text) {
2114 if (!instance_active()) 2099 if (!instance_active())
2115 return E_FAIL; 2100 return E_FAIL;
(...skipping 1530 matching lines...) Expand 10 before | Expand all | Expand 10 after
3646 ui::AXIntAttribute attribute, 3631 ui::AXIntAttribute attribute,
3647 const char* ia2_attr) { 3632 const char* ia2_attr) {
3648 int value; 3633 int value;
3649 if (GetIntAttribute(attribute, &value)) { 3634 if (GetIntAttribute(attribute, &value)) {
3650 win_attributes_->ia2_attributes.push_back( 3635 win_attributes_->ia2_attributes.push_back(
3651 base::ASCIIToUTF16(ia2_attr) + L":" + 3636 base::ASCIIToUTF16(ia2_attr) + L":" +
3652 base::IntToString16(value)); 3637 base::IntToString16(value));
3653 } 3638 }
3654 } 3639 }
3655 3640
3641 int32 BrowserAccessibilityWin::GetHyperlinkIndexFromChild(
3642 const BrowserAccessibilityWin& child) const {
3643 auto iterator = std::find(
3644 hyperlinks().begin(), hyperlinks().end(), child.GetId());
3645 if (iterator == hyperlinks().end())
3646 return -1;
3647
3648 return static_cast<int32>(iterator - hyperlinks().begin());
3649 }
3650
3651 int32 BrowserAccessibilityWin::GetHypertextOffsetFromHyperlinkIndex(
3652 int32 hyperlink_index) const {
3653 auto& offsets_map = hyperlink_offset_to_index();
3654 for (auto& offset_index : offsets_map)
dmazzoni 2015/07/16 19:50:23 Braces around the body of the for loop since there
3655 if (offset_index.second == hyperlink_index)
3656 return offset_index.first;
3657
3658 return -1;
3659 }
3660
3661 int32 BrowserAccessibilityWin::GetHypertextOffsetFromChild(
3662 const BrowserAccessibilityWin& child) const {
3663 int32 hyperlink_index = GetHyperlinkIndexFromChild(child);
3664 if (hyperlink_index < 0)
3665 return -1;
3666
3667 return GetHypertextOffsetFromHyperlinkIndex(hyperlink_index);
3668 }
3669
3670 int32 BrowserAccessibilityWin::GetHypertextOffsetFromDescendant(
3671 const BrowserAccessibilityWin& descendant) const {
3672 auto parent_object = descendant.GetParent()->ToBrowserAccessibilityWin();
3673 auto current_object = const_cast<BrowserAccessibilityWin*>(&descendant);
3674 while (parent_object && parent_object != this) {
3675 current_object = parent_object;
3676 parent_object = current_object->GetParent()->ToBrowserAccessibilityWin();
3677 }
3678 if (!parent_object)
3679 return -1;
3680
3681 return parent_object->GetHypertextOffsetFromChild(*current_object);
3682 }
3683
3684 int BrowserAccessibilityWin::GetSelectionAnchor() const {
3685 BrowserAccessibility* root = manager()->GetRoot();
3686 int32 anchor_id;
3687 if (!root || !root->GetIntAttribute(ui::AX_ATTR_ANCHOR_OBJECT_ID, &anchor_id))
3688 return -1;
3689
3690 BrowserAccessibilityWin* anchor_object = manager()->GetFromID(
3691 anchor_id)->ToBrowserAccessibilityWin();
3692 if (!anchor_object)
3693 return -1;
3694
3695 if (anchor_object->IsDescendantOf(this))
3696 return GetHypertextOffsetFromDescendant(*anchor_object);
3697
3698 if (IsDescendantOf(anchor_object)) {
3699 int anchor_offset;
3700 if (!root->GetIntAttribute(ui::AX_ATTR_ANCHOR_OFFSET, &anchor_offset))
3701 return -1;
3702
3703 return anchor_offset;
3704 }
3705
3706 return -1;
3707 }
3708
3709 int BrowserAccessibilityWin::GetSelectionFocus() const {
3710 BrowserAccessibility* root = manager()->GetRoot();
3711 int32 focus_id;
3712 if (!root || !root->GetIntAttribute(ui::AX_ATTR_FOCUS_OBJECT_ID, &focus_id))
3713 return -1;
3714
3715 BrowserAccessibilityWin* focus_object = manager()->GetFromID(
3716 focus_id)->ToBrowserAccessibilityWin();
3717 if (!focus_object)
3718 return -1;
3719
3720 if (focus_object->IsDescendantOf(this))
3721 return GetHypertextOffsetFromDescendant(*focus_object);
3722
3723 if (IsDescendantOf(focus_object)) {
3724 int focus_offset;
3725 if (!root->GetIntAttribute(ui::AX_ATTR_FOCUS_OFFSET, &focus_offset))
3726 return -1;
3727
3728 return focus_offset;
3729 }
3730
3731 return -1;
3732 }
3733
3734 void BrowserAccessibilityWin::GetSelectionOffsets(
3735 int* selection_start, int* selection_end) const {
3736 if (!selection_start || !selection_end)
3737 return;
3738
3739 if (GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START, selection_start) &&
3740 GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END, selection_end)) {
3741 return;
3742 }
3743
3744 *selection_start = GetSelectionAnchor();
3745 *selection_end = GetSelectionFocus();
3746 if (*selection_start < 0 || *selection_end < 0)
3747 return;
3748
3749 if (*selection_end < *selection_start)
3750 std::swap(*selection_start, *selection_end);
dmazzoni 2015/07/16 19:50:23 Are you sure this is correct? I think IA2 might su
3751
3752 // IA2 Spec says that the end of the selection should be after the last
3753 // embedded object character that is part of the selection.
3754 ++(*selection_end);
3755 }
3756
3656 base::string16 BrowserAccessibilityWin::GetNameRecursive() const { 3757 base::string16 BrowserAccessibilityWin::GetNameRecursive() const {
3657 if (!name().empty()) { 3758 if (!name().empty()) {
3658 return name(); 3759 return name();
3659 } 3760 }
3660 3761
3661 base::string16 result; 3762 base::string16 result;
3662 for (uint32 i = 0; i < PlatformChildCount(); ++i) { 3763 for (uint32 i = 0; i < PlatformChildCount(); ++i) {
3663 result += PlatformGetChild(i)->ToBrowserAccessibilityWin()-> 3764 result += PlatformGetChild(i)->ToBrowserAccessibilityWin()->
3664 GetNameRecursive(); 3765 GetNameRecursive();
3665 } 3766 }
(...skipping 711 matching lines...) Expand 10 before | Expand all | Expand 10 after
4377 ia2_role = ia_role; 4478 ia2_role = ia_role;
4378 4479
4379 win_attributes_->ia_role = ia_role; 4480 win_attributes_->ia_role = ia_role;
4380 win_attributes_->ia_state = ia_state; 4481 win_attributes_->ia_state = ia_state;
4381 win_attributes_->role_name = role_name; 4482 win_attributes_->role_name = role_name;
4382 win_attributes_->ia2_role = ia2_role; 4483 win_attributes_->ia2_role = ia2_role;
4383 win_attributes_->ia2_state = ia2_state; 4484 win_attributes_->ia2_state = ia2_state;
4384 } 4485 }
4385 4486
4386 } // namespace content 4487 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698