21NSString*
const NSAccessibilityScrollToVisibleAction =
@"AXScrollToVisible";
24static int kLiveRegionDebounceMillis = 20;
26using RoleMap = std::map<ax::mojom::Role, NSString*>;
27using EventMap = std::map<ax::mojom::Event, NSString*>;
28using ActionList = std::vector<std::pair<ax::mojom::Action, NSString*>>;
30struct AnnouncementSpec {
36RoleMap BuildRoleMap() {
37 const RoleMap::value_type roles[] = {
228 return RoleMap(
begin(roles),
end(roles));
231RoleMap BuildSubroleMap() {
232 const RoleMap::value_type subroles[] = {
275 return RoleMap(
begin(subroles),
end(subroles));
278EventMap BuildEventMap() {
279 const EventMap::value_type events[] = {
289 return EventMap(
begin(events),
end(events));
292ActionList BuildActionList() {
293 const ActionList::value_type entries[] = {
301 return ActionList(
begin(entries),
end(entries));
304const ActionList& GetActionList() {
309void PostAnnouncementNotification(NSString* announcement, NSWindow*
window,
bool is_polite) {
310 NSAccessibilityPriorityLevel priority =
311 is_polite ? NSAccessibilityPriorityMedium : NSAccessibilityPriorityHigh;
312 NSDictionary* notification_info =
313 @{NSAccessibilityAnnouncementKey : announcement,
314 NSAccessibilityPriorityKey : @(priority)};
316 NSAccessibilityPostNotificationWithUserInfo(
317 window, NSAccessibilityAnnouncementRequestedNotification, notification_info);
322 NSAccessibilityPostNotification(
target, notification);
345- (NSString*)getAXValueAsString;
348- (
std::unique_ptr<AnnouncementSpec>)announcementForEvent:(
ax::mojom::
Event)eventType;
354- (void)scheduleLiveRegionAnnouncement:(
std::unique_ptr<AnnouncementSpec>)announcement;
362@synthesize node = _node;
364+ (NSString*)nativeRoleFromAXRole:(
ax::mojom::
Role)role {
366 RoleMap::const_iterator it = role_map->find(role);
367 return it != role_map->end() ? it->second : NSAccessibilityUnknownRole;
370+ (NSString*)nativeSubroleFromAXRole:(
ax::mojom::
Role)role {
372 RoleMap::const_iterator it = subrole_map->find(role);
373 return it != subrole_map->end() ? it->second : nil;
376+ (NSString*)nativeNotificationFromAXEvent:(
ax::mojom::
Event)event {
378 EventMap::const_iterator it = event_map->find(
event);
379 return it != event_map->end() ? it->second : nil;
382- (instancetype)initWithNode:(
ui::AXPlatformNodeBase*)node {
393 NSAccessibilityPostNotification(
self, NSAccessibilityUIElementDestroyedNotification);
396- (NSRect)boundsInScreen {
397 if (!_node || !_node->GetDelegate())
404 std::string attributeValue;
405 if (_node->GetStringAttribute(attribute, &attributeValue))
406 return @(attributeValue.data());
410- (NSString*)getAXValueAsString {
411 id value = [
self AXValueInternal];
412 return [value isKindOfClass:[NSString class]] ?
value : nil;
415- (NSString*)getName {
416 return @(_node->GetName().data());
419- (
std::unique_ptr<AnnouncementSpec>)announcementForEvent:(
ax::mojom::
Event)eventType {
425 if (liveStatus ==
"off")
428 NSString*
name = [
self getName];
429 NSString* announcementText =
name;
430 if ([announcementText
length] <= 0) {
433 if ([announcementText
length] == 0)
436 auto announcement = std::make_unique<AnnouncementSpec>();
439 announcement->is_polite = liveStatus !=
"assertive";
443- (void)scheduleLiveRegionAnnouncement:(
std::unique_ptr<AnnouncementSpec>)announcement {
452 dispatch_after(kLiveRegionDebounceMillis * NSEC_PER_MSEC, dispatch_get_main_queue(), ^{
463- (
BOOL)accessibilityIsIgnored {
467 return [[
self AXRoleInternal] isEqualToString:NSAccessibilityUnknownRole] ||
471- (
id)accessibilityHitTest:(NSPoint)point {
472 if (!NSPointInRect(point, [
self boundsInScreen]))
475 for (
id child in [[
self AXChildrenInternal] reverseObjectEnumerator]) {
476 if (!NSPointInRect(point, [child accessibilityFrame]))
478 if (
id foundChild = [child accessibilityHitTest:point])
483 return NSAccessibilityUnignoredAncestor(
self);
486- (
BOOL)accessibilityNotifiesWhenDestroyed {
490- (
id)accessibilityFocusedUIElement {
491 return _node ? _node->GetDelegate()->GetFocus() : nil;
497- (NSArray*)accessibilityActionNames {
504 const ActionList& action_list = GetActionList();
508 BASE_DCHECK([action_list[0].second isEqualToString:NSAccessibilityPressAction]);
509 for (
const auto& item : action_list) {
510 if (
data.HasAction(item.first) || HasImplicitAction(
data, item.first))
511 [axActions addObject:item.second];
514 if (AlsoUseShowMenuActionForDefaultAction(
data))
515 [axActions addObject:NSAccessibilityShowMenuAction];
517 return axActions.autorelease();
520- (void)accessibilityPerformAction:(NSString*)action {
523 if (![[
self accessibilityActionNames] containsObject:
action])
527 if ([
action isEqualToString:NSAccessibilityShowMenuAction] &&
528 AlsoUseShowMenuActionForDefaultAction(_node->GetData())) {
531 for (
const ActionList::value_type& entry : GetActionList()) {
532 if ([
action isEqualToString:entry.second]) {
533 data.action = entry.first;
544 _node->GetDelegate()->AccessibilityPerformAction(
data);
547- (NSString*)AXRoleInternal {
551 return [[
self class] nativeRoleFromAXRole:_node->GetData().role];
554- (NSString*)AXRoleDescriptionInternal {
555 switch (_node->GetData().role) {
569 return NSAccessibilityRoleDescription([
self AXRoleInternal], [
self AXSubroleInternal]);
572- (NSString*)AXSubroleInternal {
577 return NSAccessibilitySecureTextFieldSubrole;
585- (NSString*)AXHelpInternal {
589 NSString*
desc = [
self getStringAttribute:ax::mojom::StringAttribute::kDescription];
590 NSString*
key = [
self getStringAttribute:ax::mojom::StringAttribute::kKeyShortcuts];
592 return key.length ?
key :
@"";
595 return [NSString stringWithFormat:@"%@ %@", desc, key];
598- (
id)AXValueInternal {
601 return [
self AXSelectedInternal];
608 NSString*
value = [
self getName];
609 if (
value.length == 0) {
610 value = [
self getStringAttribute:ax::mojom::StringAttribute::kValue];
614 return [
self getName];
617 if (_node->IsPlatformCheckable()) {
624 return [
self getStringAttribute:ax::mojom::StringAttribute::kValue];
627- (NSNumber*)AXEnabledInternal {
631- (NSNumber*)AXFocusedInternal {
633 return @(_node->GetDelegate()->GetFocus() == _node->GetNativeViewAccessible());
637- (
id)AXParentInternal {
640 return NSAccessibilityUnignoredAncestor(_node->GetParent());
643- (NSArray*)AXChildrenInternal {
647 int count = _node->GetChildCount();
648 NSMutableArray* children = [NSMutableArray arrayWithCapacity:count];
649 for (
auto child_iterator_ptr = _node->GetDelegate()->ChildrenBegin();
650 *child_iterator_ptr != *_node->GetDelegate()->ChildrenEnd(); ++(*child_iterator_ptr)) {
651 [children addObject:child_iterator_ptr->GetNativeViewAccessible()];
653 return NSAccessibilityUnignoredChildren(children);
656- (
id)AXWindowInternal {
657 return _node->GetDelegate()->GetNSWindow();
660- (
id)AXTopLevelUIElementInternal {
661 return [
self AXWindowInternal];
664- (NSValue*)AXPositionInternal {
665 return [NSValue valueWithPoint:self.boundsInScreen.origin];
668- (NSValue*)AXSizeInternal {
669 return [NSValue valueWithSize:self.boundsInScreen.size];
672- (NSString*)AXTitleInternal {
676 return [
self getName];
679- (NSNumber*)AXSelectedInternal {
683- (NSString*)AXPlaceholderValueInternal {
684 return [
self getStringAttribute:ax::mojom::StringAttribute::kPlaceholder];
687- (NSString*)AXMenuItemMarkChar {
694 return @"\xE2\x9C\x93";
700- (NSString*)AXSelectedTextInternal {
702 [[
self AXSelectedTextRangeInternal] getValue:&selectedTextRange];
703 return [[
self getAXValueAsString] substringWithRange:selectedTextRange];
706- (NSValue*)AXSelectedTextRangeInternal {
709 NSAssert((
start >= 0 &&
end >= 0) || (
start == -1 &&
end == -1),
@"selection is invalid");
712 return [NSValue valueWithRange:{NSNotFound, 0}];
715 return [NSValue valueWithRange:{static_cast<NSUInteger>(std::min(start, end)),
716 static_cast<NSUInteger>(abs(end - start))}];
719- (NSNumber*)AXNumberOfCharactersInternal {
720 return @([[
self getAXValueAsString] length]);
723- (NSValue*)AXVisibleCharacterRangeInternal {
724 return [NSValue valueWithRange:{0, [[
self getAXValueAsString] length]}];
727- (NSNumber*)AXInsertionPointLineNumberInternal {
734- (NSString*)description {
735 return [NSString stringWithFormat:@"%@ - %@ (%@)", [
super description], [
self AXTitleInternal],
736 [
self AXRoleInternal]];
748- (NSArray*)accessibilityChildren {
749 return [
self AXChildrenInternal];
752- (
BOOL)isAccessibilityElement {
755 return (![[
self AXRoleInternal] isEqualToString:NSAccessibilityUnknownRole] &&
758- (
BOOL)isAccessibilityEnabled {
759 return [[
self AXEnabledInternal] boolValue];
761- (NSRect)accessibilityFrame {
762 return [
self boundsInScreen];
765- (NSString*)accessibilityLabel {
770 return [
self AXTitleInternal];
773- (NSString*)accessibilityTitle {
774 return [
self AXTitleInternal];
777- (
id)accessibilityValue {
778 return [
self AXValueInternal];
781- (NSAccessibilityRole)accessibilityRole {
782 return [
self AXRoleInternal];
785- (NSString*)accessibilityRoleDescription {
786 return [
self AXRoleDescriptionInternal];
789- (NSAccessibilitySubrole)accessibilitySubrole {
790 return [
self AXSubroleInternal];
793- (NSString*)accessibilityHelp {
794 return [
self AXHelpInternal];
797- (
id)accessibilityParent {
798 return [
self AXParentInternal];
801- (
id)accessibilityWindow {
802 return [
self AXWindowInternal];
805- (
id)accessibilityTopLevelUIElement {
806 return [
self AXTopLevelUIElementInternal];
809- (
BOOL)accessibilitySelected {
810 return [[
self AXSelectedInternal] boolValue];
813- (
BOOL)isAccessibilitySelectorAllowed:(
SEL)selector {
821 if (selector ==
@selector(setAccessibilityValue:)) {
836 if (selector ==
@selector(setAccessibilitySelectedText:) ||
837 selector ==
@selector(setAccessibilitySelectedTextRange:) ||
838 selector ==
@selector(setAccessibilitySelectedTextMarkerRange:)) {
842 if (selector ==
@selector(setAccessibilityFocused:))
846 return [
super isAccessibilitySelectorAllowed:selector];
849- (void)setAccessibilityValue:(
id)value {
856 if ([
value isKindOfClass:[NSString
class]]) {
857 data.value = std::string([
value UTF8String]);
858 }
else if ([
value isKindOfClass:[NSValue
class]]) {
862 NSRange range = [value rangeValue];
863 data.anchor_offset = range.location;
864 data.focus_offset = NSMaxRange(range);
866 _node->GetDelegate()->AccessibilityPerformAction(
data);
869- (void)setAccessibilityFocused:(
BOOL)isFocused {
874 _node->GetDelegate()->AccessibilityPerformAction(
data);
877- (void)setAccessibilitySelectedText:(NSString*)text {
882 data.value = std::string([
text UTF8String]);
884 _node->GetDelegate()->AccessibilityPerformAction(
data);
887- (void)setAccessibilitySelectedTextRange:(NSRange)range {
892 data.anchor_offset = range.location;
893 data.focus_offset = NSMaxRange(range);
894 _node->GetDelegate()->AccessibilityPerformAction(
data);
902- (NSInteger)accessibilityInsertionPointLineNumber {
903 return [[
self AXInsertionPointLineNumberInternal] integerValue];
906- (NSInteger)accessibilityNumberOfCharacters {
909 return [[
self AXNumberOfCharactersInternal] integerValue];
912- (NSString*)accessibilityPlaceholderValue {
916 return [
self AXPlaceholderValueInternal];
919- (NSString*)accessibilitySelectedText {
923 return [
self AXSelectedTextInternal];
926- (NSRange)accessibilitySelectedTextRange {
928 return NSMakeRange(0, 0);
931 [[
self AXSelectedTextRangeInternal] getValue:&r];
935- (NSArray*)accessibilitySelectedTextRanges {
939 return @[ [
self AXSelectedTextRangeInternal] ];
942- (NSRange)accessibilitySharedCharacterRange {
944 return NSMakeRange(0, 0);
947 [[
self AXSelectedTextRangeInternal] getValue:&r];
951- (NSArray*)accessibilitySharedTextUIElements {
958- (NSRange)accessibilityVisibleCharacterRange {
960 return NSMakeRange(0, 0);
962 return [[
self AXVisibleCharacterRangeInternal] rangeValue];
965- (NSString*)accessibilityStringForRange:(NSRange)range {
969 return [[
self getAXValueAsString] substringWithRange:range];
972- (NSAttributedString*)accessibilityAttributedStringForRange:(NSRange)range {
977 [[NSAttributedString alloc] initWithString:[
self accessibilityStringForRange:range]]);
978 return attributedString.autorelease();
981- (NSData*)accessibilityRTFForRange:(NSRange)range {
985- (NSRect)accessibilityFrameForRange:(NSRange)range {
989- (NSInteger)accessibilityLineForIndex:(NSInteger)index {
994- (NSRange)accessibilityRangeForIndex:(NSInteger)index {
996 return NSMakeRange(0, 0);
999- (NSRange)accessibilityStyleRangeForIndex:(NSInteger)index {
1001 return NSMakeRange(0, 0);
1004 return NSMakeRange(0, [
self accessibilityNumberOfCharacters]);
1007- (NSRange)accessibilityRangeForLine:(NSInteger)line {
1009 return NSMakeRange(0, 0);
1012 BASE_LOG() <<
"Views textfields are single-line.";
1015 return NSMakeRange(0, [
self accessibilityNumberOfCharacters]);
1018- (NSRange)accessibilityRangeForPosition:(NSPoint)point {
1022 return NSMakeRange(0, 0);
1028- (NSArray*)accessibilitySharedFocusElements {
1029 if (![[
self AXFocusedInternal] boolValue])
1033- (
id)accessibilityFocusedWindow {
1034 if (![[
self AXFocusedInternal] boolValue])
1038- (
id)accessibilityApplicationFocusedUIElement {
1039 if (![[
self AXFocusedInternal] boolValue])
1043- (
BOOL)isAccessibilityFocused {
1044 return [[
self AXFocusedInternal] boolValue];
1054 node->
Init(delegate);
1061 return [accessible node];
1067AXPlatformNodeMac::~AXPlatformNodeMac() {}
1089 return native_node_.
get();
1101 if (
auto announcement = [native_node_ announcementForEvent:
event_type]) {
1102 [
native_node_ scheduleLiveRegionAnnouncement:std::move(announcement)];
ax::mojom::Event event_type
void reset(NST object=nil)
static const char * begin(const StringSlice &s)
API_AVAILABLE(ios(13.0)) @interface FlutterTextPlaceholder UITextRange * selectedTextRange
@ kPdfActionableHighlight
std::string UTF16ToUTF8(std::u16string src)
DEF_SWITCHES_START aot vmservice shared library name
GFX_EXPORT NSRect ScreenRectToNSRect(const Rect &rect)
UnimplementedNativeViewAccessible * NativeViewAccessible
AX_EXPORT bool IsNameExposedInAXValueForRole(ax::mojom::Role role)
bool IsMenuItem(ax::mojom::Role role)
bool IsListItem(const ax::mojom::Role role)
std::shared_ptr< const fml::Mapping > data
#define BASE_DCHECK(condition)
#define BASE_UNREACHABLE()