Bug 1173364 - support ARIA table and cell roles, r=marcoz
authorAlexander Surkov <surkov.alexander@gmail.com>
Thu, 25 Jun 2015 11:59:06 -0700
changeset 250210 a4bcc7ee6e5c0582ec95b5caf34ecb46dcf37bda
parent 250209 a5cd9f18f1b6173844f26da8780635c1683f80c4
child 250211 28bbd1fb7ed10f2ec33b1b0129ed3ad335e5ae59
push id61479
push usersurkov.alexander@gmail.com
push dateThu, 25 Jun 2015 18:59:39 +0000
treeherdermozilla-inbound@a4bcc7ee6e5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmarcoz
bugs1173364
milestone41.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 1173364 - support ARIA table and cell roles, r=marcoz
accessible/base/ARIAMap.cpp
accessible/base/Filters.cpp
accessible/generic/ARIAGridAccessible.cpp
accessible/tests/mochitest/table/a11y.ini
accessible/tests/mochitest/table/test_headers_ariatable.html
accessible/tests/mochitest/tree/a11y.ini
accessible/tests/mochitest/tree/test_aria_table.html
--- a/accessible/base/ARIAMap.cpp
+++ b/accessible/base/ARIAMap.cpp
@@ -93,16 +93,26 @@ static nsRoleMapEntry sWAIRoleMaps[] =
     kUseMapRole,
     eNoValue,
     ePressAction,
     eNoLiveAttr,
     eButton,
     kNoReqStates
     // eARIAPressed is auto applied on any button
   },
+  { // cell
+    &nsGkAtoms::cell,
+    roles::CELL,
+    kUseMapRole,
+    eNoValue,
+    eNoAction,
+    eNoLiveAttr,
+    eTableCell,
+    kNoReqStates
+  },
   { // checkbox
     &nsGkAtoms::checkbox,
     roles::CHECKBUTTON,
     kUseMapRole,
     eNoValue,
     eCheckUncheckAction,
     eNoLiveAttr,
     kGenericAccType,
@@ -626,16 +636,27 @@ static nsRoleMapEntry sWAIRoleMaps[] =
     kUseMapRole,
     eNoValue,
     eSwitchAction,
     eNoLiveAttr,
     kGenericAccType,
     kNoReqStates,
     eARIASelectable
   },
+  { // table
+    &nsGkAtoms::table,
+    roles::TABLE,
+    kUseMapRole,
+    eNoValue,
+    eNoAction,
+    eNoLiveAttr,
+    eTable,
+    kNoReqStates,
+    eARIASelectable
+  },
   { // tablist
     &nsGkAtoms::tablist,
     roles::PAGETABLIST,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
     eSelect,
--- a/accessible/base/Filters.cpp
+++ b/accessible/base/Filters.cpp
@@ -43,18 +43,19 @@ filters::GetRow(Accessible* aAccessible)
 
   return eSkipSubtree;
 }
 
 uint32_t
 filters::GetCell(Accessible* aAccessible)
 {
   a11y::role role = aAccessible->Role();
-  return role == roles::GRID_CELL || role == roles::ROWHEADER ||
-    role == roles::COLUMNHEADER ? eMatch : eSkipSubtree;
+  return role == roles::CELL || role == roles::GRID_CELL ||
+         role == roles::ROWHEADER || role == roles::COLUMNHEADER ?
+    eMatch : eSkipSubtree;
 }
 
 uint32_t
 filters::GetEmbeddedObject(Accessible* aAccessible)
 {
   return nsAccUtils::IsEmbeddedObject(aAccessible) ?
     eMatch | eSkipSubtree : eSkipSubtree;
 }
--- a/accessible/generic/ARIAGridAccessible.cpp
+++ b/accessible/generic/ARIAGridAccessible.cpp
@@ -63,27 +63,30 @@ ARIAGridAccessible::RowCount()
   while (rowIter.Next())
     rowCount++;
 
   return rowCount;
 }
 
 Accessible*
 ARIAGridAccessible::CellAt(uint32_t aRowIndex, uint32_t aColumnIndex)
-{ 
+{
   Accessible* row = GetRowAt(aRowIndex);
   if (!row)
     return nullptr;
 
   return GetCellInRowAt(row, aColumnIndex);
 }
 
 bool
 ARIAGridAccessible::IsColSelected(uint32_t aColIdx)
 {
+  if (IsARIARole(nsGkAtoms::table))
+    return false;
+
   AccIterator rowIter(this, filters::GetRow);
   Accessible* row = rowIter.Next();
   if (!row)
     return false;
 
   do {
     if (!nsAccUtils::IsARIASelected(row)) {
       Accessible* cell = GetCellInRowAt(row, aColIdx);
@@ -93,16 +96,19 @@ ARIAGridAccessible::IsColSelected(uint32
   } while ((row = rowIter.Next()));
 
   return true;
 }
 
 bool
 ARIAGridAccessible::IsRowSelected(uint32_t aRowIdx)
 {
+  if (IsARIARole(nsGkAtoms::table))
+    return false;
+
   Accessible* row = GetRowAt(aRowIdx);
   if(!row)
     return false;
 
   if (!nsAccUtils::IsARIASelected(row)) {
     AccIterator cellIter(row, filters::GetCell);
     Accessible* cell = nullptr;
     while ((cell = cellIter.Next())) {
@@ -112,32 +118,38 @@ ARIAGridAccessible::IsRowSelected(uint32
   }
 
   return true;
 }
 
 bool
 ARIAGridAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx)
 {
+  if (IsARIARole(nsGkAtoms::table))
+    return false;
+
   Accessible* row = GetRowAt(aRowIdx);
   if(!row)
     return false;
 
   if (!nsAccUtils::IsARIASelected(row)) {
     Accessible* cell = GetCellInRowAt(row, aColIdx);
     if (!cell || !nsAccUtils::IsARIASelected(cell))
       return false;
   }
 
   return true;
 }
 
 uint32_t
 ARIAGridAccessible::SelectedCellCount()
 {
+  if (IsARIARole(nsGkAtoms::table))
+    return 0;
+
   uint32_t count = 0, colCount = ColCount();
 
   AccIterator rowIter(this, filters::GetRow);
   Accessible* row = nullptr;
 
   while ((row = rowIter.Next())) {
     if (nsAccUtils::IsARIASelected(row)) {
       count += colCount;
@@ -154,16 +166,19 @@ ARIAGridAccessible::SelectedCellCount()
   }
 
   return count;
 }
 
 uint32_t
 ARIAGridAccessible::SelectedColCount()
 {
+  if (IsARIARole(nsGkAtoms::table))
+    return 0;
+
   uint32_t colCount = ColCount();
   if (!colCount)
     return 0;
 
   AccIterator rowIter(this, filters::GetRow);
   Accessible* row = rowIter.Next();
   if (!row)
     return 0;
@@ -188,16 +203,19 @@ ARIAGridAccessible::SelectedColCount()
   } while ((row = rowIter.Next()));
 
   return selColCount;
 }
 
 uint32_t
 ARIAGridAccessible::SelectedRowCount()
 {
+  if (IsARIARole(nsGkAtoms::table))
+    return 0;
+
   uint32_t count = 0;
 
   AccIterator rowIter(this, filters::GetRow);
   Accessible* row = nullptr;
 
   while ((row = rowIter.Next())) {
     if (nsAccUtils::IsARIASelected(row)) {
       count++;
@@ -222,16 +240,19 @@ ARIAGridAccessible::SelectedRowCount()
   }
 
   return count;
 }
 
 void
 ARIAGridAccessible::SelectedCells(nsTArray<Accessible*>* aCells)
 {
+  if (IsARIARole(nsGkAtoms::table))
+    return;
+
   AccIterator rowIter(this, filters::GetRow);
 
   Accessible* row = nullptr;
   while ((row = rowIter.Next())) {
     AccIterator cellIter(row, filters::GetCell);
     Accessible* cell = nullptr;
 
     if (nsAccUtils::IsARIASelected(row)) {
@@ -246,16 +267,19 @@ ARIAGridAccessible::SelectedCells(nsTArr
         aCells->AppendElement(cell);
     }
   }
 }
 
 void
 ARIAGridAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells)
 {
+  if (IsARIARole(nsGkAtoms::table))
+    return;
+
   uint32_t colCount = ColCount();
 
   AccIterator rowIter(this, filters::GetRow);
   Accessible* row = nullptr;
   for (uint32_t rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
     if (nsAccUtils::IsARIASelected(row)) {
       for (uint32_t colIdx = 0; colIdx < colCount; colIdx++)
         aCells->AppendElement(rowIdx * colCount + colIdx);
@@ -270,16 +294,19 @@ ARIAGridAccessible::SelectedCellIndices(
         aCells->AppendElement(rowIdx * colCount + colIdx);
     }
   }
 }
 
 void
 ARIAGridAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols)
 {
+  if (IsARIARole(nsGkAtoms::table))
+    return;
+
   uint32_t colCount = ColCount();
   if (!colCount)
     return;
 
   AccIterator rowIter(this, filters::GetRow);
   Accessible* row = rowIter.Next();
   if (!row)
     return;
@@ -304,16 +331,19 @@ ARIAGridAccessible::SelectedColIndices(n
   for (uint32_t colIdx = 0; colIdx < colCount; colIdx++)
     if (isColSelArray[colIdx])
       aCols->AppendElement(colIdx);
 }
 
 void
 ARIAGridAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows)
 {
+  if (IsARIARole(nsGkAtoms::table))
+    return;
+
   AccIterator rowIter(this, filters::GetRow);
   Accessible* row = nullptr;
   for (uint32_t rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
     if (nsAccUtils::IsARIASelected(row)) {
       aRows->AppendElement(rowIdx);
       continue;
     }
 
@@ -333,28 +363,34 @@ ARIAGridAccessible::SelectedRowIndices(n
     if (isRowSelected)
       aRows->AppendElement(rowIdx);
   }
 }
 
 void
 ARIAGridAccessible::SelectRow(uint32_t aRowIdx)
 {
+  if (IsARIARole(nsGkAtoms::table))
+    return;
+
   AccIterator rowIter(this, filters::GetRow);
 
   Accessible* row = nullptr;
   for (uint32_t rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
     DebugOnly<nsresult> rv = SetARIASelected(row, rowIdx == aRowIdx);
     NS_ASSERTION(NS_SUCCEEDED(rv), "SetARIASelected() Shouldn't fail!");
   }
 }
 
 void
 ARIAGridAccessible::SelectCol(uint32_t aColIdx)
 {
+  if (IsARIARole(nsGkAtoms::table))
+    return;
+
   AccIterator rowIter(this, filters::GetRow);
 
   Accessible* row = nullptr;
   while ((row = rowIter.Next())) {
     // Unselect all cells in the row.
     DebugOnly<nsresult> rv = SetARIASelected(row, false);
     NS_ASSERTION(NS_SUCCEEDED(rv), "SetARIASelected() Shouldn't fail!");
 
@@ -363,25 +399,30 @@ ARIAGridAccessible::SelectCol(uint32_t a
     if (cell)
       SetARIASelected(cell, true);
   }
 }
 
 void
 ARIAGridAccessible::UnselectRow(uint32_t aRowIdx)
 {
+  if (IsARIARole(nsGkAtoms::table))
+    return;
+
   Accessible* row = GetRowAt(aRowIdx);
-
   if (row)
     SetARIASelected(row, false);
 }
 
 void
 ARIAGridAccessible::UnselectCol(uint32_t aColIdx)
 {
+  if (IsARIARole(nsGkAtoms::table))
+    return;
+
   AccIterator rowIter(this, filters::GetRow);
 
   Accessible* row = nullptr;
   while ((row = rowIter.Next())) {
     Accessible* cell = GetCellInRowAt(row, aColIdx);
     if (cell)
       SetARIASelected(cell, false);
   }
@@ -416,16 +457,19 @@ ARIAGridAccessible::GetCellInRowAt(Acces
 
   return cell;
 }
 
 nsresult
 ARIAGridAccessible::SetARIASelected(Accessible* aAccessible,
                                     bool aIsSelected, bool aNotify)
 {
+  if (IsARIARole(nsGkAtoms::table))
+    return NS_OK;
+
   nsIContent *content = aAccessible->GetContent();
   NS_ENSURE_STATE(content);
 
   nsresult rv = NS_OK;
   if (aIsSelected)
     rv = content->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
                           NS_LITERAL_STRING("true"), aNotify);
   else
@@ -519,18 +563,18 @@ ARIAGridCellAccessible::ColIdx() const
   if (!row)
     return 0;
 
   int32_t indexInRow = IndexInParent();
   uint32_t colIdx = 0;
   for (int32_t idx = 0; idx < indexInRow; idx++) {
     Accessible* cell = row->GetChildAt(idx);
     roles::Role role = cell->Role();
-    if (role == roles::GRID_CELL || role == roles::ROWHEADER ||
-        role == roles::COLUMNHEADER)
+    if (role == roles::CELL || role == roles::GRID_CELL ||
+        role == roles::ROWHEADER || role == roles::COLUMNHEADER)
       colIdx++;
   }
 
   return colIdx;
 }
 
 uint32_t
 ARIAGridCellAccessible::RowIdx() const
@@ -588,18 +632,18 @@ ARIAGridCellAccessible::NativeAttributes
   int32_t colIdx = 0, colCount = 0;
   uint32_t childCount = thisRow->ChildCount();
   for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
     Accessible* child = thisRow->GetChildAt(childIdx);
     if (child == this)
       colIdx = colCount;
 
     roles::Role role = child->Role();
-    if (role == roles::GRID_CELL || role == roles::ROWHEADER ||
-        role == roles::COLUMNHEADER)
+    if (role == roles::CELL || role == roles::GRID_CELL ||
+        role == roles::ROWHEADER || role == roles::COLUMNHEADER)
       colCount++;
   }
 
   int32_t rowIdx = RowIndexFor(thisRow);
 
   nsAutoString stringIdx;
   stringIdx.AppendInt(rowIdx * colCount + colIdx);
   nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx);
--- a/accessible/tests/mochitest/table/a11y.ini
+++ b/accessible/tests/mochitest/table/a11y.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 
 [test_headers_ariagrid.html]
+[test_headers_ariatable.html]
 [test_headers_listbox.xul]
 [test_headers_table.html]
 [test_headers_tree.xul]
 [test_indexes_ariagrid.html]
 [test_indexes_listbox.xul]
 [test_indexes_table.html]
 [test_indexes_tree.xul]
 [test_layoutguess.html]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/table/test_headers_ariatable.html
@@ -0,0 +1,96 @@
+<!DOCTYPE HTML PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+  <title>Table header information cells for ARIA table</title>
+  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../table.js"></script>
+
+  <script type="application/javascript">
+
+    function doTest()
+    {
+      //////////////////////////////////////////////////////////////////////////
+      // column and row headers from markup
+
+      headerInfoMap = [
+        {
+          cell: "table_dc_1",
+          rowHeaderCells: [ "table_rh_1" ],
+          columnHeaderCells: [ "table_ch_2" ]
+        },
+        {
+          cell: "table_dc_2",
+          rowHeaderCells: [ "table_rh_1" ],
+          columnHeaderCells: [ "table_ch_3" ]
+        },
+        {
+          cell: "table_dc_3",
+          rowHeaderCells: [ "table_rh_2" ],
+          columnHeaderCells: [ "table_ch_2" ]
+        },
+        {
+          cell: "table_dc_4",
+          rowHeaderCells: [ "table_rh_2" ],
+          columnHeaderCells: [ "table_ch_3" ]
+        },
+        {
+          cell: "table_rh_1",
+          rowHeaderCells: [],
+          columnHeaderCells: [ "table_ch_1" ]
+        },
+        {
+          cell: "table_rh_2",
+          rowHeaderCells: [],
+          columnHeaderCells: [ "table_ch_1" ]
+        }
+      ];
+
+      testHeaderCells(headerInfoMap);
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+
+<body>
+  <a target="_blank"
+     title="support ARIA table and cell roles"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=1173364">Bug 1173364</a>
+
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <div role="table">
+    <div role="row">
+      <span id="table_ch_1" role="columnheader">col_1</span>
+      <span id="table_ch_2" role="columnheader">col_2</span>
+      <span id="table_ch_3" role="columnheader">col_3</span>
+    </div>
+    <div role="row">
+      <span id="table_rh_1" role="rowheader">row_1</span>
+      <span id="table_dc_1" role="cell">cell1</span>
+      <span id="table_dc_2" role="cell">cell2</span>
+    </div>
+    <div role="row">
+      <span id="table_rh_2" role="rowheader">row_2</span>
+      <span id="table_dc_3" role="cell">cell3</span>
+      <span id="table_dc_4" role="cell">cell4</span>
+    </div>
+  </div>
+
+</body>
+</html>
--- a/accessible/tests/mochitest/tree/a11y.ini
+++ b/accessible/tests/mochitest/tree/a11y.ini
@@ -6,16 +6,17 @@ support-files =
 [test_applicationacc.xul]
 skip-if = true # Bug 561508
 [test_aria_globals.html]
 [test_aria_grid.html]
 [test_aria_imgmap.html]
 [test_aria_list.html]
 [test_aria_menu.html]
 [test_aria_presentation.html]
+[test_aria_table.html]
 [test_brokencontext.html]
 [test_button.xul]
 [test_canvas.html]
 [test_combobox.xul]
 [test_cssoverflow.html]
 [test_dochierarchy.html]
 [test_dockids.html]
 [test_filectrl.html]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/tree/test_aria_table.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>ARIA table tests</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../role.js"></script>
+
+  <script type="application/javascript">
+    function doTest()
+    {
+      //////////////////////////////////////////////////////////////////////////
+      // table having rowgroups
+
+      var accTree =
+        { TABLE: [
+          { GROUPING: [
+            { ROW: [
+              { CELL: [
+                { TEXT_LEAF: [ ] }
+              ] }
+            ] }
+          ] },
+        ] };
+
+      testAccessibleTree("table", accTree);
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank"
+     title="support ARIA table and cell roles"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=1173364">
+    Bug 1173364
+  </a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <div id="table" role="table">
+    <div role="rowgroup">
+      <div role="row">
+        <div role="cell">cell</div>
+      </div>
+    </div>
+  </div>
+
+</body>
+</html>