Bug 1625870 - Support figure and figcaption is OSX. r=morgan
authorEitan Isaacson <eitan@monotonous.org>
Tue, 28 Apr 2020 19:45:51 +0000
changeset 526548 86ffe587bcc89dc1fc7f4399246a7a0070fddb56
parent 526547 316c72999bc16821fe301434afbbeafb9be43207
child 526549 6cdc2132e4de12ea6588f668b58edae5d6450342
push id37358
push useropoprus@mozilla.com
push dateWed, 29 Apr 2020 03:05:14 +0000
treeherdermozilla-central@6bb8423186c1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmorgan
bugs1625870
milestone77.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 1625870 - Support figure and figcaption is OSX. r=morgan Differential Revision: https://phabricator.services.mozilla.com/D72509
accessible/base/RoleMap.h
accessible/html/HTMLFormControlAccessible.cpp
accessible/mac/mozAccessible.mm
accessible/tests/browser/mac/browser_roles_elements.js
accessible/tests/mochitest/elm/test_figure.html
--- a/accessible/base/RoleMap.h
+++ b/accessible/base/RoleMap.h
@@ -943,17 +943,17 @@ ROLE(ENTRY,
      ROLE_SYSTEM_TEXT,
      ROLE_SYSTEM_TEXT,
      java::SessionAccessibility::CLASSNAME_EDITTEXT,
      eNameFromValueRule)
 
 ROLE(CAPTION,
      "caption",
      ATK_ROLE_CAPTION,
-     NSAccessibilityStaticTextRole,
+     NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_CAPTION,
      java::SessionAccessibility::CLASSNAME_VIEW,
      eNameFromSubtreeIfReqRule)
 
 ROLE(NON_NATIVE_DOCUMENT,
      "non-native document",
      ATK_ROLE_DOCUMENT_FRAME,
--- a/accessible/html/HTMLFormControlAccessible.cpp
+++ b/accessible/html/HTMLFormControlAccessible.cpp
@@ -633,16 +633,17 @@ HTMLFigureAccessible::HTMLFigureAccessib
 ENameValueFlag HTMLFigureAccessible::NativeName(nsString& aName) const {
   ENameValueFlag nameFlag = HyperTextAccessibleWrap::NativeName(aName);
   if (!aName.IsEmpty()) return nameFlag;
 
   nsIContent* captionContent = Caption();
   if (captionContent)
     nsTextEquivUtils::AppendTextEquivFromContent(this, captionContent, &aName);
 
+  aName.CompressWhitespace();
   return eNameOK;
 }
 
 Relation HTMLFigureAccessible::RelationByType(RelationType aType) const {
   Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
   if (aType == RelationType::LABELLED_BY) rel.AppendTarget(mDoc, Caption());
 
   return rel;
--- a/accessible/mac/mozAccessible.mm
+++ b/accessible/mac/mozAccessible.mm
@@ -596,50 +596,57 @@ static const uint64_t kCacheInitialized 
 }
 
 - (NSString*)accessibilityActionDescription:(NSString*)action {
   // by default we return whatever the MacOS API know about.
   // if you have custom actions, override.
   return NSAccessibilityActionDescription(action);
 }
 
+- (BOOL)providesLabelNotTitle {
+  // These accessible types are the exception to the rule of label vs. title:
+  // They may be named explicitly, but they still provide a label not a title.
+  return mRole == roles::GROUPING || mRole == roles::RADIO_GROUP || mRole == roles::FIGURE ||
+         mRole == roles::GRAPHIC;
+}
+
 - (NSString*)accessibilityLabel {
   AccessibleWrap* accWrap = [self getGeckoAccessible];
   ProxyAccessible* proxy = [self getProxyAccessible];
   if (!accWrap && !proxy) {
     return nil;
   }
 
   nsAutoString name;
 
   /* If our accessible is:
    * 1. Named by invisible text, or
    * 2. Has more than one labeling relation, or
-   * 3. Is a grouping
+   * 3. Is a special role defined in providesLabelNotTitle
    *   ... return its name as a label (AXDescription).
    */
   if (accWrap) {
     ENameValueFlag flag = accWrap->Name(name);
     if (flag == eNameFromSubtree) {
       return nil;
     }
 
-    if (mRole != roles::GROUPING && mRole != roles::RADIO_GROUP) {
+    if (![self providesLabelNotTitle]) {
       Relation rel = accWrap->RelationByType(RelationType::LABELLED_BY);
       if (rel.Next() && !rel.Next()) {
         return nil;
       }
     }
   } else if (proxy) {
     uint32_t flag = proxy->Name(name);
     if (flag == eNameFromSubtree) {
       return nil;
     }
 
-    if (mRole != roles::GROUPING && mRole != roles::RADIO_GROUP) {
+    if (![self providesLabelNotTitle]) {
       nsTArray<ProxyAccessible*> rels = proxy->RelationByType(RelationType::LABELLED_BY);
       if (rels.Length() == 1) {
         return nil;
       }
     }
   }
 
   return nsCocoaUtils::ToNSString(name);
@@ -1123,18 +1130,18 @@ struct RoleDescrComparator {
   }
 
   return NSAccessibilityRoleDescription([self role], subrole);
 }
 
 - (NSString*)title {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
-  // If this is a grouping we provide the name in the label (AXDescription).
-  if (mRole == roles::GROUPING || mRole == roles::RADIO_GROUP) {
+  // In some special cases we provide the name in the label (AXDescription).
+  if ([self providesLabelNotTitle]) {
     return nil;
   }
 
   nsAutoString title;
   if (AccessibleWrap* accWrap = [self getGeckoAccessible])
     accWrap->Name(title);
   else if (ProxyAccessible* proxy = [self getProxyAccessible])
     proxy->Name(title);
--- a/accessible/tests/browser/mac/browser_roles_elements.js
+++ b/accessible/tests/browser/mac/browser_roles_elements.js
@@ -22,8 +22,62 @@ addAccessibleTask(`<hr id="hr" />`, (bro
     "AXRole for hr is AXSplitter"
   );
   is(
     hr.getAttributeValue("AXSubrole"),
     "AXContentSeparator",
     "Subrole for hr is AXContentSeparator"
   );
 });
+
+addAccessibleTask(
+  `
+  <figure id="figure">
+    <img id="img" src="http://example.com/a11y/accessible/tests/mochitest/moz.png" alt="Logo">
+    <p>Non-image figure content</p>
+    <figcaption id="figcaption">Old Mozilla logo</figcaption>
+  </figure>`,
+  (browser, accDoc) => {
+    let figure = getNativeInterface(accDoc, "figure");
+    ok(!figure.getAttributeValue("AXTitle"), "Figure should not have a title");
+    is(
+      figure.getAttributeValue("AXDescription"),
+      "Old Mozilla logo",
+      "Correct figure label"
+    );
+    is(figure.getAttributeValue("AXRole"), "AXGroup", "Correct figure role");
+    is(
+      figure.getAttributeValue("AXRoleDescription"),
+      "figure",
+      "Correct figure role description"
+    );
+
+    let img = getNativeInterface(accDoc, "img");
+    ok(!img.getAttributeValue("AXTitle"), "img should not have a title");
+    is(img.getAttributeValue("AXDescription"), "Logo", "Correct img label");
+    is(img.getAttributeValue("AXRole"), "AXImage", "Correct img role");
+    is(
+      img.getAttributeValue("AXRoleDescription"),
+      "image",
+      "Correct img role description"
+    );
+
+    let figcaption = getNativeInterface(accDoc, "figcaption");
+    ok(
+      !figcaption.getAttributeValue("AXTitle"),
+      "figcaption should not have a title"
+    );
+    ok(
+      !figcaption.getAttributeValue("AXDescription"),
+      "figcaption should not have a label"
+    );
+    is(
+      figcaption.getAttributeValue("AXRole"),
+      "AXGroup",
+      "Correct figcaption role"
+    );
+    is(
+      figcaption.getAttributeValue("AXRoleDescription"),
+      "group",
+      "Correct figcaption role description"
+    );
+  }
+);
--- a/accessible/tests/mochitest/elm/test_figure.html
+++ b/accessible/tests/mochitest/elm/test_figure.html
@@ -20,17 +20,17 @@
 
   <script type="application/javascript">
 
     function doTest() {
       testRole("figure", ROLE_FIGURE);
       testRole("figcaption", ROLE_CAPTION);
 
       todo(false, "figure name gets extra whitespace in the end!");
-      testName("figure", "figure caption ");
+      testName("figure", "figure caption");
       testName("figcaption", null);
 
       testRelation("figure", RELATION_LABELLED_BY, "figcaption");
       testRelation("figcaption", RELATION_LABEL_FOR, "figure");
 
       testAttrs("figure", {"xml-roles": "figure"}, true);
 
       SimpleTest.finish();