2011-06-24  Mario Sanchez Prada  <msanchez@igalia.com>

        Reviewed by Chris Fleizach.

        [GTK] Consider rows being ignored when adding children to tables
        https://bugs.webkit.org/show_bug.cgi?id=62718

        Unskip accessibility test that will be passing from now on.

        * platform/gtk/Skipped: Unskipped passing test.
2011-06-24  Mario Sanchez Prada  <msanchez@igalia.com>

        Reviewed by Chris Fleizach.

        [GTK] Consider rows being ignored when adding children to tables
        https://bugs.webkit.org/show_bug.cgi?id=62718

        Hide row objects in tables in GTK's accessibility wrapper.

        This is a different approach in the way WebCore's accessible
        rows are exposed to assistive technologies in the GTK port,
        since from now on those objects are kept in WebCore (they do not
        declare to ignore accessibility) and just bypassed in the mapping
        to ATK, allowing to hide them in the ATK hierarchy while, at the
        same time, keeping them internally to be able to provide enough
        information to determine tables related information, such as rows
        counting or finding an cell for specific coordinates.

        * accessibility/gtk/AccessibilityObjectAtk.cpp:
        (WebCore::AccessibilityObject::accessibilityPlatformIncludesObject):
        Do not ignore accessibility for table rows here.

        * accessibility/gtk/AccessibilityObjectWrapperAtk.cpp:
        (webkit_accessible_get_parent): Bypass rows when needed.
        (getNChildrenForTable): New, find the number of children for a
        table, which will be the addition of all cells for its rows.
        (webkit_accessible_get_n_children): Call to getNChildrenForTable
        for accessibility tables if needed.
        (getChildForTable): New, bypass rows when needed, retrieving
        cells as if they were direct children for tables.
        (webkit_accessible_ref_child): Call to refChildForTable if needed.
        (getIndexInParentForCellInRow): New, get the index for a given
        cell in its parent table, considering other rows' cells.
        (webkit_accessible_get_index_in_parent): Call to
        getIndexInParentForCellInRow if needed.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@89660 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp b/Source/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp
index 566356c..dfb7a78 100644
--- a/Source/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp
+++ b/Source/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp
@@ -293,29 +293,100 @@
 static AtkObject* webkit_accessible_get_parent(AtkObject* object)
 {
     AccessibilityObject* coreObject = core(object);
+    if (!coreObject)
+        return 0;
+
     AccessibilityObject* coreParent = coreObject->parentObjectUnignored();
+
     if (!coreParent && isRootObject(coreObject))
         return atkParentOfRootObject(object);
 
     if (!coreParent)
         return 0;
 
+    // GTK doesn't expose table rows to Assistive technologies, but we
+    // need to have them anyway in the hierarchy from WebCore to
+    // properly perform coordinates calculations when requested.
+    if (coreParent->isTableRow() && coreObject->isTableCell())
+        coreParent = coreParent->parentObjectUnignored();
+
     return coreParent->wrapper();
 }
 
+static gint getNChildrenForTable(AccessibilityObject* coreObject)
+{
+    AccessibilityObject::AccessibilityChildrenVector tableChildren = coreObject->children();
+    size_t tableChildrenCount = tableChildren.size();
+    size_t cellsCount = 0;
+
+    // Look for the actual index of the cell inside the table.
+    for (unsigned i = 0; i < tableChildrenCount; ++i) {
+        if (tableChildren[i]->isTableRow()) {
+            AccessibilityObject::AccessibilityChildrenVector rowChildren = tableChildren[i]->children();
+            cellsCount += rowChildren.size();
+        } else
+            cellsCount++;
+    }
+
+    return cellsCount;
+}
+
 static gint webkit_accessible_get_n_children(AtkObject* object)
 {
-    return core(object)->children().size();
+    AccessibilityObject* coreObject = core(object);
+
+    // Tables should be treated in a different way because rows should
+    // be bypassed for GTK when exposing the accessible hierarchy.
+    if (coreObject->isAccessibilityTable())
+        return getNChildrenForTable(coreObject);
+
+    return coreObject->children().size();
+}
+
+static AccessibilityObject* getChildForTable(AccessibilityObject* coreObject, gint index)
+{
+    AccessibilityObject::AccessibilityChildrenVector tableChildren = coreObject->children();
+    size_t tableChildrenCount = tableChildren.size();
+    size_t cellsCount = 0;
+    AccessibilityObject* coreChild = 0;
+
+    // Look for the actual index of the cell inside the table.
+    size_t current = static_cast<size_t>(index);
+    for (unsigned i = 0; i < tableChildrenCount; ++i) {
+        if (tableChildren[i]->isTableRow()) {
+            AccessibilityObject::AccessibilityChildrenVector rowChildren = tableChildren[i]->children();
+            size_t rowChildrenCount = rowChildren.size();
+            if (current < cellsCount + rowChildrenCount)
+                return rowChildren.at(current - cellsCount).get();
+            cellsCount += rowChildrenCount;
+        } else if (cellsCount == current)
+            return tableChildren[i].get();
+        else
+            cellsCount++;
+    }
+
+    // Shouldn't reach if the child was found.
+    return 0;
 }
 
 static AtkObject* webkit_accessible_ref_child(AtkObject* object, gint index)
 {
-    AccessibilityObject* coreObject = core(object);
-    AccessibilityObject::AccessibilityChildrenVector children = coreObject->children();
-    if (index < 0 || static_cast<unsigned>(index) >= children.size())
+    if (index < 0)
         return 0;
 
-    AccessibilityObject* coreChild = children.at(index).get();
+    AccessibilityObject* coreObject = core(object);
+    AccessibilityObject* coreChild = 0;
+
+    // Tables are special cases in GTK because rows should be
+    // bypassed, but still taking their cells into account.
+    if (coreObject->isAccessibilityTable())
+        coreChild = getChildForTable(coreObject, index);
+    else {
+        AccessibilityObject::AccessibilityChildrenVector children = coreObject->children();
+        if (static_cast<unsigned>(index) >= children.size())
+            return 0;
+        coreChild = children.at(index).get();
+    }
 
     if (!coreChild)
         return 0;
@@ -327,6 +398,42 @@
     return child;
 }
 
+static gint getIndexInParentForCellInRow(AccessibilityObject* coreObject)
+{
+    AccessibilityObject* parent = coreObject->parentObjectUnignored();
+    if (!parent)
+        return -1;
+
+    AccessibilityObject* grandParent = parent->parentObjectUnignored();
+    if (!grandParent)
+        return -1;
+
+    AccessibilityObject::AccessibilityChildrenVector rows = grandParent->children();
+    size_t rowsCount = rows.size();
+    size_t previousCellsCount = 0;
+
+    // Look for the actual index of the cell inside the table.
+    for (unsigned i = 0; i < rowsCount; ++i) {
+        if (!rows[i]->isTableRow())
+            continue;
+
+        AccessibilityObject::AccessibilityChildrenVector cells = rows[i]->children();
+        size_t cellsCount = cells.size();
+
+        if (rows[i] == parent) {
+            for (unsigned j = 0; j < cellsCount; ++j) {
+                if (cells[j] == coreObject)
+                    return previousCellsCount + j;
+            }
+        }
+
+        previousCellsCount += cellsCount;
+    }
+
+    return -1;
+}
+
+
 static gint webkit_accessible_get_index_in_parent(AtkObject* object)
 {
     AccessibilityObject* coreObject = core(object);
@@ -347,6 +454,11 @@
         }
     }
 
+    // Need to calculate the index of the cell in the table, as
+    // rows won't be exposed to assistive technologies in GTK.
+    if (parent && parent->isTableRow() && coreObject->isTableCell())
+        return getIndexInParentForCellInRow(coreObject);
+
     AccessibilityObject::AccessibilityChildrenVector children = parent->children();
     unsigned count = children.size();
     for (unsigned i = 0; i < count; ++i) {