Index: ui/accessibility/platform/text_marker_helper_mac.mm |
diff --git a/ui/accessibility/platform/text_marker_helper_mac.mm b/ui/accessibility/platform/text_marker_helper_mac.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..96f10ef1b85d4cc5d73b8082c82f4b44f8bf3c48 |
--- /dev/null |
+++ b/ui/accessibility/platform/text_marker_helper_mac.mm |
@@ -0,0 +1,255 @@ |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#import "ui/accessibility/platform/text_marker_helper_mac.h" |
+ |
+#import <Cocoa/Cocoa.h> |
+ |
+#import "base/mac/foundation_util.h" |
+#include "base/mac/scoped_cftyperef.h" |
+#include "ui/accessibility/ax_position.h" |
+#include "ui/accessibility/ax_range.h" |
+ |
+extern "C" { |
+ |
+// The following are private accessibility APIs required for cursor navigation |
+// and text selection. VoiceOver started relying on them in Mac OS X 10.11. |
+AXTextMarkerRef AXTextMarkerCreate(CFAllocatorRef allocator, |
+ const UInt8* bytes, |
+ CFIndex length); |
+ |
+AXTextMarkerRangeRef AXTextMarkerRangeCreate(CFAllocatorRef allocator, |
+ AXTextMarkerRef start_marker, |
+ AXTextMarkerRef end_marker); |
+ |
+} // extern "C" |
+ |
+namespace { |
+ |
+// to call |release| on it to transfer ownership of the position to the text |
+// marker object. |
+id CreateTextMarker(std::unique_ptr<ui::AXPositionBase> position) { |
+ AXTextMarkerRef text_marker = AXTextMarkerCreate( |
+ kCFAllocatorDefault, reinterpret_cast<const UInt8*>(position.release()), |
+ sizeof(ui::AXPositionBase)); |
+ return static_cast<id>( |
+ base::mac::CFTypeRefToNSObjectAutorelease(text_marker)); |
+} |
+ |
+// |range| is destructed at the end of this method and ownership of its |anchor| |
+// and |focus| are transfered to the marker range object. |
+id CreateTextMarkerRange(const ui::AXAbstractRange range) { |
+ AXTextMarkerRef start_marker = AXTextMarkerCreate( |
+ kCFAllocatorDefault, reinterpret_cast<const UInt8*>(range.anchor()), |
+ sizeof(ui::AXPositionBase)); |
+ AXTextMarkerRef end_marker = AXTextMarkerCreate( |
+ kCFAllocatorDefault, reinterpret_cast<const UInt8*>(range.focus()), |
+ sizeof(ui::AXPositionBase)); |
+ AXTextMarkerRangeRef marker_range = |
+ AXTextMarkerRangeCreate(kCFAllocatorDefault, start_marker, end_marker); |
+ return static_cast<id>( |
+ base::mac::CFTypeRefToNSObjectAutorelease(marker_range)); |
+} |
+ |
+} // namespace |
+ |
+@interface TextMarkerHelperMac () |
+- (std::unique_ptr<ui::AXPositionBase>)extractFrom:(id)parameter; |
+@end |
+ |
+@implementation TextMarkerHelperMac { |
+ std::unique_ptr<ui::PositionFactory> factory_; |
+} |
+ |
+- (instancetype)initWithFactory:(std::unique_ptr<ui::PositionFactory>)factory { |
+ if ((self = [super init])) { |
+ factory_ = std::move(factory); |
+ } |
+ return self; |
+} |
+ |
+- (id)startTextMarker { |
+ std::unique_ptr<ui::AXPositionBase> root = factory_->GetRoot(); |
+ return root ? CreateTextMarker(root->CreatePositionAtStartOfAnchor()) : nil; |
+} |
+ |
+- (id)endTextMarker { |
+ std::unique_ptr<ui::AXPositionBase> root = factory_->GetRoot(); |
+ return root ? CreateTextMarker(root->CreatePositionAtEndOfAnchor()) : nil; |
+} |
+ |
+- (id)selectedTextMarkerRange { |
+ std::unique_ptr<ui::AXAbstractRange> selection = factory_->GetSelection(); |
+ return selection ? CreateTextMarkerRange(std::move(*selection)) : nil; |
+} |
+ |
+- (std::unique_ptr<ui::AXPositionBase>)extractFrom:(id)parameter { |
+ AXTextMarkerRef marker = base::mac::CFCastStrict<AXTextMarkerRef>(parameter); |
+ return factory_->ExtractFromMarker(marker); |
+} |
+ |
+- (id)AXTextMarkerRangeForUIElement:(id)parameter { |
+ std::unique_ptr<ui::AXPositionBase> startPosition = factory_->GetRoot(); |
+ std::unique_ptr<ui::AXPositionBase> endPosition = |
+ startPosition->CreatePositionAtEndOfAnchor(); |
+ ui::AXAbstractRange range = |
+ ui::AXAbstractRange(std::move(startPosition), std::move(endPosition)); |
+ return CreateTextMarkerRange(std::move(range)); |
+} |
+ |
+- (id)AXNextTextMarkerForTextMarker:(id)parameter { |
+ std::unique_ptr<ui::AXPositionBase> position = [self extractFrom:parameter]; |
+ if (position->IsNullPosition()) |
+ return nil; |
+ return CreateTextMarker(position->CreateNextCharacterPosition()); |
+} |
+ |
+- (id)AXPreviousTextMarkerForTextMarker:(id)parameter { |
+ std::unique_ptr<ui::AXPositionBase> position = [self extractFrom:parameter]; |
+ if (position->IsNullPosition()) |
+ return nil; |
+ return CreateTextMarker(position->CreatePreviousCharacterPosition()); |
+} |
+ |
+- (id)AXLeftWordTextMarkerRangeForTextMarker:(id)parameter { |
+ std::unique_ptr<ui::AXPositionBase> endPosition = |
+ [self extractFrom:parameter]; |
+ if (endPosition->IsNullPosition()) |
+ return nil; |
+ |
+ std::unique_ptr<ui::AXPositionBase> startWordPosition = |
+ endPosition->CreatePreviousWordStartPosition(); |
+ std::unique_ptr<ui::AXPositionBase> endWordPosition = |
+ endPosition->CreatePreviousWordEndPosition(); |
+ std::unique_ptr<ui::AXPositionBase> startPosition = |
+ *startWordPosition <= *endWordPosition ? std::move(endWordPosition) |
+ : std::move(startWordPosition); |
+ ui::AXAbstractRange range(std::move(startPosition), std::move(endPosition)); |
+ return CreateTextMarkerRange(std::move(range)); |
+} |
+ |
+- (id)AXRightWordTextMarkerRangeForTextMarker:(id)parameter { |
+ std::unique_ptr<ui::AXPositionBase> startPosition = |
+ [self extractFrom:parameter]; |
+ if (startPosition->IsNullPosition()) |
+ return nil; |
+ |
+ std::unique_ptr<ui::AXPositionBase> endWordPosition = |
+ startPosition->CreateNextWordEndPosition(); |
+ std::unique_ptr<ui::AXPositionBase> startWordPosition = |
+ startPosition->CreateNextWordStartPosition(); |
+ std::unique_ptr<ui::AXPositionBase> endPosition = |
+ *startWordPosition <= *endWordPosition ? std::move(startWordPosition) |
+ : std::move(endWordPosition); |
+ ui::AXAbstractRange range(std::move(startPosition), std::move(endPosition)); |
+ return CreateTextMarkerRange(std::move(range)); |
+} |
+ |
+- (id)AXNextWordEndTextMarkerForTextMarker:(id)parameter { |
+ std::unique_ptr<ui::AXPositionBase> position = [self extractFrom:parameter]; |
+ if (position->IsNullPosition()) |
+ return nil; |
+ return CreateTextMarker(position->CreateNextWordEndPosition()); |
+} |
+ |
+- (id)AXPreviousWordStartTextMarkerForTextMarker:(id)parameter { |
+ std::unique_ptr<ui::AXPositionBase> position = [self extractFrom:parameter]; |
+ if (position->IsNullPosition()) |
+ return nil; |
+ return CreateTextMarker(position->CreatePreviousWordStartPosition()); |
+} |
+ |
+- (id)AXTextMarkerRangeForLine:(id)parameter { |
+ std::unique_ptr<ui::AXPositionBase> position = [self extractFrom:parameter]; |
+ if (position->IsNullPosition()) |
+ return nil; |
+ |
+ std::unique_ptr<ui::AXPositionBase> startPosition = |
+ position->CreatePreviousLineStartPosition(); |
+ std::unique_ptr<ui::AXPositionBase> endPosition = |
+ position->CreateNextLineEndPosition(); |
+ ui::AXAbstractRange range(std::move(startPosition), std::move(endPosition)); |
+ return CreateTextMarkerRange(std::move(range)); |
+} |
+ |
+- (id)AXLeftLineTextMarkerRangeForTextMarker:(id)parameter { |
+ std::unique_ptr<ui::AXPositionBase> endPosition = |
+ [self extractFrom:parameter]; |
+ if (endPosition->IsNullPosition()) |
+ return nil; |
+ |
+ std::unique_ptr<ui::AXPositionBase> startLinePosition = |
+ endPosition->CreatePreviousLineStartPosition(); |
+ std::unique_ptr<ui::AXPositionBase> endLinePosition = |
+ endPosition->CreatePreviousLineEndPosition(); |
+ std::unique_ptr<ui::AXPositionBase> startPosition = |
+ *startLinePosition <= *endLinePosition ? std::move(endLinePosition) |
+ : std::move(startLinePosition); |
+ ui::AXAbstractRange range(std::move(startPosition), std::move(endPosition)); |
+ return CreateTextMarkerRange(std::move(range)); |
+} |
+ |
+- (id)AXRightLineTextMarkerRangeForTextMarker:(id)parameter { |
+ std::unique_ptr<ui::AXPositionBase> startPosition = |
+ [self extractFrom:parameter]; |
+ if (startPosition->IsNullPosition()) |
+ return nil; |
+ |
+ std::unique_ptr<ui::AXPositionBase> startLinePosition = |
+ startPosition->CreateNextLineStartPosition(); |
+ std::unique_ptr<ui::AXPositionBase> endLinePosition = |
+ startPosition->CreateNextLineEndPosition(); |
+ std::unique_ptr<ui::AXPositionBase> endPosition = |
+ *startLinePosition <= *endLinePosition ? std::move(startLinePosition) |
+ : std::move(endLinePosition); |
+ ui::AXAbstractRange range(std::move(startPosition), std::move(endPosition)); |
+ return CreateTextMarkerRange(std::move(range)); |
+} |
+ |
+- (id)AXNextLineEndTextMarkerForTextMarker:(id)parameter { |
+ std::unique_ptr<ui::AXPositionBase> position = [self extractFrom:parameter]; |
+ if (position->IsNullPosition()) |
+ return nil; |
+ return CreateTextMarker(position->CreateNextLineEndPosition()); |
+} |
+ |
+- (id)AXPreviousLineStartTextMarkerForTextMarker:(id)parameter { |
+ std::unique_ptr<ui::AXPositionBase> position = [self extractFrom:parameter]; |
+ if (position->IsNullPosition()) |
+ return nil; |
+ return CreateTextMarker(position->CreatePreviousLineStartPosition()); |
+} |
+ |
+- (id)AXLineTextMarkerRangeForTextMarker:(id)parameter { |
+ std::unique_ptr<ui::AXPositionBase> position = [self extractFrom:parameter]; |
+ if (position->IsNullPosition()) |
+ return nil; |
+ |
+ ui::AXAbstractRange range(position->CreatePreviousLineStartPosition(), |
+ position->CreateNextLineEndPosition()); |
+ return CreateTextMarkerRange(std::move(range)); |
+} |
+ |
+- (id)AXTextMarkerRangeForUnorderedTextMarkers:(id)parameter { |
+ if (![parameter isKindOfClass:[NSArray class]]) |
+ return nil; |
+ |
+ NSArray* text_marker_array = parameter; |
+ if ([text_marker_array count] != 2) |
+ return nil; |
+ |
+ std::unique_ptr<ui::AXPositionBase> startPosition = |
+ [self extractFrom:[text_marker_array objectAtIndex:0]]; |
+ std::unique_ptr<ui::AXPositionBase> endPosition = |
+ [self extractFrom:[text_marker_array objectAtIndex:1]]; |
+ if (*startPosition <= *endPosition) { |
+ return CreateTextMarkerRange( |
+ ui::AXAbstractRange(std::move(startPosition), std::move(endPosition))); |
+ } else { |
+ return CreateTextMarkerRange( |
+ ui::AXAbstractRange(std::move(endPosition), std::move(startPosition))); |
+ } |
+} |
+ |
+@end |