Bug 1357071 - Implement support for implicit values for aria-value* attributes for scrollbar and slider roles, r=Jamie
authorMaliha Islam <mislam@mozilla.com>
Thu, 29 Aug 2019 06:39:28 +0000
changeset 551094 7af553376576253a34735954c2f0e22b85847fec
parent 551093 ecf3e677949399f0d886170c5bac66a5f0f34766
child 551095 d6f691b8f534e3d3e9caca579460181fdec8542f
push id11865
push userbtara@mozilla.com
push dateMon, 02 Sep 2019 08:54:37 +0000
treeherdermozilla-beta@37f59c4671b3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersJamie
bugs1357071
milestone70.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 1357071 - Implement support for implicit values for aria-value* attributes for scrollbar and slider roles, r=Jamie Differential Revision: https://phabricator.services.mozilla.com/D43293
accessible/generic/Accessible-inl.h
accessible/generic/Accessible.cpp
accessible/generic/Accessible.h
accessible/tests/browser/e10s/browser_caching_value.js
accessible/tests/mochitest/events/test_valuechange.html
accessible/tests/mochitest/role/test_aria.html
accessible/tests/mochitest/value/a11y.ini
accessible/tests/mochitest/value/test_ariavalue.html
--- a/accessible/generic/Accessible-inl.h
+++ b/accessible/generic/Accessible-inl.h
@@ -66,28 +66,34 @@ inline bool Accessible::IsSearchbox() co
 }
 
 inline bool Accessible::HasGenericType(AccGenericType aType) const {
   const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
   return (mGenericTypes & aType) ||
          (roleMapEntry && roleMapEntry->IsOfType(aType));
 }
 
-inline bool Accessible::HasNumericValue() const {
-  if (mStateFlags & eHasNumericValue) return true;
+inline bool Accessible::NativeHasNumericValue() const {
+  return mStateFlags & eHasNumericValue;
+}
 
+inline bool Accessible::ARIAHasNumericValue() const {
   const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
   if (!roleMapEntry || roleMapEntry->valueRule == eNoValue) return false;
 
   if (roleMapEntry->valueRule == eHasValueMinMaxIfFocusable)
     return InteractiveState() & states::FOCUSABLE;
 
   return true;
 }
 
+inline bool Accessible::HasNumericValue() const {
+  return NativeHasNumericValue() || ARIAHasNumericValue();
+}
+
 inline bool Accessible::IsDefunct() const {
   MOZ_ASSERT(mStateFlags & eIsDefunct || IsApplication() || IsDoc() ||
                  mStateFlags & eSharedNode || mContent,
              "No content");
   return mStateFlags & eIsDefunct;
 }
 
 inline void Accessible::ScrollTo(uint32_t aHow) const {
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -1372,18 +1372,22 @@ void Accessible::Value(nsString& aValue)
     // equivalent. For the string value, we will try the optional text
     // equivalent first.
     if (!mContent->IsElement()) {
       return;
     }
 
     if (!mContent->AsElement()->GetAttr(kNameSpaceID_None,
                                         nsGkAtoms::aria_valuetext, aValue)) {
-      mContent->AsElement()->GetAttr(kNameSpaceID_None,
-                                     nsGkAtoms::aria_valuenow, aValue);
+      if (!NativeHasNumericValue()) {
+        double checkValue = CurValue();
+        if (!IsNaN(checkValue)) {
+          aValue.AppendFloat(checkValue);
+        }
+      }
     }
     return;
   }
 
   if (!roleMapEntry) {
     return;
   }
 
@@ -1407,29 +1411,37 @@ void Accessible::Value(nsString& aValue)
       }
     }
 
     if (option) nsTextEquivUtils::GetTextEquivFromSubtree(option, aValue);
   }
 }
 
 double Accessible::MaxValue() const {
-  return AttrNumericValue(nsGkAtoms::aria_valuemax);
+  double checkValue = AttrNumericValue(nsGkAtoms::aria_valuemax);
+  return IsNaN(checkValue) && !NativeHasNumericValue() ? 100 : checkValue;
 }
 
 double Accessible::MinValue() const {
-  return AttrNumericValue(nsGkAtoms::aria_valuemin);
+  double checkValue = AttrNumericValue(nsGkAtoms::aria_valuemin);
+  return IsNaN(checkValue) && !NativeHasNumericValue() ? 0 : checkValue;
 }
 
 double Accessible::Step() const {
   return UnspecifiedNaN<double>();  // no mimimum increment (step) in ARIA.
 }
 
 double Accessible::CurValue() const {
-  return AttrNumericValue(nsGkAtoms::aria_valuenow);
+  double checkValue = AttrNumericValue(nsGkAtoms::aria_valuenow);
+  if (IsNaN(checkValue) && !NativeHasNumericValue()) {
+    double minValue = MinValue();
+    return minValue + ((MaxValue() - minValue) / 2);
+  }
+
+  return checkValue;
 }
 
 bool Accessible::SetCurValue(double aValue) {
   const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
   if (!roleMapEntry || roleMapEntry->valueRule == eNoValue) return false;
 
   const uint32_t kValueCannotChange = states::READONLY | states::UNAVAILABLE;
   if (State() & kValueCannotChange) return false;
--- a/accessible/generic/Accessible.h
+++ b/accessible/generic/Accessible.h
@@ -896,16 +896,26 @@ class Accessible : public nsISupports {
   /**
    * Return true if the accessible has associated DOM content.
    */
   bool HasOwnContent() const {
     return mContent && !(mStateFlags & eSharedNode);
   }
 
   /**
+   * Return true if native markup has a numeric value.
+   */
+  bool NativeHasNumericValue() const;
+
+  /**
+   * Return true if ARIA specifies support for a numeric value.
+   */
+  bool ARIAHasNumericValue() const;
+
+  /**
    * Return true if the accessible has a numeric value.
    */
   bool HasNumericValue() const;
 
   /**
    * Return true if the accessible state change is processed by handling proper
    * DOM UI event, if otherwise then false. For example, CheckboxAccessible
    * created for HTML:input@type="checkbox" will process
--- a/accessible/tests/browser/e10s/browser_caching_value.js
+++ b/accessible/tests/browser/e10s/browser_caching_value.js
@@ -79,17 +79,17 @@ const valueTests = [
     desc:
       "Value should change to @aria-valuetext when @aria-valuenow is removed",
     id: "slider",
     attrs: [
       {
         attr: "aria-valuenow",
       },
     ],
-    expected: ["hey!", 0, 0, 7, 0],
+    expected: ["hey!", 3.5, 0, 7, 0],
   },
   {
     desc: "Initially value is not set for combobox",
     id: "combobox",
     expected: "",
   },
   {
     desc: "Value should change when @value attribute is updated",
--- a/accessible/tests/mochitest/events/test_valuechange.html
+++ b/accessible/tests/mochitest/events/test_valuechange.html
@@ -133,17 +133,17 @@
     }
 
     // enableLogging("DOMEvents");
     // gA11yEventDumpToConsole = true;
     function doTests() {
       // Test initial values
       testValue("slider_vn", "5", 5, 0, 1000, 0);
       testValue("slider_vnvt", "plain", 0, 0, 5, 0);
-      testValue("slider_vt", "hi", 0, 0, 3, 0);
+      testValue("slider_vt", "hi", 1.5, 0, 3, 0);
       testValue("scrollbar", "5", 5, 0, 1000, 0);
       testValue("splitter", "5", 5, 0, 1000, 0);
       testValue("progress", "22%", 22, 0, 100, 0);
       testValue("range", "6", 6, 0, 10, 1);
 
       // Test that elements which should not expose values do not
       var accSeparator = getAccessible("separator", [nsIAccessibleValue], null, DONOTFAIL_IF_NO_INTERFACE);
       ok(!accSeparator, "value interface is not exposed for separator");
--- a/accessible/tests/mochitest/role/test_aria.html
+++ b/accessible/tests/mochitest/role/test_aria.html
@@ -253,17 +253,17 @@
   <span id="aria_presentation" role="presentation" tabindex="0"/>
   <span id="aria_progressbar" role="progressbar"/>
   <span id="aria_radio" role="radio"/>
   <span id="aria_radiogroup" role="radiogroup"/>
   <span id="aria_region_no_name" role="region"/>
   <span id="aria_region_has_label" role="region" aria-label="label"/>
   <span id="aria_region_has_labelledby" role="region" aria-labelledby="label"/><span id="label" aria-label="label">
   <span id="aria_region_has_title" role="region" title="title"/>
-  <span id="aria_region_empty_name" role="region" aria-label="" title="" aria-labelledby="empty"/><span id="empty"/>
+  <span id="aria_region_empty_name" role="region" aria-label="" title="" aria-labelledby="empty"></span><span id="empty"></span>
   <span id="aria_row" role="row"/>
   <span id="aria_rowheader" role="rowheader"/>
   <span id="aria_scrollbar" role="scrollbar"/>
   <span id="aria_searchbox" role="textbox"/>
   <span id="aria_separator" role="separator"/>
   <span id="aria_slider" role="slider"/>
   <span id="aria_spinbutton" role="spinbutton"/>
   <span id="aria_status" role="status"/>
--- a/accessible/tests/mochitest/value/a11y.ini
+++ b/accessible/tests/mochitest/value/a11y.ini
@@ -1,8 +1,9 @@
 [DEFAULT]
 support-files =
   !/accessible/tests/mochitest/*.js
 
+[test_ariavalue.html]
 [test_general.html]
 [test_number.html]
 [test_progress.html]
 [test_range.html]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/value/test_ariavalue.html
@@ -0,0 +1,68 @@
+<html>
+
+<head>
+  <title>nsIAccessible value testing for implicit aria-value* attributes</title>
+
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript" src="../common.js"></script>
+  <script type="application/javascript" src="../value.js"></script>
+
+  <script src="chrome://mochikit/content/chrome-harness.js"></script>
+
+  <script type="application/javascript">
+    function doTest() {
+      for (const role of ["slider", "scrollbar"]) {
+        testValue(`${role}_default`, "50", 50, 0, 100, 0);
+        testValue(`${role}_min1max50`, "25.5", 25.5, 1, 50, 0);
+        testValue(`${role}_max200`, "100", 100, 0, 200, 0);
+        testValue(`${role}_min10`, "55", 55, 10, 100, 0);
+        testValue(`${role}_vt`, "juice", 50, 0, 100, 0);
+        testValue(`${role}_vn`, "6", 6, 0, 100, 0);
+        testValue(`${role}_vtvn`, "juice", 6, 0, 100, 0);
+      }
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+
+</head>
+
+<body>
+
+  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1357071"
+    title="Add support for implicit values for aria-value* attributes for scrollbar and slider roles">
+    Bug 1357071
+  </a>
+
+  <p id="display"></p>
+  <div id="content" style="display: none">
+  </div>
+  <pre id="test">
+  </pre>
+
+  <!-- ARIA sliders -->
+  <div id="slider_default" role="slider">vanilla slider</div>
+  <div id="slider_min1max50" role="slider" aria-valuemin="1" aria-valuemax="50">banana slider</div>
+  <div id="slider_max200" role="slider" aria-valuemax="200">cherry slider</div>
+  <div id="slider_min10" role="slider" aria-valuemin="10">strawberry slider</div>
+  <div id="slider_vt" role="slider" aria-valuetext="juice">orange slider</div>
+  <div id="slider_vn" role="slider" aria-valuenow="6">chocolate slider</div>
+  <div id="slider_vtvn" role="slider" aria-valuetext="juice" aria-valuenow="6">apple slider</div>
+
+  <!-- ARIA scrollbars -->
+  <div id="scrollbar_default" role="scrollbar">vanilla scrollbar</div>
+  <div id="scrollbar_min1max50" role="scrollbar" aria-valuemin="1" aria-valuemax="50">banana scrollbar</div>
+  <div id="scrollbar_max200" role="scrollbar" aria-valuemax="200">cherry scrollbar</div>
+  <div id="scrollbar_min10" role="scrollbar" aria-valuemin="10">strawberry scrollbar</div>
+  <div id="scrollbar_vt" role="scrollbar" aria-valuetext="juice">orange scrollbar</div>
+  <div id="scrollbar_vn" role="scrollbar" aria-valuenow="6">chocolate scrollbar</div>
+  <div id="scrollbar_vtvn" role="scrollbar" aria-valuetext="juice" aria-valuenow="6">apple scrollbar</div>
+</body>
+
+</html>