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 2244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |