OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #import "ui/accessibility/platform/text_marker_helper_mac.h" |
| 6 |
| 7 #import <Cocoa/Cocoa.h> |
| 8 |
| 9 #import "base/mac/foundation_util.h" |
| 10 #include "base/mac/scoped_cftyperef.h" |
| 11 #include "ui/accessibility/ax_position.h" |
| 12 #include "ui/accessibility/ax_range.h" |
| 13 |
| 14 extern "C" { |
| 15 |
| 16 // The following are private accessibility APIs required for cursor navigation |
| 17 // and text selection. VoiceOver started relying on them in Mac OS X 10.11. |
| 18 AXTextMarkerRef AXTextMarkerCreate(CFAllocatorRef allocator, |
| 19 const UInt8* bytes, |
| 20 CFIndex length); |
| 21 |
| 22 AXTextMarkerRangeRef AXTextMarkerRangeCreate(CFAllocatorRef allocator, |
| 23 AXTextMarkerRef start_marker, |
| 24 AXTextMarkerRef end_marker); |
| 25 |
| 26 } // extern "C" |
| 27 |
| 28 namespace { |
| 29 |
| 30 // to call |release| on it to transfer ownership of the position to the text |
| 31 // marker object. |
| 32 id CreateTextMarker(std::unique_ptr<ui::AXPositionBase> position) { |
| 33 AXTextMarkerRef text_marker = AXTextMarkerCreate( |
| 34 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(position.release()), |
| 35 sizeof(ui::AXPositionBase)); |
| 36 return static_cast<id>( |
| 37 base::mac::CFTypeRefToNSObjectAutorelease(text_marker)); |
| 38 } |
| 39 |
| 40 // |range| is destructed at the end of this method and ownership of its |anchor| |
| 41 // and |focus| are transfered to the marker range object. |
| 42 id CreateTextMarkerRange(const ui::AXAbstractRange range) { |
| 43 AXTextMarkerRef start_marker = AXTextMarkerCreate( |
| 44 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(range.anchor()), |
| 45 sizeof(ui::AXPositionBase)); |
| 46 AXTextMarkerRef end_marker = AXTextMarkerCreate( |
| 47 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(range.focus()), |
| 48 sizeof(ui::AXPositionBase)); |
| 49 AXTextMarkerRangeRef marker_range = |
| 50 AXTextMarkerRangeCreate(kCFAllocatorDefault, start_marker, end_marker); |
| 51 return static_cast<id>( |
| 52 base::mac::CFTypeRefToNSObjectAutorelease(marker_range)); |
| 53 } |
| 54 |
| 55 } // namespace |
| 56 |
| 57 @interface TextMarkerHelperMac () |
| 58 - (std::unique_ptr<ui::AXPositionBase>)extractFrom:(id)parameter; |
| 59 @end |
| 60 |
| 61 @implementation TextMarkerHelperMac { |
| 62 std::unique_ptr<ui::PositionFactory> factory_; |
| 63 } |
| 64 |
| 65 - (instancetype)initWithFactory:(std::unique_ptr<ui::PositionFactory>)factory { |
| 66 if ((self = [super init])) { |
| 67 factory_ = std::move(factory); |
| 68 } |
| 69 return self; |
| 70 } |
| 71 |
| 72 - (id)startTextMarker { |
| 73 std::unique_ptr<ui::AXPositionBase> root = factory_->GetRoot(); |
| 74 return root ? CreateTextMarker(root->CreatePositionAtStartOfAnchor()) : nil; |
| 75 } |
| 76 |
| 77 - (id)endTextMarker { |
| 78 std::unique_ptr<ui::AXPositionBase> root = factory_->GetRoot(); |
| 79 return root ? CreateTextMarker(root->CreatePositionAtEndOfAnchor()) : nil; |
| 80 } |
| 81 |
| 82 - (id)selectedTextMarkerRange { |
| 83 std::unique_ptr<ui::AXAbstractRange> selection = factory_->GetSelection(); |
| 84 return selection ? CreateTextMarkerRange(std::move(*selection)) : nil; |
| 85 } |
| 86 |
| 87 - (std::unique_ptr<ui::AXPositionBase>)extractFrom:(id)parameter { |
| 88 AXTextMarkerRef marker = base::mac::CFCastStrict<AXTextMarkerRef>(parameter); |
| 89 return factory_->ExtractFromMarker(marker); |
| 90 } |
| 91 |
| 92 - (id)AXTextMarkerRangeForUIElement:(id)parameter { |
| 93 std::unique_ptr<ui::AXPositionBase> startPosition = factory_->GetRoot(); |
| 94 std::unique_ptr<ui::AXPositionBase> endPosition = |
| 95 startPosition->CreatePositionAtEndOfAnchor(); |
| 96 ui::AXAbstractRange range = |
| 97 ui::AXAbstractRange(std::move(startPosition), std::move(endPosition)); |
| 98 return CreateTextMarkerRange(std::move(range)); |
| 99 } |
| 100 |
| 101 - (id)AXNextTextMarkerForTextMarker:(id)parameter { |
| 102 std::unique_ptr<ui::AXPositionBase> position = [self extractFrom:parameter]; |
| 103 if (position->IsNullPosition()) |
| 104 return nil; |
| 105 return CreateTextMarker(position->CreateNextCharacterPosition()); |
| 106 } |
| 107 |
| 108 - (id)AXPreviousTextMarkerForTextMarker:(id)parameter { |
| 109 std::unique_ptr<ui::AXPositionBase> position = [self extractFrom:parameter]; |
| 110 if (position->IsNullPosition()) |
| 111 return nil; |
| 112 return CreateTextMarker(position->CreatePreviousCharacterPosition()); |
| 113 } |
| 114 |
| 115 - (id)AXLeftWordTextMarkerRangeForTextMarker:(id)parameter { |
| 116 std::unique_ptr<ui::AXPositionBase> endPosition = |
| 117 [self extractFrom:parameter]; |
| 118 if (endPosition->IsNullPosition()) |
| 119 return nil; |
| 120 |
| 121 std::unique_ptr<ui::AXPositionBase> startWordPosition = |
| 122 endPosition->CreatePreviousWordStartPosition(); |
| 123 std::unique_ptr<ui::AXPositionBase> endWordPosition = |
| 124 endPosition->CreatePreviousWordEndPosition(); |
| 125 std::unique_ptr<ui::AXPositionBase> startPosition = |
| 126 *startWordPosition <= *endWordPosition ? std::move(endWordPosition) |
| 127 : std::move(startWordPosition); |
| 128 ui::AXAbstractRange range(std::move(startPosition), std::move(endPosition)); |
| 129 return CreateTextMarkerRange(std::move(range)); |
| 130 } |
| 131 |
| 132 - (id)AXRightWordTextMarkerRangeForTextMarker:(id)parameter { |
| 133 std::unique_ptr<ui::AXPositionBase> startPosition = |
| 134 [self extractFrom:parameter]; |
| 135 if (startPosition->IsNullPosition()) |
| 136 return nil; |
| 137 |
| 138 std::unique_ptr<ui::AXPositionBase> endWordPosition = |
| 139 startPosition->CreateNextWordEndPosition(); |
| 140 std::unique_ptr<ui::AXPositionBase> startWordPosition = |
| 141 startPosition->CreateNextWordStartPosition(); |
| 142 std::unique_ptr<ui::AXPositionBase> endPosition = |
| 143 *startWordPosition <= *endWordPosition ? std::move(startWordPosition) |
| 144 : std::move(endWordPosition); |
| 145 ui::AXAbstractRange range(std::move(startPosition), std::move(endPosition)); |
| 146 return CreateTextMarkerRange(std::move(range)); |
| 147 } |
| 148 |
| 149 - (id)AXNextWordEndTextMarkerForTextMarker:(id)parameter { |
| 150 std::unique_ptr<ui::AXPositionBase> position = [self extractFrom:parameter]; |
| 151 if (position->IsNullPosition()) |
| 152 return nil; |
| 153 return CreateTextMarker(position->CreateNextWordEndPosition()); |
| 154 } |
| 155 |
| 156 - (id)AXPreviousWordStartTextMarkerForTextMarker:(id)parameter { |
| 157 std::unique_ptr<ui::AXPositionBase> position = [self extractFrom:parameter]; |
| 158 if (position->IsNullPosition()) |
| 159 return nil; |
| 160 return CreateTextMarker(position->CreatePreviousWordStartPosition()); |
| 161 } |
| 162 |
| 163 - (id)AXTextMarkerRangeForLine:(id)parameter { |
| 164 std::unique_ptr<ui::AXPositionBase> position = [self extractFrom:parameter]; |
| 165 if (position->IsNullPosition()) |
| 166 return nil; |
| 167 |
| 168 std::unique_ptr<ui::AXPositionBase> startPosition = |
| 169 position->CreatePreviousLineStartPosition(); |
| 170 std::unique_ptr<ui::AXPositionBase> endPosition = |
| 171 position->CreateNextLineEndPosition(); |
| 172 ui::AXAbstractRange range(std::move(startPosition), std::move(endPosition)); |
| 173 return CreateTextMarkerRange(std::move(range)); |
| 174 } |
| 175 |
| 176 - (id)AXLeftLineTextMarkerRangeForTextMarker:(id)parameter { |
| 177 std::unique_ptr<ui::AXPositionBase> endPosition = |
| 178 [self extractFrom:parameter]; |
| 179 if (endPosition->IsNullPosition()) |
| 180 return nil; |
| 181 |
| 182 std::unique_ptr<ui::AXPositionBase> startLinePosition = |
| 183 endPosition->CreatePreviousLineStartPosition(); |
| 184 std::unique_ptr<ui::AXPositionBase> endLinePosition = |
| 185 endPosition->CreatePreviousLineEndPosition(); |
| 186 std::unique_ptr<ui::AXPositionBase> startPosition = |
| 187 *startLinePosition <= *endLinePosition ? std::move(endLinePosition) |
| 188 : std::move(startLinePosition); |
| 189 ui::AXAbstractRange range(std::move(startPosition), std::move(endPosition)); |
| 190 return CreateTextMarkerRange(std::move(range)); |
| 191 } |
| 192 |
| 193 - (id)AXRightLineTextMarkerRangeForTextMarker:(id)parameter { |
| 194 std::unique_ptr<ui::AXPositionBase> startPosition = |
| 195 [self extractFrom:parameter]; |
| 196 if (startPosition->IsNullPosition()) |
| 197 return nil; |
| 198 |
| 199 std::unique_ptr<ui::AXPositionBase> startLinePosition = |
| 200 startPosition->CreateNextLineStartPosition(); |
| 201 std::unique_ptr<ui::AXPositionBase> endLinePosition = |
| 202 startPosition->CreateNextLineEndPosition(); |
| 203 std::unique_ptr<ui::AXPositionBase> endPosition = |
| 204 *startLinePosition <= *endLinePosition ? std::move(startLinePosition) |
| 205 : std::move(endLinePosition); |
| 206 ui::AXAbstractRange range(std::move(startPosition), std::move(endPosition)); |
| 207 return CreateTextMarkerRange(std::move(range)); |
| 208 } |
| 209 |
| 210 - (id)AXNextLineEndTextMarkerForTextMarker:(id)parameter { |
| 211 std::unique_ptr<ui::AXPositionBase> position = [self extractFrom:parameter]; |
| 212 if (position->IsNullPosition()) |
| 213 return nil; |
| 214 return CreateTextMarker(position->CreateNextLineEndPosition()); |
| 215 } |
| 216 |
| 217 - (id)AXPreviousLineStartTextMarkerForTextMarker:(id)parameter { |
| 218 std::unique_ptr<ui::AXPositionBase> position = [self extractFrom:parameter]; |
| 219 if (position->IsNullPosition()) |
| 220 return nil; |
| 221 return CreateTextMarker(position->CreatePreviousLineStartPosition()); |
| 222 } |
| 223 |
| 224 - (id)AXLineTextMarkerRangeForTextMarker:(id)parameter { |
| 225 std::unique_ptr<ui::AXPositionBase> position = [self extractFrom:parameter]; |
| 226 if (position->IsNullPosition()) |
| 227 return nil; |
| 228 |
| 229 ui::AXAbstractRange range(position->CreatePreviousLineStartPosition(), |
| 230 position->CreateNextLineEndPosition()); |
| 231 return CreateTextMarkerRange(std::move(range)); |
| 232 } |
| 233 |
| 234 - (id)AXTextMarkerRangeForUnorderedTextMarkers:(id)parameter { |
| 235 if (![parameter isKindOfClass:[NSArray class]]) |
| 236 return nil; |
| 237 |
| 238 NSArray* text_marker_array = parameter; |
| 239 if ([text_marker_array count] != 2) |
| 240 return nil; |
| 241 |
| 242 std::unique_ptr<ui::AXPositionBase> startPosition = |
| 243 [self extractFrom:[text_marker_array objectAtIndex:0]]; |
| 244 std::unique_ptr<ui::AXPositionBase> endPosition = |
| 245 [self extractFrom:[text_marker_array objectAtIndex:1]]; |
| 246 if (*startPosition <= *endPosition) { |
| 247 return CreateTextMarkerRange( |
| 248 ui::AXAbstractRange(std::move(startPosition), std::move(endPosition))); |
| 249 } else { |
| 250 return CreateTextMarkerRange( |
| 251 ui::AXAbstractRange(std::move(endPosition), std::move(startPosition))); |
| 252 } |
| 253 } |
| 254 |
| 255 @end |
OLD | NEW |