Diff
Modified: trunk/LayoutTests/ChangeLog (188202 => 188203)
--- trunk/LayoutTests/ChangeLog 2015-08-10 00:10:01 UTC (rev 188202)
+++ trunk/LayoutTests/ChangeLog 2015-08-10 01:53:10 UTC (rev 188203)
@@ -1,3 +1,20 @@
+2015-08-09 Nan Wang <[email protected]>
+
+ AX: CSS table display styles can cause malformed, inaccessible AXTables to be exposed to the AX tree
+ https://bugs.webkit.org/show_bug.cgi?id=136415
+ <rdar://problem/22026625>
+
+ Reviewed by Chris Fleizach.
+
+ * accessibility/aria-table-with-presentational-elements-expected.txt:
+ * accessibility/aria-table-with-presentational-elements.html:
+ * accessibility/mac/malformed-table-expected.txt: Added.
+ * accessibility/mac/malformed-table.html: Added.
+ * platform/mac-mavericks/accessibility/roles-exposed-expected.txt:
+ * platform/mac/accessibility/aria-table-hierarchy-expected.txt:
+ * platform/mac/accessibility/aria-tables-expected.txt:
+ * platform/mac/accessibility/roles-exposed-expected.txt:
+
2015-08-08 Darin Adler <[email protected]>
Remove -webkit-color-correction CSS property
Modified: trunk/LayoutTests/accessibility/aria-table-with-presentational-elements-expected.txt (188202 => 188203)
--- trunk/LayoutTests/accessibility/aria-table-with-presentational-elements-expected.txt 2015-08-10 00:10:01 UTC (rev 188202)
+++ trunk/LayoutTests/accessibility/aria-table-with-presentational-elements-expected.txt 2015-08-10 01:53:10 UTC (rev 188203)
@@ -4,7 +4,7 @@
PASS row.role is 'AXRole: AXRow'
-PASS row.parentElement().role is 'AXRole: AXGrid'
+PASS row.parentElement().role is 'AXRole: AXTable'
PASS successfullyParsed is true
TEST COMPLETE
Modified: trunk/LayoutTests/accessibility/aria-table-with-presentational-elements.html (188202 => 188203)
--- trunk/LayoutTests/accessibility/aria-table-with-presentational-elements.html 2015-08-10 00:10:01 UTC (rev 188202)
+++ trunk/LayoutTests/accessibility/aria-table-with-presentational-elements.html 2015-08-10 01:53:10 UTC (rev 188203)
@@ -32,7 +32,7 @@
var table = accessibilityController.accessibleElementById("table");
var row = table.rowAtIndex(0);
shouldBe("row.role", "'AXRole: AXRow'");
- shouldBe("row.parentElement().role", "'AXRole: AXGrid'");
+ shouldBe("row.parentElement().role", "'AXRole: AXTable'");
document.getElementById("content").style.visibility = "hidden";
}
Added: trunk/LayoutTests/accessibility/mac/malformed-table-expected.txt (0 => 188203)
--- trunk/LayoutTests/accessibility/mac/malformed-table-expected.txt (rev 0)
+++ trunk/LayoutTests/accessibility/mac/malformed-table-expected.txt 2015-08-10 01:53:10 UTC (rev 188203)
@@ -0,0 +1,53 @@
+Table with CSS and ARIA
+Heading one Heading two
+a b
+Table with CSS and no ARIA
+Heading one Heading two
+a b
+This tests that contents in malformed tables are accessible.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS table1.role is 'AXRole: AXTable'
+PASS table2.role is 'AXRole: AXTable'
+PASS table1ColumnCount is 2
+PASS table1RowCount is 2
+PASS table2ColumnCount is 2
+PASS table2RowCount is 2
+
+Check rows for Table1
+PASS rowa.isEqual(rowb) is true
+PASS rowa.role is 'AXRole: AXRow'
+PASS rowa.isEqual(rowb) is true
+PASS rowa.role is 'AXRole: AXRow'
+
+Check rows for Table2
+PASS rowa.isEqual(rowb) is true
+PASS rowa.role is 'AXRole: AXRow'
+PASS rowa.isEqual(rowb) is true
+PASS rowa.role is 'AXRole: AXRow'
+
+Check cells for Table1
+PASS cella.isEqual(cellb) is true
+PASS cella.role is 'AXRole: AXCell'
+PASS cella.isEqual(cellb) is true
+PASS cella.role is 'AXRole: AXCell'
+PASS cella.isEqual(cellb) is true
+PASS cella.role is 'AXRole: AXCell'
+PASS cella.isEqual(cellb) is true
+PASS cella.role is 'AXRole: AXCell'
+
+Check cells for Table2
+PASS cella.isEqual(cellb) is true
+PASS cella.role is 'AXRole: AXCell'
+PASS cella.isEqual(cellb) is true
+PASS cella.role is 'AXRole: AXCell'
+PASS cella.isEqual(cellb) is true
+PASS cella.role is 'AXRole: AXCell'
+PASS cella.isEqual(cellb) is true
+PASS cella.role is 'AXRole: AXCell'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/accessibility/mac/malformed-table.html (0 => 188203)
--- trunk/LayoutTests/accessibility/mac/malformed-table.html (rev 0)
+++ trunk/LayoutTests/accessibility/mac/malformed-table.html 2015-08-10 01:53:10 UTC (rev 188203)
@@ -0,0 +1,107 @@
+<!DOCTYPE>
+<html>
+<script src=""
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <title>Table test</title>
+ <style>
+ table {border: 1px solid;}
+ table th {background-color: #eeeeee;}
+ table td {background-color: #dddddd;}
+ .table thead {display:block;}
+ .table tbody {display:block;}
+ .table2 thead {display:block;}
+ .table2 tbody {display:block;}
+ </style>
+</head>
+<body id="body">
+
+<table role="grid" class="table" id="table">
+ <caption>Table with CSS and ARIA</caption>
+ <thead>
+ <tr role="row">
+ <th role="gridcell">Heading one</th>
+ <th role="gridcell">Heading two</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr role="row">
+ <td role="gridcell">a</td>
+ <td role="gridcell">b</td>
+ </tr>
+ </tbody>
+</table>
+
+<table class="table2" id="table2">
+ <caption>Table with CSS and no ARIA</caption>
+ <thead>
+ <tr>
+ <th>Heading one</th>
+ <th>Heading two</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>a</td>
+ <td>b</td>
+ </tr>
+ <tbody>
+</table>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+
+ description("This tests that contents in malformed tables are accessible.");
+
+ if (window.accessibilityController) {
+ var table1 = accessibilityController.accessibleElementById("table");
+ var table2 = accessibilityController.accessibleElementById("table2");
+ var tableArray = [table1, table2];
+ // check for table role
+ shouldBe("table1.role", "'AXRole: AXTable'");
+ shouldBe("table2.role", "'AXRole: AXTable'");
+
+ // check for correct column and row count
+ var table1ColumnCount = table1.numberAttributeValue("AXColumnCount");
+ var table1RowCount = table1.numberAttributeValue("AXRowCount");
+ var table2ColumnCount = table2.numberAttributeValue("AXColumnCount");
+ var table2RowCount = table2.numberAttributeValue("AXRowCount");
+ shouldBe("table1ColumnCount", "2");
+ shouldBe("table1RowCount", "2");
+ shouldBe("table2ColumnCount", "2");
+ shouldBe("table2RowCount", "2");
+
+ // check rows
+ for (var tableIndex = 0; tableIndex < 2; tableIndex++) {
+ debug("\nCheck rows for Table" + (tableIndex+1));
+ var table = tableArray[tableIndex];
+ for (var i = 0; i < 2; i++) {
+ var rowa = table.rowAtIndex(i);
+ var rowb = table.childAtIndex(i);
+ shouldBeTrue("rowa.isEqual(rowb)");
+ shouldBe("rowa.role", "'AXRole: AXRow'");
+ }
+ }
+
+ // check cells
+ for (var tableIndex = 0; tableIndex < 2; tableIndex++) {
+ debug("\nCheck cells for Table" + (tableIndex+1));
+ var table = tableArray[tableIndex];
+ for (var i = 0; i < 2; i++) {
+ for (var j = 0; j < 2; j++) {
+ var cella = table.cellForColumnAndRow(i, j);
+ var cellb = table.childAtIndex(j).childAtIndex(i);
+ shouldBeTrue("cella.isEqual(cellb)");
+ shouldBe("cella.role", "'AXRole: AXCell'");
+ }
+ }
+ }
+ }
+
+</script>
+
+<script src=""
+</body>
+</html>
Modified: trunk/LayoutTests/platform/mac/accessibility/aria-table-hierarchy-expected.txt (188202 => 188203)
--- trunk/LayoutTests/platform/mac/accessibility/aria-table-hierarchy-expected.txt 2015-08-10 00:10:01 UTC (rev 188202)
+++ trunk/LayoutTests/platform/mac/accessibility/aria-table-hierarchy-expected.txt 2015-08-10 01:53:10 UTC (rev 188203)
@@ -25,7 +25,7 @@
AXRole: AXWebArea AXValue:
- AXRole: AXGrid AXValue:
+ AXRole: AXTable AXValue:
AXRole: AXRow AXValue:
AXRole: AXCell AXValue:
AXRole: AXStaticText AXValue: foo
@@ -38,7 +38,7 @@
AXRole: AXCell AXValue:
AXRole: AXStaticText AXValue: bar
AXRole: AXGroup AXValue:
- AXRole: AXGrid AXValue:
+ AXRole: AXTable AXValue:
AXRole: AXRow AXValue:
AXRole: AXCell AXValue:
AXRole: AXStaticText AXValue: Odd
@@ -73,7 +73,7 @@
AXRole: AXStaticText AXValue: Odd
AXRole: AXCell AXValue:
AXRole: AXStaticText AXValue: Even
- AXRole: AXGrid AXValue:
+ AXRole: AXTable AXValue:
AXRole: AXRow AXValue:
AXRole: AXCell AXValue:
AXRole: AXStaticText AXValue: hello
@@ -86,7 +86,7 @@
AXRole: AXCell AXValue:
AXRole: AXStaticText AXValue: world
AXRole: AXGroup AXValue:
- AXRole: AXGrid AXValue:
+ AXRole: AXTable AXValue:
AXRole: AXRow AXValue:
AXRole: AXCell AXValue:
AXRole: AXStaticText AXValue: Odd
Modified: trunk/LayoutTests/platform/mac/accessibility/aria-tables-expected.txt (188202 => 188203)
--- trunk/LayoutTests/platform/mac/accessibility/aria-tables-expected.txt 2015-08-10 00:10:01 UTC (rev 188202)
+++ trunk/LayoutTests/platform/mac/accessibility/aria-tables-expected.txt 2015-08-10 01:53:10 UTC (rev 188203)
@@ -10,8 +10,8 @@
header 1 header 2 header 2
cell cell cell
cell
-AXRole: AXGrid
-AXRole: AXGrid
+AXRole: AXTable
+AXRole: AXTable
AXRole: AXCell
AXRole: AXCell
AXRole: AXCell
Modified: trunk/LayoutTests/platform/mac/accessibility/roles-exposed-expected.txt (188202 => 188203)
--- trunk/LayoutTests/platform/mac/accessibility/roles-exposed-expected.txt 2015-08-10 00:10:01 UTC (rev 188202)
+++ trunk/LayoutTests/platform/mac/accessibility/roles-exposed-expected.txt 2015-08-10 01:53:10 UTC (rev 188203)
@@ -875,9 +875,9 @@
AXRoleDescription: group
div[role=grid]
- AXRole: AXGrid
+ AXRole: AXTable
AXSubrole:
- AXRoleDescription: grid
+ AXRoleDescription: table
div[role=rowgroup]
AXRole:
@@ -1135,9 +1135,9 @@
AXRoleDescription: outline row
div[role=treegrid]
- AXRole: AXGrid
+ AXRole: AXTable
AXSubrole:
- AXRoleDescription: grid
+ AXRoleDescription: table
div[role=rowgroup]
AXRole:
Modified: trunk/LayoutTests/platform/mac-mavericks/accessibility/roles-exposed-expected.txt (188202 => 188203)
--- trunk/LayoutTests/platform/mac-mavericks/accessibility/roles-exposed-expected.txt 2015-08-10 00:10:01 UTC (rev 188202)
+++ trunk/LayoutTests/platform/mac-mavericks/accessibility/roles-exposed-expected.txt 2015-08-10 01:53:10 UTC (rev 188203)
@@ -875,9 +875,9 @@
AXRoleDescription: group
div[role=grid]
- AXRole: AXGrid
+ AXRole: AXTable
AXSubrole:
- AXRoleDescription: grid
+ AXRoleDescription: table
div[role=rowgroup]
AXRole:
@@ -1135,9 +1135,9 @@
AXRoleDescription: outline row
div[role=treegrid]
- AXRole: AXGrid
+ AXRole: AXTable
AXSubrole:
- AXRoleDescription: grid
+ AXRoleDescription: table
div[role=rowgroup]
AXRole:
Modified: trunk/Source/WebCore/ChangeLog (188202 => 188203)
--- trunk/Source/WebCore/ChangeLog 2015-08-10 00:10:01 UTC (rev 188202)
+++ trunk/Source/WebCore/ChangeLog 2015-08-10 01:53:10 UTC (rev 188203)
@@ -1,3 +1,33 @@
+2015-08-09 Nan Wang <[email protected]>
+
+ AX: CSS table display styles can cause malformed, inaccessible AXTables to be exposed to the AX tree
+ https://bugs.webkit.org/show_bug.cgi?id=136415
+ <rdar://problem/22026625>
+
+ Reviewed by Chris Fleizach.
+
+ Applying CSS display styles to tables can end up inserting anonymous RenderTableRows, which is not handled well by the
+ accessibility code, which treats these as the actual rows. We can address this by diving deeper into anonymous nodes
+ and finding the real rows and cells we want. In addition, another thing also causing malformed tables is that "grid"
+ roles are being exposed as AXGrid instead of AXTable.
+
+ Test: accessibility/mac/malformed-table.html
+
+ * accessibility/AccessibilityARIAGrid.cpp:
+ (WebCore::AccessibilityARIAGrid::addRowDescendant):
+ * accessibility/AccessibilityTable.cpp:
+ (WebCore::AccessibilityTable::addChildren):
+ (WebCore::AccessibilityTable::addTableCellChild):
+ (WebCore::AccessibilityTable::addChildrenFromSection):
+ * accessibility/AccessibilityTable.h:
+ * accessibility/AccessibilityTableCell.cpp:
+ (WebCore::AccessibilityTableCell::parentTable):
+ (WebCore::AccessibilityTableCell::rowIndexRange):
+ * accessibility/AccessibilityTableRow.cpp:
+ (WebCore::AccessibilityTableRow::parentTable):
+ * accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
+ (createAccessibilityRoleMap):
+
2015-08-08 Darin Adler <[email protected]>
Remove -webkit-color-correction CSS property
Modified: trunk/Source/WebCore/accessibility/AccessibilityARIAGrid.cpp (188202 => 188203)
--- trunk/Source/WebCore/accessibility/AccessibilityARIAGrid.cpp 2015-08-10 00:10:01 UTC (rev 188202)
+++ trunk/Source/WebCore/accessibility/AccessibilityARIAGrid.cpp 2015-08-10 01:53:10 UTC (rev 188203)
@@ -87,9 +87,9 @@
if (!rowChild)
return;
- if (!rowChild->isTableRow()) {
+ if (!rowChild->isTableRow() || !rowChild->node()) {
// Although a "grid" should have rows as its direct descendants, if this is not a table row,
- // dive deeper into the descendants to try to find a valid row.
+ // or this row is anonymous, dive deeper into the descendants to try to find a valid row.
for (const auto& child : rowChild->children())
addRowDescendant(child.get(), appendedRows, columnCount);
} else
Modified: trunk/Source/WebCore/accessibility/AccessibilityTable.cpp (188202 => 188203)
--- trunk/Source/WebCore/accessibility/AccessibilityTable.cpp 2015-08-10 00:10:01 UTC (rev 188202)
+++ trunk/Source/WebCore/accessibility/AccessibilityTable.cpp 2015-08-10 01:53:10 UTC (rev 188203)
@@ -44,6 +44,8 @@
#include "RenderTableCell.h"
#include "RenderTableSection.h"
+#include <wtf/Deque.h>
+
namespace WebCore {
using namespace HTMLNames;
@@ -421,6 +423,29 @@
}
+void AccessibilityTable::addTableCellChild(AccessibilityObject* rowObject, HashSet<AccessibilityObject*>& appendedRows, unsigned& columnCount)
+{
+ if (!rowObject || !is<AccessibilityTableRow>(*rowObject))
+ return;
+
+ auto& row = downcast<AccessibilityTableRow>(*rowObject);
+ // We need to check every cell for a new row, because cell spans
+ // can cause us to miss rows if we just check the first column.
+ if (appendedRows.contains(&row))
+ return;
+
+ row.setRowIndex(static_cast<int>(m_rows.size()));
+ m_rows.append(&row);
+ if (!row.accessibilityIsIgnored())
+ m_children.append(&row);
+ appendedRows.add(&row);
+
+ // store the maximum number of columns
+ unsigned rowCellCount = row.children().size();
+ if (rowCellCount > columnCount)
+ columnCount = rowCellCount;
+}
+
void AccessibilityTable::addChildrenFromSection(RenderTableSection* tableSection, unsigned& maxColumnCount)
{
ASSERT(tableSection);
@@ -437,20 +462,23 @@
continue;
AccessibilityObject& rowObject = *axCache->getOrCreate(renderRow);
- if (!is<AccessibilityTableRow>(rowObject))
- continue;
- auto& row = downcast<AccessibilityTableRow>(rowObject);
- // We need to check every cell for a new row, because cell spans
- // can cause us to miss rows if we just check the first column.
- if (appendedRows.contains(&row))
- continue;
-
- row.setRowIndex(static_cast<int>(m_rows.size()));
- m_rows.append(&row);
- if (!row.accessibilityIsIgnored())
- m_children.append(&row);
- appendedRows.add(&row);
+ // If the row is anonymous, we should dive deeper into the descendants to try to find a valid row.
+ if (renderRow->isAnonymous()) {
+ Deque<AccessibilityObject*> queue;
+ queue.append(&rowObject);
+
+ while (!queue.isEmpty()) {
+ AccessibilityObject* obj = queue.takeFirst();
+ if (obj->node() && is<AccessibilityTableRow>(*obj)) {
+ addTableCellChild(obj, appendedRows, maxColumnCount);
+ continue;
+ }
+ for (auto child = obj->firstChild(); child; child = child->nextSibling())
+ queue.append(child);
+ }
+ } else
+ addTableCellChild(&rowObject, appendedRows, maxColumnCount);
}
maxColumnCount = std::max(tableSection->numColumns(), maxColumnCount);
Modified: trunk/Source/WebCore/accessibility/AccessibilityTable.h (188202 => 188203)
--- trunk/Source/WebCore/accessibility/AccessibilityTable.h 2015-08-10 00:10:01 UTC (rev 188202)
+++ trunk/Source/WebCore/accessibility/AccessibilityTable.h 2015-08-10 01:53:10 UTC (rev 188203)
@@ -98,6 +98,7 @@
virtual void titleElementText(Vector<AccessibilityText>&) const override final;
HTMLTableElement* tableElement() const;
void addChildrenFromSection(RenderTableSection*, unsigned& maxColumnCount);
+ void addTableCellChild(AccessibilityObject*, HashSet<AccessibilityObject*>& appendedRows, unsigned& columnCount);
};
} // namespace WebCore
Modified: trunk/Source/WebCore/accessibility/AccessibilityTableCell.cpp (188202 => 188203)
--- trunk/Source/WebCore/accessibility/AccessibilityTableCell.cpp 2015-08-10 00:10:01 UTC (rev 188202)
+++ trunk/Source/WebCore/accessibility/AccessibilityTableCell.cpp 2015-08-10 01:53:10 UTC (rev 188203)
@@ -93,6 +93,24 @@
AccessibilityObject* parentTable = axObjectCache()->get(downcast<RenderTableCell>(*m_renderer).table());
if (!is<AccessibilityTable>(parentTable))
return nullptr;
+
+ // The RenderTableCell's table() object might be anonymous sometimes. We should handle it gracefully
+ // by finding the right table.
+ if (!parentTable->node()) {
+ for (AccessibilityObject* parent = parentObject(); parent; parent = parent->parentObject()) {
+ // If this is a non-anonymous table object, but not an accessibility table, we should stop because
+ // we don't want to choose another ancestor table as this cell's table.
+ if (is<AccessibilityTable>(*parent)) {
+ auto& parentTable = downcast<AccessibilityTable>(*parent);
+ if (parentTable.isExposableThroughAccessibility())
+ return &parentTable;
+ if (parentTable.node())
+ break;
+ }
+ }
+ return nullptr;
+ }
+
return downcast<AccessibilityTable>(parentTable);
}
@@ -306,8 +324,15 @@
// Don't add row offsets for bottom sections that are placed in before the body section.
if (tableSection == footerSection)
continue;
- if (tableSection == section)
+ if (tableSection == section) {
+ // If the table section is anonymous, we should to use the parent row's API to get the rowIndex
+ if (tableSection->isAnonymous()) {
+ AccessibilityObject* parent = parentObjectUnignored();
+ if (is<AccessibilityTableRow>(*parent))
+ rowOffset = downcast<AccessibilityTableRow>(*parent).rowIndex();
+ }
break;
+ }
rowOffset += tableSection->numRows();
}
Modified: trunk/Source/WebCore/accessibility/AccessibilityTableRow.cpp (188202 => 188203)
--- trunk/Source/WebCore/accessibility/AccessibilityTableRow.cpp 2015-08-10 00:10:01 UTC (rev 188202)
+++ trunk/Source/WebCore/accessibility/AccessibilityTableRow.cpp 2015-08-10 01:53:10 UTC (rev 188203)
@@ -98,13 +98,14 @@
// The parent table might not be the direct ancestor of the row unfortunately. ARIA states that role="grid" should
// only have "row" elements, but if not, we still should handle it gracefully by finding the right table.
for (AccessibilityObject* parent = parentObject(); parent; parent = parent->parentObject()) {
- // If this is a table object, but not an accessibility table, we should stop because we don't want to
+ // If this is a non-anonymous table object, but not an accessibility table, we should stop because we don't want to
// choose another ancestor table as this row's table.
if (is<AccessibilityTable>(*parent)) {
auto& parentTable = downcast<AccessibilityTable>(*parent);
if (parentTable.isExposableThroughAccessibility())
return &parentTable;
- break;
+ if (parentTable.node())
+ break;
}
}
Modified: trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm (188202 => 188203)
--- trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm 2015-08-10 00:10:01 UTC (rev 188202)
+++ trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm 2015-08-10 01:53:10 UTC (rev 188203)
@@ -1918,7 +1918,7 @@
{ RulerMarkerRole, NSAccessibilityRulerMarkerRole },
{ LinkRole, NSAccessibilityLinkRole },
{ DisclosureTriangleRole, NSAccessibilityDisclosureTriangleRole },
- { GridRole, NSAccessibilityGridRole },
+ { GridRole, NSAccessibilityTableRole },
{ WebCoreLinkRole, NSAccessibilityLinkRole },
{ ImageMapLinkRole, NSAccessibilityLinkRole },
{ ImageMapRole, @"AXImageMap" },