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

Side by Side Diff: content/browser/accessibility/browser_accessibility_cocoa.mm

Issue 2565833002: Uses |AXPosition| to enable navigation by character, word and line in content editables on the Mac. (Closed)
Patch Set: Fixed some boundary errors. Created 4 years 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
« no previous file with comments | « no previous file | ui/accessibility/ax_node_position_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 #import "content/browser/accessibility/browser_accessibility_cocoa.h"
6
5 #include <execinfo.h> 7 #include <execinfo.h>
6 #include <stddef.h> 8 #include <stddef.h>
7 #include <stdint.h> 9 #include <stdint.h>
8 10 #include <string.h>
9 #import "content/browser/accessibility/browser_accessibility_cocoa.h"
10 11
11 #include <map> 12 #include <map>
13 #include <memory>
14 #include <utility>
12 15
13 #include "base/mac/foundation_util.h" 16 #include "base/mac/foundation_util.h"
14 #include "base/mac/scoped_cftyperef.h" 17 #include "base/mac/scoped_cftyperef.h"
15 #include "base/strings/string16.h" 18 #include "base/strings/string16.h"
16 #include "base/strings/sys_string_conversions.h" 19 #include "base/strings/sys_string_conversions.h"
17 #include "base/strings/utf_string_conversions.h" 20 #include "base/strings/utf_string_conversions.h"
18 #include "content/app/strings/grit/content_strings.h" 21 #include "content/app/strings/grit/content_strings.h"
19 #include "content/browser/accessibility/ax_platform_position.h" 22 #include "content/browser/accessibility/ax_platform_position.h"
20 #include "content/browser/accessibility/browser_accessibility_mac.h" 23 #include "content/browser/accessibility/browser_accessibility_mac.h"
21 #include "content/browser/accessibility/browser_accessibility_manager.h" 24 #include "content/browser/accessibility/browser_accessibility_manager.h"
22 #include "content/browser/accessibility/browser_accessibility_manager_mac.h" 25 #include "content/browser/accessibility/browser_accessibility_manager_mac.h"
23 #include "content/browser/accessibility/one_shot_accessibility_tree_search.h" 26 #include "content/browser/accessibility/one_shot_accessibility_tree_search.h"
24 #include "content/public/common/content_client.h" 27 #include "content/public/common/content_client.h"
25 #include "third_party/skia/include/core/SkColor.h" 28 #include "third_party/skia/include/core/SkColor.h"
29 #include "ui/accessibility/ax_range.h"
26 #import "ui/accessibility/platform/ax_platform_node_mac.h" 30 #import "ui/accessibility/platform/ax_platform_node_mac.h"
27 31
32 using AXPlatformPositionInstance =
33 content::AXPlatformPosition::AXPositionInstance;
34 using AXPlatformRange = ui::AXRange<AXPlatformPositionInstance::element_type>;
28 using content::AXPlatformPosition; 35 using content::AXPlatformPosition;
29 using content::AXTreeIDRegistry; 36 using content::AXTreeIDRegistry;
30 using content::AccessibilityMatchPredicate; 37 using content::AccessibilityMatchPredicate;
31 using content::BrowserAccessibility; 38 using content::BrowserAccessibility;
32 using content::BrowserAccessibilityDelegate; 39 using content::BrowserAccessibilityDelegate;
33 using content::BrowserAccessibilityManager; 40 using content::BrowserAccessibilityManager;
34 using content::BrowserAccessibilityManagerMac; 41 using content::BrowserAccessibilityManagerMac;
35 using content::ContentClient; 42 using content::ContentClient;
36 using content::OneShotAccessibilityTreeSearch; 43 using content::OneShotAccessibilityTreeSearch;
37 using ui::AXNodeData; 44 using ui::AXNodeData;
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 AXTextMarkerRef AXTextMarkerRangeCopyStartMarker( 128 AXTextMarkerRef AXTextMarkerRangeCopyStartMarker(
122 AXTextMarkerRangeRef text_marker_range); 129 AXTextMarkerRangeRef text_marker_range);
123 130
124 AXTextMarkerRef AXTextMarkerRangeCopyEndMarker( 131 AXTextMarkerRef AXTextMarkerRangeCopyEndMarker(
125 AXTextMarkerRangeRef text_marker_range); 132 AXTextMarkerRangeRef text_marker_range);
126 133
127 #endif // MAC_OS_X_VERSION_10_11 134 #endif // MAC_OS_X_VERSION_10_11
128 135
129 } // extern "C" 136 } // extern "C"
130 137
131 id CreateTextMarker(const BrowserAccessibility& object, 138 // to call |release| on it to transfer ownership of the position to the text
132 int offset, 139 // marker object.
133 ui::AXTextAffinity affinity) { 140 id CreateTextMarker(AXPlatformPositionInstance position) {
134 if (!object.instance_active()) 141 AXTextMarkerRef text_marker = AXTextMarkerCreate(
135 return nil; 142 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(position.release()),
136 143 sizeof(AXPlatformPosition));
137 const auto manager = object.manager(); 144 return static_cast<id>(
138 DCHECK(manager); 145 base::mac::CFTypeRefToNSObjectAutorelease(text_marker));
139 auto marker_data = AXPlatformPosition::CreateTextPosition(
140 manager->ax_tree_id(), object.GetId(), offset, affinity);
141 return (id)base::mac::CFTypeRefToNSObjectAutorelease(
142 AXTextMarkerCreate(kCFAllocatorDefault,
143 reinterpret_cast<const UInt8*>(marker_data.release()),
144 sizeof(AXPlatformPosition)));
145 } 146 }
146 147
147 id CreateTextMarkerRange(const BrowserAccessibility& start_object, 148 // |range| is destructed at the end of this method and ownership of its |anchor|
148 int start_offset, 149 // and |focus| are transfered to the marker range object.
149 ui::AXTextAffinity start_affinity, 150 id CreateTextMarkerRange(const AXPlatformRange range) {
150 const BrowserAccessibility& end_object, 151 AXTextMarkerRef start_marker = AXTextMarkerCreate(
151 int end_offset, 152 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(range.anchor()),
152 ui::AXTextAffinity end_affinity) { 153 sizeof(AXPlatformPosition));
153 id start_marker = CreateTextMarker( 154 AXTextMarkerRef end_marker = AXTextMarkerCreate(
154 start_object, start_offset, start_affinity); 155 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(range.focus()),
155 id end_marker = CreateTextMarker(end_object, end_offset, end_affinity); 156 sizeof(AXPlatformPosition));
156 return (id)base::mac::CFTypeRefToNSObjectAutorelease( 157 AXTextMarkerRangeRef marker_range =
157 AXTextMarkerRangeCreate(kCFAllocatorDefault, start_marker, end_marker)); 158 AXTextMarkerRangeCreate(kCFAllocatorDefault, start_marker, end_marker);
159 return static_cast<id>(
160 base::mac::CFTypeRefToNSObjectAutorelease(marker_range));
158 } 161 }
159 162
160 bool GetTextMarkerData(AXTextMarkerRef text_marker, 163 AXPlatformPositionInstance CreatePositionFromTextMarker(
161 BrowserAccessibility** object, 164 AXTextMarkerRef text_marker) {
162 int* offset,
163 ui::AXTextAffinity* affinity) {
164 DCHECK(text_marker); 165 DCHECK(text_marker);
165 DCHECK(object && offset);
166 if (AXTextMarkerGetLength(text_marker) != sizeof(AXPlatformPosition)) 166 if (AXTextMarkerGetLength(text_marker) != sizeof(AXPlatformPosition))
167 return false; 167 return AXPlatformPosition::CreateNullPosition();
168 const UInt8* source_buffer = AXTextMarkerGetBytePtr(text_marker); 168 const UInt8* source_buffer = AXTextMarkerGetBytePtr(text_marker);
169 if (!source_buffer) 169 if (!source_buffer)
170 return false; 170 return AXPlatformPosition::CreateNullPosition();
171 UInt8* destination_buffer = new UInt8[sizeof(AXPlatformPosition)]; 171 UInt8* destination_buffer = new UInt8[sizeof(AXPlatformPosition)];
172 std::memcpy(destination_buffer, source_buffer, sizeof(AXPlatformPosition)); 172 std::memcpy(destination_buffer, source_buffer, sizeof(AXPlatformPosition));
173 AXPlatformPosition::AXPositionInstance marker_data( 173 AXPlatformPosition::AXPositionInstance position(
174 reinterpret_cast<AXPlatformPosition::AXPositionInstance::pointer>( 174 reinterpret_cast<AXPlatformPosition::AXPositionInstance::pointer>(
175 destination_buffer)); 175 destination_buffer));
176 if (marker_data->IsNullPosition()) 176 if (!position)
177 return false; 177 return AXPlatformPosition::CreateNullPosition();
178 178 return position;
179 *object = marker_data->GetAnchor();
180 if (!*object)
181 return false;
182
183 *offset = marker_data->text_offset();
184 if (*offset < 0)
185 return false;
186
187 *affinity = marker_data->affinity();
188 return true;
189 } 179 }
190 180
191 bool GetTextMarkerRange(AXTextMarkerRangeRef marker_range, 181 AXPlatformRange CreateRangeFromTextMarkerRange(
192 BrowserAccessibility** start_object, 182 AXTextMarkerRangeRef marker_range) {
193 int* start_offset,
194 ui::AXTextAffinity* start_affinity,
195 BrowserAccessibility** end_object,
196 int* end_offset,
197 ui::AXTextAffinity* end_affinity) {
198 DCHECK(marker_range); 183 DCHECK(marker_range);
199 DCHECK(start_object && start_offset);
200 DCHECK(end_object && end_offset);
201
202 base::ScopedCFTypeRef<AXTextMarkerRef> start_marker( 184 base::ScopedCFTypeRef<AXTextMarkerRef> start_marker(
203 AXTextMarkerRangeCopyStartMarker(marker_range)); 185 AXTextMarkerRangeCopyStartMarker(marker_range));
204 base::ScopedCFTypeRef<AXTextMarkerRef> end_marker( 186 base::ScopedCFTypeRef<AXTextMarkerRef> end_marker(
205 AXTextMarkerRangeCopyEndMarker(marker_range)); 187 AXTextMarkerRangeCopyEndMarker(marker_range));
206 if (!start_marker.get() || !end_marker.get()) 188 if (!start_marker.get() || !end_marker.get())
207 return false; 189 return AXPlatformRange();
208 190
209 return GetTextMarkerData(start_marker.get(), 191 AXPlatformPositionInstance anchor =
210 start_object, start_offset, start_affinity) && 192 CreatePositionFromTextMarker(start_marker.get());
211 GetTextMarkerData(end_marker.get(), 193 AXPlatformPositionInstance focus =
212 end_object, end_offset, end_affinity); 194 CreatePositionFromTextMarker(end_marker.get());
195 // |AXPlatformRange| takes ownership of its anchor and focus.
196 return AXPlatformRange(std::move(anchor), std::move(focus));
197 }
198
199 AXPlatformPositionInstance CreateTextPosition(
200 const BrowserAccessibility& object,
201 int offset,
202 ui::AXTextAffinity affinity) {
203 if (!object.instance_active())
204 return AXPlatformPosition::CreateNullPosition();
205
206 const BrowserAccessibilityManager* manager = object.manager();
207 DCHECK(manager);
208 return AXPlatformPosition::CreateTextPosition(
209 manager->ax_tree_id(), object.GetId(), offset, affinity);
210 }
211
212 AXPlatformRange CreateTextRange(const BrowserAccessibility& start_object,
213 int start_offset,
214 ui::AXTextAffinity start_affinity,
215 const BrowserAccessibility& end_object,
216 int end_offset,
217 ui::AXTextAffinity end_affinity) {
218 AXPlatformPositionInstance anchor =
219 CreateTextPosition(start_object, start_offset, start_affinity);
220 AXPlatformPositionInstance focus =
221 CreateTextPosition(end_object, end_offset, end_affinity);
222 // |AXPlatformRange| takes ownership of its anchor and focus.
223 return AXPlatformRange(std::move(anchor), std::move(focus));
213 } 224 }
214 225
215 void AddMisspelledTextAttributes( 226 void AddMisspelledTextAttributes(
216 const std::vector<const BrowserAccessibility*>& text_only_objects, 227 const std::vector<const BrowserAccessibility*>& text_only_objects,
217 NSMutableAttributedString* attributed_string) { 228 NSMutableAttributedString* attributed_string) {
218 [attributed_string beginEditing]; 229 [attributed_string beginEditing];
219 for (const BrowserAccessibility* text_object : text_only_objects) { 230 for (const BrowserAccessibility* text_object : text_only_objects) {
220 const std::vector<int32_t>& marker_types = 231 const std::vector<int32_t>& marker_types =
221 text_object->GetIntListAttribute(ui::AX_ATTR_MARKER_TYPES); 232 text_object->GetIntListAttribute(ui::AX_ATTR_MARKER_TYPES);
222 const std::vector<int>& marker_starts = 233 const std::vector<int>& marker_starts =
(...skipping 13 matching lines...) Expand all
236 [attributed_string 247 [attributed_string
237 addAttribute:NSAccessibilityMarkedMisspelledTextAttribute 248 addAttribute:NSAccessibilityMarkedMisspelledTextAttribute
238 value:@YES 249 value:@YES
239 range:NSMakeRange(misspelling_start, misspelling_length)]; 250 range:NSMakeRange(misspelling_start, misspelling_length)];
240 } 251 }
241 } 252 }
242 [attributed_string endEditing]; 253 [attributed_string endEditing];
243 } 254 }
244 255
245 NSString* GetTextForTextMarkerRange(AXTextMarkerRangeRef marker_range) { 256 NSString* GetTextForTextMarkerRange(AXTextMarkerRangeRef marker_range) {
246 BrowserAccessibility* start_object; 257 AXPlatformRange range = CreateRangeFromTextMarkerRange(marker_range);
247 BrowserAccessibility* end_object; 258 if (range.IsNull())
248 int start_offset, end_offset;
249 ui::AXTextAffinity start_affinity, end_affinity;
250 if (!GetTextMarkerRange(marker_range,
251 &start_object, &start_offset, &start_affinity,
252 &end_object, &end_offset, &end_affinity)) {
253 return nil; 259 return nil;
254 } 260 return base::SysUTF16ToNSString(range.GetText());
255 DCHECK(start_object && end_object);
256 DCHECK_GE(start_offset, 0);
257 DCHECK_GE(end_offset, 0);
258
259 return base::SysUTF16ToNSString(BrowserAccessibilityManager::GetTextForRange(
260 *start_object, start_offset, *end_object, end_offset));
261 } 261 }
262 262
263 NSAttributedString* GetAttributedTextForTextMarkerRange( 263 NSAttributedString* GetAttributedTextForTextMarkerRange(
264 AXTextMarkerRangeRef marker_range) { 264 AXTextMarkerRangeRef marker_range) {
265 BrowserAccessibility* start_object; 265 BrowserAccessibility* start_object;
266 BrowserAccessibility* end_object; 266 BrowserAccessibility* end_object;
267 int start_offset, end_offset; 267 int start_offset, end_offset;
268 ui::AXTextAffinity start_affinity, end_affinity; 268 ui::AXTextAffinity start_affinity, end_affinity;
269 if (!GetTextMarkerRange(marker_range, 269 AXPlatformRange ax_range = CreateRangeFromTextMarkerRange(marker_range);
270 &start_object, &start_offset, &start_affinity, 270 if (ax_range.IsNull())
271 &end_object, &end_offset, &end_affinity)) {
272 return nil; 271 return nil;
273 } 272 start_object = ax_range.anchor()->GetAnchor();
273 end_object = ax_range.focus()->GetAnchor();
274 start_offset = ax_range.anchor()->text_offset();
275 end_offset = ax_range.focus()->text_offset();
276 start_affinity = ax_range.anchor()->affinity();
277 end_affinity = ax_range.focus()->affinity();
274 278
275 NSString* text = base::SysUTF16ToNSString( 279 NSString* text = base::SysUTF16ToNSString(
276 BrowserAccessibilityManager::GetTextForRange(*start_object, *end_object)); 280 BrowserAccessibilityManager::GetTextForRange(*start_object, *end_object));
277 if ([text length] == 0) 281 if ([text length] == 0)
278 return nil; 282 return nil;
279 283
280 // Be permissive with the start and end offsets. 284 // Be permissive with the start and end offsets.
281 if (start_object == end_object && end_offset < start_offset) 285 if (start_object == end_object && end_offset < start_offset)
282 std::swap(start_offset, end_offset); 286 std::swap(start_offset, end_offset);
283 287
(...skipping 611 matching lines...) Expand 10 before | Expand all | Expand 10 after
895 - (NSNumber*)enabled { 899 - (NSNumber*)enabled {
896 if (![self instanceActive]) 900 if (![self instanceActive])
897 return nil; 901 return nil;
898 return [NSNumber numberWithBool: 902 return [NSNumber numberWithBool:
899 !GetState(browserAccessibility_, ui::AX_STATE_DISABLED)]; 903 !GetState(browserAccessibility_, ui::AX_STATE_DISABLED)];
900 } 904 }
901 905
902 // Returns a text marker that points to the last character in the document that 906 // Returns a text marker that points to the last character in the document that
903 // can be selected with VoiceOver. 907 // can be selected with VoiceOver.
904 - (id)endTextMarker { 908 - (id)endTextMarker {
905 if (![self instanceActive])
906 return nil;
907
908 const BrowserAccessibility* root = 909 const BrowserAccessibility* root =
909 browserAccessibility_->manager()->GetRoot(); 910 browserAccessibility_->manager()->GetRoot();
910 if (!root) 911 if (!root)
911 return nil; 912 return nil;
912 913
913 const BrowserAccessibility* last_text_object = 914 AXPlatformPositionInstance position =
914 root->InternalDeepestLastChild(); 915 CreateTextPosition(*root, 0, ui::AX_TEXT_AFFINITY_DOWNSTREAM);
915 if (last_text_object && !last_text_object->IsTextOnlyObject()) { 916 return CreateTextMarker(position->CreatePositionAtEndOfAnchor());
916 last_text_object =
917 BrowserAccessibilityManager::PreviousTextOnlyObject(last_text_object);
918 }
919 while (last_text_object) {
920 last_text_object =
921 BrowserAccessibilityManager::PreviousTextOnlyObject(last_text_object);
922 }
923 if (!last_text_object)
924 return nil;
925
926 return CreateTextMarker(*last_text_object,
927 last_text_object->GetText().length(),
928 ui::AX_TEXT_AFFINITY_DOWNSTREAM);
929 } 917 }
930 918
931 - (NSNumber*)expanded { 919 - (NSNumber*)expanded {
932 if (![self instanceActive]) 920 if (![self instanceActive])
933 return nil; 921 return nil;
934 return [NSNumber numberWithBool: 922 return [NSNumber numberWithBool:
935 GetState(browserAccessibility_, ui::AX_STATE_EXPANDED)]; 923 GetState(browserAccessibility_, ui::AX_STATE_EXPANDED)];
936 } 924 }
937 925
938 - (NSNumber*)focused { 926 - (NSNumber*)focused {
(...skipping 690 matching lines...) Expand 10 before | Expand all | Expand 10 after
1629 1617
1630 int anchorOffset = manager->GetTreeData().sel_anchor_offset; 1618 int anchorOffset = manager->GetTreeData().sel_anchor_offset;
1631 int focusOffset = manager->GetTreeData().sel_focus_offset; 1619 int focusOffset = manager->GetTreeData().sel_focus_offset;
1632 if (anchorOffset < 0 || focusOffset < 0) 1620 if (anchorOffset < 0 || focusOffset < 0)
1633 return nil; 1621 return nil;
1634 1622
1635 ui::AXTextAffinity anchorAffinity = 1623 ui::AXTextAffinity anchorAffinity =
1636 manager->GetTreeData().sel_anchor_affinity; 1624 manager->GetTreeData().sel_anchor_affinity;
1637 ui::AXTextAffinity focusAffinity = manager->GetTreeData().sel_focus_affinity; 1625 ui::AXTextAffinity focusAffinity = manager->GetTreeData().sel_focus_affinity;
1638 1626
1639 return CreateTextMarkerRange(*anchorObject, anchorOffset, anchorAffinity, 1627 return CreateTextMarkerRange(CreateTextRange(*anchorObject, anchorOffset,
1640 *focusObject, focusOffset, focusAffinity); 1628 anchorAffinity, *focusObject,
1629 focusOffset, focusAffinity));
1641 } 1630 }
1642 1631
1643 - (NSValue*)size { 1632 - (NSValue*)size {
1644 if (![self instanceActive]) 1633 if (![self instanceActive])
1645 return nil; 1634 return nil;
1646 gfx::Rect bounds = browserAccessibility_->GetPageBoundsRect(); 1635 gfx::Rect bounds = browserAccessibility_->GetPageBoundsRect();
1647 return [NSValue valueWithSize:NSMakeSize(bounds.width(), bounds.height())]; 1636 return [NSValue valueWithSize:NSMakeSize(bounds.width(), bounds.height())];
1648 } 1637 }
1649 1638
1650 - (NSString*)sortDirection { 1639 - (NSString*)sortDirection {
(...skipping 16 matching lines...) Expand all
1667 default: 1656 default:
1668 NOTREACHED(); 1657 NOTREACHED();
1669 } 1658 }
1670 1659
1671 return nil; 1660 return nil;
1672 } 1661 }
1673 1662
1674 // Returns a text marker that points to the first character in the document that 1663 // Returns a text marker that points to the first character in the document that
1675 // can be selected with VoiceOver. 1664 // can be selected with VoiceOver.
1676 - (id)startTextMarker { 1665 - (id)startTextMarker {
1677 if (![self instanceActive])
1678 return nil;
1679
1680 const BrowserAccessibility* root = 1666 const BrowserAccessibility* root =
1681 browserAccessibility_->manager()->GetRoot(); 1667 browserAccessibility_->manager()->GetRoot();
1682 if (!root) 1668 if (!root)
1683 return nil; 1669 return nil;
1684 1670
1685 const BrowserAccessibility* first_text_object = 1671 AXPlatformPositionInstance position =
1686 root->InternalDeepestFirstChild(); 1672 CreateTextPosition(*root, 0, ui::AX_TEXT_AFFINITY_DOWNSTREAM);
1687 if (first_text_object && !first_text_object->IsTextOnlyObject()) { 1673 return CreateTextMarker(position->CreatePositionAtStartOfAnchor());
1688 first_text_object =
1689 BrowserAccessibilityManager::NextTextOnlyObject(first_text_object);
1690 }
1691 while (first_text_object) {
1692 first_text_object =
1693 BrowserAccessibilityManager::NextTextOnlyObject(first_text_object);
1694 }
1695 if (!first_text_object)
1696 return nil;
1697
1698 return CreateTextMarker(*first_text_object, 0, ui::AX_TEXT_AFFINITY_UPSTREAM);
1699 } 1674 }
1700 1675
1701 // Returns a subrole based upon the role. 1676 // Returns a subrole based upon the role.
1702 - (NSString*) subrole { 1677 - (NSString*) subrole {
1703 if (![self instanceActive]) 1678 if (![self instanceActive])
1704 return nil; 1679 return nil;
1705 ui::AXRole browserAccessibilityRole = [self internalRole]; 1680 ui::AXRole browserAccessibilityRole = [self internalRole];
1706 if (browserAccessibilityRole == ui::AX_ROLE_TEXT_FIELD && 1681 if (browserAccessibilityRole == ui::AX_ROLE_TEXT_FIELD &&
1707 GetState(browserAccessibility_, ui::AX_STATE_PROTECTED)) { 1682 GetState(browserAccessibility_, ui::AX_STATE_PROTECTED)) {
1708 return NSAccessibilitySecureTextFieldSubrole; 1683 return NSAccessibilitySecureTextFieldSubrole;
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
1985 SEL selector = 1960 SEL selector =
1986 NSSelectorFromString([self methodNameForAttribute:attribute]); 1961 NSSelectorFromString([self methodNameForAttribute:attribute]);
1987 if (selector) 1962 if (selector)
1988 return [self performSelector:selector]; 1963 return [self performSelector:selector];
1989 1964
1990 return nil; 1965 return nil;
1991 } 1966 }
1992 1967
1993 // Returns the accessibility value for the given attribute and parameter. If the 1968 // Returns the accessibility value for the given attribute and parameter. If the
1994 // value isn't supported this will return nil. 1969 // value isn't supported this will return nil.
1995 // TODO(nektar): Implement all unimplemented attributes, e.g. text markers.
1996 - (id)accessibilityAttributeValue:(NSString*)attribute 1970 - (id)accessibilityAttributeValue:(NSString*)attribute
1997 forParameter:(id)parameter { 1971 forParameter:(id)parameter {
1998 if (![self instanceActive]) 1972 if (![self instanceActive])
1999 return nil; 1973 return nil;
2000 1974
2001 const std::vector<int> line_breaks = 1975 const std::vector<int> line_breaks =
2002 browserAccessibility_->GetLineStartOffsets(); 1976 browserAccessibility_->GetLineStartOffsets();
2003 base::string16 value = browserAccessibility_->GetValue(); 1977 base::string16 value = browserAccessibility_->GetValue();
2004 int len = static_cast<int>(value.size()); 1978 int len = static_cast<int>(value.size());
2005 1979
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
2087 if (colIndex == column) 2061 if (colIndex == column)
2088 return ToBrowserAccessibilityCocoa(cell); 2062 return ToBrowserAccessibilityCocoa(cell);
2089 if (colIndex > column) 2063 if (colIndex > column)
2090 break; 2064 break;
2091 } 2065 }
2092 } 2066 }
2093 return nil; 2067 return nil;
2094 } 2068 }
2095 2069
2096 if ([attribute isEqualToString:@"AXUIElementForTextMarker"]) { 2070 if ([attribute isEqualToString:@"AXUIElementForTextMarker"]) {
2097 BrowserAccessibility* object; 2071 AXPlatformPositionInstance position =
2098 int offset; 2072 CreatePositionFromTextMarker(parameter);
2099 ui::AXTextAffinity affinity; 2073 if (!position->IsNullPosition())
2100 if (GetTextMarkerData(parameter, &object, &offset, &affinity)) 2074 return ToBrowserAccessibilityCocoa(position->GetAnchor());
2101 return ToBrowserAccessibilityCocoa(object);
2102 2075
2103 return nil; 2076 return nil;
2104 } 2077 }
2105 2078
2106 if ([attribute isEqualToString:@"AXTextMarkerRangeForUIElement"]) { 2079 if ([attribute isEqualToString:@"AXTextMarkerRangeForUIElement"]) {
2107 return CreateTextMarkerRange(*browserAccessibility_, 0, 2080 AXPlatformPositionInstance startPosition = CreateTextPosition(
2108 ui::AX_TEXT_AFFINITY_UPSTREAM, 2081 *browserAccessibility_, 0, ui::AX_TEXT_AFFINITY_DOWNSTREAM);
2109 *browserAccessibility_, 2082 AXPlatformPositionInstance endPosition =
2110 browserAccessibility_->GetText().length(), 2083 startPosition->CreatePositionAtEndOfAnchor();
2111 ui::AX_TEXT_AFFINITY_DOWNSTREAM); 2084 AXPlatformRange range =
2085 AXPlatformRange(std::move(startPosition), std::move(endPosition));
2086 return CreateTextMarkerRange(std::move(range));
2112 } 2087 }
2113 2088
2114 if ([attribute isEqualToString:@"AXStringForTextMarkerRange"]) 2089 if ([attribute isEqualToString:@"AXStringForTextMarkerRange"])
2115 GetTextForTextMarkerRange(parameter); 2090 return GetTextForTextMarkerRange(parameter);
2116 2091
2117 if ([attribute isEqualToString:@"AXAttributedStringForTextMarkerRange"]) 2092 if ([attribute isEqualToString:@"AXAttributedStringForTextMarkerRange"])
2118 return GetAttributedTextForTextMarkerRange(parameter); 2093 return GetAttributedTextForTextMarkerRange(parameter);
2119 2094
2120 if ([attribute isEqualToString:@"AXNextTextMarkerForTextMarker"]) { 2095 if ([attribute isEqualToString:@"AXNextTextMarkerForTextMarker"]) {
2121 BrowserAccessibility* object; 2096 AXPlatformPositionInstance position =
2122 int offset; 2097 CreatePositionFromTextMarker(parameter);
2123 ui::AXTextAffinity affinity; 2098 if (position->IsNullPosition())
2124 if (!GetTextMarkerData(parameter, &object, &offset, &affinity))
2125 return nil; 2099 return nil;
2126 2100 return CreateTextMarker(position->CreateNextCharacterPosition());
2127 DCHECK(object);
2128 if ((object->IsSimpleTextControl() || object->IsTextOnlyObject()) &&
2129 offset < static_cast<int>(object->GetText().length())) {
2130 ++offset;
2131 } else {
2132 do {
2133 object = BrowserAccessibilityManager::NextTextOnlyObject(object);
2134 } while (
2135 object &&
2136 !(object->IsTextOnlyObject() && object->GetText().length() == 0));
2137 if (!object)
2138 return nil;
2139
2140 offset = 0;
2141 }
2142
2143 return CreateTextMarker(*object, offset, ui::AX_TEXT_AFFINITY_DOWNSTREAM);
2144 } 2101 }
2145 2102
2146 if ([attribute isEqualToString:@"AXPreviousTextMarkerForTextMarker"]) { 2103 if ([attribute isEqualToString:@"AXPreviousTextMarkerForTextMarker"]) {
2147 BrowserAccessibility* object; 2104 AXPlatformPositionInstance position =
2148 int offset; 2105 CreatePositionFromTextMarker(parameter);
2149 ui::AXTextAffinity affinity; 2106 if (position->IsNullPosition())
2150 if (!GetTextMarkerData(parameter, &object, &offset, &affinity)) 2107 return nil;
2108 return CreateTextMarker(position->CreatePreviousCharacterPosition());
2109 }
2110
2111 if ([attribute isEqualToString:@"AXLeftWordTextMarkerRangeForTextMarker"]) {
2112 AXPlatformPositionInstance position =
2113 CreatePositionFromTextMarker(parameter);
2114 if (position->IsNullPosition())
2151 return nil; 2115 return nil;
2152 2116
2153 DCHECK(object); 2117 AXPlatformPositionInstance startPosition =
2154 if ((object->IsSimpleTextControl() || object->IsTextOnlyObject()) && 2118 position->CreatePreviousWordStartPosition();
2155 offset > 0) { 2119 AXPlatformPositionInstance endPosition =
2156 --offset; 2120 startPosition->CreateNextWordEndPosition();
2157 } else { 2121 AXPlatformRange range(std::move(startPosition), std::move(endPosition));
2158 do { 2122 return CreateTextMarkerRange(std::move(range));
2159 object = BrowserAccessibilityManager::PreviousTextOnlyObject(object);
2160 } while (
2161 object &&
2162 !(object->IsTextOnlyObject() && object->GetText().length() == 0));
2163 if (!object)
2164 return nil;
2165
2166 offset = object->GetText().length() - 1;
2167 }
2168
2169 return CreateTextMarker(*object, offset, ui::AX_TEXT_AFFINITY_DOWNSTREAM);
2170 }
2171
2172 // Currently we approximate end offsets of words and do not actually calculate
2173 // end offsets of lines, but use the start offset of the next line instead.
2174 // This seems to work in simple text fields.
2175 // TODO(nektar): Fix end offsets of words and lines.
2176 if ([attribute isEqualToString:@"AXLeftWordTextMarkerRangeForTextMarker"]) {
2177 BrowserAccessibility* object;
2178 int original_offset;
2179 ui::AXTextAffinity affinity;
2180 if (!GetTextMarkerData(parameter, &object, &original_offset, &affinity))
2181 return nil;
2182
2183 int start_offset =
2184 object->GetWordStartBoundary(original_offset, ui::BACKWARDS_DIRECTION);
2185 DCHECK_GE(start_offset, 0);
2186
2187 int end_offset =
2188 object->GetWordStartBoundary(start_offset, ui::FORWARDS_DIRECTION);
2189 DCHECK_GE(end_offset, 0);
2190 if (start_offset < end_offset &&
2191 end_offset < static_cast<int>(object->GetText().length())) {
2192 --end_offset;
2193 }
2194 return CreateTextMarkerRange(*object, start_offset, affinity,
2195 *object, end_offset, affinity);
2196 } 2123 }
2197 2124
2198 if ([attribute isEqualToString:@"AXRightWordTextMarkerRangeForTextMarker"]) { 2125 if ([attribute isEqualToString:@"AXRightWordTextMarkerRangeForTextMarker"]) {
2199 BrowserAccessibility* object; 2126 AXPlatformPositionInstance position =
2200 int original_offset; 2127 CreatePositionFromTextMarker(parameter);
2201 ui::AXTextAffinity affinity; 2128 if (position->IsNullPosition())
2202 if (!GetTextMarkerData(parameter, &object, &original_offset, &affinity))
2203 return nil; 2129 return nil;
2204 2130
2205 int start_offset = 2131 AXPlatformPositionInstance endPosition =
2206 object->GetWordStartBoundary(original_offset, ui::FORWARDS_DIRECTION); 2132 position->CreateNextWordEndPosition();
2207 DCHECK_GE(start_offset, 0); 2133 AXPlatformPositionInstance startPosition =
2208 2134 endPosition->CreatePreviousWordStartPosition();
2209 int end_offset = 2135 AXPlatformRange range(std::move(startPosition), std::move(endPosition));
2210 object->GetWordStartBoundary(start_offset, ui::FORWARDS_DIRECTION); 2136 return CreateTextMarkerRange(std::move(range));
2211 DCHECK_GE(end_offset, 0);
2212 if (start_offset < end_offset &&
2213 end_offset < static_cast<int>(object->GetText().length())) {
2214 --end_offset;
2215 }
2216 return CreateTextMarkerRange(*object, start_offset, affinity,
2217 *object, end_offset, affinity);
2218 } 2137 }
2219 2138
2220 if ([attribute isEqualToString:@"AXNextWordEndTextMarkerForTextMarker"]) { 2139 if ([attribute isEqualToString:@"AXNextWordEndTextMarkerForTextMarker"]) {
2221 BrowserAccessibility* object; 2140 AXPlatformPositionInstance position =
2222 int offset; 2141 CreatePositionFromTextMarker(parameter);
2223 ui::AXTextAffinity affinity; 2142 if (position->IsNullPosition())
2224 if (!GetTextMarkerData(parameter, &object, &offset, &affinity))
2225 return nil; 2143 return nil;
2226 2144 return CreateTextMarker(position->CreateNextWordEndPosition());
2227 offset = object->GetWordStartBoundary(offset, ui::FORWARDS_DIRECTION);
2228 DCHECK_GE(offset, 0);
2229 if (offset > 0 && offset < static_cast<int>(object->GetText().length()))
2230 --offset;
2231 return CreateTextMarker(*object, offset, affinity);
2232 } 2145 }
2233 2146
2234 if ([attribute 2147 if ([attribute
2235 isEqualToString:@"AXPreviousWordStartTextMarkerForTextMarker"]) { 2148 isEqualToString:@"AXPreviousWordStartTextMarkerForTextMarker"]) {
2236 BrowserAccessibility* object; 2149 AXPlatformPositionInstance position =
2237 int offset; 2150 CreatePositionFromTextMarker(parameter);
2238 ui::AXTextAffinity affinity; 2151 if (position->IsNullPosition())
2239 if (!GetTextMarkerData(parameter, &object, &offset, &affinity))
2240 return nil; 2152 return nil;
2241 2153 return CreateTextMarker(position->CreatePreviousWordStartPosition());
2242 offset = object->GetWordStartBoundary(offset, ui::BACKWARDS_DIRECTION);
2243 DCHECK_GE(offset, 0);
2244 return CreateTextMarker(*object, offset, affinity);
2245 } 2154 }
2246 2155
2247 if ([attribute isEqualToString:@"AXNextLineEndTextMarkerForTextMarker"]) { 2156 if ([attribute isEqualToString:@"AXNextLineEndTextMarkerForTextMarker"]) {
2248 BrowserAccessibility* object; 2157 AXPlatformPositionInstance position =
2249 int offset; 2158 CreatePositionFromTextMarker(parameter);
2250 ui::AXTextAffinity affinity; 2159 if (position->IsNullPosition())
2251 if (!GetTextMarkerData(parameter, &object, &offset, &affinity))
2252 return nil; 2160 return nil;
2253 2161 return CreateTextMarker(position->CreateNextLineEndPosition());
2254 offset = object->GetLineStartBoundary(
2255 offset, ui::FORWARDS_DIRECTION, affinity);
2256 DCHECK_GE(offset, 0);
2257 return CreateTextMarker(*object, offset, affinity);
2258 } 2162 }
2259 2163
2260 if ([attribute 2164 if ([attribute
2261 isEqualToString:@"AXPreviousLineStartTextMarkerForTextMarker"]) { 2165 isEqualToString:@"AXPreviousLineStartTextMarkerForTextMarker"]) {
2262 BrowserAccessibility* object; 2166 AXPlatformPositionInstance position =
2263 int offset; 2167 CreatePositionFromTextMarker(parameter);
2264 ui::AXTextAffinity affinity; 2168 if (position->IsNullPosition())
2265 if (!GetTextMarkerData(parameter, &object, &offset, &affinity))
2266 return nil; 2169 return nil;
2267 2170 return CreateTextMarker(position->CreatePreviousLineStartPosition());
2268 offset = object->GetLineStartBoundary(
2269 offset, ui::BACKWARDS_DIRECTION, affinity);
2270 DCHECK_GE(offset, 0);
2271 return CreateTextMarker(*object, offset, affinity);
2272 } 2171 }
2273 2172
2274 if ([attribute isEqualToString:@"AXLengthForTextMarkerRange"]) { 2173 if ([attribute isEqualToString:@"AXLengthForTextMarkerRange"]) {
2275 NSString* text = GetTextForTextMarkerRange(parameter); 2174 NSString* text = GetTextForTextMarkerRange(parameter);
2276 return [NSNumber numberWithInt:[text length]]; 2175 return [NSNumber numberWithInt:[text length]];
2277 } 2176 }
2278 2177
2279 if ([attribute isEqualToString: 2178 if ([attribute isEqualToString:
2280 NSAccessibilityBoundsForRangeParameterizedAttribute]) { 2179 NSAccessibilityBoundsForRangeParameterizedAttribute]) {
2281 if ([self internalRole] != ui::AX_ROLE_STATIC_TEXT) 2180 if ([self internalRole] != ui::AX_ROLE_STATIC_TEXT)
(...skipping 25 matching lines...) Expand all
2307 BrowserAccessibility* match = search.GetMatchAtIndex(i); 2206 BrowserAccessibility* match = search.GetMatchAtIndex(i);
2308 [result addObject:ToBrowserAccessibilityCocoa(match)]; 2207 [result addObject:ToBrowserAccessibilityCocoa(match)];
2309 } 2208 }
2310 return result; 2209 return result;
2311 } 2210 }
2312 return nil; 2211 return nil;
2313 } 2212 }
2314 2213
2315 if ([attribute isEqualToString: 2214 if ([attribute isEqualToString:
2316 NSAccessibilityLineTextMarkerRangeForTextMarkerParameterizedAttribute ]) { 2215 NSAccessibilityLineTextMarkerRangeForTextMarkerParameterizedAttribute ]) {
2317 BrowserAccessibility* object; 2216 AXPlatformPositionInstance position =
2318 int offset; 2217 CreatePositionFromTextMarker(parameter);
2319 ui::AXTextAffinity affinity; 2218 if (position->IsNullPosition())
2320 if (!GetTextMarkerData(parameter, &object, &offset, &affinity))
2321 return nil; 2219 return nil;
2322 2220
2323 DCHECK(object); 2221 AXPlatformRange range(position->CreatePreviousLineStartPosition(),
2324 int startOffset = 2222 position->CreateNextLineEndPosition());
2325 object->GetLineStartBoundary(offset, ui::BACKWARDS_DIRECTION, affinity); 2223 return CreateTextMarkerRange(std::move(range));
2326 int endOffset =
2327 object->GetLineStartBoundary(offset, ui::FORWARDS_DIRECTION, affinity);
2328 return CreateTextMarkerRange(
2329 *object, startOffset, ui::AX_TEXT_AFFINITY_UPSTREAM,
2330 *object, endOffset, ui::AX_TEXT_AFFINITY_DOWNSTREAM);
2331 } 2224 }
2332 2225
2333 if ([attribute isEqualToString: 2226 if ([attribute isEqualToString:
2334 NSAccessibilityBoundsForTextMarkerRangeParameterizedAttribute]) { 2227 NSAccessibilityBoundsForTextMarkerRangeParameterizedAttribute]) {
2335 BrowserAccessibility* startObject; 2228 BrowserAccessibility* startObject;
2336 BrowserAccessibility* endObject; 2229 BrowserAccessibility* endObject;
2337 int startOffset, endOffset; 2230 int startOffset, endOffset;
2338 ui::AXTextAffinity startAffinity, endAffinity; 2231 AXPlatformRange range = CreateRangeFromTextMarkerRange(parameter);
2339 if (!GetTextMarkerRange(parameter, 2232 if (range.IsNull())
2340 &startObject, &startOffset, &startAffinity,
2341 &endObject, &endOffset, &endAffinity)) {
2342 return nil; 2233 return nil;
2343 } 2234
2235 startObject = range.anchor()->GetAnchor();
2236 endObject = range.focus()->GetAnchor();
2237 startOffset = range.anchor()->text_offset();
2238 endOffset = range.focus()->text_offset();
2344 DCHECK(startObject && endObject); 2239 DCHECK(startObject && endObject);
2345 DCHECK_GE(startOffset, 0); 2240 DCHECK_GE(startOffset, 0);
2346 DCHECK_GE(endOffset, 0); 2241 DCHECK_GE(endOffset, 0);
2347 2242
2348 gfx::Rect rect = BrowserAccessibilityManager::GetPageBoundsForRange( 2243 gfx::Rect rect = BrowserAccessibilityManager::GetPageBoundsForRange(
2349 *startObject, startOffset, *endObject, endOffset); 2244 *startObject, startOffset, *endObject, endOffset);
2350 NSPoint origin = NSMakePoint(rect.x(), rect.y()); 2245 NSPoint origin = NSMakePoint(rect.x(), rect.y());
2351 NSSize size = NSMakeSize(rect.width(), rect.height()); 2246 NSSize size = NSMakeSize(rect.width(), rect.height());
2352 NSPoint pointInScreen = [self pointInScreen:origin size:size]; 2247 NSPoint pointInScreen = [self pointInScreen:origin size:size];
2353 NSRect nsrect = NSMakeRect( 2248 NSRect nsrect = NSMakeRect(
2354 pointInScreen.x, pointInScreen.y, rect.width(), rect.height()); 2249 pointInScreen.x, pointInScreen.y, rect.width(), rect.height());
2355 return [NSValue valueWithRect:nsrect]; 2250 return [NSValue valueWithRect:nsrect];
2356 } 2251 }
2357 2252
2358 if ([attribute isEqualToString: 2253 if ([attribute isEqualToString:
2359 NSAccessibilityTextMarkerRangeForUnorderedTextMarkersParameterizedAtt ribute]) { 2254 NSAccessibilityTextMarkerRangeForUnorderedTextMarkersParameterizedAtt ribute]) {
2360 if (![parameter isKindOfClass:[NSArray class]]) 2255 if (![parameter isKindOfClass:[NSArray class]])
2361 return nil; 2256 return nil;
2362 2257
2363 NSArray* array = parameter; 2258 NSArray* text_marker_array = parameter;
2364 id first = [array objectAtIndex:0]; 2259 if ([text_marker_array count] != 2)
2365 id second = [array objectAtIndex:1];
2366 BrowserAccessibility* object1;
2367 int offset1;
2368 ui::AXTextAffinity affinity1;
2369 if (!GetTextMarkerData(first, &object1, &offset1, &affinity1))
2370 return nil; 2260 return nil;
2371 2261
2372 BrowserAccessibility* object2; 2262 AXPlatformPositionInstance startPosition =
2373 int offset2; 2263 CreatePositionFromTextMarker([text_marker_array objectAtIndex:0]);
2374 ui::AXTextAffinity affinity2; 2264 AXPlatformPositionInstance endPosition =
2375 if (!GetTextMarkerData(second, &object2, &offset2, &affinity2)) 2265 CreatePositionFromTextMarker([text_marker_array objectAtIndex:1]);
2376 return nil; 2266 if (*startPosition <= *endPosition) {
2377 2267 return CreateTextMarkerRange(
2378 bool isInOrder = true; 2268 AXPlatformRange(std::move(startPosition), std::move(endPosition)));
2379 if (object1 == object2) { 2269 } else {
2380 if (offset2 > offset1) 2270 return CreateTextMarkerRange(
2381 isInOrder = true; 2271 AXPlatformRange(std::move(endPosition), std::move(startPosition)));
2382 else if (offset2 < offset1)
2383 isInOrder = false;
2384 else
2385 return nil;
2386 } 2272 }
2387
2388 ui::AXTreeOrder order = BrowserAccessibilityManager::CompareNodes(
2389 *object1, *object2);
2390 if (order == ui::AX_TREE_ORDER_BEFORE ||
2391 (order == ui::AX_TREE_ORDER_EQUAL && offset1 < offset2)) {
2392 return CreateTextMarkerRange(*object1, offset1, affinity1,
2393 *object2, offset2, affinity2);
2394 }
2395 if (order == ui::AX_TREE_ORDER_AFTER ||
2396 (order == ui::AX_TREE_ORDER_EQUAL && offset1 > offset2)) {
2397 return CreateTextMarkerRange(*object2, offset2, affinity2,
2398 *object1, offset1, affinity1);
2399 }
2400 return nil;
2401 } 2273 }
2402 2274
2403 if ([attribute isEqualToString: 2275 if ([attribute isEqualToString:
2404 NSAccessibilityIndexForChildUIElementParameterizedAttribute]) { 2276 NSAccessibilityIndexForChildUIElementParameterizedAttribute]) {
2405 if (![parameter isKindOfClass:[BrowserAccessibilityCocoa class]]) 2277 if (![parameter isKindOfClass:[BrowserAccessibilityCocoa class]])
2406 return nil; 2278 return nil;
2407 2279
2408 BrowserAccessibilityCocoa* childCocoaObj = 2280 BrowserAccessibilityCocoa* childCocoaObj =
2409 (BrowserAccessibilityCocoa*)parameter; 2281 (BrowserAccessibilityCocoa*)parameter;
2410 BrowserAccessibility* child = [childCocoaObj browserAccessibility]; 2282 BrowserAccessibility* child = [childCocoaObj browserAccessibility];
(...skipping 472 matching lines...) Expand 10 before | Expand all | Expand 10 after
2883 } 2755 }
2884 2756
2885 - (BOOL)accessibilityNotifiesWhenDestroyed { 2757 - (BOOL)accessibilityNotifiesWhenDestroyed {
2886 // Indicate that BrowserAccessibilityCocoa will post a notification when it's 2758 // Indicate that BrowserAccessibilityCocoa will post a notification when it's
2887 // destroyed (see -detach). This allows VoiceOver to do some internal things 2759 // destroyed (see -detach). This allows VoiceOver to do some internal things
2888 // more efficiently. 2760 // more efficiently.
2889 return YES; 2761 return YES;
2890 } 2762 }
2891 2763
2892 @end 2764 @end
OLDNEW
« no previous file with comments | « no previous file | ui/accessibility/ax_node_position_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698