Bug 1374316 - Add aria-readonly to several roles as per ARIA 1.1. r=surkov
authorJoanmarie Diggs <jdiggs@igalia.com>
Mon, 19 Jun 2017 11:09:23 -0400
changeset 364948 87825515d40b
parent 364947 2254061f8f51
child 364949 c4d6c50a1434
push id91659
push userryanvm@gmail.com
push dateTue, 20 Jun 2017 17:26:20 +0000
treeherdermozilla-inbound@87825515d40b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssurkov
bugs1374316
milestone56.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 1374316 - Add aria-readonly to several roles as per ARIA 1.1. r=surkov In ARIA 1.1, aria-readonly became a supported property of switch, menuitemcheckbox, menuitemradio, and radiogroup. aria-checked is not, and has not been, a supported property of menuitem. This property should only be supported on checkable subclasses of the ARIA menuitem role, namely menuitemcheckbox and menuitemradio.
accessible/base/ARIAMap.cpp
accessible/tests/mochitest/attributes/test_obj.html
accessible/tests/mochitest/test_aria_token_attrs.html
--- a/accessible/base/ARIAMap.cpp
+++ b/accessible/base/ARIAMap.cpp
@@ -783,40 +783,41 @@ static const nsRoleMapEntry sWAIRoleMaps
   { // menuitem
     &nsGkAtoms::menuitem,
     roles::MENUITEM,
     kUseMapRole,
     eNoValue,
     eClickAction,
     eNoLiveAttr,
     kGenericAccType,
-    kNoReqStates,
-    eARIACheckedMixed
+    kNoReqStates
   },
   { // menuitemcheckbox
     &nsGkAtoms::menuitemcheckbox,
     roles::CHECK_MENU_ITEM,
     kUseMapRole,
     eNoValue,
     eClickAction,
     eNoLiveAttr,
     kGenericAccType,
     kNoReqStates,
-    eARIACheckableMixed
+    eARIACheckableMixed,
+    eARIAReadonly
   },
   { // menuitemradio
     &nsGkAtoms::menuitemradio,
     roles::RADIO_MENU_ITEM,
     kUseMapRole,
     eNoValue,
     eClickAction,
     eNoLiveAttr,
     kGenericAccType,
     kNoReqStates,
-    eARIACheckableBool
+    eARIACheckableBool,
+    eARIAReadonly
   },
   { // navigation
     &nsGkAtoms::navigation,
     roles::NOTHING,
     kUseNativeRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
@@ -891,17 +892,18 @@ static const nsRoleMapEntry sWAIRoleMaps
     &nsGkAtoms::radiogroup,
     roles::RADIO_GROUP,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
     kGenericAccType,
     kNoReqStates,
-    eARIAOrientation
+    eARIAOrientation,
+    eARIAReadonly
   },
   { // region
     &nsGkAtoms::region,
     roles::PANE,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
@@ -1024,17 +1026,18 @@ static const nsRoleMapEntry sWAIRoleMaps
     &nsGkAtoms::_switch,
     roles::SWITCH,
     kUseMapRole,
     eNoValue,
     eCheckUncheckAction,
     eNoLiveAttr,
     kGenericAccType,
     kNoReqStates,
-    eARIACheckableBool
+    eARIACheckableBool,
+    eARIAReadonly
   },
   { // tab
     &nsGkAtoms::tab,
     roles::PAGETAB,
     kUseMapRole,
     eNoValue,
     eSwitchAction,
     eNoLiveAttr,
--- a/accessible/tests/mochitest/attributes/test_obj.html
+++ b/accessible/tests/mochitest/attributes/test_obj.html
@@ -25,17 +25,19 @@ https://bugzilla.mozilla.org/show_bug.cg
       testAttrs("atomic", {"atomic" : "true", "container-atomic" : "true"}, true);
       testAttrs(getNode("atomic").firstChild, {"container-atomic" : "true"}, true);
       testAbsentAttrs("atomic_false", {"atomic" : "false", "container-atomic" : "false"});
       testAbsentAttrs(getNode("atomic_false").firstChild, {"container-atomic" : "false"});
 
       testAttrs("autocomplete", {"autocomplete" : "true"}, true);
       testAttrs("checkbox", {"checkable" : "true"}, true);
       testAttrs("checkedCheckbox", {"checkable" : "true"}, true);
-      testAttrs("checkedMenuitem", {"checkable" : "true"}, true);
+      testAbsentAttrs("checkedMenuitem", {"checkable" : "true"}, true);
+      testAttrs("checkedMenuitemCheckbox", {"checkable" : "true"}, true);
+      testAttrs("checkedMenuitemRadio", {"checkable" : "true"}, true);
       testAttrs("checkedOption", {"checkable" : "true"}, true);
       testAttrs("checkedRadio", {"checkable" : "true"}, true);
       testAttrs("checkedTreeitem", {"checkable" : "true"}, true);
       testAttrs("dropeffect", {"dropeffect" : "copy"}, true);
       testAttrs("grabbed", {"grabbed" : "true"}, true);
       testAbsentAttrs("haspopup", { "haspopup": "false" });
       testAttrs("hidden", {"hidden" : "true"}, true);
       testAbsentAttrs("hidden_false", { "hidden": "false" });
@@ -200,16 +202,18 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   <!-- aria -->
   <div id="atomic" aria-atomic="true">live region</div>
   <div id="atomic_false" aria-atomic="false">live region</div>
   <div id="autocomplete" role="textbox" aria-autocomplete="true"></div>
   <div id="checkbox" role="checkbox"></div>
   <div id="checkedCheckbox" role="checkbox" aria-checked="true"></div>
   <div id="checkedMenuitem" role="menuitem" aria-checked="true"></div>
+  <div id="checkedMenuitemCheckbox" role="menuitemcheckbox" aria-checked="true"></div>
+  <div id="checkedMenuitemRadio" role="menuitemradio" aria-checked="true"></div>
   <div id="checkedOption" role="option" aria-checked="true"></div>
   <div id="checkedRadio" role="radio" aria-checked="true"></div>
   <div id="checkedTreeitem" role="treeitem" aria-checked="true"></div>
   <div id="dropeffect" aria-dropeffect="copy"></div>
   <div id="grabbed" aria-grabbed="true"></div>
   <div id="haspopup" aria-haspopup="true"></div>
   <div id="hidden" aria-hidden="true"></div>
   <div id="hidden_false" aria-hidden="false"></div>
--- a/accessible/tests/mochitest/test_aria_token_attrs.html
+++ b/accessible/tests/mochitest/test_aria_token_attrs.html
@@ -91,37 +91,72 @@ https://bugzilla.mozilla.org/show_bug.cg
 
       // test (option) checkable and checked states
       testStates("option_checked_true", (STATE_CHECKABLE | STATE_CHECKED));
       testStates("option_checked_false", STATE_CHECKABLE, 0, STATE_CHECKED);
       testStates("option_checked_empty", 0 , 0, STATE_CHECKABLE | STATE_CHECKED);
       testStates("option_checked_undefined", 0, 0, STATE_CHECKABLE | STATE_CHECKED);
       testStates("option_checked_absent", 0, 0, STATE_CHECKABLE | STATE_CHECKED);
 
-      // test (menuitem) checkable and checked states
-      testStates("menuitem_checked_true", (STATE_CHECKABLE | STATE_CHECKED));
-      testStates("menuitem_checked_false", STATE_CHECKABLE, 0, STATE_CHECKED);
+      // test (menuitem) checkable and checked states, which are unsupported on this role
+      testStates("menuitem_checked_true", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
+      testStates("menuitem_checked_false", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
       testStates("menuitem_checked_empty", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
       testStates("menuitem_checked_undefined", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
       testStates("menuitem_checked_absent", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
 
+      // test (menuitemcheckbox) checkable and checked states
+      testStates("menuitemcheckbox_checked_true", (STATE_CHECKABLE | STATE_CHECKED));
+      testStates("menuitemcheckbox_checked_false", STATE_CHECKABLE, 0, STATE_CHECKED);
+      testStates("menuitemcheckbox_checked_empty", STATE_CHECKABLE, 0, STATE_CHECKED);
+      testStates("menuitemcheckbox_checked_undefined", STATE_CHECKABLE, 0, STATE_CHECKED);
+      testStates("menuitemcheckbox_checked_absent", STATE_CHECKABLE, 0, STATE_CHECKED);
+
+      // test (menuitemcheckbox) readonly states
+      testStates("menuitemcheckbox_readonly_true", STATE_READONLY);
+      testStates("menuitemcheckbox_readonly_false", 0, 0, STATE_READONLY);
+      testStates("menuitemcheckbox_readonly_empty", 0, 0, STATE_READONLY);
+      testStates("menuitemcheckbox_readonly_undefined", 0, 0, STATE_READONLY);
+      testStates("menuitemcheckbox_readonly_absent", 0, 0, STATE_READONLY);
+
       // test (menuitemradio) checkable and checked states
       testStates("menuitemradio_checked_true", (STATE_CHECKABLE | STATE_CHECKED));
       testStates("menuitemradio_checked_false", STATE_CHECKABLE, 0, STATE_CHECKED);
       testStates("menuitemradio_checked_empty", STATE_CHECKABLE, 0, STATE_CHECKED);
       testStates("menuitemradio_checked_undefined", STATE_CHECKABLE, 0, STATE_CHECKED);
       testStates("menuitemradio_checked_absent", STATE_CHECKABLE, 0, STATE_CHECKED);
 
+      // test (menuitemradio) readonly states
+      testStates("menuitemradio_readonly_true", STATE_READONLY);
+      testStates("menuitemradio_readonly_false", 0, 0, STATE_READONLY);
+      testStates("menuitemradio_readonly_empty", 0, 0, STATE_READONLY);
+      testStates("menuitemradio_readonly_undefined", 0, 0, STATE_READONLY);
+      testStates("menuitemradio_readonly_absent", 0, 0, STATE_READONLY);
+
       // test (radio) checkable and checked states
       testStates("radio_checked_true", (STATE_CHECKABLE | STATE_CHECKED));
       testStates("radio_checked_false", STATE_CHECKABLE, 0, STATE_CHECKED);
       testStates("radio_checked_empty", STATE_CHECKABLE, 0, STATE_CHECKED);
       testStates("radio_checked_undefined", STATE_CHECKABLE, 0, STATE_CHECKED);
       testStates("radio_checked_absent", STATE_CHECKABLE, 0, STATE_CHECKED);
 
+      // test (radiogroup) readonly states
+      testStates("radiogroup_readonly_true", STATE_READONLY);
+      testStates("radiogroup_readonly_false", 0, 0, STATE_READONLY);
+      testStates("radiogroup_readonly_empty", 0, 0, STATE_READONLY);
+      testStates("radiogroup_readonly_undefined", 0, 0, STATE_READONLY);
+      testStates("radiogroup_readonly_absent", 0, 0, STATE_READONLY);
+
+      // test (switch) readonly states
+      testStates("switch_readonly_true", STATE_READONLY);
+      testStates("switch_readonly_false", 0, 0, STATE_READONLY);
+      testStates("switch_readonly_empty", 0, 0, STATE_READONLY);
+      testStates("switch_readonly_undefined", 0, 0, STATE_READONLY);
+      testStates("switch_readonly_absent", 0, 0, STATE_READONLY);
+
       // test (textbox) multiline states
       testStates("textbox_multiline_true", 0, EXT_STATE_MULTI_LINE);
       testStates("textbox_multiline_false", 0, EXT_STATE_SINGLE_LINE);
       testStates("textbox_multiline_empty", 0, EXT_STATE_SINGLE_LINE);
       testStates("textbox_multiline_undefined", 0, EXT_STATE_SINGLE_LINE);
       testStates("textbox_multiline_absent", 0, EXT_STATE_SINGLE_LINE);
 
       // test (textbox) readonly states
@@ -255,35 +290,80 @@ https://bugzilla.mozilla.org/show_bug.cg
   <div id="listbox_multiselectable_undefined" role="listbox" aria-multiselectable="undefined">
     <div id="option_checked_undefined" role="option" aria-checked="undefined">item</div>
   </div>
   <div id="listbox_multiselectable_absent" role="listbox">
     <div id="option_checked_absent" role="option">item</div>
   </div>
 
   <div role="menu">
-    <div id="menuitem_checked_true" role="menuitem" aria-checked="true">This menuitem has aria-checked="true" and should get STATE_CHECKABLE. It should also get STATE_checked.</div>
-    <div id="menuitem_checked_false" role="menuitem" aria-checked="false">This menuitem has aria-checked="false" and should get STATE_CHECKABLE.</div>
-    <div id="menuitem_checked_empty" role="menuitem" aria-checked="">This menuitem has aria-checked="" and should <emph>not</emph> get STATE_CHECKABLE.</div>
-    <div id="menuitem_checked_undefined" role="menuitem" aria-checked="undefined">This menuitem has aria-checked="undefined" and should <emph>not</emph> get STATE_CHECKABLE.</div>
-    <div id="menuitem_checked_absent" role="menuitem">This menuitem has <emph>no</emph> aria-checked attribute and should <emph>not</emph> get STATE_CHECKABLE.</div>
+    <div id="menuitem_checked_true" role="menuitem" aria-checked="true">Generic menuitems don't support aria-checked.</div>
+    <div id="menuitem_checked_false" role="menuitem" aria-checked="false">Generic menuitems don't support aria-checked.</div>
+    <div id="menuitem_checked_empty" role="menuitem" aria-checked="">Generic menuitems don't support aria-checked.</div>
+    <div id="menuitem_checked_undefined" role="menuitem" aria-checked="undefined">Generic menuitems don't support aria-checked.</div>
+    <div id="menuitem_checked_absent" role="menuitem">Generic menuitems don't support aria-checked.</div>
+
+    <div id="menuitemcheckbox_checked_true" role="menuitemcheckbox" aria-checked="true">This menuitemcheckbox has aria-checked="true" and should get STATE_CHECKABLE. It should also get STATE_checked.</div>
+    <div id="menuitemcheckbox_checked_false" role="menuitemcheckbox" aria-checked="false">This menuitemcheckbox has aria-checked="false" and should get STATE_CHECKABLE.</div>
+    <div id="menuitemcheckbox_checked_empty" role="menuitemcheckbox" aria-checked="">This menuitemcheckbox has aria-checked="" and should <emph>not</emph> get STATE_CHECKABLE.</div>
+    <div id="menuitemcheckbox_checked_undefined" role="menuitemcheckbox" aria-checked="undefined">This menuitemcheckbox has aria-checked="undefined" and should <emph>not</emph> get STATE_CHECKABLE.</div>
+    <div id="menuitemcheckbox_checked_absent" role="menuitemcheckbox">This menuitemcheckbox has <emph>no</emph> aria-checked attribute and should <emph>not</emph> get STATE_CHECKABLE.</div>
+
+    <div id="menuitemcheckbox_readonly_true" role="menuitemcheckbox" aria-readonly="true">This menuitemcheckbox has aria-readonly="true" and should get STATE_READONLY.</div>
+    <div id="menuitemcheckbox_readonly_false" role="menuitemcheckbox" aria-readonly="false">This menuitemcheckbox has aria-readonly="false" and should <emph>not</emph> get STATE_READONLY.</div>
+    <div id="menuitemcheckbox_readonly_empty" role="menuitemcheckbox" aria-readonly="">This menuitemcheckbox has aria-readonly="" and should <emph>not</emph> get STATE_READONLY.</div>
+    <div id="menuitemcheckbox_readonly_undefined" role="menuitemcheckbox" aria-readonly="undefined">This menuitemcheckbox has aria-readonly="undefined" and should <emph>not</emph> get STATE_READONLY.</div>
+    <div id="menuitemcheckbox_readonly_absent" role="menuitemcheckbox">This menuitemcheckbox has <emph>no</emph> aria-readonly attribute and should <emph>not</emph> get STATE_READONLY.</div>
 
     <div id="menuitemradio_checked_true" role="menuitemradio" aria-checked="true">This menuitem has aria-checked="true" and should get STATE_CHECKABLE. It should also get STATE_checked.</div>
     <div id="menuitemradio_checked_false" role="menuitemradio" aria-checked="false">This menuitem has aria-checked="false" and should get STATE_CHECKABLE.</div>
     <div id="menuitemradio_checked_empty" role="menuitemradio" aria-checked="">This menuitem has aria-checked="" and should <emph>not</emph> get STATE_CHECKABLE.</div>
     <div id="menuitemradio_checked_undefined" role="menuitemradio" aria-checked="undefined">This menuitem has aria-checked="undefined" and should <emph>not</emph> get STATE_CHECKABLE.</div>
     <div id="menuitemradio_checked_absent" role="menuitemradio">This menuitem has <emph>no</emph> aria-checked attribute but should get STATE_CHECKABLE.</div>
   </div>
 
+    <div id="menuitemradio_readonly_true" role="menuitemradio" aria-readonly="true">This menuitemradio has aria-readonly="true" and should get STATE_READONLY.</div>
+    <div id="menuitemradio_readonly_false" role="menuitemradio" aria-readonly="false">This menuitemradio has aria-readonly="false" and should <emph>not</emph> get STATE_READONLY.</div>
+    <div id="menuitemradio_readonly_empty" role="menuitemradio" aria-readonly="">This menuitemradio has aria-readonly="" and should <emph>not</emph> get STATE_READONLY.</div>
+    <div id="menuitemradio_readonly_undefined" role="menuitemradio" aria-readonly="undefined">This menuitemradio has aria-readonly="undefined" and should <emph>not</emph> get STATE_READONLY.</div>
+    <div id="menuitemradio_readonly_absent" role="menuitemradio">This menuitemradio has <emph>no</emph> aria-readonly attribute and should <emph>not</emph> get STATE_READONLY.</div>
+
   <div id="radio_checked_true" role="radio" aria-checked="true">This menuitem has aria-checked="true" and should get STATE_CHECKABLE. It should also get STATE_CHECKED.</div>
   <div id="radio_checked_false" role="radio" aria-checked="false">This menuitem has aria-checked="false" and should get STATE_CHECKABLE.</div>
   <div id="radio_checked_empty" role="radio" aria-checked="">This menuitem has aria-checked="" and should <emph>not</emph> get STATE_CHECKABLE.</div>
   <div id="radio_checked_undefined" role="radio" aria-checked="undefined">This menuitem has aria-checked="undefined" and should <emph>not</emph> get STATE_CHECKABLE.</div>
   <div id="radio_checked_absent" role="radio">This menuitem has <emph>no</emph> aria-checked attribute but should get STATE_CHECKABLE.</div>
 
+  <div id="radiogroup_readonly_true" role="radiogroup" aria-readonly="true">
+    <div role="radio">yes</div>
+    <div role="radio">no</div>
+  </div>
+  <div id="radiogroup_readonly_false" role="radiogroup" aria-readonly="false">
+    <div role="radio">yes</div>
+    <div role="radio">no</div>
+  </div>
+  <div id="radiogroup_readonly_empty" role="radiogroup" aria-readonly="">
+    <div role="radio">yes</div>
+    <div role="radio">no</div>
+  </div>
+  <div id="radiogroup_readonly_undefined" role="radiogroup" aria-readonly="undefined">
+    <div role="radio">yes</div>
+    <div role="radio">no</div>
+  </div>
+  <div id="radiogroup_readonly_absent" role="radiogroup">
+    <div role="radio">yes</div>
+    <div role="radio">no</div>
+  </div>
+
+  <div id="switch_readonly_true" role="switch" aria-readonly="true">This switch has aria-readonly="true" and should get STATE_READONLY.</div>
+  <div id="switch_readonly_false" role="switch" aria-readonly="false">This switch has aria-readonly="false" and should <emph>not</emph> get STATE_READONLY.</div>
+  <div id="switch_readonly_empty" role="switch" aria-readonly="">This switch has aria-readonly="" and should <emph>not</emph> get STATE_READONLY.</div>
+  <div id="switch_readonly_undefined" role="switch" aria-readonly="undefined">This switch has aria-readonly="undefined" and should <emph>not</emph> get STATE_READONLY.</div>
+  <div id="switch_readonly_absent" role="switch">This switch has <emph>no</emph> aria-readonly attribute and should <emph>not</emph> get STATE_READONLY.</div>
+
   <div id="textbox_readonly_true" role="textbox" aria-readonly="true"></div>
   <div id="textbox_readonly_false" role="textbox" aria-readonly="false"></div>
   <div id="textbox_readonly_empty" role="textbox" aria-readonly=""></div>
   <div id="textbox_readonly_undefined" role="textbox" aria-readonly="undefined"></div>
   <div id="textbox_readonly_absent" role="textbox"></div>
 
   <div id="textbox_multiline_true" role="textbox" aria-multiline="true"></div>
   <div id="textbox_multiline_false" role="textbox" aria-multiline="false"></div>