Bug 1616679: Map accessible actions to Mac actions based on action name. r=eeejay
authorMorgan Reschenberg <mreschenberg@mozilla.com>
Wed, 25 Mar 2020 22:09:59 +0000
changeset 520446 85bae8580dde1e86c3d11582474ff4af9f92b768
parent 520445 202ac04e9c8d7b1be18197b20dfdabb6f1e83ceb
child 520447 5f32745a79fe357e7e247b35d3e7ba09f453b688
push id37250
push userdvarga@mozilla.com
push dateThu, 26 Mar 2020 04:04:15 +0000
treeherdermozilla-central@85bae8580dde [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerseeejay
bugs1616679
milestone76.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1616679: Map accessible actions to Mac actions based on action name. r=eeejay Differential Revision: https://phabricator.services.mozilla.com/D67200
accessible/mac/mozAccessible.mm
accessible/mac/mozActionElements.h
accessible/mac/mozActionElements.mm
accessible/mac/mozHTMLAccessible.mm
--- a/accessible/mac/mozAccessible.mm
+++ b/accessible/mac/mozAccessible.mm
@@ -478,17 +478,55 @@ static inline NSMutableArray* ConvertToN
 
   if (nativeChild) return nativeChild;
 
   // if we didn't find anything, return ourself or child view.
   return GetObjectOrRepresentedView(self);
 }
 
 - (NSArray*)accessibilityActionNames {
-  return @[ NSAccessibilityScrollToVisibleAction ];
+  AccessibleWrap* accWrap = [self getGeckoAccessible];
+  ProxyAccessible* proxy = [self getProxyAccessible];
+  // Create actions array
+  NSMutableArray* actions = [NSMutableArray new];
+  if (!accWrap && !proxy) return actions;
+
+  uint8_t count = 0;
+  if (accWrap) {
+    count = accWrap->ActionCount();
+  } else if (proxy) {
+    count = proxy->ActionCount();
+  }
+
+  // Check if the accessible has an existing gecko
+  // action, and add the corresponding Mac action to
+  // the actions array. `count` is guaranteed to be 0 or 1
+  if (count) {
+    nsAutoString name;
+    if (accWrap) {
+      accWrap->ActionNameAt(0, name);
+    } else if (proxy) {
+      proxy->ActionNameAt(0, name);
+    }
+    if (name.EqualsLiteral("select")) {
+      [actions addObject:NSAccessibilityPickAction];
+    } else {
+      [actions addObject:NSAccessibilityPressAction];
+    }
+  }
+
+  // Regardless of `count`, add actions that should be
+  // performable on all accessibles. If we added a press
+  // action, it will be first in the list. We append other
+  // actions here to maintain that invariant.
+  [actions addObject:NSAccessibilityScrollToVisibleAction];
+  // XXX(morgan): we should implement `show menu` as
+  // an "always performable" action. See bug 1623402.
+
+  return actions;
 }
 
 - (NSString*)accessibilityActionDescription:(NSString*)action {
   // by default we return whatever the MacOS API know about.
   // if you have custom actions, override.
   return NSAccessibilityActionDescription(action);
 }
 
@@ -532,24 +570,31 @@ static inline NSMutableArray* ConvertToN
       }
     }
   }
 
   return nsCocoaUtils::ToNSString(name);
 }
 
 - (void)accessibilityPerformAction:(NSString*)action {
+  RefPtr<AccessibleWrap> accWrap = [self getGeckoAccessible];
+  ProxyAccessible* proxy = [self getProxyAccessible];
+
   if ([action isEqualToString:NSAccessibilityScrollToVisibleAction]) {
-    RefPtr<AccessibleWrap> accWrap = [self getGeckoAccessible];
-    ProxyAccessible* proxy = [self getProxyAccessible];
     if (accWrap) {
       accWrap->ScrollTo(nsIAccessibleScrollType::SCROLL_TYPE_ANYWHERE);
     } else if (proxy) {
       proxy->ScrollTo(nsIAccessibleScrollType::SCROLL_TYPE_ANYWHERE);
     }
+  } else {
+    if (accWrap) {
+      accWrap->DoAction(0);
+    } else if (proxy) {
+      proxy->DoAction(0);
+    }
   }
 }
 
 - (id)accessibilityFocusedUIElement {
   AccessibleWrap* accWrap = [self getGeckoAccessible];
   ProxyAccessible* proxy = [self getProxyAccessible];
   if (!accWrap && !proxy) return nil;
 
--- a/accessible/mac/mozActionElements.h
+++ b/accessible/mac/mozActionElements.h
@@ -6,17 +6,16 @@
 #import <Cocoa/Cocoa.h>
 #import "mozAccessible.h"
 
 /* Simple subclasses for things like checkboxes, buttons, etc. */
 
 @interface mozButtonAccessible : mozAccessible {
 }
 - (BOOL)hasPopup;
-- (void)click;
 @end
 
 @interface mozCheckboxAccessible : mozButtonAccessible
 // returns one of the constants defined in CheckboxValue
 - (int)isChecked;
 @end
 
 /**
--- a/accessible/mac/mozActionElements.mm
+++ b/accessible/mac/mozActionElements.mm
@@ -65,75 +65,16 @@ enum CheckboxValue {
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
 - (BOOL)accessibilityIsIgnored {
   return ![self getGeckoAccessible] && ![self getProxyAccessible];
 }
 
-- (NSArray*)accessibilityActionNames {
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
-
-  NSArray* actions = [super accessibilityActionNames];
-  if ([self isEnabled]) {
-    // VoiceOver expects the press action to be the first in the list.
-    if ([self hasPopup]) {
-      return [@[ NSAccessibilityPressAction, NSAccessibilityShowMenuAction ]
-          arrayByAddingObjectsFromArray:actions];
-    }
-    return [@[ NSAccessibilityPressAction ] arrayByAddingObjectsFromArray:actions];
-  }
-
-  return actions;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
-}
-
-- (NSString*)accessibilityActionDescription:(NSString*)action {
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
-
-  if ([action isEqualToString:NSAccessibilityPressAction]) {
-    return @"press button";  // XXX: localize this later?
-  }
-
-  if ([self hasPopup]) {
-    if ([action isEqualToString:NSAccessibilityShowMenuAction]) return @"show menu";
-  }
-
-  return nil;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
-}
-
-- (void)accessibilityPerformAction:(NSString*)action {
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
-
-  if ([self isEnabled] && [action isEqualToString:NSAccessibilityPressAction]) {
-    // TODO: this should bring up the menu, but currently doesn't.
-    //       once msaa and atk have merged better, they will implement
-    //       the action needed to show the menu.
-    [self click];
-  } else {
-    [super accessibilityPerformAction:action];
-  }
-
-  NS_OBJC_END_TRY_ABORT_BLOCK;
-}
-
-- (void)click {
-  // both buttons and checkboxes have only one action. we should really stop using arbitrary
-  // arrays with actions, and define constants for these actions.
-  if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
-    accWrap->DoAction(0);
-  } else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
-    proxy->DoAction(0);
-  }
-}
-
 - (BOOL)hasPopup {
   if (AccessibleWrap* accWrap = [self getGeckoAccessible])
     return accWrap->NativeState() & states::HASPOPUP;
 
   if (ProxyAccessible* proxy = [self getProxyAccessible])
     return proxy->NativeState() & states::HASPOPUP;
 
   return false;
--- a/accessible/mac/mozHTMLAccessible.mm
+++ b/accessible/mac/mozHTMLAccessible.mm
@@ -71,35 +71,16 @@
   // if we're expired, we don't support any actions.
   if (![self getGeckoAccessible] && ![self getProxyAccessible]) return [NSArray array];
 
   // Always advertise press action first.
   return [@[ NSAccessibilityPressAction ]
       arrayByAddingObjectsFromArray:[super accessibilityActionNames]];
 }
 
-- (void)accessibilityPerformAction:(NSString*)action {
-  AccessibleWrap* accWrap = [self getGeckoAccessible];
-  ProxyAccessible* proxy = [self getProxyAccessible];
-  if (!accWrap && !proxy) {
-    return;
-  }
-
-  if ([action isEqualToString:NSAccessibilityPressAction]) {
-    if (accWrap) {
-      accWrap->DoAction(0);
-    } else if (proxy) {
-      proxy->DoAction(0);
-    }
-    return;
-  }
-
-  [super accessibilityPerformAction:action];
-}
-
 - (NSString*)customDescription {
   return @"";
 }
 
 - (NSString*)value {
   return @"";
 }