Focusable thead, tbody, and tfoot need an accessible object

Table sections were being unconditionally ignored (excluded from the
accessibility tree) by Blink. This causes them to not be discoverable
by assistive technologies and prevents accessibility events such as
focus changes from being emitted. Therefore:

* Add a check for focusability prior to ignoring these sections.
* If a table section is focusable, expose it with role kGroup.
* Take the presence of table sections into account when finding rows.

Bug: 874043
Change-Id: Ibb5127c126526ccddd38f7a636194090dfd25400
Reviewed-on: https://chromium-review.googlesource.com/c/1450444
Commit-Queue: Joanmarie Diggs <joanmarie.diggs@gmail.com>
Reviewed-by: Dominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#628929}
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index d1e7164..b7887520 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -948,7 +948,8 @@
   }
 
   // If it's focusable but didn't have any other name or value, compute a name
-  // from its descendants.
+  // from its descendants. Note that this is a workaround because VoiceOver
+  // does not always present focus changes if the new focus lacks a name.
   base::string16 value = owner_->GetValue();
   if (owner_->HasState(ax::mojom::State::kFocusable) &&
       !ui::IsControl(owner_->GetRole()) && value.empty() &&
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
index a283d6e..4437c98fa 100644
--- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -502,4 +502,19 @@
   RunEventTest(FILE_PATH_LITERAL("aria-pressed-changed.html"));
 }
 
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+                       AccessibilityEventsTheadFocus) {
+  RunEventTest(FILE_PATH_LITERAL("thead-focus.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+                       AccessibilityEventsTfootFocus) {
+  RunEventTest(FILE_PATH_LITERAL("tfoot-focus.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+                       AccessibilityEventsTbodyFocus) {
+  RunEventTest(FILE_PATH_LITERAL("tbody-focus.html"));
+}
+
 }  // namespace content
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index 2db3649..3603e0d 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -1864,6 +1864,11 @@
   RunHtmlTest(FILE_PATH_LITERAL("table-thead-tbody-tfoot.html"));
 }
 
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+                       AccessibilityTableFocusableSections) {
+  RunHtmlTest(FILE_PATH_LITERAL("table-focusable-sections.html"));
+}
+
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityTableSpans) {
   RunHtmlTest(FILE_PATH_LITERAL("table-spans.html"));
 }
diff --git a/content/test/data/accessibility/event/tbody-focus-expected-auralinux.txt b/content/test/data/accessibility/event/tbody-focus-expected-auralinux.txt
new file mode 100644
index 0000000..702454d
--- /dev/null
+++ b/content/test/data/accessibility/event/tbody-focus-expected-auralinux.txt
@@ -0,0 +1,4 @@
+FOCUS-EVENT role=ROLE_DOCUMENT_WEB name='(null)' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
+FOCUS-EVENT role=ROLE_PANEL name='tbody' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
+STATE-CHANGE:FOCUSED:FALSE role=ROLE_DOCUMENT_WEB name='(null)' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
+STATE-CHANGE:FOCUSED:TRUE role=ROLE_PANEL name='tbody' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
diff --git a/content/test/data/accessibility/event/tbody-focus-expected-mac.txt b/content/test/data/accessibility/event/tbody-focus-expected-mac.txt
new file mode 100644
index 0000000..2b1debd
--- /dev/null
+++ b/content/test/data/accessibility/event/tbody-focus-expected-mac.txt
@@ -0,0 +1 @@
+AXFocusedUIElementChanged on AXGroup AXDescription="tbody"
diff --git a/content/test/data/accessibility/event/tbody-focus-expected-win.txt b/content/test/data/accessibility/event/tbody-focus-expected-win.txt
new file mode 100644
index 0000000..18fdee3
--- /dev/null
+++ b/content/test/data/accessibility/event/tbody-focus-expected-win.txt
@@ -0,0 +1 @@
+EVENT_OBJECT_FOCUS on <tbody#tbody> role=ROLE_SYSTEM_GROUPING name="tbody" FOCUSED,FOCUSABLE
diff --git a/content/test/data/accessibility/event/tbody-focus.html b/content/test/data/accessibility/event/tbody-focus.html
new file mode 100644
index 0000000..1577c91
--- /dev/null
+++ b/content/test/data/accessibility/event/tbody-focus.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<body>
+<table border=1>
+<thead id="thead" tabindex="0" aria-label="thead">
+  <tr>
+    <th>Sum</th>
+    <th>Subtraction</th>
+  </tr>
+</thead>
+<tfoot id="tfoot" tabindex="0" aria-label="tfoot">
+  <tr>
+    <td>12</td>
+     <td>3</td>
+  </tr>
+</tfoot>
+<tbody id="tbody" tabindex="0" aria-label="tbody">
+  <tr>
+    <td>10</td>
+    <td>7</td>
+  </tr>
+  <tr>
+    <td>2</td>
+    <td>4</td>
+  </tr>
+</tbody>
+</table>
+<script>
+  function go() {
+    document.querySelector('tbody').focus();
+  }
+</script>
+</body>
+</html>
diff --git a/content/test/data/accessibility/event/tfoot-focus-expected-auralinux.txt b/content/test/data/accessibility/event/tfoot-focus-expected-auralinux.txt
new file mode 100644
index 0000000..c23e086
--- /dev/null
+++ b/content/test/data/accessibility/event/tfoot-focus-expected-auralinux.txt
@@ -0,0 +1,4 @@
+FOCUS-EVENT role=ROLE_DOCUMENT_WEB name='(null)' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
+FOCUS-EVENT role=ROLE_PANEL name='tfoot' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
+STATE-CHANGE:FOCUSED:FALSE role=ROLE_DOCUMENT_WEB name='(null)' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
+STATE-CHANGE:FOCUSED:TRUE role=ROLE_PANEL name='tfoot' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
diff --git a/content/test/data/accessibility/event/tfoot-focus-expected-mac.txt b/content/test/data/accessibility/event/tfoot-focus-expected-mac.txt
new file mode 100644
index 0000000..1117641
--- /dev/null
+++ b/content/test/data/accessibility/event/tfoot-focus-expected-mac.txt
@@ -0,0 +1 @@
+AXFocusedUIElementChanged on AXGroup AXDescription="tfoot"
diff --git a/content/test/data/accessibility/event/tfoot-focus-expected-win.txt b/content/test/data/accessibility/event/tfoot-focus-expected-win.txt
new file mode 100644
index 0000000..28e49b9
--- /dev/null
+++ b/content/test/data/accessibility/event/tfoot-focus-expected-win.txt
@@ -0,0 +1 @@
+EVENT_OBJECT_FOCUS on <tfoot#tfoot> role=ROLE_SYSTEM_GROUPING name="tfoot" FOCUSED,FOCUSABLE
diff --git a/content/test/data/accessibility/event/tfoot-focus.html b/content/test/data/accessibility/event/tfoot-focus.html
new file mode 100644
index 0000000..3a03eae
--- /dev/null
+++ b/content/test/data/accessibility/event/tfoot-focus.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<body>
+<table border=1>
+<thead id="thead" tabindex="0" aria-label="thead">
+  <tr>
+    <th>Sum</th>
+    <th>Subtraction</th>
+  </tr>
+</thead>
+<tfoot id="tfoot" tabindex="0" aria-label="tfoot">
+  <tr>
+    <td>12</td>
+     <td>3</td>
+  </tr>
+</tfoot>
+<tbody id="tbody" tabindex="0" aria-label="tbody">
+  <tr>
+    <td>10</td>
+    <td>7</td>
+  </tr>
+  <tr>
+    <td>2</td>
+    <td>4</td>
+  </tr>
+</tbody>
+</table>
+<script>
+  function go() {
+    document.querySelector('tfoot').focus();
+  }
+</script>
+</body>
+</html>
diff --git a/content/test/data/accessibility/event/thead-focus-expected-auralinux.txt b/content/test/data/accessibility/event/thead-focus-expected-auralinux.txt
new file mode 100644
index 0000000..4e2777a8
--- /dev/null
+++ b/content/test/data/accessibility/event/thead-focus-expected-auralinux.txt
@@ -0,0 +1,4 @@
+FOCUS-EVENT role=ROLE_DOCUMENT_WEB name='(null)' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
+FOCUS-EVENT role=ROLE_PANEL name='thead' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
+STATE-CHANGE:FOCUSED:FALSE role=ROLE_DOCUMENT_WEB name='(null)' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE
+STATE-CHANGE:FOCUSED:TRUE role=ROLE_PANEL name='thead' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
diff --git a/content/test/data/accessibility/event/thead-focus-expected-mac.txt b/content/test/data/accessibility/event/thead-focus-expected-mac.txt
new file mode 100644
index 0000000..f37da7f
--- /dev/null
+++ b/content/test/data/accessibility/event/thead-focus-expected-mac.txt
@@ -0,0 +1 @@
+AXFocusedUIElementChanged on AXGroup AXDescription="thead"
diff --git a/content/test/data/accessibility/event/thead-focus-expected-win.txt b/content/test/data/accessibility/event/thead-focus-expected-win.txt
new file mode 100644
index 0000000..0bae015f
--- /dev/null
+++ b/content/test/data/accessibility/event/thead-focus-expected-win.txt
@@ -0,0 +1 @@
+EVENT_OBJECT_FOCUS on <thead#thead> role=ROLE_SYSTEM_GROUPING name="thead" FOCUSED,FOCUSABLE
diff --git a/content/test/data/accessibility/event/thead-focus.html b/content/test/data/accessibility/event/thead-focus.html
new file mode 100644
index 0000000..a0d4b34
--- /dev/null
+++ b/content/test/data/accessibility/event/thead-focus.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<body>
+<table border=1>
+<thead id="thead" tabindex="0" aria-label="thead">
+  <tr>
+    <th>Sum</th>
+    <th>Subtraction</th>
+  </tr>
+</thead>
+<tfoot id="tfoot" tabindex="0" aria-label="tfoot">
+  <tr>
+    <td>12</td>
+     <td>3</td>
+  </tr>
+</tfoot>
+<tbody id="tbody" tabindex="0" aria-label="tbody">
+  <tr>
+    <td>10</td>
+    <td>7</td>
+  </tr>
+  <tr>
+    <td>2</td>
+    <td>4</td>
+  </tr>
+</tbody>
+</table>
+<script>
+  function go() {
+    document.querySelector('thead').focus();
+  }
+</script>
+</body>
+</html>
diff --git a/content/test/data/accessibility/html/table-focusable-sections-expected-android.txt b/content/test/data/accessibility/html/table-focusable-sections-expected-android.txt
new file mode 100644
index 0000000..f3ad78a
--- /dev/null
+++ b/content/test/data/accessibility/html/table-focusable-sections-expected-android.txt
@@ -0,0 +1,17 @@
+android.webkit.WebView focusable focused scrollable name='Table example - focusable thead, tbody, tfoot'
+++android.widget.GridView role_description='table' collection row_count=4 column_count=2
+++++android.view.View clickable focusable
+++++++android.view.View
+++++++++android.view.View role_description='column header' collection_item heading name='Sum' row_span=1 column_span=1
+++++++++android.view.View role_description='column header' collection_item heading name='Subtraction' row_span=1 column_index=1 column_span=1
+++++android.view.View clickable focusable
+++++++android.view.View
+++++++++android.view.View collection_item name='10' row_index=1 row_span=1 column_span=1
+++++++++android.view.View collection_item name='7' row_index=1 row_span=1 column_index=1 column_span=1
+++++++android.view.View
+++++++++android.view.View collection_item name='2' row_index=2 row_span=1 column_span=1
+++++++++android.view.View collection_item name='4' row_index=2 row_span=1 column_index=1 column_span=1
+++++android.view.View clickable focusable
+++++++android.view.View
+++++++++android.view.View collection_item name='12' row_index=3 row_span=1 column_span=1
+++++++++android.view.View collection_item name='3' row_index=3 row_span=1 column_index=1 column_span=1
diff --git a/content/test/data/accessibility/html/table-focusable-sections-expected-auralinux.txt b/content/test/data/accessibility/html/table-focusable-sections-expected-auralinux.txt
new file mode 100644
index 0000000..514a10a
--- /dev/null
+++ b/content/test/data/accessibility/html/table-focusable-sections-expected-auralinux.txt
@@ -0,0 +1,25 @@
+[document web] name='Table example - focusable thead, tbody, tfoot'
+++[table]
+++++[panel]
+++++++[table row]
+++++++++[column header] name='Sum'
+++++++++++[text] name='Sum'
+++++++++[column header] name='Subtraction'
+++++++++++[text] name='Subtraction'
+++++[panel]
+++++++[table row]
+++++++++[table cell] name='10'
+++++++++++[text] name='10'
+++++++++[table cell] name='7'
+++++++++++[text] name='7'
+++++++[table row]
+++++++++[table cell] name='2'
+++++++++++[text] name='2'
+++++++++[table cell] name='4'
+++++++++++[text] name='4'
+++++[panel]
+++++++[table row]
+++++++++[table cell] name='12'
+++++++++++[text] name='12'
+++++++++[table cell] name='3'
+++++++++++[text] name='3'
diff --git a/content/test/data/accessibility/html/table-focusable-sections-expected-blink.txt b/content/test/data/accessibility/html/table-focusable-sections-expected-blink.txt
new file mode 100644
index 0000000..4f01368
--- /dev/null
+++ b/content/test/data/accessibility/html/table-focusable-sections-expected-blink.txt
@@ -0,0 +1,33 @@
+rootWebArea name='Table example - focusable thead, tbody, tfoot'
+++table
+++++group
+++++++row
+++++++++columnHeader name='Sum'
+++++++++++staticText name='Sum'
+++++++++++++inlineTextBox name='Sum'
+++++++++columnHeader name='Subtraction'
+++++++++++staticText name='Subtraction'
+++++++++++++inlineTextBox name='Subtraction'
+++++group
+++++++row
+++++++++cell name='10'
+++++++++++staticText name='10'
+++++++++++++inlineTextBox name='10'
+++++++++cell name='7'
+++++++++++staticText name='7'
+++++++++++++inlineTextBox name='7'
+++++++row
+++++++++cell name='2'
+++++++++++staticText name='2'
+++++++++++++inlineTextBox name='2'
+++++++++cell name='4'
+++++++++++staticText name='4'
+++++++++++++inlineTextBox name='4'
+++++group
+++++++row
+++++++++cell name='12'
+++++++++++staticText name='12'
+++++++++++++inlineTextBox name='12'
+++++++++cell name='3'
+++++++++++staticText name='3'
+++++++++++++inlineTextBox name='3'
diff --git a/content/test/data/accessibility/html/table-focusable-sections-expected-mac.txt b/content/test/data/accessibility/html/table-focusable-sections-expected-mac.txt
new file mode 100644
index 0000000..c4f1d1d
--- /dev/null
+++ b/content/test/data/accessibility/html/table-focusable-sections-expected-mac.txt
@@ -0,0 +1,28 @@
+AXWebArea AXTitle='Table example - focusable thead, tbody, tfoot'
+++AXTable
+++++AXGroup AXDescription='Sum Subtraction'
+++++++AXRow AXIndex='0'
+++++++++AXCell AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":0}
+++++++++++AXStaticText AXValue='Sum'
+++++++++AXCell AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":0}
+++++++++++AXStaticText AXValue='Subtraction'
+++++AXGroup AXDescription='10 7 2 4'
+++++++AXRow AXIndex='1'
+++++++++AXCell AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":1}
+++++++++++AXStaticText AXValue='10'
+++++++++AXCell AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":1}
+++++++++++AXStaticText AXValue='7'
+++++++AXRow AXIndex='2'
+++++++++AXCell AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":2}
+++++++++++AXStaticText AXValue='2'
+++++++++AXCell AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":2}
+++++++++++AXStaticText AXValue='4'
+++++AXGroup AXDescription='12 3'
+++++++AXRow AXIndex='3'
+++++++++AXCell AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":3}
+++++++++++AXStaticText AXValue='12'
+++++++++AXCell AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":3}
+++++++++++AXStaticText AXValue='3'
+++++AXColumn AXIndex='0'
+++++AXColumn AXIndex='1'
+++++AXGroup
diff --git a/content/test/data/accessibility/html/table-focusable-sections-expected-win.txt b/content/test/data/accessibility/html/table-focusable-sections-expected-win.txt
new file mode 100644
index 0000000..9f9a759
--- /dev/null
+++ b/content/test/data/accessibility/html/table-focusable-sections-expected-win.txt
@@ -0,0 +1,25 @@
+ROLE_SYSTEM_DOCUMENT name='Table example - focusable thead, tbody, tfoot' READONLY FOCUSABLE
+++ROLE_SYSTEM_TABLE
+++++ROLE_SYSTEM_GROUPING FOCUSABLE
+++++++ROLE_SYSTEM_ROW
+++++++++ROLE_SYSTEM_COLUMNHEADER name='Sum'
+++++++++++ROLE_SYSTEM_STATICTEXT name='Sum'
+++++++++ROLE_SYSTEM_COLUMNHEADER name='Subtraction'
+++++++++++ROLE_SYSTEM_STATICTEXT name='Subtraction'
+++++ROLE_SYSTEM_GROUPING FOCUSABLE
+++++++ROLE_SYSTEM_ROW
+++++++++ROLE_SYSTEM_CELL name='10'
+++++++++++ROLE_SYSTEM_STATICTEXT name='10'
+++++++++ROLE_SYSTEM_CELL name='7'
+++++++++++ROLE_SYSTEM_STATICTEXT name='7'
+++++++ROLE_SYSTEM_ROW
+++++++++ROLE_SYSTEM_CELL name='2'
+++++++++++ROLE_SYSTEM_STATICTEXT name='2'
+++++++++ROLE_SYSTEM_CELL name='4'
+++++++++++ROLE_SYSTEM_STATICTEXT name='4'
+++++ROLE_SYSTEM_GROUPING FOCUSABLE
+++++++ROLE_SYSTEM_ROW
+++++++++ROLE_SYSTEM_CELL name='12'
+++++++++++ROLE_SYSTEM_STATICTEXT name='12'
+++++++++ROLE_SYSTEM_CELL name='3'
+++++++++++ROLE_SYSTEM_STATICTEXT name='3'
diff --git a/content/test/data/accessibility/html/table-focusable-sections.html b/content/test/data/accessibility/html/table-focusable-sections.html
new file mode 100644
index 0000000..8c20fce
--- /dev/null
+++ b/content/test/data/accessibility/html/table-focusable-sections.html
@@ -0,0 +1,37 @@
+<!--
+@MAC-ALLOW:AXIndex=*
+@MAC-ALLOW:AXColumnIndexRange=*
+@MAC-ALLOW:AXRowIndexRange=*
+-->
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Table example - focusable thead, tbody, tfoot</title>
+</head>
+<body>
+<table border=1>
+<thead tabindex="0">
+  <tr>
+    <th>Sum</th>
+    <th>Subtraction</th>
+  </tr>
+</thead>
+<tfoot tabindex="0">
+  <tr>
+    <td>12</td>
+     <td>3</td>
+  </tr>
+</tfoot>
+<tbody tabindex="0">
+  <tr>
+    <td>10</td>
+    <td>7</td>
+  </tr>
+  <tr>
+    <td>2</td>
+    <td>4</td>
+  </tr>
+</tbody>
+</table>
+</body>
+</html>
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
index 63a7b889..3bad59ac 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
@@ -230,9 +230,14 @@
   if (layout_object_->IsSVGRoot())
     return ax::mojom::Role::kSvgRoot;
 
-  // Table sections should be ignored.
-  if (layout_object_->IsTableSection())
+  // Table sections should be ignored if there is no reason not to, e.g.
+  // ARIA 1.2 (and Core-AAM 1.1) state that elements which are focusable
+  // and not hidden must be included in the accessibility tree.
+  if (layout_object_->IsTableSection()) {
+    if (CanSetFocusAttribute())
+      return ax::mojom::Role::kGroup;
     return ax::mojom::Role::kIgnored;
+  }
 
   if (layout_object_->IsHR())
     return ax::mojom::Role::kSplitter;
@@ -3193,6 +3198,9 @@
   if (!parent)
     return ax::mojom::Role::kGenericContainer;
 
+  if (parent->GetLayoutObject()->IsTableSection())
+    parent = parent->ParentObjectUnignored();
+
   if (parent->RoleValue() == ax::mojom::Role::kLayoutTable)
     return ax::mojom::Role::kLayoutTableRow;
 
@@ -3210,6 +3218,9 @@
     return ax::mojom::Role::kGenericContainer;
 
   AXObject* grandparent = parent->ParentObjectUnignored();
+  if (grandparent && grandparent->GetLayoutObject()->IsTableSection())
+    grandparent = grandparent->ParentObjectUnignored();
+
   if (!grandparent || !grandparent->IsTableLikeRole())
     return ax::mojom::Role::kGenericContainer;
 
diff --git a/ui/accessibility/ax_table_info.cc b/ui/accessibility/ax_table_info.cc
index 250b91d..d4e9f40 100644
--- a/ui/accessibility/ax_table_info.cc
+++ b/ui/accessibility/ax_table_info.cc
@@ -38,16 +38,17 @@
 // for each row find its cells and add them to |cell_nodes_per_row| as a
 // 2-dimensional array.
 //
-// We recursively check generic containers like <div> and any
-// nodes that are ignored, but we don't search any other roles
-// in-between a table and its rows.
+// We only recursively check for the following roles in between a table and
+// its rows: generic containers like <div>, any nodes that are ignored, and
+// table sections (which have Role::kGroup).
 void FindRowsAndThenCells(
     AXNode* node,
     std::vector<AXNode*>* row_nodes,
     std::vector<std::vector<AXNode*>>* cell_nodes_per_row) {
   for (AXNode* child : node->children()) {
     if (child->data().HasState(ax::mojom::State::kIgnored) ||
-        child->data().role == ax::mojom::Role::kGenericContainer) {
+        child->data().role == ax::mojom::Role::kGenericContainer ||
+        child->data().role == ax::mojom::Role::kGroup) {
       FindRowsAndThenCells(child, row_nodes, cell_nodes_per_row);
     } else if (child->data().role == ax::mojom::Role::kRow) {
       row_nodes->push_back(child);