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

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

Issue 2806773002: Switched to using |AXPosition| for calculating word and line boundaries on Windows. (Closed)
Patch Set: Fixed unit tests. Created 3 years, 8 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 9
10 #include <algorithm> 10 #include <algorithm>
(...skipping 2244 matching lines...) Expand 10 before | Expand all | Expand 10 after
2255 BSTR* text) { 2255 BSTR* text) {
2256 WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_TEXT_AT_OFFSET); 2256 WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_TEXT_AT_OFFSET);
2257 AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes | 2257 AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes |
2258 AccessibilityMode::kInlineTextBoxes); 2258 AccessibilityMode::kInlineTextBoxes);
2259 if (!instance_active()) 2259 if (!instance_active())
2260 return E_FAIL; 2260 return E_FAIL;
2261 2261
2262 if (!start_offset || !end_offset || !text) 2262 if (!start_offset || !end_offset || !text)
2263 return E_INVALIDARG; 2263 return E_INVALIDARG;
2264 2264
2265 const base::string16& text_str = GetText();
2266 HandleSpecialTextOffset(&offset); 2265 HandleSpecialTextOffset(&offset);
2267 if (offset < 0) 2266 if (offset < 0)
2268 return E_INVALIDARG; 2267 return E_INVALIDARG;
2269 2268
2269 const base::string16& text_str = GetText();
2270 LONG text_len = text_str.length(); 2270 LONG text_len = text_str.length();
2271 if (offset > text_len) 2271 if (offset > text_len)
2272 return E_INVALIDARG; 2272 return E_INVALIDARG;
2273 2273
2274 // The IAccessible2 spec says we don't have to implement the "sentence" 2274 // The IAccessible2 spec says we don't have to implement the "sentence"
2275 // boundary type, we can just let the screenreader handle it. 2275 // boundary type, we can just let the screenreader handle it.
2276 if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) { 2276 if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
2277 *start_offset = 0; 2277 *start_offset = 0;
2278 *end_offset = 0; 2278 *end_offset = 0;
2279 *text = NULL; 2279 *text = NULL;
(...skipping 1378 matching lines...) Expand 10 before | Expand all | Expand 10 after
3658 start_offset += child->GetText().length(); 3658 start_offset += child->GetText().length();
3659 else 3659 else
3660 start_offset += 1; 3660 start_offset += 1;
3661 } 3661 }
3662 3662
3663 win_attributes_->offset_to_text_attributes.swap(attributes_map); 3663 win_attributes_->offset_to_text_attributes.swap(attributes_map);
3664 } 3664 }
3665 3665
3666 // |offset| could either be a text character or a child index in case of 3666 // |offset| could either be a text character or a child index in case of
3667 // non-text objects. 3667 // non-text objects.
3668 // TODO(nektar): Remove this function once selection bugs are fixed in Blink.
3668 BrowserAccessibilityWin::AXPlatformPositionInstance 3669 BrowserAccessibilityWin::AXPlatformPositionInstance
3669 BrowserAccessibilityWin::CreatePositionAt(int offset) const { 3670 BrowserAccessibilityWin::CreatePositionForSelectionAt(int offset) const {
3670 if (!IsNativeTextControl() && !IsTextOnlyObject()) { 3671 if (!IsNativeTextControl() && !IsTextOnlyObject()) {
3671 DCHECK(manager_); 3672 DCHECK(manager_);
3672 const BrowserAccessibilityWin* child = this; 3673 const BrowserAccessibilityWin* child = this;
3673 // TODO(nektar): Make parents of text-only objects not include the text of 3674 // TODO(nektar): Make parents of text-only objects not include the text of
3674 // children in their hypertext. 3675 // children in their hypertext.
3675 for (size_t i = 0; i < InternalChildCount(); ++i) { 3676 for (size_t i = 0; i < InternalChildCount(); ++i) {
3676 int new_offset = offset; 3677 int new_offset = offset;
3677 child = ToBrowserAccessibilityWin(InternalGetChild(i)); 3678 child = ToBrowserAccessibilityWin(InternalGetChild(i));
3678 DCHECK(child); 3679 DCHECK(child);
3679 if (child->IsTextOnlyObject()) { 3680 if (child->IsTextOnlyObject()) {
3680 new_offset -= child->GetText().length(); 3681 new_offset -= child->GetText().length();
3681 } else { 3682 } else {
3682 new_offset -= 1; 3683 new_offset -= 1;
3683 } 3684 }
3684 if (new_offset <= 0) 3685 if (new_offset <= 0)
3685 break; 3686 break;
3686 offset = new_offset; 3687 offset = new_offset;
3687 } 3688 }
3688 AXPlatformPositionInstance position = 3689 AXPlatformPositionInstance position =
3689 AXPlatformPosition::CreateTextPosition(manager_->ax_tree_id(), 3690 AXPlatformPosition::CreateTextPosition(manager_->ax_tree_id(),
3690 child->GetId(), offset, 3691 child->GetId(), offset,
3691 ui::AX_TEXT_AFFINITY_DOWNSTREAM) 3692 ui::AX_TEXT_AFFINITY_DOWNSTREAM)
3692 ->AsLeafTextPosition(); 3693 ->AsLeafTextPosition();
3693 if (position->GetAnchor() && 3694 if (position->GetAnchor() &&
3694 position->GetAnchor()->GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX) { 3695 position->GetAnchor()->GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX) {
3695 return position->CreateParentPosition(); 3696 return position->CreateParentPosition();
3696 } 3697 }
3697 return position; 3698 return position;
3698 } 3699 }
3699 return BrowserAccessibility::CreatePositionAt(offset); 3700 return CreatePositionAt(offset);
3700 } 3701 }
3701 3702
3702 base::string16 BrowserAccessibilityWin::GetText() const { 3703 base::string16 BrowserAccessibilityWin::GetText() const {
3703 if (PlatformIsChildOfLeaf()) 3704 if (PlatformIsChildOfLeaf())
3704 return BrowserAccessibility::GetText(); 3705 return BrowserAccessibility::GetText();
3705 return win_attributes_->hypertext; 3706 return win_attributes_->hypertext;
3706 } 3707 }
3707 3708
3708 // 3709 //
3709 // Private methods. 3710 // Private methods.
(...skipping 620 matching lines...) Expand 10 before | Expand all | Expand 10 after
4330 base::ReplaceChars(*output, L",", L"\\,", output); 4331 base::ReplaceChars(*output, L",", L"\\,", output);
4331 base::ReplaceChars(*output, L"=", L"\\=", output); 4332 base::ReplaceChars(*output, L"=", L"\\=", output);
4332 base::ReplaceChars(*output, L";", L"\\;", output); 4333 base::ReplaceChars(*output, L";", L"\\;", output);
4333 } 4334 }
4334 4335
4335 void BrowserAccessibilityWin::SetIA2HypertextSelection(LONG start_offset, 4336 void BrowserAccessibilityWin::SetIA2HypertextSelection(LONG start_offset,
4336 LONG end_offset) { 4337 LONG end_offset) {
4337 HandleSpecialTextOffset(&start_offset); 4338 HandleSpecialTextOffset(&start_offset);
4338 HandleSpecialTextOffset(&end_offset); 4339 HandleSpecialTextOffset(&end_offset);
4339 AXPlatformPositionInstance start_position = 4340 AXPlatformPositionInstance start_position =
4340 CreatePositionAt(static_cast<int>(start_offset)); 4341 CreatePositionForSelectionAt(static_cast<int>(start_offset));
4341 AXPlatformPositionInstance end_position = 4342 AXPlatformPositionInstance end_position =
4342 CreatePositionAt(static_cast<int>(end_offset)); 4343 CreatePositionForSelectionAt(static_cast<int>(end_offset));
4343 manager_->SetSelection(AXPlatformRange(start_position->AsTextPosition(), 4344 manager_->SetSelection(AXPlatformRange(start_position->AsTextPosition(),
4344 end_position->AsTextPosition())); 4345 end_position->AsTextPosition()));
4345 } 4346 }
4346 4347
4347 void BrowserAccessibilityWin::StringAttributeToIA2( 4348 void BrowserAccessibilityWin::StringAttributeToIA2(
4348 ui::AXStringAttribute attribute, 4349 ui::AXStringAttribute attribute,
4349 const char* ia2_attr) { 4350 const char* ia2_attr) {
4350 base::string16 value; 4351 base::string16 value;
4351 if (GetString16Attribute(attribute, &value)) { 4352 if (GetString16Attribute(attribute, &value)) {
4352 SanitizeStringAttributeForIA2(value, &value); 4353 SanitizeStringAttributeForIA2(value, &value);
(...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after
4740 IA2TextBoundaryType ia2_boundary, 4741 IA2TextBoundaryType ia2_boundary,
4741 LONG start_offset, 4742 LONG start_offset,
4742 ui::TextBoundaryDirection direction) { 4743 ui::TextBoundaryDirection direction) {
4743 // If the boundary is relative to the caret, use the selection 4744 // If the boundary is relative to the caret, use the selection
4744 // affinity, otherwise default to downstream affinity. 4745 // affinity, otherwise default to downstream affinity.
4745 ui::AXTextAffinity affinity = start_offset == IA2_TEXT_OFFSET_CARET 4746 ui::AXTextAffinity affinity = start_offset == IA2_TEXT_OFFSET_CARET
4746 ? manager_->GetTreeData().sel_focus_affinity 4747 ? manager_->GetTreeData().sel_focus_affinity
4747 : ui::AX_TEXT_AFFINITY_DOWNSTREAM; 4748 : ui::AX_TEXT_AFFINITY_DOWNSTREAM;
4748 4749
4749 HandleSpecialTextOffset(&start_offset); 4750 HandleSpecialTextOffset(&start_offset);
4750 if (ia2_boundary == IA2_TEXT_BOUNDARY_WORD) 4751 if (ia2_boundary == IA2_TEXT_BOUNDARY_WORD) {
4751 return GetWordStartBoundary(static_cast<int>(start_offset), direction); 4752 switch (direction) {
4752 if (ia2_boundary == IA2_TEXT_BOUNDARY_LINE) { 4753 case ui::FORWARDS_DIRECTION: {
4753 return GetLineStartBoundary( 4754 AXPlatformPositionInstance position =
4754 static_cast<int>(start_offset), direction, affinity); 4755 CreatePositionAt(static_cast<int>(start_offset), affinity);
4756 AXPlatformPositionInstance next_word =
4757 position->CreateNextWordStartPosition();
4758 if (next_word->anchor_id() != GetId())
4759 next_word = position->CreatePositionAtEndOfAnchor();
4760 return next_word->text_offset();
4761 }
4762 case ui::BACKWARDS_DIRECTION: {
4763 AXPlatformPositionInstance position =
4764 CreatePositionAt(static_cast<int>(start_offset), affinity);
4765 AXPlatformPositionInstance previous_word;
4766 if (!position->AtStartOfWord()) {
4767 previous_word = position->CreatePreviousWordStartPosition();
4768 if (previous_word->anchor_id() != GetId())
4769 previous_word = position->CreatePositionAtStartOfAnchor();
4770 } else {
4771 previous_word = std::move(position);
4772 }
4773 return previous_word->text_offset();
4774 }
4775 }
4755 } 4776 }
4756 4777
4778 if (ia2_boundary == IA2_TEXT_BOUNDARY_LINE) {
4779 switch (direction) {
4780 case ui::FORWARDS_DIRECTION: {
4781 AXPlatformPositionInstance position =
4782 CreatePositionAt(static_cast<int>(start_offset), affinity);
4783 AXPlatformPositionInstance next_line =
4784 position->CreateNextLineStartPosition();
4785 if (next_line->anchor_id() != GetId())
4786 next_line = position->CreatePositionAtEndOfAnchor();
4787 return next_line->text_offset();
4788 }
4789 case ui::BACKWARDS_DIRECTION: {
4790 AXPlatformPositionInstance position =
4791 CreatePositionAt(static_cast<int>(start_offset), affinity);
4792 AXPlatformPositionInstance previous_line;
4793 if (!position->AtStartOfLine()) {
4794 previous_line = position->CreatePreviousLineStartPosition();
4795 if (previous_line->anchor_id() != GetId())
4796 previous_line = position->CreatePositionAtStartOfAnchor();
4797 } else {
4798 previous_line = std::move(position);
4799 }
4800 return previous_line->text_offset();
4801 }
4802 }
4803 }
4804
4805 // TODO(nektar): |AXPosition| can handle other types of boundaries as well.
4757 ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary); 4806 ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary);
4758 return ui::FindAccessibleTextBoundary(text, GetLineStartOffsets(), boundary, 4807 return ui::FindAccessibleTextBoundary(text, GetLineStartOffsets(), boundary,
4759 start_offset, direction, affinity); 4808 start_offset, direction, affinity);
4760 } 4809 }
4761 4810
4762 LONG BrowserAccessibilityWin::FindStartOfStyle( 4811 LONG BrowserAccessibilityWin::FindStartOfStyle(
4763 LONG start_offset, 4812 LONG start_offset,
4764 ui::TextBoundaryDirection direction) const { 4813 ui::TextBoundaryDirection direction) const {
4765 LONG text_length = static_cast<LONG>(GetText().length()); 4814 LONG text_length = static_cast<LONG>(GetText().length());
4766 DCHECK_GE(start_offset, 0); 4815 DCHECK_GE(start_offset, 0);
(...skipping 834 matching lines...) Expand 10 before | Expand all | Expand 10 after
5601 return static_cast<BrowserAccessibilityWin*>(obj); 5650 return static_cast<BrowserAccessibilityWin*>(obj);
5602 } 5651 }
5603 5652
5604 const BrowserAccessibilityWin* 5653 const BrowserAccessibilityWin*
5605 ToBrowserAccessibilityWin(const BrowserAccessibility* obj) { 5654 ToBrowserAccessibilityWin(const BrowserAccessibility* obj) {
5606 DCHECK(!obj || obj->IsNative()); 5655 DCHECK(!obj || obj->IsNative());
5607 return static_cast<const BrowserAccessibilityWin*>(obj); 5656 return static_cast<const BrowserAccessibilityWin*>(obj);
5608 } 5657 }
5609 5658
5610 } // namespace content 5659 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698