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 2468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2479 BSTR* text) { | 2479 BSTR* text) { |
2480 WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_TEXT_AT_OFFSET); | 2480 WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_TEXT_AT_OFFSET); |
2481 AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes | | 2481 AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes | |
2482 AccessibilityMode::kInlineTextBoxes); | 2482 AccessibilityMode::kInlineTextBoxes); |
2483 if (!instance_active()) | 2483 if (!instance_active()) |
2484 return E_FAIL; | 2484 return E_FAIL; |
2485 | 2485 |
2486 if (!start_offset || !end_offset || !text) | 2486 if (!start_offset || !end_offset || !text) |
2487 return E_INVALIDARG; | 2487 return E_INVALIDARG; |
2488 | 2488 |
2489 const base::string16& text_str = GetText(); | |
2490 HandleSpecialTextOffset(&offset); | 2489 HandleSpecialTextOffset(&offset); |
2491 if (offset < 0) | 2490 if (offset < 0) |
2492 return E_INVALIDARG; | 2491 return E_INVALIDARG; |
2493 | 2492 |
2493 const base::string16& text_str = GetText(); | |
2494 LONG text_len = text_str.length(); | 2494 LONG text_len = text_str.length(); |
2495 if (offset > text_len) | 2495 if (offset > text_len) |
2496 return E_INVALIDARG; | 2496 return E_INVALIDARG; |
2497 | 2497 |
2498 // The IAccessible2 spec says we don't have to implement the "sentence" | 2498 // The IAccessible2 spec says we don't have to implement the "sentence" |
2499 // boundary type, we can just let the screenreader handle it. | 2499 // boundary type, we can just let the screenreader handle it. |
2500 if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) { | 2500 if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) { |
2501 *start_offset = 0; | 2501 *start_offset = 0; |
2502 *end_offset = 0; | 2502 *end_offset = 0; |
2503 *text = NULL; | 2503 *text = NULL; |
(...skipping 1378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3882 start_offset += child->GetText().length(); | 3882 start_offset += child->GetText().length(); |
3883 else | 3883 else |
3884 start_offset += 1; | 3884 start_offset += 1; |
3885 } | 3885 } |
3886 | 3886 |
3887 win_attributes_->offset_to_text_attributes.swap(attributes_map); | 3887 win_attributes_->offset_to_text_attributes.swap(attributes_map); |
3888 } | 3888 } |
3889 | 3889 |
3890 // |offset| could either be a text character or a child index in case of | 3890 // |offset| could either be a text character or a child index in case of |
3891 // non-text objects. | 3891 // non-text objects. |
3892 // TODO(nektar): Remove this function once selection bugs are fixed in Blink. | |
3892 BrowserAccessibilityWin::AXPlatformPositionInstance | 3893 BrowserAccessibilityWin::AXPlatformPositionInstance |
3893 BrowserAccessibilityWin::CreatePositionAt(int offset) const { | 3894 BrowserAccessibilityWin::CreatePositionForSelectionAt(int offset) const { |
3894 if (!IsNativeTextControl() && !IsTextOnlyObject()) { | 3895 if (!IsNativeTextControl() && !IsTextOnlyObject()) { |
3895 DCHECK(manager_); | 3896 DCHECK(manager_); |
3896 const BrowserAccessibilityWin* child = this; | 3897 const BrowserAccessibilityWin* child = this; |
3897 // TODO(nektar): Make parents of text-only objects not include the text of | 3898 // TODO(nektar): Make parents of text-only objects not include the text of |
3898 // children in their hypertext. | 3899 // children in their hypertext. |
3899 for (size_t i = 0; i < InternalChildCount(); ++i) { | 3900 for (size_t i = 0; i < InternalChildCount(); ++i) { |
3900 int new_offset = offset; | 3901 int new_offset = offset; |
3901 child = ToBrowserAccessibilityWin(InternalGetChild(i)); | 3902 child = ToBrowserAccessibilityWin(InternalGetChild(i)); |
3902 DCHECK(child); | 3903 DCHECK(child); |
3903 if (child->IsTextOnlyObject()) { | 3904 if (child->IsTextOnlyObject()) { |
3904 new_offset -= child->GetText().length(); | 3905 new_offset -= child->GetText().length(); |
3905 } else { | 3906 } else { |
3906 new_offset -= 1; | 3907 new_offset -= 1; |
3907 } | 3908 } |
3908 if (new_offset <= 0) | 3909 if (new_offset <= 0) |
3909 break; | 3910 break; |
3910 offset = new_offset; | 3911 offset = new_offset; |
3911 } | 3912 } |
3912 AXPlatformPositionInstance position = | 3913 AXPlatformPositionInstance position = |
3913 AXPlatformPosition::CreateTextPosition(manager_->ax_tree_id(), | 3914 AXPlatformPosition::CreateTextPosition(manager_->ax_tree_id(), |
3914 child->GetId(), offset, | 3915 child->GetId(), offset, |
3915 ui::AX_TEXT_AFFINITY_DOWNSTREAM) | 3916 ui::AX_TEXT_AFFINITY_DOWNSTREAM) |
3916 ->AsLeafTextPosition(); | 3917 ->AsLeafTextPosition(); |
3917 if (position->GetAnchor() && | 3918 if (position->GetAnchor() && |
3918 position->GetAnchor()->GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX) { | 3919 position->GetAnchor()->GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX) { |
3919 return position->CreateParentPosition(); | 3920 return position->CreateParentPosition(); |
3920 } | 3921 } |
3921 return position; | 3922 return position; |
3922 } | 3923 } |
3923 return BrowserAccessibility::CreatePositionAt(offset); | 3924 return CreatePositionAt(offset); |
3924 } | 3925 } |
3925 | 3926 |
3926 base::string16 BrowserAccessibilityWin::GetText() const { | 3927 base::string16 BrowserAccessibilityWin::GetText() const { |
3927 if (PlatformIsChildOfLeaf()) | 3928 if (PlatformIsChildOfLeaf()) |
3928 return BrowserAccessibility::GetText(); | 3929 return BrowserAccessibility::GetText(); |
3929 return win_attributes_->hypertext; | 3930 return win_attributes_->hypertext; |
3930 } | 3931 } |
3931 | 3932 |
3932 // | 3933 // |
3933 // Private methods. | 3934 // Private methods. |
(...skipping 636 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4570 base::ReplaceChars(*output, L",", L"\\,", output); | 4571 base::ReplaceChars(*output, L",", L"\\,", output); |
4571 base::ReplaceChars(*output, L"=", L"\\=", output); | 4572 base::ReplaceChars(*output, L"=", L"\\=", output); |
4572 base::ReplaceChars(*output, L";", L"\\;", output); | 4573 base::ReplaceChars(*output, L";", L"\\;", output); |
4573 } | 4574 } |
4574 | 4575 |
4575 void BrowserAccessibilityWin::SetIA2HypertextSelection(LONG start_offset, | 4576 void BrowserAccessibilityWin::SetIA2HypertextSelection(LONG start_offset, |
4576 LONG end_offset) { | 4577 LONG end_offset) { |
4577 HandleSpecialTextOffset(&start_offset); | 4578 HandleSpecialTextOffset(&start_offset); |
4578 HandleSpecialTextOffset(&end_offset); | 4579 HandleSpecialTextOffset(&end_offset); |
4579 AXPlatformPositionInstance start_position = | 4580 AXPlatformPositionInstance start_position = |
4580 CreatePositionAt(static_cast<int>(start_offset)); | 4581 CreatePositionForSelectionAt(static_cast<int>(start_offset)); |
4581 AXPlatformPositionInstance end_position = | 4582 AXPlatformPositionInstance end_position = |
4582 CreatePositionAt(static_cast<int>(end_offset)); | 4583 CreatePositionForSelectionAt(static_cast<int>(end_offset)); |
4583 manager_->SetSelection(AXPlatformRange(start_position->AsTextPosition(), | 4584 manager_->SetSelection(AXPlatformRange(start_position->AsTextPosition(), |
4584 end_position->AsTextPosition())); | 4585 end_position->AsTextPosition())); |
4585 } | 4586 } |
4586 | 4587 |
4587 void BrowserAccessibilityWin::StringAttributeToIA2( | 4588 void BrowserAccessibilityWin::StringAttributeToIA2( |
4588 ui::AXStringAttribute attribute, | 4589 ui::AXStringAttribute attribute, |
4589 const char* ia2_attr) { | 4590 const char* ia2_attr) { |
4590 base::string16 value; | 4591 base::string16 value; |
4591 if (GetString16Attribute(attribute, &value)) { | 4592 if (GetString16Attribute(attribute, &value)) { |
4592 SanitizeStringAttributeForIA2(value, &value); | 4593 SanitizeStringAttributeForIA2(value, &value); |
(...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4980 IA2TextBoundaryType ia2_boundary, | 4981 IA2TextBoundaryType ia2_boundary, |
4981 LONG start_offset, | 4982 LONG start_offset, |
4982 ui::TextBoundaryDirection direction) { | 4983 ui::TextBoundaryDirection direction) { |
4983 // If the boundary is relative to the caret, use the selection | 4984 // If the boundary is relative to the caret, use the selection |
4984 // affinity, otherwise default to downstream affinity. | 4985 // affinity, otherwise default to downstream affinity. |
4985 ui::AXTextAffinity affinity = start_offset == IA2_TEXT_OFFSET_CARET | 4986 ui::AXTextAffinity affinity = start_offset == IA2_TEXT_OFFSET_CARET |
4986 ? manager_->GetTreeData().sel_focus_affinity | 4987 ? manager_->GetTreeData().sel_focus_affinity |
4987 : ui::AX_TEXT_AFFINITY_DOWNSTREAM; | 4988 : ui::AX_TEXT_AFFINITY_DOWNSTREAM; |
4988 | 4989 |
4989 HandleSpecialTextOffset(&start_offset); | 4990 HandleSpecialTextOffset(&start_offset); |
4990 if (ia2_boundary == IA2_TEXT_BOUNDARY_WORD) | 4991 if (ia2_boundary == IA2_TEXT_BOUNDARY_WORD) { |
4991 return GetWordStartBoundary(static_cast<int>(start_offset), direction); | 4992 switch (direction) { |
4992 if (ia2_boundary == IA2_TEXT_BOUNDARY_LINE) { | 4993 case ui::FORWARDS_DIRECTION: { |
4993 return GetLineStartBoundary( | 4994 AXPlatformPositionInstance position = |
4994 static_cast<int>(start_offset), direction, affinity); | 4995 CreatePositionAt(static_cast<int>(start_offset), affinity); |
4996 AXPlatformPositionInstance next_word = | |
4997 position->CreateNextWordStartPosition(); | |
4998 if (next_word->IsNullPosition()) | |
4999 next_word = position->CreatePositionAtEndOfAnchor(); | |
5000 return next_word->text_offset(); | |
5001 } | |
5002 case ui::BACKWARDS_DIRECTION: { | |
5003 AXPlatformPositionInstance position = | |
5004 CreatePositionAt(static_cast<int>(start_offset), affinity); | |
5005 AXPlatformPositionInstance previous_word; | |
5006 if (!position->AtStartOfWord()) { | |
5007 previous_word = position->CreatePreviousWordStartPosition(); | |
dmazzoni
2017/04/10 22:39:49
Just curious, should CreatePreviousWordStartPositi
| |
5008 if (previous_word->IsNullPosition()) | |
5009 previous_word = position->CreatePositionAtStartOfAnchor(); | |
5010 } else { | |
5011 previous_word = std::move(position); | |
5012 } | |
5013 return previous_word->text_offset(); | |
5014 } | |
5015 } | |
dmazzoni
2017/04/10 22:39:49
Maybe add a NOTREACHED() after the switch since th
| |
4995 } | 5016 } |
4996 | 5017 |
5018 if (ia2_boundary == IA2_TEXT_BOUNDARY_LINE) { | |
5019 switch (direction) { | |
5020 case ui::FORWARDS_DIRECTION: { | |
5021 AXPlatformPositionInstance position = | |
5022 CreatePositionAt(static_cast<int>(start_offset), affinity); | |
5023 AXPlatformPositionInstance next_line = | |
5024 position->CreateNextLineStartPosition(); | |
5025 if (next_line->IsNullPosition()) | |
5026 next_line = position->CreatePositionAtEndOfAnchor(); | |
5027 return next_line->text_offset(); | |
5028 } | |
5029 case ui::BACKWARDS_DIRECTION: { | |
5030 AXPlatformPositionInstance position = | |
5031 CreatePositionAt(static_cast<int>(start_offset), affinity); | |
5032 AXPlatformPositionInstance previous_line; | |
5033 if (!position->AtStartOfLine()) { | |
5034 previous_line = position->CreatePreviousLineStartPosition(); | |
5035 if (previous_line->IsNullPosition()) | |
5036 previous_line = position->CreatePositionAtStartOfAnchor(); | |
5037 } else { | |
5038 previous_line = std::move(position); | |
5039 } | |
5040 return previous_line->text_offset(); | |
5041 } | |
5042 } | |
dmazzoni
2017/04/10 22:39:49
NOTREACHED
| |
5043 } | |
5044 | |
5045 // TODO(nektar): |AXPosition| can handle other types of boundaries as well. | |
4997 ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary); | 5046 ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary); |
4998 return ui::FindAccessibleTextBoundary(text, GetLineStartOffsets(), boundary, | 5047 return ui::FindAccessibleTextBoundary(text, GetLineStartOffsets(), boundary, |
4999 start_offset, direction, affinity); | 5048 start_offset, direction, affinity); |
5000 } | 5049 } |
5001 | 5050 |
5002 LONG BrowserAccessibilityWin::FindStartOfStyle( | 5051 LONG BrowserAccessibilityWin::FindStartOfStyle( |
5003 LONG start_offset, | 5052 LONG start_offset, |
5004 ui::TextBoundaryDirection direction) const { | 5053 ui::TextBoundaryDirection direction) const { |
5005 LONG text_length = static_cast<LONG>(GetText().length()); | 5054 LONG text_length = static_cast<LONG>(GetText().length()); |
5006 DCHECK_GE(start_offset, 0); | 5055 DCHECK_GE(start_offset, 0); |
(...skipping 826 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5833 return static_cast<BrowserAccessibilityWin*>(obj); | 5882 return static_cast<BrowserAccessibilityWin*>(obj); |
5834 } | 5883 } |
5835 | 5884 |
5836 const BrowserAccessibilityWin* | 5885 const BrowserAccessibilityWin* |
5837 ToBrowserAccessibilityWin(const BrowserAccessibility* obj) { | 5886 ToBrowserAccessibilityWin(const BrowserAccessibility* obj) { |
5838 DCHECK(!obj || obj->IsNative()); | 5887 DCHECK(!obj || obj->IsNative()); |
5839 return static_cast<const BrowserAccessibilityWin*>(obj); | 5888 return static_cast<const BrowserAccessibilityWin*>(obj); |
5840 } | 5889 } |
5841 | 5890 |
5842 } // namespace content | 5891 } // namespace content |
OLD | NEW |