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

Unified Diff: ui/accessibility/platform/text_marker_helper_mac.mm

Issue 2940923003: a11y: Move CreateTextMarker[Range] to TextMarkerHelperMac.
Patch Set: squish? Created 3 years, 6 months 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/accessibility/platform/text_marker_helper_mac.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..a4d3025b1cb39370aa1c335b37649aa8ca99df28
--- /dev/null
+++ b/ui/accessibility/platform/text_marker_helper_mac.mm
@@ -0,0 +1,293 @@
+// 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"
+
+using ui::AXPositionPointer;
+using ui::AXRangePointer;
+using ui::AXPositionData;
+
+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);
+const UInt8* AXTextMarkerGetBytePtr(AXTextMarkerRef text_marker);
+size_t AXTextMarkerGetLength(AXTextMarkerRef text_marker);
+AXTextMarkerRef AXTextMarkerRangeCopyStartMarker(
+ AXTextMarkerRangeRef text_marker_range);
+AXTextMarkerRef AXTextMarkerRangeCopyEndMarker(
+ AXTextMarkerRangeRef text_marker_range);
+
+} // extern "C"
+
+namespace {
+
+constexpr size_t kDataSize = sizeof(AXPositionData);
+
+// AXTextMarkerCreate copies from data buffer given to it.
+id CreateTextMarker(AXPositionPointer position) {
+ AXPositionData data;
+ position->ToData(&data);
+
+ AXTextMarkerRef text_marker = AXTextMarkerCreate(
+ kCFAllocatorDefault, reinterpret_cast<const UInt8*>(&data), kDataSize);
+ return static_cast<id>(
+ base::mac::CFTypeRefToNSObjectAutorelease(text_marker));
+}
+
+// |range| is destructed at the end of this method. |anchor| and |focus| are
+// copied into the individual text markers.
+id CreateTextMarkerRange(AXRangePointer range) {
+ AXPositionData anchor, focus;
+ range.first->ToData(&anchor);
+ range.second->ToData(&focus);
+
+ base::ScopedCFTypeRef<AXTextMarkerRef> start_marker(AXTextMarkerCreate(
+ kCFAllocatorDefault, reinterpret_cast<const UInt8*>(&anchor), kDataSize));
+ base::ScopedCFTypeRef<AXTextMarkerRef> end_marker(AXTextMarkerCreate(
+ kCFAllocatorDefault, reinterpret_cast<const UInt8*>(&focus), kDataSize));
+ AXTextMarkerRangeRef marker_range =
+ AXTextMarkerRangeCreate(kCFAllocatorDefault, start_marker, end_marker);
+ return static_cast<id>(
+ base::mac::CFTypeRefToNSObjectAutorelease(marker_range));
+}
+
+bool ExtractData(AXTextMarkerRef text_marker, AXPositionData* data) {
+ DCHECK(text_marker);
+
+ if (AXTextMarkerGetLength(text_marker) != kDataSize)
+ return false;
+
+ const UInt8* source_buffer = AXTextMarkerGetBytePtr(text_marker);
+ if (!source_buffer)
+ return false;
+
+ *data = *reinterpret_cast<const AXPositionData*>(source_buffer);
+ return true;
+}
+
+// Of two positions, returns the one that comes first (destroys the other).
+AXPositionPointer FirstOf(AXPositionPointer a, AXPositionPointer b) {
+ return b->Compare(a) ? std::move(b) : std::move(a);
+}
+
+} // namespace
+
+@interface TextMarkerHelperMac ()
+- (AXPositionPointer)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 {
+ AXPositionPointer root = factory_->GetRoot();
+ return root ? CreateTextMarker(root->PositionAtStartOfAnchor()) : nil;
+}
+
+- (id)endTextMarker {
+ AXPositionPointer root = factory_->GetRoot();
+ return root ? CreateTextMarker(root->PositionAtEndOfAnchor()) : nil;
+}
+
+- (id)selectedTextMarkerRange {
+ AXRangePointer selection = factory_->GetSelection();
+ if (!selection.first || !selection.second)
+ return nil;
+ return CreateTextMarkerRange(std::move(selection));
+}
+
+- (AXPositionPointer)extractFrom:(id)parameter {
+ AXPositionData data;
+ if (ExtractData(base::mac::CFCastStrict<AXTextMarkerRef>(parameter), &data))
+ return factory_->GetFromData(data);
+ return factory_->GetFromData(ui::AXAbstractPosition::kNullData);
+}
+
+- (id)AXTextMarkerRangeForUIElement:(id)parameter {
+ AXPositionPointer startPosition = factory_->GetRoot();
+ AXPositionPointer endPosition = startPosition->PositionAtEndOfAnchor();
+ AXRangePointer range =
+ AXRangePointer(std::move(startPosition), std::move(endPosition));
+ return CreateTextMarkerRange(std::move(range));
+}
+
+- (id)AXUIElementForTextMarker:(id)parameter {
+ AXPositionData data;
+ if (ExtractData(base::mac::CFCastStrict<AXTextMarkerRef>(parameter), &data))
+ return factory_->GetAccessibilityObject(data);
+ return nil;
+}
+
+- (id)AXNextTextMarkerForTextMarker:(id)parameter {
+ AXPositionPointer position = [self extractFrom:parameter];
+ if (position->IsNull())
+ return nil;
+ return CreateTextMarker(position->NextCharacterPosition());
+}
+
+- (id)AXPreviousTextMarkerForTextMarker:(id)parameter {
+ AXPositionPointer position = [self extractFrom:parameter];
+ if (position->IsNull())
+ return nil;
+ return CreateTextMarker(position->PreviousCharacterPosition());
+}
+
+- (id)AXLeftWordTextMarkerRangeForTextMarker:(id)parameter {
+ AXPositionPointer endPosition = [self extractFrom:parameter];
+ if (endPosition->IsNull())
+ return nil;
+
+ AXPositionPointer startPosition =
+ FirstOf(endPosition->PreviousWordStartPosition(),
+ endPosition->PreviousWordEndPosition());
+ AXRangePointer range(std::move(startPosition), std::move(endPosition));
+ return CreateTextMarkerRange(std::move(range));
+}
+
+- (id)AXRightWordTextMarkerRangeForTextMarker:(id)parameter {
+ AXPositionPointer startPosition = [self extractFrom:parameter];
+ if (startPosition->IsNull())
+ return nil;
+
+ AXPositionPointer endPosition =
+ FirstOf(startPosition->NextWordEndPosition(),
+ startPosition->NextWordStartPosition());
+ AXRangePointer range(std::move(startPosition), std::move(endPosition));
+ return CreateTextMarkerRange(std::move(range));
+}
+
+- (id)AXNextWordEndTextMarkerForTextMarker:(id)parameter {
+ AXPositionPointer position = [self extractFrom:parameter];
+ if (position->IsNull())
+ return nil;
+ return CreateTextMarker(position->NextWordEndPosition());
+}
+
+- (id)AXPreviousWordStartTextMarkerForTextMarker:(id)parameter {
+ AXPositionPointer position = [self extractFrom:parameter];
+ if (position->IsNull())
+ return nil;
+ return CreateTextMarker(position->PreviousWordStartPosition());
+}
+
+- (id)AXTextMarkerRangeForLine:(id)parameter {
+ AXPositionPointer position = [self extractFrom:parameter];
+ if (position->IsNull())
+ return nil;
+
+ AXPositionPointer startPosition = position->PreviousLineStartPosition();
+ AXPositionPointer endPosition = position->NextLineEndPosition();
+ AXRangePointer range(std::move(startPosition), std::move(endPosition));
+ return CreateTextMarkerRange(std::move(range));
+}
+
+- (id)AXLeftLineTextMarkerRangeForTextMarker:(id)parameter {
+ AXPositionPointer endPosition = [self extractFrom:parameter];
+ if (endPosition->IsNull())
+ return nil;
+
+ AXPositionPointer startPosition =
+ FirstOf(endPosition->PreviousLineStartPosition(),
+ endPosition->PreviousLineEndPosition());
+ AXRangePointer range(std::move(startPosition), std::move(endPosition));
+ return CreateTextMarkerRange(std::move(range));
+}
+
+- (id)AXRightLineTextMarkerRangeForTextMarker:(id)parameter {
+ AXPositionPointer startPosition = [self extractFrom:parameter];
+ if (startPosition->IsNull())
+ return nil;
+
+ AXPositionPointer endPosition =
+ FirstOf(startPosition->NextLineStartPosition(),
+ startPosition->NextLineEndPosition());
+ AXRangePointer range(std::move(startPosition), std::move(endPosition));
+ return CreateTextMarkerRange(std::move(range));
+}
+
+- (id)AXNextLineEndTextMarkerForTextMarker:(id)parameter {
+ AXPositionPointer position = [self extractFrom:parameter];
+ if (position->IsNull())
+ return nil;
+ return CreateTextMarker(position->NextLineEndPosition());
+}
+
+- (id)AXPreviousLineStartTextMarkerForTextMarker:(id)parameter {
+ AXPositionPointer position = [self extractFrom:parameter];
+ if (position->IsNull())
+ return nil;
+ return CreateTextMarker(position->PreviousLineStartPosition());
+}
+
+- (id)AXLineTextMarkerRangeForTextMarker:(id)parameter {
+ AXPositionPointer position = [self extractFrom:parameter];
+ if (position->IsNull())
+ return nil;
+
+ AXRangePointer range(position->PreviousLineStartPosition(),
+ position->NextLineEndPosition());
+ return CreateTextMarkerRange(std::move(range));
+}
+
+- (id)AXTextMarkerRangeForUnorderedTextMarkers:(id)parameter {
+ if (![parameter isKindOfClass:[NSArray class]])
+ return nil;
+
+ NSArray* textMarkerArray = parameter;
+ if ([textMarkerArray count] != 2)
+ return nil;
+
+ AXPositionPointer startPosition =
+ [self extractFrom:[textMarkerArray objectAtIndex:0]];
+ AXPositionPointer endPosition =
+ [self extractFrom:[textMarkerArray objectAtIndex:1]];
+ if (endPosition->Compare(startPosition)) {
+ return CreateTextMarkerRange(
+ AXRangePointer(std::move(endPosition), std::move(startPosition)));
+ }
+ return CreateTextMarkerRange(
+ AXRangePointer(std::move(startPosition), std::move(endPosition)));
+}
+
++ (BOOL)getRangeDataFromMarkerRange:(id)parameter
+ start:(ui::AXPositionData*)start
+ end:(ui::AXPositionData*)end {
+ AXTextMarkerRangeRef markerRange =
+ base::mac::CFCastStrict<AXTextMarkerRangeRef>(parameter);
+ DCHECK(markerRange);
+
+ base::ScopedCFTypeRef<AXTextMarkerRef> startMarker(
+ AXTextMarkerRangeCopyStartMarker(markerRange));
+ base::ScopedCFTypeRef<AXTextMarkerRef> endMarker(
+ AXTextMarkerRangeCopyEndMarker(markerRange));
+ if (!startMarker || !endMarker)
+ return NO;
+
+ return ExtractData(startMarker, start) && ExtractData(endMarker, end);
+}
+
+@end
« no previous file with comments | « ui/accessibility/platform/text_marker_helper_mac.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698