| 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 #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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |