| 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
|
|
|