Log Message
[GTK][a11y] Add implementation of table and table cell interfaces when building with ATSPI https://bugs.webkit.org/show_bug.cgi?id=233694
Reviewed by Adrian Perez de Castro. Source/WebCore: * SourcesGTK.txt: * accessibility/AccessibilityTableColumn.cpp: (WebCore::AccessibilityTableColumn::computeAccessibilityIsIgnored const): Do not expose column for ATSPI. * accessibility/AccessibilityTableHeaderContainer.cpp: (WebCore::AccessibilityTableHeaderContainer::computeAccessibilityIsIgnored const): Do not expose header container either. * accessibility/atspi/AccessibilityObjectAtspi.cpp: (WebCore::AccessibilityObjectAtspi::interfacesForObject): (WebCore::AccessibilityObjectAtspi::path): (WebCore::AccessibilityObjectAtspi::wrapperVector const): (WebCore::AccessibilityObjectAtspi::children const): (WebCore::AccessibilityObjectAtspi::buildInterfaces const): * accessibility/atspi/AccessibilityObjectAtspi.h: * accessibility/atspi/AccessibilityObjectTableAtspi.cpp: Added. (WebCore::AccessibilityObjectAtspi::rowCount const): (WebCore::AccessibilityObjectAtspi::columnCount const): (WebCore::AccessibilityObjectAtspi::cell const): (WebCore::AccessibilityObjectAtspi::tableCaption const): (WebCore::AccessibilityObjectAtspi::cellIndex const): (WebCore::AccessibilityObjectAtspi::rowAtIndex const): (WebCore::AccessibilityObjectAtspi::columnAtIndex const): (WebCore::AccessibilityObjectAtspi::rowHeader const): (WebCore::AccessibilityObjectAtspi::columnHeader const): (WebCore::AccessibilityObjectAtspi::rowDescription const): (WebCore::AccessibilityObjectAtspi::columnDescription const): (WebCore::AccessibilityObjectAtspi::rowExtent const): (WebCore::AccessibilityObjectAtspi::columnExtent const): (WebCore::AccessibilityObjectAtspi::cells const): (WebCore::AccessibilityObjectAtspi::rows const): (WebCore::AccessibilityObjectAtspi::rowHeaders const): (WebCore::AccessibilityObjectAtspi::columnHeaders const): * accessibility/atspi/AccessibilityObjectTableCellAtspi.cpp: Added. (WebCore::AccessibilityObjectAtspi::cellRowHeaders const): (WebCore::AccessibilityObjectAtspi::cellColumnHeaders const): (WebCore::AccessibilityObjectAtspi::rowSpan const): (WebCore::AccessibilityObjectAtspi::columnSpan const): (WebCore::AccessibilityObjectAtspi::cellPosition const): * accessibility/atspi/xml/TableCell.xml: Tools: Add unit tests and WTR implementation for tables. * TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp: (testTableBasic): (beforeAll): * WebKitTestRunner/InjectedBundle/atspi/AccessibilityUIElementAtspi.cpp: (WTR::AccessibilityUIElement::rowAtIndex): (WTR::elementsVector): (WTR::attributesOfElements): (WTR::AccessibilityUIElement::attributesOfChildren): (WTR::AccessibilityUIElement::numberAttributeValue): (WTR::makeJSArray): (WTR::AccessibilityUIElement::rowHeaders const): (WTR::AccessibilityUIElement::columnHeaders const): (WTR::AccessibilityUIElement::attributesOfColumnHeaders): (WTR::AccessibilityUIElement::attributesOfRowHeaders): (WTR::AccessibilityUIElement::attributesOfRows): (WTR::AccessibilityUIElement::attributesOfVisibleCells): (WTR::AccessibilityUIElement::rowCount): (WTR::AccessibilityUIElement::columnCount): (WTR::AccessibilityUIElement::rowIndexRange): (WTR::AccessibilityUIElement::columnIndexRange): (WTR::AccessibilityUIElement::cellForColumnAndRow):
Modified Paths
- trunk/Source/WebCore/ChangeLog
- trunk/Source/WebCore/SourcesGTK.txt
- trunk/Source/WebCore/accessibility/AccessibilityTableColumn.cpp
- trunk/Source/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp
- trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp
- trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.h
- trunk/Source/WebCore/accessibility/atspi/xml/TableCell.xml
- trunk/Tools/ChangeLog
- trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp
- trunk/Tools/WebKitTestRunner/InjectedBundle/atspi/AccessibilityUIElementAtspi.cpp
Added Paths
Diff
Modified: trunk/Source/WebCore/ChangeLog (286415 => 286416)
--- trunk/Source/WebCore/ChangeLog 2021-12-02 08:06:24 UTC (rev 286415)
+++ trunk/Source/WebCore/ChangeLog 2021-12-02 08:16:13 UTC (rev 286416)
@@ -1,3 +1,48 @@
+2021-12-01 Carlos Garcia Campos <[email protected]>
+
+ [GTK][a11y] Add implementation of table and table cell interfaces when building with ATSPI
+ https://bugs.webkit.org/show_bug.cgi?id=233694
+
+ Reviewed by Adrian Perez de Castro.
+
+ * SourcesGTK.txt:
+ * accessibility/AccessibilityTableColumn.cpp:
+ (WebCore::AccessibilityTableColumn::computeAccessibilityIsIgnored const): Do not expose column for ATSPI.
+ * accessibility/AccessibilityTableHeaderContainer.cpp:
+ (WebCore::AccessibilityTableHeaderContainer::computeAccessibilityIsIgnored const): Do not expose header container either.
+ * accessibility/atspi/AccessibilityObjectAtspi.cpp:
+ (WebCore::AccessibilityObjectAtspi::interfacesForObject):
+ (WebCore::AccessibilityObjectAtspi::path):
+ (WebCore::AccessibilityObjectAtspi::wrapperVector const):
+ (WebCore::AccessibilityObjectAtspi::children const):
+ (WebCore::AccessibilityObjectAtspi::buildInterfaces const):
+ * accessibility/atspi/AccessibilityObjectAtspi.h:
+ * accessibility/atspi/AccessibilityObjectTableAtspi.cpp: Added.
+ (WebCore::AccessibilityObjectAtspi::rowCount const):
+ (WebCore::AccessibilityObjectAtspi::columnCount const):
+ (WebCore::AccessibilityObjectAtspi::cell const):
+ (WebCore::AccessibilityObjectAtspi::tableCaption const):
+ (WebCore::AccessibilityObjectAtspi::cellIndex const):
+ (WebCore::AccessibilityObjectAtspi::rowAtIndex const):
+ (WebCore::AccessibilityObjectAtspi::columnAtIndex const):
+ (WebCore::AccessibilityObjectAtspi::rowHeader const):
+ (WebCore::AccessibilityObjectAtspi::columnHeader const):
+ (WebCore::AccessibilityObjectAtspi::rowDescription const):
+ (WebCore::AccessibilityObjectAtspi::columnDescription const):
+ (WebCore::AccessibilityObjectAtspi::rowExtent const):
+ (WebCore::AccessibilityObjectAtspi::columnExtent const):
+ (WebCore::AccessibilityObjectAtspi::cells const):
+ (WebCore::AccessibilityObjectAtspi::rows const):
+ (WebCore::AccessibilityObjectAtspi::rowHeaders const):
+ (WebCore::AccessibilityObjectAtspi::columnHeaders const):
+ * accessibility/atspi/AccessibilityObjectTableCellAtspi.cpp: Added.
+ (WebCore::AccessibilityObjectAtspi::cellRowHeaders const):
+ (WebCore::AccessibilityObjectAtspi::cellColumnHeaders const):
+ (WebCore::AccessibilityObjectAtspi::rowSpan const):
+ (WebCore::AccessibilityObjectAtspi::columnSpan const):
+ (WebCore::AccessibilityObjectAtspi::cellPosition const):
+ * accessibility/atspi/xml/TableCell.xml:
+
2021-12-02 Manuel Rego Casasnovas <[email protected]>
[selectors] :focus-visible should stop matching after blur
Modified: trunk/Source/WebCore/SourcesGTK.txt (286415 => 286416)
--- trunk/Source/WebCore/SourcesGTK.txt 2021-12-02 08:06:24 UTC (rev 286415)
+++ trunk/Source/WebCore/SourcesGTK.txt 2021-12-02 08:16:13 UTC (rev 286416)
@@ -48,6 +48,8 @@
accessibility/atspi/AccessibilityObjectHypertextAtspi.cpp
accessibility/atspi/AccessibilityObjectImageAtspi.cpp
accessibility/atspi/AccessibilityObjectSelectionAtspi.cpp
+accessibility/atspi/AccessibilityObjectTableAtspi.cpp
+accessibility/atspi/AccessibilityObjectTableCellAtspi.cpp
accessibility/atspi/AccessibilityObjectTextAtspi.cpp
accessibility/atspi/AccessibilityObjectValueAtspi.cpp
accessibility/atspi/AccessibilityRootAtspi.cpp
Modified: trunk/Source/WebCore/accessibility/AccessibilityTableColumn.cpp (286415 => 286416)
--- trunk/Source/WebCore/accessibility/AccessibilityTableColumn.cpp 2021-12-02 08:06:24 UTC (rev 286415)
+++ trunk/Source/WebCore/accessibility/AccessibilityTableColumn.cpp 2021-12-02 08:16:13 UTC (rev 286416)
@@ -172,7 +172,7 @@
if (!m_parent)
return true;
-#if PLATFORM(IOS_FAMILY) || USE(ATK)
+#if PLATFORM(IOS_FAMILY) || USE(ATK) || USE(ATSPI)
return true;
#endif
Modified: trunk/Source/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp (286415 => 286416)
--- trunk/Source/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp 2021-12-02 08:06:24 UTC (rev 286415)
+++ trunk/Source/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp 2021-12-02 08:16:13 UTC (rev 286416)
@@ -54,7 +54,7 @@
if (!m_parent)
return true;
-#if PLATFORM(IOS_FAMILY) || USE(ATK)
+#if PLATFORM(IOS_FAMILY) || USE(ATK) || USE(ATSPI)
return true;
#endif
Modified: trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp (286415 => 286416)
--- trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp 2021-12-02 08:06:24 UTC (rev 286415)
+++ trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp 2021-12-02 08:16:13 UTC (rev 286416)
@@ -100,6 +100,15 @@
if (coreObject.canHaveSelectedChildren())
interfaces.add(Interface::Selection);
+ if (coreObject.isTable())
+ interfaces.add(Interface::Table);
+
+ if (coreObject.roleValue() == AccessibilityRole::Cell
+ || coreObject.roleValue() == AccessibilityRole::GridCell
+ || coreObject.roleValue() == AccessibilityRole::ColumnHeader
+ || coreObject.roleValue() == AccessibilityRole::RowHeader)
+ interfaces.add(Interface::TableCell);
+
return interfaces;
}
@@ -500,6 +509,10 @@
interfaces.append({ const_cast<GDBusInterfaceInfo*>(&webkit_image_interface), &s_imageFunctions });
if (m_interfaces.contains(Interface::Selection))
interfaces.append({ const_cast<GDBusInterfaceInfo*>(&webkit_selection_interface), &s_selectionFunctions });
+ if (m_interfaces.contains(Interface::Table))
+ interfaces.append({ const_cast<GDBusInterfaceInfo*>(&webkit_table_interface), &s_tableFunctions });
+ if (m_interfaces.contains(Interface::TableCell))
+ interfaces.append({ const_cast<GDBusInterfaceInfo*>(&webkit_table_cell_interface), &s_tableCellFunctions });
m_path = atspiRoot->atspi().registerObject(*this, WTFMove(interfaces));
}
@@ -556,8 +569,10 @@
if (!axParent)
return nullptr;
- if (auto* atspiParent = axParent->wrapper())
+ if (auto* atspiParent = axParent->wrapper()) {
+ atspiParent->setRoot(root());
return atspiParent;
+ }
return std::nullopt;
}
@@ -598,18 +613,13 @@
return wrapper;
}
-Vector<RefPtr<AccessibilityObjectAtspi>> AccessibilityObjectAtspi::children() const
+Vector<RefPtr<AccessibilityObjectAtspi>> AccessibilityObjectAtspi::wrapperVector(const Vector<RefPtr<AXCoreObject>>& elements) const
{
- RELEASE_ASSERT(!isMainThread());
- if (!m_axObject)
- return { };
-
- const auto& children = m_axObject->children();
Vector<RefPtr<AccessibilityObjectAtspi>> wrappers;
- wrappers.reserveInitialCapacity(children.size());
+ wrappers.reserveInitialCapacity(elements.size());
auto* root = this->root();
- for (const auto& child : children) {
- if (auto* wrapper = child->wrapper()) {
+ for (const auto& element : elements) {
+ if (auto* wrapper = element->wrapper()) {
wrapper->setRoot(root);
wrappers.uncheckedAppend(wrapper);
}
@@ -617,6 +627,15 @@
return wrappers;
}
+Vector<RefPtr<AccessibilityObjectAtspi>> AccessibilityObjectAtspi::children() const
+{
+ RELEASE_ASSERT(!isMainThread());
+ if (!m_axObject)
+ return { };
+
+ return wrapperVector(m_axObject->children());
+}
+
int AccessibilityObjectAtspi::indexInParent() const
{
RELEASE_ASSERT(!isMainThread());
@@ -1152,6 +1171,10 @@
g_variant_builder_add(builder, "s", webkit_image_interface.name);
if (m_interfaces.contains(Interface::Selection))
g_variant_builder_add(builder, "s", webkit_selection_interface.name);
+ if (m_interfaces.contains(Interface::Table))
+ g_variant_builder_add(builder, "s", webkit_table_interface.name);
+ if (m_interfaces.contains(Interface::TableCell))
+ g_variant_builder_add(builder, "s", webkit_table_cell_interface.name);
}
void AccessibilityObjectAtspi::serialize(GVariantBuilder* builder) const
Modified: trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.h (286415 => 286416)
--- trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.h 2021-12-02 08:06:24 UTC (rev 286415)
+++ trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.h 2021-12-02 08:16:13 UTC (rev 286416)
@@ -52,7 +52,9 @@
Action = 1 << 6,
Document = 1 << 7,
Image = 1 << 8,
- Selection = 1 << 9
+ Selection = 1 << 9,
+ Table = 1 << 10,
+ TableCell = 1 << 11
};
const OptionSet<Interface>& interfaces() const { return m_interfaces; }
@@ -138,9 +140,24 @@
WEBCORE_EXPORT bool clearSelection() const;
void selectionChanged();
+ WEBCORE_EXPORT AccessibilityObjectAtspi* cell(unsigned row, unsigned column) const;
+ WEBCORE_EXPORT unsigned rowCount() const;
+ WEBCORE_EXPORT unsigned columnCount() const;
+ WEBCORE_EXPORT Vector<RefPtr<AccessibilityObjectAtspi>> cells() const;
+ WEBCORE_EXPORT Vector<RefPtr<AccessibilityObjectAtspi>> rows() const;
+ WEBCORE_EXPORT Vector<RefPtr<AccessibilityObjectAtspi>> rowHeaders() const;
+ WEBCORE_EXPORT Vector<RefPtr<AccessibilityObjectAtspi>> columnHeaders() const;
+
+ WEBCORE_EXPORT Vector<RefPtr<AccessibilityObjectAtspi>> cellRowHeaders() const;
+ WEBCORE_EXPORT Vector<RefPtr<AccessibilityObjectAtspi>> cellColumnHeaders() const;
+ WEBCORE_EXPORT unsigned rowSpan() const;
+ WEBCORE_EXPORT unsigned columnSpan() const;
+ WEBCORE_EXPORT std::pair<std::optional<unsigned>, std::optional<unsigned>> cellPosition() const;
+
private:
explicit AccessibilityObjectAtspi(AXCoreObject*);
+ Vector<RefPtr<AccessibilityObjectAtspi>> wrapperVector(const Vector<RefPtr<AXCoreObject>>&) const;
int indexInParent() const;
GVariant* parentReference() const;
void childAdded(AccessibilityObjectAtspi&);
@@ -189,6 +206,18 @@
bool isChildSelected(unsigned) const;
bool selectAll() const;
+ AccessibilityObjectAtspi* rowHeader(unsigned) const;
+ AccessibilityObjectAtspi* columnHeader(unsigned) const;
+ unsigned rowExtent(unsigned row, unsigned column) const;
+ unsigned columnExtent(unsigned row, unsigned column) const;
+
+ AccessibilityObjectAtspi* tableCaption() const;
+ std::optional<unsigned> cellIndex(unsigned row, unsigned column) const;
+ std::optional<unsigned> rowAtIndex(unsigned) const;
+ std::optional<unsigned> columnAtIndex(unsigned) const;
+ String rowDescription(unsigned) const;
+ String columnDescription(unsigned) const;
+
static OptionSet<Interface> interfacesForObject(AXCoreObject&);
static GDBusInterfaceVTable s_accessibleFunctions;
@@ -201,6 +230,8 @@
static GDBusInterfaceVTable s_documentFunctions;
static GDBusInterfaceVTable s_imageFunctions;
static GDBusInterfaceVTable s_selectionFunctions;
+ static GDBusInterfaceVTable s_tableFunctions;
+ static GDBusInterfaceVTable s_tableCellFunctions;
AXCoreObject* m_axObject { nullptr };
AXCoreObject* m_coreObject { nullptr };
Added: trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectTableAtspi.cpp (0 => 286416)
--- trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectTableAtspi.cpp (rev 0)
+++ trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectTableAtspi.cpp 2021-12-02 08:16:13 UTC (rev 286416)
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2021 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "AccessibilityObjectAtspi.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATSPI)
+
+#include "AccessibilityRootAtspi.h"
+#include "HTMLTableCaptionElement.h"
+#include "HTMLTableElement.h"
+#include "RenderElement.h"
+#include <gio/gio.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+GDBusInterfaceVTable AccessibilityObjectAtspi::s_tableFunctions = {
+ // method_call
+ [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar* methodName, GVariant* parameters, GDBusMethodInvocation* invocation, gpointer userData) {
+ RELEASE_ASSERT(!isMainThread());
+ auto atspiObject = Ref { *static_cast<AccessibilityObjectAtspi*>(userData) };
+ atspiObject->updateBackingStore();
+
+ if (!g_strcmp0(methodName, "GetAccessibleAt")) {
+ int row, column;
+ g_variant_get(parameters, "(ii)", &row, &column);
+ auto* cell = row >= 0 && column >= 0 ? atspiObject->cell(row, column) : nullptr;
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(@(so))", cell ? cell->reference() : atspiObject->root()->atspi().nullReference()));
+ } else if (!g_strcmp0(methodName, "GetIndexAt")) {
+ int row, column;
+ g_variant_get(parameters, "(ii)", &row, &column);
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", row >= 0 && column >= 0 ? atspiObject->cellIndex(row, column).value_or(-1) : -1));
+ } else if (!g_strcmp0(methodName, "GetRowAtIndex")) {
+ int index;
+ g_variant_get(parameters, "(i)", &index);
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", index >= 0 ? atspiObject->rowAtIndex(index).value_or(-1) : -1));
+ } else if (!g_strcmp0(methodName, "GetColumnAtIndex")) {
+ int index;
+ g_variant_get(parameters, "(i)", &index);
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", index >= 0 ? atspiObject->columnAtIndex(index).value_or(-1) : -1));
+ } else if (!g_strcmp0(methodName, "GetRowDescription")) {
+ int index;
+ g_variant_get(parameters, "(i)", &index);
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", index >= 0 ? atspiObject->rowDescription(index).utf8().data() : ""));
+ } else if (!g_strcmp0(methodName, "GetColumnDescription")) {
+ int index;
+ g_variant_get(parameters, "(i)", &index);
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", index >= 0 ? atspiObject->columnDescription(index).utf8().data() : ""));
+ } else if (!g_strcmp0(methodName, "GetRowExtentAt")) {
+ int row, column;
+ g_variant_get(parameters, "(ii)", &row, &column);
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", row >= 0 && column >= 0 ? atspiObject->rowExtent(row, column) : -1));
+ } else if (!g_strcmp0(methodName, "GetColumnExtentAt")) {
+ int row, column;
+ g_variant_get(parameters, "(ii)", &row, &column);
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", row >= 0 && column >= 0 ? atspiObject->columnExtent(row, column) : -1));
+ } else if (!g_strcmp0(methodName, "GetRowHeader")) {
+ int row;
+ g_variant_get(parameters, "(i)", &row);
+ auto* header = row >= 0 ? atspiObject->rowHeader(row) : nullptr;
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(@(so))", header ? header->reference() : atspiObject->root()->atspi().nullReference()));
+ } else if (!g_strcmp0(methodName, "GetColumnHeader")) {
+ int column;
+ g_variant_get(parameters, "(i)", &column);
+ auto* header = column >= 0 ? atspiObject->columnHeader(column) : nullptr;
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(@(so))", header ? header->reference() : atspiObject->root()->atspi().nullReference()));
+ } else if (!g_strcmp0(methodName, "GetRowColumnExtentsAtIndex")) {
+ int index;
+ g_variant_get(parameters, "(i)", &index);
+ if (index < 0) {
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(biiiib)", FALSE, -1, -1, -1, -1, FALSE));
+ return;
+ }
+
+ auto row = atspiObject->rowAtIndex(index);
+ auto column = atspiObject->columnAtIndex(index);
+ auto* cell = atspiObject->m_axObject ? atspiObject->m_axObject->cellForColumnAndRow(*column, *row) : nullptr;
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(biiiib)", cell && cell->isTableCell() ? TRUE : FALSE,
+ row.value_or(-1), column.value_or(-1), row && column ? atspiObject->rowExtent(*row, *column) : -1,
+ row && column ? atspiObject->columnExtent(*row, *column) : -1, FALSE));
+ } else if (!g_strcmp0(methodName, "GetSelectedRows")
+ || !g_strcmp0(methodName, "GetSelectedColumns")
+ || !g_strcmp0(methodName, "IsRowSelected")
+ || !g_strcmp0(methodName, "IsColumnSelected")
+ || !g_strcmp0(methodName, "IsSelected")
+ || !g_strcmp0(methodName, "AddRowSelection")
+ || !g_strcmp0(methodName, "AddColumnSelection")
+ || !g_strcmp0(methodName, "RemoveRowSelection")
+ || !g_strcmp0(methodName, "RemoveColumnSelection"))
+ g_dbus_method_invocation_return_error_literal(invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
+ },
+ // get_property
+ [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar* propertyName, GError** error, gpointer userData) -> GVariant* {
+ RELEASE_ASSERT(!isMainThread());
+ auto atspiObject = Ref { *static_cast<AccessibilityObjectAtspi*>(userData) };
+ atspiObject->updateBackingStore();
+
+ if (!g_strcmp0(propertyName, "NRows"))
+ return g_variant_new_int32(atspiObject->rowCount());
+ if (!g_strcmp0(propertyName, "NColumns"))
+ return g_variant_new_int32(atspiObject->columnCount());
+ if (!g_strcmp0(propertyName, "Caption")) {
+ auto* caption = atspiObject->tableCaption();
+ return caption ? caption->reference() : atspiObject->root()->atspi().nullReference();
+ }
+ if (!g_strcmp0(propertyName, "Summary"))
+ return atspiObject->root()->atspi().nullReference();
+ if (!g_strcmp0(propertyName, "NSelectedRows"))
+ return g_variant_new_int32(0);
+ if (!g_strcmp0(propertyName, "NSelectedColumns"))
+ return g_variant_new_int32(0);
+
+ g_set_error(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Unknown property '%s'", propertyName);
+ return nullptr;
+ },
+ // set_property,
+ nullptr,
+ // padding
+ nullptr
+};
+
+unsigned AccessibilityObjectAtspi::rowCount() const
+{
+ RELEASE_ASSERT(!isMainThread());
+ if (!m_axObject)
+ return 0;
+
+ return m_axObject->rowCount();
+}
+
+unsigned AccessibilityObjectAtspi::columnCount() const
+{
+ RELEASE_ASSERT(!isMainThread());
+ if (!m_axObject)
+ return 0;
+
+ return m_axObject->columnCount();
+}
+
+AccessibilityObjectAtspi* AccessibilityObjectAtspi::cell(unsigned row, unsigned column) const
+{
+ RELEASE_ASSERT(!isMainThread());
+ if (!m_axObject)
+ return nullptr;
+
+ if (auto* tableCell = m_axObject->cellForColumnAndRow(column, row)) {
+ if (auto* wrapper = tableCell->wrapper()) {
+ wrapper->setRoot(root());
+ return wrapper;
+ }
+ }
+
+ return nullptr;
+}
+
+AccessibilityObjectAtspi* AccessibilityObjectAtspi::tableCaption() const
+{
+ return Accessibility::retrieveValueFromMainThread<AccessibilityObjectAtspi*>([this]() -> AccessibilityObjectAtspi* {
+ if (m_coreObject)
+ m_coreObject->updateBackingStore();
+
+ if (!m_coreObject)
+ return nullptr;
+
+ if (auto* node = m_coreObject->node()) {
+ if (!is<HTMLTableElement>(node))
+ return nullptr;
+
+ if (auto caption = downcast<HTMLTableElement>(*node).caption()) {
+ if (auto* renderer = caption->renderer()) {
+ if (auto* element = AccessibilityObject::firstAccessibleObjectFromNode(renderer->element())) {
+ if (auto* wrapper = element->wrapper()) {
+ wrapper->setRoot(root());
+ return wrapper;
+ }
+ }
+ }
+ }
+ }
+
+ return nullptr;
+ });
+}
+
+std::optional<unsigned> AccessibilityObjectAtspi::cellIndex(unsigned row, unsigned column) const
+{
+ RELEASE_ASSERT(!isMainThread());
+ if (!m_axObject)
+ return std::nullopt;
+
+ auto* cell = m_axObject->cellForColumnAndRow(column, row);
+ if (!cell)
+ return std::nullopt;
+
+ auto cells = m_axObject->cells();
+ AXCoreObject::AccessibilityChildrenVector::iterator position;
+ position = std::find(cells.begin(), cells.end(), cell);
+ if (position == cells.end())
+ return std::nullopt;
+ return position - cells.begin();
+}
+
+std::optional<unsigned> AccessibilityObjectAtspi::rowAtIndex(unsigned index) const
+{
+ RELEASE_ASSERT(!isMainThread());
+ if (!m_axObject)
+ return std::nullopt;
+
+ auto cells = m_axObject->cells();
+ if (index >= cells.size())
+ return std::nullopt;
+
+ return cells[index]->rowIndexRange().first;
+}
+
+std::optional<unsigned> AccessibilityObjectAtspi::columnAtIndex(unsigned index) const
+{
+ RELEASE_ASSERT(!isMainThread());
+ if (!m_axObject)
+ return std::nullopt;
+
+ auto cells = m_axObject->cells();
+ if (index >= cells.size())
+ return std::nullopt;
+
+ return cells[index]->columnIndexRange().first;
+}
+
+AccessibilityObjectAtspi* AccessibilityObjectAtspi::rowHeader(unsigned row) const
+{
+ RELEASE_ASSERT(!isMainThread());
+ if (!m_axObject)
+ return nullptr;
+
+ auto headers = m_axObject->rowHeaders();
+ for (const auto& header : headers) {
+ auto range = header->rowIndexRange();
+ if (range.first <= row && row < range.first + range.second) {
+ if (auto* wrapper = header->wrapper()) {
+ wrapper->setRoot(root());
+ return wrapper;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+AccessibilityObjectAtspi* AccessibilityObjectAtspi::columnHeader(unsigned column) const
+{
+ RELEASE_ASSERT(!isMainThread());
+ if (!m_axObject)
+ return nullptr;
+
+ auto headers = m_axObject->columnHeaders();
+ for (const auto& header : headers) {
+ auto range = header->columnIndexRange();
+ if (range.first <= column && column < range.first + range.second) {
+ if (auto* wrapper = header->wrapper()) {
+ wrapper->setRoot(root());
+ return wrapper;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+String AccessibilityObjectAtspi::rowDescription(unsigned row) const
+{
+ RELEASE_ASSERT(!isMainThread());
+ if (!m_axObject)
+ return { };
+
+ StringBuilder builder;
+ bool isFirst = true;
+ auto headers = m_axObject->rowHeaders();
+ for (const auto& header : headers) {
+ auto* wrapper = header->wrapper();
+ if (!wrapper)
+ continue;
+
+ auto range = header->rowIndexRange();
+ if (range.first <= row && row < range.first + range.second) {
+ wrapper->updateBackingStore();
+ auto text = wrapper->text();
+ if (text.isEmpty())
+ continue;
+
+ if (!isFirst)
+ builder.append(' ');
+ else
+ isFirst = false;
+ builder.append(text);
+ }
+ }
+ return builder.toString();
+}
+
+String AccessibilityObjectAtspi::columnDescription(unsigned column) const
+{
+ RELEASE_ASSERT(!isMainThread());
+ if (!m_axObject)
+ return { };
+
+ StringBuilder builder;
+ bool isFirst = true;
+ auto headers = m_axObject->columnHeaders();
+ for (const auto& header : headers) {
+ auto* wrapper = header->wrapper();
+ if (!wrapper)
+ continue;
+
+ auto range = header->columnIndexRange();
+ if (range.first <= column && column < range.first + range.second) {
+ wrapper->updateBackingStore();
+ auto text = wrapper->text();
+ if (text.isEmpty())
+ continue;
+
+ if (!isFirst)
+ builder.append(' ');
+ else
+ isFirst = false;
+ builder.append(text);
+ }
+ }
+ return builder.toString();
+}
+
+unsigned AccessibilityObjectAtspi::rowExtent(unsigned row, unsigned column) const
+{
+ RELEASE_ASSERT(!isMainThread());
+ if (!m_axObject)
+ return 0;
+
+ auto* cell = m_axObject->cellForColumnAndRow(column, row);
+ return cell ? cell->rowIndexRange().second : 0;
+}
+
+unsigned AccessibilityObjectAtspi::columnExtent(unsigned row, unsigned column) const
+{
+ RELEASE_ASSERT(!isMainThread());
+ if (!m_axObject)
+ return 0;
+
+ auto* cell = m_axObject->cellForColumnAndRow(column, row);
+ return cell ? cell->columnIndexRange().second : 0;
+}
+
+Vector<RefPtr<AccessibilityObjectAtspi>> AccessibilityObjectAtspi::cells() const
+{
+ RELEASE_ASSERT(isMainThread());
+ if (!m_coreObject)
+ return { };
+
+ return wrapperVector(m_coreObject->cells());
+}
+
+Vector<RefPtr<AccessibilityObjectAtspi>> AccessibilityObjectAtspi::rows() const
+{
+ RELEASE_ASSERT(isMainThread());
+ if (!m_coreObject)
+ return { };
+
+ return wrapperVector(m_coreObject->rows());
+}
+
+Vector<RefPtr<AccessibilityObjectAtspi>> AccessibilityObjectAtspi::rowHeaders() const
+{
+ RELEASE_ASSERT(isMainThread());
+ if (!m_coreObject)
+ return { };
+
+ return wrapperVector(m_coreObject->rowHeaders());
+}
+
+Vector<RefPtr<AccessibilityObjectAtspi>> AccessibilityObjectAtspi::columnHeaders() const
+{
+ RELEASE_ASSERT(isMainThread());
+ if (!m_coreObject)
+ return { };
+
+ return wrapperVector(m_coreObject->columnHeaders());
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATSPI)
Added: trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectTableCellAtspi.cpp (0 => 286416)
--- trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectTableCellAtspi.cpp (rev 0)
+++ trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectTableCellAtspi.cpp 2021-12-02 08:16:13 UTC (rev 286416)
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2021 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "AccessibilityObjectAtspi.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATSPI)
+
+#include "AccessibilityAtspiEnums.h"
+#include "AccessibilityRootAtspi.h"
+#include <gio/gio.h>
+
+namespace WebCore {
+
+GDBusInterfaceVTable AccessibilityObjectAtspi::s_tableCellFunctions = {
+ // method_call
+ [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar* methodName, GVariant*, GDBusMethodInvocation* invocation, gpointer userData) {
+ RELEASE_ASSERT(!isMainThread());
+ auto atspiObject = Ref { *static_cast<AccessibilityObjectAtspi*>(userData) };
+ atspiObject->updateBackingStore();
+
+ if (!g_strcmp0(methodName, "GetRowHeaderCells")) {
+ GVariantBuilder builder = G_VARIANT_BUILDER_INIT(G_VARIANT_TYPE("a(so)"));
+ for (const auto& wrapper : atspiObject->cellRowHeaders())
+ g_variant_builder_add(&builder, "@(so)", wrapper->reference());
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(a(so))", &builder));
+ } else if (!g_strcmp0(methodName, "GetColumnHeaderCells")) {
+ GVariantBuilder builder = G_VARIANT_BUILDER_INIT(G_VARIANT_TYPE("a(so)"));
+ for (const auto& wrapper : atspiObject->cellColumnHeaders())
+ g_variant_builder_add(&builder, "@(so)", wrapper->reference());
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(a(so))", &builder));
+ } else if (!g_strcmp0(methodName, "GetRowColumnSpan")) {
+ auto position = atspiObject->cellPosition();
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(iiii)", position.first.value_or(-1), position.second.value_or(-1), atspiObject->rowSpan(), atspiObject->columnSpan()));
+ }
+ },
+ // get_property
+ [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar* propertyName, GError** error, gpointer userData) -> GVariant* {
+ RELEASE_ASSERT(!isMainThread());
+ auto atspiObject = Ref { *static_cast<AccessibilityObjectAtspi*>(userData) };
+ atspiObject->updateBackingStore();
+
+ if (!g_strcmp0(propertyName, "ColumnSpan"))
+ return g_variant_new_int32(atspiObject->columnSpan());
+ if (!g_strcmp0(propertyName, "Position")) {
+ auto position = atspiObject->cellPosition();
+ return g_variant_new("(ii)", position.first.value_or(-1), position.second.value_or(-1));
+ }
+ if (!g_strcmp0(propertyName, "RowSpan"))
+ return g_variant_new_int32(atspiObject->rowSpan());
+ if (!g_strcmp0(propertyName, "Table")) {
+ auto* axObject = atspiObject->m_axObject;
+ if (!axObject || !axObject->isTableCell())
+ return atspiObject->root()->atspi().nullReference();
+
+ AccessibilityObjectAtspi* wrapper = atspiObject.ptr();
+ while (auto parent = wrapper->parent()) {
+ wrapper = parent.value();
+ if (!wrapper)
+ break;
+
+ wrapper->updateBackingStore();
+ axObject = wrapper->m_axObject;
+ if (axObject && axObject->isTable())
+ break;
+ }
+ return wrapper ? wrapper->reference() : atspiObject->root()->atspi().nullReference();
+ }
+
+ g_set_error(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Unknown property '%s'", propertyName);
+ return nullptr;
+ },
+ // set_property,
+ nullptr,
+ // padding
+ nullptr
+};
+
+Vector<RefPtr<AccessibilityObjectAtspi>> AccessibilityObjectAtspi::cellRowHeaders() const
+{
+ RELEASE_ASSERT(!isMainThread());
+ if (!m_axObject)
+ return { };
+
+ // Only return headers for cells that are not headers.
+ if (role() != Atspi::Role::TableCell)
+ return { };
+
+ auto headers = m_axObject->rowHeaders();
+ Vector<RefPtr<AccessibilityObjectAtspi>> wrappers;
+ wrappers.reserveInitialCapacity(headers.size());
+ auto* root = this->root();
+ for (const auto& header : headers) {
+ if (auto* wrapper = header->wrapper()) {
+ wrapper->setRoot(root);
+ wrappers.uncheckedAppend(wrapper);
+ }
+ }
+ return wrappers;
+}
+
+Vector<RefPtr<AccessibilityObjectAtspi>> AccessibilityObjectAtspi::cellColumnHeaders() const
+{
+ RELEASE_ASSERT(!isMainThread());
+ if (!m_axObject)
+ return { };
+
+ // Only return headers for cells that are not headers.
+ if (role() != Atspi::Role::TableCell)
+ return { };
+
+ auto headers = m_axObject->columnHeaders();
+ Vector<RefPtr<AccessibilityObjectAtspi>> wrappers;
+ wrappers.reserveInitialCapacity(headers.size());
+ auto* root = this->root();
+ for (const auto& header : headers) {
+ if (auto* wrapper = header->wrapper()) {
+ wrapper->setRoot(root);
+ wrappers.uncheckedAppend(wrapper);
+ }
+ }
+ return wrappers;
+}
+
+unsigned AccessibilityObjectAtspi::rowSpan() const
+{
+ RELEASE_ASSERT(!isMainThread());
+ if (!m_axObject)
+ return 0;
+
+ return m_axObject->rowIndexRange().second;
+}
+
+unsigned AccessibilityObjectAtspi::columnSpan() const
+{
+ RELEASE_ASSERT(!isMainThread());
+ if (!m_axObject)
+ return 0;
+
+ return m_axObject->columnIndexRange().second;
+}
+
+std::pair<std::optional<unsigned>, std::optional<unsigned>> AccessibilityObjectAtspi::cellPosition() const
+{
+ RELEASE_ASSERT(!isMainThread());
+ std::pair<std::optional<unsigned>, std::optional<unsigned>> position;
+ if (!m_axObject)
+ return position;
+
+ position.first = m_axObject->rowIndexRange().first;
+ position.second = m_axObject->columnIndexRange().first;
+
+ return position;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATSPI)
Modified: trunk/Source/WebCore/accessibility/atspi/xml/TableCell.xml (286415 => 286416)
--- trunk/Source/WebCore/accessibility/atspi/xml/TableCell.xml 2021-12-02 08:06:24 UTC (rev 286415)
+++ trunk/Source/WebCore/accessibility/atspi/xml/TableCell.xml 2021-12-02 08:16:13 UTC (rev 286416)
@@ -14,8 +14,17 @@
<annotation name="org.qtproject.QtDBus.QtTypeName" value="QSpiObjectReference"/>
</property>
+ <method name="GetRowHeaderCells">
+ <arg direction="out" type="a(so)"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QSpiObjectReferenceArray"/>
+ </method>
+
+ <method name="GetColumnHeaderCells">
+ <arg direction="out" type="a(so)"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QSpiObjectReferenceArray"/>
+ </method>
+
<method name="GetRowColumnSpan">
- <arg direction="out" type="b" />
<arg direction="out" name="row" type="i" />
<arg direction="out" name="col" type="i" />
<arg direction="out" name="row_extents" type="i" />
Modified: trunk/Tools/ChangeLog (286415 => 286416)
--- trunk/Tools/ChangeLog 2021-12-02 08:06:24 UTC (rev 286415)
+++ trunk/Tools/ChangeLog 2021-12-02 08:16:13 UTC (rev 286416)
@@ -1,3 +1,34 @@
+2021-12-01 Carlos Garcia Campos <[email protected]>
+
+ [GTK][a11y] Add implementation of table and table cell interfaces when building with ATSPI
+ https://bugs.webkit.org/show_bug.cgi?id=233694
+
+ Reviewed by Adrian Perez de Castro.
+
+ Add unit tests and WTR implementation for tables.
+
+ * TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp:
+ (testTableBasic):
+ (beforeAll):
+ * WebKitTestRunner/InjectedBundle/atspi/AccessibilityUIElementAtspi.cpp:
+ (WTR::AccessibilityUIElement::rowAtIndex):
+ (WTR::elementsVector):
+ (WTR::attributesOfElements):
+ (WTR::AccessibilityUIElement::attributesOfChildren):
+ (WTR::AccessibilityUIElement::numberAttributeValue):
+ (WTR::makeJSArray):
+ (WTR::AccessibilityUIElement::rowHeaders const):
+ (WTR::AccessibilityUIElement::columnHeaders const):
+ (WTR::AccessibilityUIElement::attributesOfColumnHeaders):
+ (WTR::AccessibilityUIElement::attributesOfRowHeaders):
+ (WTR::AccessibilityUIElement::attributesOfRows):
+ (WTR::AccessibilityUIElement::attributesOfVisibleCells):
+ (WTR::AccessibilityUIElement::rowCount):
+ (WTR::AccessibilityUIElement::columnCount):
+ (WTR::AccessibilityUIElement::rowIndexRange):
+ (WTR::AccessibilityUIElement::columnIndexRange):
+ (WTR::AccessibilityUIElement::cellForColumnAndRow):
+
2021-12-01 Sihui Liu <[email protected]>
FileSystemSyncAccessHandle should be invalidated when network process crashes
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp (286415 => 286416)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp 2021-12-02 08:06:24 UTC (rev 286415)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp 2021-12-02 08:16:13 UTC (rev 286416)
@@ -2332,6 +2332,418 @@
#endif
}
+static void testTableBasic(AccessibilityTest* test, gconstpointer)
+{
+#if !USE(ATSPI)
+ g_test_skip("Tables work differently with ATK");
+#else
+ test->showInWindow(800, 600);
+ test->loadHtml(
+ "<html>"
+ " <body>"
+ " <table>"
+ " <caption>Table Caption</caption>"
+ " <tr><th>Column 1</th><th>Column 2</th><th>Column 3</th></tr>"
+ " <tr><th rowspan='2'>Row 1 Cell 1</th><td>Row 1 Cell 2</td><td>Row 1 Cell 3</td></tr>"
+ " <tr><td>Row 2 Cell 2</td><td>Row 2 Cell 3</td></tr>"
+ " <tr><td colspan='3'>Row 3 Cell 1</td></tr>"
+ " </table>"
+ " </body>"
+ "</html>",
+ nullptr);
+ test->waitUntilLoadFinished();
+
+ auto testApp = test->findTestApplication();
+ g_assert_true(ATSPI_IS_ACCESSIBLE(testApp.get()));
+
+ auto documentWeb = test->findDocumentWeb(testApp.get());
+ g_assert_true(ATSPI_IS_ACCESSIBLE(documentWeb.get()));
+ g_assert_cmpint(atspi_accessible_get_child_count(documentWeb.get(), nullptr), ==, 1);
+
+ auto table = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 0, nullptr));
+ g_assert_true(ATSPI_IS_TABLE(table.get()));
+ g_assert_cmpint(atspi_accessible_get_role(table.get(), nullptr), ==, ATSPI_ROLE_TABLE);
+ g_assert_cmpint(atspi_accessible_get_child_count(table.get(), nullptr), ==, 5);
+ g_assert_cmpint(atspi_table_get_n_rows(ATSPI_TABLE(table.get()), nullptr), ==, 4);
+ g_assert_cmpint(atspi_table_get_n_columns(ATSPI_TABLE(table.get()), nullptr), ==, 3);
+
+ auto caption = adoptGRef(atspi_table_get_caption(ATSPI_TABLE(table.get()), nullptr));
+ g_assert_true(ATSPI_IS_ACCESSIBLE(caption.get()));
+ g_assert_cmpint(atspi_accessible_get_role(caption.get(), nullptr), ==, ATSPI_ROLE_CAPTION);
+ g_assert_true(ATSPI_IS_TEXT(caption.get()));
+ GUniquePtr<char> text(atspi_text_get_text(ATSPI_TEXT(caption.get()), 0, -1, nullptr));
+ g_assert_cmpstr(text.get(), ==, "Table Caption");
+
+ text.reset(atspi_table_get_row_description(ATSPI_TABLE(table.get()), 0, nullptr));
+ g_assert_cmpstr(text.get(), ==, "");
+ g_assert_null(atspi_table_get_row_header(ATSPI_TABLE(table.get()), 0, nullptr));
+ text.reset(atspi_table_get_row_description(ATSPI_TABLE(table.get()), 1, nullptr));
+ g_assert_cmpstr(text.get(), ==, "Row 1 Cell 1");
+ auto rowHeader = adoptGRef(atspi_table_get_row_header(ATSPI_TABLE(table.get()), 1, nullptr));
+ g_assert_true(ATSPI_IS_ACCESSIBLE(rowHeader.get()));
+ text.reset(atspi_table_get_row_description(ATSPI_TABLE(table.get()), 2, nullptr));
+ g_assert_cmpstr(text.get(), ==, "Row 1 Cell 1");
+ auto header = adoptGRef(atspi_table_get_row_header(ATSPI_TABLE(table.get()), 2, nullptr));
+ g_assert_true(rowHeader.get() == header.get());
+ text.reset(atspi_table_get_row_description(ATSPI_TABLE(table.get()), 3, nullptr));
+ g_assert_cmpstr(text.get(), ==, "");
+ g_assert_null(atspi_table_get_row_header(ATSPI_TABLE(table.get()), 3, nullptr));
+
+ text.reset(atspi_table_get_column_description(ATSPI_TABLE(table.get()), 0, nullptr));
+ g_assert_cmpstr(text.get(), ==, "Column 1");
+ auto columnHeader0 = adoptGRef(atspi_table_get_column_header(ATSPI_TABLE(table.get()), 0, nullptr));
+ g_assert_true(ATSPI_IS_ACCESSIBLE(columnHeader0.get()));
+ text.reset(atspi_table_get_column_description(ATSPI_TABLE(table.get()), 1, nullptr));
+ g_assert_cmpstr(text.get(), ==, "Column 2");
+ auto columnHeader1 = adoptGRef(atspi_table_get_column_header(ATSPI_TABLE(table.get()), 1, nullptr));
+ g_assert_true(ATSPI_IS_ACCESSIBLE(columnHeader1.get()));
+ text.reset(atspi_table_get_column_description(ATSPI_TABLE(table.get()), 2, nullptr));
+ g_assert_cmpstr(text.get(), ==, "Column 3");
+ auto columnHeader2 = adoptGRef(atspi_table_get_column_header(ATSPI_TABLE(table.get()), 2, nullptr));
+ g_assert_true(ATSPI_IS_ACCESSIBLE(columnHeader2.get()));
+
+ g_assert_cmpint(atspi_table_get_index_at(ATSPI_TABLE(table.get()), 0, 0, nullptr), ==, 0);
+ g_assert_cmpint(atspi_table_get_row_at_index(ATSPI_TABLE(table.get()), 0, nullptr), ==, 0);
+ g_assert_cmpint(atspi_table_get_column_at_index(ATSPI_TABLE(table.get()), 0, nullptr), ==, 0);
+ g_assert_cmpint(atspi_table_get_row_extent_at(ATSPI_TABLE(table.get()), 0, 0, nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_get_column_extent_at(ATSPI_TABLE(table.get()), 0, 0, nullptr), ==, 1);
+ int row, column, rowSpan, columnSpan;
+ gboolean isSelected;
+ g_assert_true(atspi_table_get_row_column_extents_at_index(ATSPI_TABLE(table.get()), 0, &row, &column, &rowSpan, &columnSpan, &isSelected, nullptr));
+ g_assert_cmpint(row, ==, 0);
+ g_assert_cmpint(column, ==, 0);
+ g_assert_cmpint(rowSpan, ==, 1);
+ g_assert_cmpint(columnSpan, ==, 1);
+ g_assert_false(isSelected);
+ auto cell0 = adoptGRef(atspi_table_get_accessible_at(ATSPI_TABLE(table.get()), 0, 0, nullptr));
+ g_assert_true(ATSPI_IS_TABLE_CELL(cell0.get()));
+ g_assert_true(cell0.get() == columnHeader0.get());
+ g_assert_cmpint(atspi_table_cell_get_row_span(ATSPI_TABLE_CELL(cell0.get()), nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_cell_get_column_span(ATSPI_TABLE_CELL(cell0.get()), nullptr), ==, 1);
+ g_assert_true(atspi_table_cell_get_position(ATSPI_TABLE_CELL(cell0.get()), &row, &column, nullptr));
+ g_assert_cmpint(row, ==, 0);
+ g_assert_cmpint(column, ==, 0);
+ atspi_table_cell_get_row_column_span(ATSPI_TABLE_CELL(cell0.get()), &row, &column, &rowSpan, &columnSpan, nullptr);
+ g_assert_cmpint(row, ==, 0);
+ g_assert_cmpint(column, ==, 0);
+ g_assert_cmpint(rowSpan, ==, 1);
+ g_assert_cmpint(columnSpan, ==, 1);
+ auto cellTable = adoptGRef(atspi_table_cell_get_table(ATSPI_TABLE_CELL(cell0.get()), nullptr));
+ g_assert_true(table.get() == cellTable.get());
+ GRefPtr<GPtrArray> rowHeaders = adoptGRef(atspi_table_cell_get_row_header_cells(ATSPI_TABLE_CELL(cell0.get()), nullptr));
+ g_assert_cmpint(rowHeaders->len, ==, 0);
+ GRefPtr<GPtrArray> columnHeaders = adoptGRef(atspi_table_cell_get_column_header_cells(ATSPI_TABLE_CELL(cell0.get()), nullptr));
+ g_assert_cmpint(columnHeaders->len, ==, 0);
+ g_assert_true(ATSPI_IS_TEXT(cell0.get()));
+ text.reset(atspi_text_get_text(ATSPI_TEXT(cell0.get()), 0, -1, nullptr));
+ g_assert_cmpstr(text.get(), ==, "Column 1");
+
+ g_assert_cmpint(atspi_table_get_index_at(ATSPI_TABLE(table.get()), 0, 1, nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_get_row_at_index(ATSPI_TABLE(table.get()), 1, nullptr), ==, 0);
+ g_assert_cmpint(atspi_table_get_column_at_index(ATSPI_TABLE(table.get()), 1, nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_get_row_extent_at(ATSPI_TABLE(table.get()), 0, 1, nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_get_column_extent_at(ATSPI_TABLE(table.get()), 0, 1, nullptr), ==, 1);
+ g_assert_true(atspi_table_get_row_column_extents_at_index(ATSPI_TABLE(table.get()), 1, &row, &column, &rowSpan, &columnSpan, &isSelected, nullptr));
+ g_assert_cmpint(row, ==, 0);
+ g_assert_cmpint(column, ==, 1);
+ g_assert_cmpint(rowSpan, ==, 1);
+ g_assert_cmpint(columnSpan, ==, 1);
+ g_assert_false(isSelected);
+ auto cell1 = adoptGRef(atspi_table_get_accessible_at(ATSPI_TABLE(table.get()), 0, 1, nullptr));
+ g_assert_true(ATSPI_IS_TABLE_CELL(cell1.get()));
+ g_assert_true(cell1.get() == columnHeader1.get());
+ g_assert_cmpint(atspi_table_cell_get_row_span(ATSPI_TABLE_CELL(cell1.get()), nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_cell_get_column_span(ATSPI_TABLE_CELL(cell1.get()), nullptr), ==, 1);
+ g_assert_true(atspi_table_cell_get_position(ATSPI_TABLE_CELL(cell1.get()), &row, &column, nullptr));
+ g_assert_cmpint(row, ==, 0);
+ g_assert_cmpint(column, ==, 1);
+ atspi_table_cell_get_row_column_span(ATSPI_TABLE_CELL(cell1.get()), &row, &column, &rowSpan, &columnSpan, nullptr);
+ g_assert_cmpint(row, ==, 0);
+ g_assert_cmpint(column, ==, 1);
+ g_assert_cmpint(rowSpan, ==, 1);
+ g_assert_cmpint(columnSpan, ==, 1);
+ cellTable = adoptGRef(atspi_table_cell_get_table(ATSPI_TABLE_CELL(cell1.get()), nullptr));
+ g_assert_true(table.get() == cellTable.get());
+ rowHeaders = adoptGRef(atspi_table_cell_get_row_header_cells(ATSPI_TABLE_CELL(cell1.get()), nullptr));
+ g_assert_cmpint(rowHeaders->len, ==, 0);
+ columnHeaders = adoptGRef(atspi_table_cell_get_column_header_cells(ATSPI_TABLE_CELL(cell1.get()), nullptr));
+ g_assert_cmpint(columnHeaders->len, ==, 0);
+ g_assert_true(ATSPI_IS_TEXT(cell1.get()));
+ text.reset(atspi_text_get_text(ATSPI_TEXT(cell1.get()), 0, -1, nullptr));
+ g_assert_cmpstr(text.get(), ==, "Column 2");
+
+ g_assert_cmpint(atspi_table_get_index_at(ATSPI_TABLE(table.get()), 0, 2, nullptr), ==, 2);
+ g_assert_cmpint(atspi_table_get_row_at_index(ATSPI_TABLE(table.get()), 2, nullptr), ==, 0);
+ g_assert_cmpint(atspi_table_get_column_at_index(ATSPI_TABLE(table.get()), 2, nullptr), ==, 2);
+ g_assert_cmpint(atspi_table_get_row_extent_at(ATSPI_TABLE(table.get()), 0, 2, nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_get_column_extent_at(ATSPI_TABLE(table.get()), 0, 2, nullptr), ==, 1);
+ g_assert_true(atspi_table_get_row_column_extents_at_index(ATSPI_TABLE(table.get()), 2, &row, &column, &rowSpan, &columnSpan, &isSelected, nullptr));
+ g_assert_cmpint(row, ==, 0);
+ g_assert_cmpint(column, ==, 2);
+ g_assert_cmpint(rowSpan, ==, 1);
+ g_assert_cmpint(columnSpan, ==, 1);
+ g_assert_false(isSelected);
+ auto cell2 = adoptGRef(atspi_table_get_accessible_at(ATSPI_TABLE(table.get()), 0, 2, nullptr));
+ g_assert_true(ATSPI_IS_TABLE_CELL(cell2.get()));
+ g_assert_true(cell2.get() == columnHeader2.get());
+ g_assert_cmpint(atspi_table_cell_get_row_span(ATSPI_TABLE_CELL(cell2.get()), nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_cell_get_column_span(ATSPI_TABLE_CELL(cell2.get()), nullptr), ==, 1);
+ g_assert_true(atspi_table_cell_get_position(ATSPI_TABLE_CELL(cell2.get()), &row, &column, nullptr));
+ g_assert_cmpint(row, ==, 0);
+ g_assert_cmpint(column, ==, 2);
+ atspi_table_cell_get_row_column_span(ATSPI_TABLE_CELL(cell2.get()), &row, &column, &rowSpan, &columnSpan, nullptr);
+ g_assert_cmpint(row, ==, 0);
+ g_assert_cmpint(column, ==, 2);
+ g_assert_cmpint(rowSpan, ==, 1);
+ g_assert_cmpint(columnSpan, ==, 1);
+ cellTable = adoptGRef(atspi_table_cell_get_table(ATSPI_TABLE_CELL(cell2.get()), nullptr));
+ g_assert_true(table.get() == cellTable.get());
+ rowHeaders = adoptGRef(atspi_table_cell_get_row_header_cells(ATSPI_TABLE_CELL(cell2.get()), nullptr));
+ g_assert_cmpint(rowHeaders->len, ==, 0);
+ columnHeaders = adoptGRef(atspi_table_cell_get_column_header_cells(ATSPI_TABLE_CELL(cell2.get()), nullptr));
+ g_assert_cmpint(columnHeaders->len, ==, 0);
+ g_assert_true(ATSPI_IS_TEXT(cell2.get()));
+ text.reset(atspi_text_get_text(ATSPI_TEXT(cell2.get()), 0, -1, nullptr));
+ g_assert_cmpstr(text.get(), ==, "Column 3");
+
+ g_assert_cmpint(atspi_table_get_index_at(ATSPI_TABLE(table.get()), 1, 0, nullptr), ==, 3);
+ g_assert_cmpint(atspi_table_get_row_at_index(ATSPI_TABLE(table.get()), 3, nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_get_column_at_index(ATSPI_TABLE(table.get()), 3, nullptr), ==, 0);
+ g_assert_cmpint(atspi_table_get_row_extent_at(ATSPI_TABLE(table.get()), 1, 0, nullptr), ==, 2);
+ g_assert_cmpint(atspi_table_get_column_extent_at(ATSPI_TABLE(table.get()), 1, 0, nullptr), ==, 1);
+ g_assert_true(atspi_table_get_row_column_extents_at_index(ATSPI_TABLE(table.get()), 3, &row, &column, &rowSpan, &columnSpan, &isSelected, nullptr));
+ g_assert_cmpint(row, ==, 1);
+ g_assert_cmpint(column, ==, 0);
+ g_assert_cmpint(rowSpan, ==, 2);
+ g_assert_cmpint(columnSpan, ==, 1);
+ g_assert_false(isSelected);
+ auto cell3 = adoptGRef(atspi_table_get_accessible_at(ATSPI_TABLE(table.get()), 1, 0, nullptr));
+ g_assert_true(ATSPI_IS_TABLE_CELL(cell3.get()));
+ g_assert_true(cell3.get() == rowHeader.get());
+ g_assert_cmpint(atspi_table_cell_get_row_span(ATSPI_TABLE_CELL(cell3.get()), nullptr), ==, 2);
+ g_assert_cmpint(atspi_table_cell_get_column_span(ATSPI_TABLE_CELL(cell3.get()), nullptr), ==, 1);
+ g_assert_true(atspi_table_cell_get_position(ATSPI_TABLE_CELL(cell3.get()), &row, &column, nullptr));
+ g_assert_cmpint(row, ==, 1);
+ g_assert_cmpint(column, ==, 0);
+ atspi_table_cell_get_row_column_span(ATSPI_TABLE_CELL(cell3.get()), &row, &column, &rowSpan, &columnSpan, nullptr);
+ g_assert_cmpint(row, ==, 1);
+ g_assert_cmpint(column, ==, 0);
+ g_assert_cmpint(rowSpan, ==, 2);
+ g_assert_cmpint(columnSpan, ==, 1);
+ cellTable = adoptGRef(atspi_table_cell_get_table(ATSPI_TABLE_CELL(cell3.get()), nullptr));
+ g_assert_true(table.get() == cellTable.get());
+ rowHeaders = adoptGRef(atspi_table_cell_get_row_header_cells(ATSPI_TABLE_CELL(cell3.get()), nullptr));
+ g_assert_cmpint(rowHeaders->len, ==, 0);
+ columnHeaders = adoptGRef(atspi_table_cell_get_column_header_cells(ATSPI_TABLE_CELL(cell3.get()), nullptr));
+ g_assert_cmpint(columnHeaders->len, ==, 0);
+ g_assert_true(ATSPI_IS_TEXT(cell3.get()));
+ text.reset(atspi_text_get_text(ATSPI_TEXT(cell3.get()), 0, -1, nullptr));
+ g_assert_cmpstr(text.get(), ==, "Row 1 Cell 1");
+
+ g_assert_cmpint(atspi_table_get_index_at(ATSPI_TABLE(table.get()), 1, 1, nullptr), ==, 4);
+ g_assert_cmpint(atspi_table_get_row_at_index(ATSPI_TABLE(table.get()), 4, nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_get_column_at_index(ATSPI_TABLE(table.get()), 4, nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_get_row_extent_at(ATSPI_TABLE(table.get()), 1, 1, nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_get_column_extent_at(ATSPI_TABLE(table.get()), 1, 1, nullptr), ==, 1);
+ g_assert_true(atspi_table_get_row_column_extents_at_index(ATSPI_TABLE(table.get()), 4, &row, &column, &rowSpan, &columnSpan, &isSelected, nullptr));
+ g_assert_cmpint(row, ==, 1);
+ g_assert_cmpint(column, ==, 1);
+ g_assert_cmpint(rowSpan, ==, 1);
+ g_assert_cmpint(columnSpan, ==, 1);
+ g_assert_false(isSelected);
+ auto cell4 = adoptGRef(atspi_table_get_accessible_at(ATSPI_TABLE(table.get()), 1, 1, nullptr));
+ g_assert_true(ATSPI_IS_TABLE_CELL(cell4.get()));
+ g_assert_cmpint(atspi_table_cell_get_row_span(ATSPI_TABLE_CELL(cell4.get()), nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_cell_get_column_span(ATSPI_TABLE_CELL(cell4.get()), nullptr), ==, 1);
+ g_assert_true(atspi_table_cell_get_position(ATSPI_TABLE_CELL(cell4.get()), &row, &column, nullptr));
+ g_assert_cmpint(row, ==, 1);
+ g_assert_cmpint(column, ==, 1);
+ atspi_table_cell_get_row_column_span(ATSPI_TABLE_CELL(cell4.get()), &row, &column, &rowSpan, &columnSpan, nullptr);
+ g_assert_cmpint(row, ==, 1);
+ g_assert_cmpint(column, ==, 1);
+ g_assert_cmpint(rowSpan, ==, 1);
+ g_assert_cmpint(columnSpan, ==, 1);
+ cellTable = adoptGRef(atspi_table_cell_get_table(ATSPI_TABLE_CELL(cell4.get()), nullptr));
+ g_assert_true(table.get() == cellTable.get());
+ rowHeaders = adoptGRef(atspi_table_cell_get_row_header_cells(ATSPI_TABLE_CELL(cell4.get()), nullptr));
+ g_assert_cmpint(rowHeaders->len, ==, 1);
+ g_assert_true(rowHeaders->pdata[0] == rowHeader.get());
+ g_ptr_array_foreach(rowHeaders.get(), reinterpret_cast<GFunc>(reinterpret_cast<GCallback>(g_object_unref)), nullptr);
+ columnHeaders = adoptGRef(atspi_table_cell_get_column_header_cells(ATSPI_TABLE_CELL(cell4.get()), nullptr));
+ g_assert_cmpint(columnHeaders->len, ==, 1);
+ g_assert_true(columnHeaders->pdata[0] == columnHeader1.get());
+ g_ptr_array_foreach(columnHeaders.get(), reinterpret_cast<GFunc>(reinterpret_cast<GCallback>(g_object_unref)), nullptr);
+ g_assert_true(ATSPI_IS_TEXT(cell4.get()));
+ text.reset(atspi_text_get_text(ATSPI_TEXT(cell4.get()), 0, -1, nullptr));
+ g_assert_cmpstr(text.get(), ==, "Row 1 Cell 2");
+
+ g_assert_cmpint(atspi_table_get_index_at(ATSPI_TABLE(table.get()), 1, 2, nullptr), ==, 5);
+ g_assert_cmpint(atspi_table_get_row_at_index(ATSPI_TABLE(table.get()), 5, nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_get_column_at_index(ATSPI_TABLE(table.get()), 5, nullptr), ==, 2);
+ g_assert_cmpint(atspi_table_get_row_extent_at(ATSPI_TABLE(table.get()), 1, 2, nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_get_column_extent_at(ATSPI_TABLE(table.get()), 1, 2, nullptr), ==, 1);
+ g_assert_true(atspi_table_get_row_column_extents_at_index(ATSPI_TABLE(table.get()), 5, &row, &column, &rowSpan, &columnSpan, &isSelected, nullptr));
+ g_assert_cmpint(row, ==, 1);
+ g_assert_cmpint(column, ==, 2);
+ g_assert_cmpint(rowSpan, ==, 1);
+ g_assert_cmpint(columnSpan, ==, 1);
+ g_assert_false(isSelected);
+ auto cell5 = adoptGRef(atspi_table_get_accessible_at(ATSPI_TABLE(table.get()), 1, 2, nullptr));
+ g_assert_true(ATSPI_IS_TABLE_CELL(cell5.get()));
+ g_assert_cmpint(atspi_table_cell_get_row_span(ATSPI_TABLE_CELL(cell5.get()), nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_cell_get_column_span(ATSPI_TABLE_CELL(cell5.get()), nullptr), ==, 1);
+ g_assert_true(atspi_table_cell_get_position(ATSPI_TABLE_CELL(cell5.get()), &row, &column, nullptr));
+ g_assert_cmpint(row, ==, 1);
+ g_assert_cmpint(column, ==, 2);
+ atspi_table_cell_get_row_column_span(ATSPI_TABLE_CELL(cell5.get()), &row, &column, &rowSpan, &columnSpan, nullptr);
+ g_assert_cmpint(row, ==, 1);
+ g_assert_cmpint(column, ==, 2);
+ g_assert_cmpint(rowSpan, ==, 1);
+ g_assert_cmpint(columnSpan, ==, 1);
+ cellTable = adoptGRef(atspi_table_cell_get_table(ATSPI_TABLE_CELL(cell5.get()), nullptr));
+ g_assert_true(table.get() == cellTable.get());
+ rowHeaders = adoptGRef(atspi_table_cell_get_row_header_cells(ATSPI_TABLE_CELL(cell5.get()), nullptr));
+ g_assert_cmpint(rowHeaders->len, ==, 1);
+ g_assert_true(rowHeaders->pdata[0] == rowHeader.get());
+ g_ptr_array_foreach(rowHeaders.get(), reinterpret_cast<GFunc>(reinterpret_cast<GCallback>(g_object_unref)), nullptr);
+ columnHeaders = adoptGRef(atspi_table_cell_get_column_header_cells(ATSPI_TABLE_CELL(cell5.get()), nullptr));
+ g_assert_cmpint(columnHeaders->len, ==, 1);
+ g_assert_true(columnHeaders->pdata[0] == columnHeader2.get());
+ g_ptr_array_foreach(columnHeaders.get(), reinterpret_cast<GFunc>(reinterpret_cast<GCallback>(g_object_unref)), nullptr);
+ g_assert_true(ATSPI_IS_TEXT(cell5.get()));
+ text.reset(atspi_text_get_text(ATSPI_TEXT(cell5.get()), 0, -1, nullptr));
+ g_assert_cmpstr(text.get(), ==, "Row 1 Cell 3");
+
+ g_assert_cmpint(atspi_table_get_index_at(ATSPI_TABLE(table.get()), 2, 0, nullptr), ==, 3);
+ g_assert_cmpint(atspi_table_get_row_extent_at(ATSPI_TABLE(table.get()), 2, 0, nullptr), ==, 2);
+ g_assert_cmpint(atspi_table_get_column_extent_at(ATSPI_TABLE(table.get()), 2, 0, nullptr), ==, 1);
+ auto cell = adoptGRef(atspi_table_get_accessible_at(ATSPI_TABLE(table.get()), 2, 0, nullptr));
+ g_assert_true(cell3.get() == cell.get());
+
+ g_assert_cmpint(atspi_table_get_index_at(ATSPI_TABLE(table.get()), 2, 1, nullptr), ==, 6);
+ g_assert_cmpint(atspi_table_get_row_at_index(ATSPI_TABLE(table.get()), 6, nullptr), ==, 2);
+ g_assert_cmpint(atspi_table_get_column_at_index(ATSPI_TABLE(table.get()), 6, nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_get_row_extent_at(ATSPI_TABLE(table.get()), 2, 1, nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_get_column_extent_at(ATSPI_TABLE(table.get()), 2, 1, nullptr), ==, 1);
+ g_assert_true(atspi_table_get_row_column_extents_at_index(ATSPI_TABLE(table.get()), 6, &row, &column, &rowSpan, &columnSpan, &isSelected, nullptr));
+ g_assert_cmpint(row, ==, 2);
+ g_assert_cmpint(column, ==, 1);
+ g_assert_cmpint(rowSpan, ==, 1);
+ g_assert_cmpint(columnSpan, ==, 1);
+ g_assert_false(isSelected);
+ auto cell6 = adoptGRef(atspi_table_get_accessible_at(ATSPI_TABLE(table.get()), 2, 1, nullptr));
+ g_assert_true(ATSPI_IS_TABLE_CELL(cell6.get()));
+ g_assert_cmpint(atspi_table_cell_get_row_span(ATSPI_TABLE_CELL(cell6.get()), nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_cell_get_column_span(ATSPI_TABLE_CELL(cell6.get()), nullptr), ==, 1);
+ g_assert_true(atspi_table_cell_get_position(ATSPI_TABLE_CELL(cell6.get()), &row, &column, nullptr));
+ g_assert_cmpint(row, ==, 2);
+ g_assert_cmpint(column, ==, 1);
+ atspi_table_cell_get_row_column_span(ATSPI_TABLE_CELL(cell6.get()), &row, &column, &rowSpan, &columnSpan, nullptr);
+ g_assert_cmpint(row, ==, 2);
+ g_assert_cmpint(column, ==, 1);
+ g_assert_cmpint(rowSpan, ==, 1);
+ g_assert_cmpint(columnSpan, ==, 1);
+ cellTable = adoptGRef(atspi_table_cell_get_table(ATSPI_TABLE_CELL(cell6.get()), nullptr));
+ g_assert_true(table.get() == cellTable.get());
+ rowHeaders = adoptGRef(atspi_table_cell_get_row_header_cells(ATSPI_TABLE_CELL(cell6.get()), nullptr));
+ g_assert_cmpint(rowHeaders->len, ==, 1);
+ g_assert_true(rowHeaders->pdata[0] == rowHeader.get());
+ g_ptr_array_foreach(rowHeaders.get(), reinterpret_cast<GFunc>(reinterpret_cast<GCallback>(g_object_unref)), nullptr);
+ columnHeaders = adoptGRef(atspi_table_cell_get_column_header_cells(ATSPI_TABLE_CELL(cell6.get()), nullptr));
+ g_assert_cmpint(columnHeaders->len, ==, 1);
+ g_assert_true(columnHeaders->pdata[0] == columnHeader1.get());
+ g_ptr_array_foreach(columnHeaders.get(), reinterpret_cast<GFunc>(reinterpret_cast<GCallback>(g_object_unref)), nullptr);
+ g_assert_true(ATSPI_IS_TEXT(cell6.get()));
+ text.reset(atspi_text_get_text(ATSPI_TEXT(cell6.get()), 0, -1, nullptr));
+ g_assert_cmpstr(text.get(), ==, "Row 2 Cell 2");
+
+ g_assert_cmpint(atspi_table_get_index_at(ATSPI_TABLE(table.get()), 2, 2, nullptr), ==, 7);
+ g_assert_cmpint(atspi_table_get_row_at_index(ATSPI_TABLE(table.get()), 7, nullptr), ==, 2);
+ g_assert_cmpint(atspi_table_get_column_at_index(ATSPI_TABLE(table.get()), 7, nullptr), ==, 2);
+ g_assert_cmpint(atspi_table_get_row_extent_at(ATSPI_TABLE(table.get()), 2, 2, nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_get_column_extent_at(ATSPI_TABLE(table.get()), 2, 2, nullptr), ==, 1);
+ g_assert_true(atspi_table_get_row_column_extents_at_index(ATSPI_TABLE(table.get()), 7, &row, &column, &rowSpan, &columnSpan, &isSelected, nullptr));
+ g_assert_cmpint(row, ==, 2);
+ g_assert_cmpint(column, ==, 2);
+ g_assert_cmpint(rowSpan, ==, 1);
+ g_assert_cmpint(columnSpan, ==, 1);
+ g_assert_false(isSelected);
+ auto cell7 = adoptGRef(atspi_table_get_accessible_at(ATSPI_TABLE(table.get()), 2, 2, nullptr));
+ g_assert_true(ATSPI_IS_TABLE_CELL(cell7.get()));
+ g_assert_cmpint(atspi_table_cell_get_row_span(ATSPI_TABLE_CELL(cell7.get()), nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_cell_get_column_span(ATSPI_TABLE_CELL(cell7.get()), nullptr), ==, 1);
+ g_assert_true(atspi_table_cell_get_position(ATSPI_TABLE_CELL(cell7.get()), &row, &column, nullptr));
+ g_assert_cmpint(row, ==, 2);
+ g_assert_cmpint(column, ==, 2);
+ atspi_table_cell_get_row_column_span(ATSPI_TABLE_CELL(cell7.get()), &row, &column, &rowSpan, &columnSpan, nullptr);
+ g_assert_cmpint(row, ==, 2);
+ g_assert_cmpint(column, ==, 2);
+ g_assert_cmpint(rowSpan, ==, 1);
+ g_assert_cmpint(columnSpan, ==, 1);
+ cellTable = adoptGRef(atspi_table_cell_get_table(ATSPI_TABLE_CELL(cell7.get()), nullptr));
+ g_assert_true(table.get() == cellTable.get());
+ rowHeaders = adoptGRef(atspi_table_cell_get_row_header_cells(ATSPI_TABLE_CELL(cell7.get()), nullptr));
+ g_assert_cmpint(rowHeaders->len, ==, 1);
+ g_assert_true(rowHeaders->pdata[0] == rowHeader.get());
+ g_ptr_array_foreach(rowHeaders.get(), reinterpret_cast<GFunc>(reinterpret_cast<GCallback>(g_object_unref)), nullptr);
+ columnHeaders = adoptGRef(atspi_table_cell_get_column_header_cells(ATSPI_TABLE_CELL(cell7.get()), nullptr));
+ g_assert_cmpint(columnHeaders->len, ==, 1);
+ g_assert_true(columnHeaders->pdata[0] == columnHeader2.get());
+ g_ptr_array_foreach(columnHeaders.get(), reinterpret_cast<GFunc>(reinterpret_cast<GCallback>(g_object_unref)), nullptr);
+ g_assert_true(ATSPI_IS_TEXT(cell7.get()));
+ text.reset(atspi_text_get_text(ATSPI_TEXT(cell7.get()), 0, -1, nullptr));
+ g_assert_cmpstr(text.get(), ==, "Row 2 Cell 3");
+
+ g_assert_cmpint(atspi_table_get_index_at(ATSPI_TABLE(table.get()), 3, 0, nullptr), ==, 8);
+ g_assert_cmpint(atspi_table_get_row_at_index(ATSPI_TABLE(table.get()), 8, nullptr), ==, 3);
+ g_assert_cmpint(atspi_table_get_column_at_index(ATSPI_TABLE(table.get()), 8, nullptr), ==, 0);
+ g_assert_cmpint(atspi_table_get_row_extent_at(ATSPI_TABLE(table.get()), 3, 0, nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_get_column_extent_at(ATSPI_TABLE(table.get()), 3, 0, nullptr), ==, 3);
+ g_assert_true(atspi_table_get_row_column_extents_at_index(ATSPI_TABLE(table.get()), 8, &row, &column, &rowSpan, &columnSpan, &isSelected, nullptr));
+ g_assert_cmpint(row, ==, 3);
+ g_assert_cmpint(column, ==, 0);
+ g_assert_cmpint(rowSpan, ==, 1);
+ g_assert_cmpint(columnSpan, ==, 3);
+ g_assert_false(isSelected);
+ auto cell8 = adoptGRef(atspi_table_get_accessible_at(ATSPI_TABLE(table.get()), 3, 0, nullptr));
+ g_assert_true(ATSPI_IS_TABLE_CELL(cell8.get()));
+ g_assert_cmpint(atspi_table_cell_get_row_span(ATSPI_TABLE_CELL(cell8.get()), nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_cell_get_column_span(ATSPI_TABLE_CELL(cell8.get()), nullptr), ==, 3);
+ g_assert_true(atspi_table_cell_get_position(ATSPI_TABLE_CELL(cell8.get()), &row, &column, nullptr));
+ g_assert_cmpint(row, ==, 3);
+ g_assert_cmpint(column, ==, 0);
+ atspi_table_cell_get_row_column_span(ATSPI_TABLE_CELL(cell8.get()), &row, &column, &rowSpan, &columnSpan, nullptr);
+ g_assert_cmpint(row, ==, 3);
+ g_assert_cmpint(column, ==, 0);
+ g_assert_cmpint(rowSpan, ==, 1);
+ g_assert_cmpint(columnSpan, ==, 3);
+ cellTable = adoptGRef(atspi_table_cell_get_table(ATSPI_TABLE_CELL(cell8.get()), nullptr));
+ g_assert_true(table.get() == cellTable.get());
+ rowHeaders = adoptGRef(atspi_table_cell_get_row_header_cells(ATSPI_TABLE_CELL(cell8.get()), nullptr));
+ g_assert_cmpint(rowHeaders->len, ==, 0);
+ g_ptr_array_foreach(rowHeaders.get(), reinterpret_cast<GFunc>(reinterpret_cast<GCallback>(g_object_unref)), nullptr);
+ columnHeaders = adoptGRef(atspi_table_cell_get_column_header_cells(ATSPI_TABLE_CELL(cell8.get()), nullptr));
+ g_assert_cmpint(columnHeaders->len, ==, 1);
+ g_assert_true(columnHeaders->pdata[0] == columnHeader0.get());
+ g_ptr_array_foreach(columnHeaders.get(), reinterpret_cast<GFunc>(reinterpret_cast<GCallback>(g_object_unref)), nullptr);
+ g_assert_true(ATSPI_IS_TEXT(cell8.get()));
+ text.reset(atspi_text_get_text(ATSPI_TEXT(cell8.get()), 0, -1, nullptr));
+ g_assert_cmpstr(text.get(), ==, "Row 3 Cell 1");
+
+ g_assert_cmpint(atspi_table_get_index_at(ATSPI_TABLE(table.get()), 3, 1, nullptr), ==, 8);
+ g_assert_cmpint(atspi_table_get_row_extent_at(ATSPI_TABLE(table.get()), 3, 1, nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_get_column_extent_at(ATSPI_TABLE(table.get()), 3, 1, nullptr), ==, 3);
+ cell = adoptGRef(atspi_table_get_accessible_at(ATSPI_TABLE(table.get()), 3, 1, nullptr));
+ g_assert_true(cell8.get() == cell.get());
+
+ g_assert_cmpint(atspi_table_get_index_at(ATSPI_TABLE(table.get()), 3, 2, nullptr), ==, 8);
+ g_assert_cmpint(atspi_table_get_row_extent_at(ATSPI_TABLE(table.get()), 3, 2, nullptr), ==, 1);
+ g_assert_cmpint(atspi_table_get_column_extent_at(ATSPI_TABLE(table.get()), 3, 2, nullptr), ==, 3);
+ cell = adoptGRef(atspi_table_get_accessible_at(ATSPI_TABLE(table.get()), 3, 2, nullptr));
+ g_assert_true(cell8.get() == cell.get());
+#endif
+}
+
void beforeAll()
{
AccessibilityTest::add("WebKitAccessibility", "accessible/basic-hierarchy", testAccessibleBasicHierarchy);
@@ -2360,6 +2772,7 @@
AccessibilityTest::add("WebKitAccessibility", "image/basic", testImageBasic);
AccessibilityTest::add("WebKitAccessibility", "selection/listbox", testSelectionListBox);
AccessibilityTest::add("WebKitAccessibility", "selection/menulist", testSelectionMenuList);
+ AccessibilityTest::add("WebKitAccessibility", "table/basic", testTableBasic);
}
void afterAll()
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/atspi/AccessibilityUIElementAtspi.cpp (286415 => 286416)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/atspi/AccessibilityUIElementAtspi.cpp 2021-12-02 08:06:24 UTC (rev 286415)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/atspi/AccessibilityUIElementAtspi.cpp 2021-12-02 08:16:13 UTC (rev 286416)
@@ -156,7 +156,15 @@
RefPtr<AccessibilityUIElement> AccessibilityUIElement::rowAtIndex(unsigned index)
{
- return nullptr;
+ if (!m_element->interfaces().contains(WebCore::AccessibilityObjectAtspi::Interface::Table))
+ return nullptr;
+
+ m_element->updateBackingStore();
+ auto rows = m_element->rows();
+ if (index >= rows.size())
+ return nullptr;
+
+ return AccessibilityUIElement::create(rows[index].get());
}
RefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedChildAtIndex(unsigned index) const
@@ -296,6 +304,21 @@
return builder.toString();
}
+static Vector<RefPtr<AccessibilityUIElement>> elementsVector(const Vector<RefPtr<WebCore::AccessibilityObjectAtspi>>& wrappers)
+{
+ Vector<RefPtr<AccessibilityUIElement>> elements;
+ elements.reserveInitialCapacity(wrappers.size());
+ for (auto& wrapper : wrappers)
+ elements.uncheckedAppend(AccessibilityUIElement::create(wrapper.get()));
+ return elements;
+}
+
+static String attributesOfElements(const Vector<RefPtr<WebCore::AccessibilityObjectAtspi>>& wrappers)
+{
+ auto elements = elementsVector(wrappers);
+ return attributesOfElements(elements);
+}
+
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfChildren()
{
m_element->updateBackingStore();
@@ -306,12 +329,7 @@
children = m_element->children();
});
- Vector<RefPtr<AccessibilityUIElement>> elements;
- elements.reserveInitialCapacity(children.size());
- for (auto& child : children)
- elements.uncheckedAppend(AccessibilityUIElement::create(child.get()));
-
- return OpaqueJSString::tryCreate(attributesOfElements(elements)).leakRef();
+ return OpaqueJSString::tryCreate(attributesOfElements(children)).leakRef();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::allAttributes()
@@ -352,6 +370,18 @@
return attributes.get("setsize").toDouble();
if (attributeName == "AXARIAPosInSet")
return attributes.get("posinset").toDouble();
+ if (attributeName == "AXARIAColumnCount")
+ return attributes.get("colcount").toDouble();
+ if (attributeName == "AXARIARowCount")
+ return attributes.get("rowcount").toDouble();
+ if (attributeName == "AXARIAColumnIndex")
+ return attributes.get("colindex").toDouble();
+ if (attributeName == "AXARIARowIndex")
+ return attributes.get("rowindex").toDouble();
+ if (attributeName == "AXARIAColumnSpan")
+ return attributes.get("colspan").toDouble();
+ if (attributeName == "AXARIARowSpan")
+ return attributes.get("rowspan").toDouble();
return 0;
}
@@ -361,14 +391,51 @@
return nullptr;
}
+static JSValueRef makeJSArray(const Vector<RefPtr<AccessibilityUIElement>>& elements)
+{
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
+ JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
+
+ size_t elementCount = elements.size();
+ auto valueElements = makeUniqueArray<JSValueRef>(elementCount);
+ for (size_t i = 0; i < elementCount; i++)
+ valueElements[i] = JSObjectMake(context, elements[i]->wrapperClass(), elements[i].get());
+
+ return JSObjectMakeArray(context, elementCount, valueElements.get(), nullptr);
+}
+
JSValueRef AccessibilityUIElement::rowHeaders() const
{
- return nullptr;
+ if (m_element->interfaces().contains(WebCore::AccessibilityObjectAtspi::Interface::Table))
+ return makeJSArray(elementsVector(m_element->rowHeaders()));
+
+ if (m_element->interfaces().contains(WebCore::AccessibilityObjectAtspi::Interface::TableCell)) {
+ Vector<RefPtr<WebCore::AccessibilityObjectAtspi>> headers;
+ s_controller->executeOnAXThreadAndWait([this, &headers] {
+ m_element->updateBackingStore();
+ headers = m_element->cellRowHeaders();
+ });
+ return makeJSArray(elementsVector(headers));
+ }
+
+ return makeJSArray({ });
}
JSValueRef AccessibilityUIElement::columnHeaders() const
{
- return nullptr;
+ if (m_element->interfaces().contains(WebCore::AccessibilityObjectAtspi::Interface::Table))
+ return makeJSArray(elementsVector(m_element->columnHeaders()));
+
+ if (m_element->interfaces().contains(WebCore::AccessibilityObjectAtspi::Interface::TableCell)) {
+ Vector<RefPtr<WebCore::AccessibilityObjectAtspi>> headers;
+ s_controller->executeOnAXThreadAndWait([this, &headers] {
+ m_element->updateBackingStore();
+ headers = m_element->cellColumnHeaders();
+ });
+ return makeJSArray(elementsVector(headers));
+ }
+
+ return makeJSArray({ });
}
RefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementAttributeValue(JSStringRef attribute) const
@@ -998,12 +1065,20 @@
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumnHeaders()
{
- return JSStringCreateWithCharacters(0, 0);
+ if (!m_element->interfaces().contains(WebCore::AccessibilityObjectAtspi::Interface::Table))
+ return JSStringCreateWithCharacters(0, 0);
+
+ m_element->updateBackingStore();
+ return OpaqueJSString::tryCreate(attributesOfElements(m_element->columnHeaders())).leakRef();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRowHeaders()
{
- return JSStringCreateWithCharacters(0, 0);
+ if (!m_element->interfaces().contains(WebCore::AccessibilityObjectAtspi::Interface::Table))
+ return JSStringCreateWithCharacters(0, 0);
+
+ m_element->updateBackingStore();
+ return OpaqueJSString::tryCreate(attributesOfElements(m_element->rowHeaders())).leakRef();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumns()
@@ -1013,12 +1088,20 @@
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRows()
{
- return JSStringCreateWithCharacters(0, 0);
+ if (!m_element->interfaces().contains(WebCore::AccessibilityObjectAtspi::Interface::Table))
+ return JSStringCreateWithCharacters(0, 0);
+
+ m_element->updateBackingStore();
+ return OpaqueJSString::tryCreate(attributesOfElements(m_element->rows())).leakRef();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfVisibleCells()
{
- return JSStringCreateWithCharacters(0, 0);
+ if (!m_element->interfaces().contains(WebCore::AccessibilityObjectAtspi::Interface::Table))
+ return JSStringCreateWithCharacters(0, 0);
+
+ m_element->updateBackingStore();
+ return OpaqueJSString::tryCreate(attributesOfElements(m_element->cells())).leakRef();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfHeader()
@@ -1028,12 +1111,28 @@
int AccessibilityUIElement::rowCount()
{
- return 0;
+ if (!m_element->interfaces().contains(WebCore::AccessibilityObjectAtspi::Interface::Table))
+ return 0;
+
+ int count;
+ s_controller->executeOnAXThreadAndWait([this, &count] {
+ m_element->updateBackingStore();
+ count = m_element->rowCount();
+ });
+ return count;
}
int AccessibilityUIElement::columnCount()
{
- return 0;
+ if (!m_element->interfaces().contains(WebCore::AccessibilityObjectAtspi::Interface::Table))
+ return 0;
+
+ int count;
+ s_controller->executeOnAXThreadAndWait([this, &count] {
+ m_element->updateBackingStore();
+ count = m_element->columnCount();
+ });
+ return count;
}
int AccessibilityUIElement::indexInTable()
@@ -1043,17 +1142,54 @@
JSRetainPtr<JSStringRef> AccessibilityUIElement::rowIndexRange()
{
- return JSStringCreateWithCharacters(0, 0);
+ if (!m_element->interfaces().contains(WebCore::AccessibilityObjectAtspi::Interface::TableCell))
+ return JSStringCreateWithCharacters(0, 0);
+
+ std::optional<unsigned> position, span;
+ s_controller->executeOnAXThreadAndWait([this, &position, &span] {
+ m_element->updateBackingStore();
+ position = m_element->cellPosition().first;
+ span = m_element->rowSpan();
+ });
+
+ if (!position || !span)
+ return JSStringCreateWithCharacters(0, 0);
+
+ return OpaqueJSString::tryCreate(makeString('{', *position, ", ", *span, '}')).leakRef();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::columnIndexRange()
{
- return JSStringCreateWithCharacters(0, 0);
+ if (!m_element->interfaces().contains(WebCore::AccessibilityObjectAtspi::Interface::TableCell))
+ return JSStringCreateWithCharacters(0, 0);
+
+ std::optional<unsigned> position, span;
+ s_controller->executeOnAXThreadAndWait([this, &position, &span] {
+ m_element->updateBackingStore();
+ position = m_element->cellPosition().second;
+ span = m_element->columnSpan();
+ });
+
+ if (!position || !span)
+ return JSStringCreateWithCharacters(0, 0);
+
+ return OpaqueJSString::tryCreate(makeString('{', *position, ", ", *span, '}')).leakRef();
}
-RefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(unsigned column, unsigned row)
{
- return nullptr;
+ if (!m_element->interfaces().contains(WebCore::AccessibilityObjectAtspi::Interface::Table))
+ return nullptr;
+
+ RefPtr<WebCore::AccessibilityObjectAtspi> cell;
+ s_controller->executeOnAXThreadAndWait([this, &cell, column, row] {
+ m_element->updateBackingStore();
+ cell = m_element->cell(row, column);
+ });
+ if (!cell)
+ return nullptr;
+
+ return AccessibilityUIElement::create(cell.get());
}
RefPtr<AccessibilityUIElement> AccessibilityUIElement::horizontalScrollbar() const
_______________________________________________ webkit-changes mailing list [email protected] https://lists.webkit.org/mailman/listinfo/webkit-changes
