Bug 1178272 - Move table semantics to a separate mozTableAccessible.mm file. r=surkov
authorFrédéric Wang <fred.wang@free.fr>
Thu, 01 Oct 2015 16:00:00 +0200
changeset 265958 c10f8817d787f4c7b7a2309b9ad070b2644de45a
parent 265957 df81ed8cf22259e2fcc70a52db5949c1bd883ab0
child 265959 9a0c443ed6f3488bfdd67669e5b3cdb767a45e8e
push id66078
push usercbook@mozilla.com
push dateMon, 05 Oct 2015 07:30:10 +0000
treeherdermozilla-inbound@b958e25b1ecf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssurkov
bugs1178272
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1178272 - Move table semantics to a separate mozTableAccessible.mm file. r=surkov
accessible/mac/AccessibleWrap.mm
accessible/mac/Platform.mm
accessible/mac/moz.build
accessible/mac/mozAccessible.mm
accessible/mac/mozTableAccessible.h
accessible/mac/mozTableAccessible.mm
--- a/accessible/mac/AccessibleWrap.mm
+++ b/accessible/mac/AccessibleWrap.mm
@@ -8,16 +8,17 @@
 
 #include "Accessible-inl.h"
 #include "nsAccUtils.h"
 #include "Role.h"
 
 #import "mozAccessible.h"
 #import "mozActionElements.h"
 #import "mozHTMLAccessible.h"
+#import "mozTableAccessible.h"
 #import "mozTextAccessible.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 AccessibleWrap::
   AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
   Accessible(aContent, aDoc), mNativeObject(nil),
@@ -57,16 +58,25 @@ AccessibleWrap::GetNativeInterface(void*
 Class
 AccessibleWrap::GetNativeType ()
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
   if (IsXULTabpanels())
     return [mozPaneAccessible class];
 
+  if (IsTable())
+    return [mozTableAccessible class];
+
+  if (IsTableRow())
+    return [mozTableRowAccessible class];
+
+  if (IsTableCell())
+    return [mozTableCellAccessible class];
+
   return GetTypeFromRole(Role());
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
 // this method is very important. it is fired when an accessible object "dies". after this point
 // the object might still be around (because some 3rd party still has a ref to it), but it is
 // in fact 'dead'.
--- a/accessible/mac/Platform.mm
+++ b/accessible/mac/Platform.mm
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #import <Cocoa/Cocoa.h>
 
 #include "Platform.h"
 #include "ProxyAccessible.h"
+#include "mozTableAccessible.h"
 
 #include "nsAppShell.h"
 
 namespace mozilla {
 namespace a11y {
 
 // Mac a11y whitelisting
 static bool sA11yShouldBeEnabled = false;
@@ -33,17 +34,28 @@ void
 PlatformShutdown()
 {
 }
 
 void
 ProxyCreated(ProxyAccessible* aProxy, uint32_t)
 {
   // Pass in dummy state for now as retrieving proxy state requires IPC.
-  Class type = GetTypeFromRole(aProxy->Role());
+  // Note that we can use ProxyAccessible::IsTable* functions here because they
+  // do not use IPC calls but that might change after bug 1210477.
+  Class type;
+  if (aProxy->IsTable())
+    type = [mozTableAccessible class];
+  else if (aProxy->IsTableRow())
+    type = [mozTableRowAccessible class];
+  else if (aProxy->IsTableCell())
+    type = [mozTableCellAccessible class];
+  else
+    type = GetTypeFromRole(aProxy->Role());
+
   uintptr_t accWrap = reinterpret_cast<uintptr_t>(aProxy) | IS_PROXY;
   mozAccessible* mozWrapper = [[type alloc] initWithAccessible:accWrap];
   aProxy->SetWrapper(reinterpret_cast<uintptr_t>(mozWrapper));
 }
 
 void
 ProxyDestroyed(ProxyAccessible* aProxy)
 {
--- a/accessible/mac/moz.build
+++ b/accessible/mac/moz.build
@@ -16,16 +16,17 @@ EXPORTS.mozilla.a11y += [
 UNIFIED_SOURCES += [
     'AccessibleWrap.mm',
     'DocAccessibleWrap.mm',
     'MacUtils.mm',
     'mozAccessible.mm',
     'mozActionElements.mm',
     'mozDocAccessible.mm',
     'mozHTMLAccessible.mm',
+    'mozTableAccessible.mm',
     'mozTextAccessible.mm',
     'Platform.mm',
     'RootAccessibleWrap.mm',
 ]
 
 LOCAL_INCLUDES += [
     '/accessible/base',
     '/accessible/generic',
--- a/accessible/mac/mozAccessible.mm
+++ b/accessible/mac/mozAccessible.mm
@@ -219,52 +219,16 @@ ConvertToNSArray(nsTArray<ProxyAccessibl
   if (ProxyAccessible* proxy = [self getProxyAccessible])
     return (noRole && !(proxy->State() & states::FOCUSABLE));
 
   return true;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
 }
 
-- (BOOL)isLayoutTablePart
-{
-  if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
-    TableAccessible* table = nullptr;
-    if (accWrap->IsTable()) {
-      table = accWrap->AsTable();
-    } else if (accWrap->IsTableRow()) {
-      for (Accessible* acc = accWrap; acc; acc = acc->Parent()) {
-        if (acc->IsTable()) {
-          table = acc->AsTable();
-          break;
-        }
-      }
-    } else if (accWrap->IsTableCell()) {
-      table = accWrap->AsTableCell()->Table();
-    }
-    return table && table->IsProbablyLayoutTable();
-  }
-
-  if (ProxyAccessible* proxy = [self getProxyAccessible]) {
-    ProxyAccessible* tableProxy = nullptr;
-    if (proxy->IsTable()) {
-      tableProxy = proxy;
-    } else if (proxy->IsTableRow() || proxy->IsTableCell()) {
-      for (tableProxy = proxy; tableProxy; tableProxy = tableProxy->Parent()) {
-        if (tableProxy->IsTable()) {
-          break;
-        }
-      }
-    }
-    return tableProxy && tableProxy->TableIsProbablyForLayout();
-  }
-
-  return false;
-}
-
 - (NSArray*)additionalAccessibilityAttributeNames
 {
   NSMutableArray* additional = [NSMutableArray array];
   switch (mRole) {
     case roles::MATHML_ROOT:
       [additional addObject:NSAccessibilityMathRootIndexAttribute];
       [additional addObject:NSAccessibilityMathRootRadicandAttribute];
       break;
@@ -311,20 +275,16 @@ ConvertToNSArray(nsTArray<ProxyAccessibl
 
   // if we're expired, we don't support any attributes.
   AccessibleWrap* accWrap = [self getGeckoAccessible];
   ProxyAccessible* proxy = [self getProxyAccessible];
   if (!accWrap && !proxy)
     return [NSArray array];
 
   static NSArray* generalAttributes = nil;
-  static NSArray* tableAttrs = nil;
-  static NSArray* tableRowAttrs = nil;
-  static NSArray* tableCellAttrs = nil;
-  NSMutableArray* tempArray = nil;
 
   if (!generalAttributes) {
     // standard attributes that are shared and supported by all generic elements.
     generalAttributes = [[NSArray alloc] initWithObjects:  NSAccessibilityChildrenAttribute,
                                                            NSAccessibilityParentAttribute,
                                                            NSAccessibilityRoleAttribute,
                                                            NSAccessibilityTitleAttribute,
                                                            NSAccessibilityValueAttribute,
@@ -339,51 +299,18 @@ ConvertToNSArray(nsTArray<ProxyAccessibl
                                                            NSAccessibilityTitleUIElementAttribute,
                                                            NSAccessibilityTopLevelUIElementAttribute,
 #if DEBUG
                                                            @"AXMozDescription",
 #endif
                                                            nil];
   }
 
-  if (!tableAttrs) {
-    tempArray = [[NSMutableArray alloc] initWithArray:generalAttributes];
-    [tempArray addObject:NSAccessibilityRowCountAttribute];
-    [tempArray addObject:NSAccessibilityColumnCountAttribute];
-    [tempArray addObject:NSAccessibilityRowsAttribute];
-    tableAttrs = [[NSArray alloc] initWithArray:tempArray];
-    [tempArray release];
-  }
-  if (!tableRowAttrs) {
-    tempArray = [[NSMutableArray alloc] initWithArray:generalAttributes];
-    [tempArray addObject:NSAccessibilityIndexAttribute];
-    tableRowAttrs = [[NSArray alloc] initWithArray:tempArray];
-    [tempArray release];
-  }
-  if (!tableCellAttrs) {
-    tempArray = [[NSMutableArray alloc] initWithArray:generalAttributes];
-    [tempArray addObject:NSAccessibilityRowIndexRangeAttribute];
-    [tempArray addObject:NSAccessibilityColumnIndexRangeAttribute];
-    [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute];
-    [tempArray addObject:NSAccessibilityColumnHeaderUIElementsAttribute];
-    tableCellAttrs = [[NSArray alloc] initWithArray:tempArray];
-    [tempArray release];
-  }
-
   NSArray* objectAttributes = generalAttributes;
 
-  if (![self isLayoutTablePart]) {
-    if ((accWrap && accWrap->IsTable()) || (proxy && proxy->IsTable()))
-      objectAttributes = tableAttrs;
-    else if ((accWrap && accWrap->IsTableRow()) || (proxy && proxy->IsTableRow()))
-      objectAttributes = tableRowAttrs;
-    else if ((accWrap && accWrap->IsTableCell()) || (proxy && proxy->IsTableCell()))
-      objectAttributes = tableCellAttrs;
-  }
-
   NSArray* additionalAttributes = [self additionalAccessibilityAttributeNames];
   if ([additionalAttributes count])
     objectAttributes = [objectAttributes arrayByAddingObjectsFromArray:additionalAttributes];
 
   return objectAttributes;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
@@ -458,124 +385,16 @@ ConvertToNSArray(nsTArray<ProxyAccessibl
     }
     nsTArray<ProxyAccessible*> rel = proxy->RelationByType(RelationType::LABELLED_BY);
     ProxyAccessible* tempProxy = rel.SafeElementAt(0);
     return tempProxy ? GetNativeFromProxy(tempProxy) : nil;
   }
   if ([attribute isEqualToString:NSAccessibilityHelpAttribute])
     return [self help];
 
-  if (accWrap) {
-    if (accWrap->IsTable()) {
-      TableAccessible* table = accWrap->AsTable();
-      if ([attribute isEqualToString:NSAccessibilityRowCountAttribute])
-        return @(table->RowCount());
-      if ([attribute isEqualToString:NSAccessibilityColumnCountAttribute])
-        return @(table->ColCount());
-      if ([attribute isEqualToString:NSAccessibilityRowsAttribute]) {
-        // Create a new array with the list of table rows.
-        NSMutableArray* nativeArray = [[NSMutableArray alloc] init];
-        uint32_t totalCount = accWrap->ChildCount();
-        for (uint32_t i = 0; i < totalCount; i++) {
-          if (accWrap->GetChildAt(i)->IsTableRow()) {
-            mozAccessible* curNative =
-              GetNativeFromGeckoAccessible(accWrap->GetChildAt(i));
-            if (curNative)
-              [nativeArray addObject:GetObjectOrRepresentedView(curNative)];
-          }
-        }
-        return nativeArray;
-      }
-    } else if (accWrap->IsTableRow()) {
-      if ([attribute isEqualToString:NSAccessibilityIndexAttribute]) {
-        // Count the number of rows before that one to obtain the row index.
-        uint32_t index = 0;
-        Accessible* parent = accWrap->Parent();
-        if (parent) {
-          for (int32_t i = accWrap->IndexInParent() - 1; i >= 0; i--) {
-            if (parent->GetChildAt(i)->IsTableRow()) {
-              index++;
-            }
-          }
-        }
-        return [NSNumber numberWithUnsignedInteger:index];
-      }
-    } else if (accWrap->IsTableCell()) {
-      TableCellAccessible* cell = accWrap->AsTableCell();
-      if ([attribute isEqualToString:NSAccessibilityRowIndexRangeAttribute])
-        return [NSValue valueWithRange:NSMakeRange(cell->RowIdx(),
-                                                   cell->RowExtent())];
-      if ([attribute isEqualToString:NSAccessibilityColumnIndexRangeAttribute])
-        return [NSValue valueWithRange:NSMakeRange(cell->ColIdx(),
-                                                   cell->ColExtent())];
-      if ([attribute isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
-        nsAutoTArray<Accessible*, 10> headerCells;
-        cell->RowHeaderCells(&headerCells);
-        return ConvertToNSArray(headerCells);
-      }
-      if ([attribute isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute]) {
-        nsAutoTArray<Accessible*, 10> headerCells;
-        cell->ColHeaderCells(&headerCells);
-        return ConvertToNSArray(headerCells);
-      }
-    }
-  } else if (proxy) {
-    if (proxy->IsTable()) {
-      if ([attribute isEqualToString:NSAccessibilityRowCountAttribute])
-        return @(proxy->TableRowCount());
-      if ([attribute isEqualToString:NSAccessibilityColumnCountAttribute])
-        return @(proxy->TableColumnCount());
-      if ([attribute isEqualToString:NSAccessibilityRowsAttribute]) {
-        // Create a new array with the list of table rows.
-        NSMutableArray* nativeArray = [[NSMutableArray alloc] init];
-        uint32_t totalCount = proxy->ChildrenCount();
-        for (uint32_t i = 0; i < totalCount; i++) {
-          if (proxy->ChildAt(i)->IsTableRow()) {
-            mozAccessible* curNative =
-              GetNativeFromProxy(proxy->ChildAt(i));
-            if (curNative)
-              [nativeArray addObject:GetObjectOrRepresentedView(curNative)];
-          }
-        }
-        return nativeArray;
-      }
-    } else if (proxy->IsTableRow()) {
-      if ([attribute isEqualToString:NSAccessibilityIndexAttribute]) {
-        // Count the number of rows before that one to obtain the row index.
-        uint32_t index = 0;
-        ProxyAccessible* parent = proxy->Parent();
-        if (parent) {
-          for (int32_t i = proxy->IndexInParent() - 1; i >= 0; i--) {
-            if (parent->ChildAt(i)->IsTableRow()) {
-              index++;
-            }
-          }
-        }
-        return [NSNumber numberWithUnsignedInteger:index];
-      }
-    } else if (proxy->IsTableCell()) {
-      if ([attribute isEqualToString:NSAccessibilityRowIndexRangeAttribute])
-        return [NSValue valueWithRange:NSMakeRange(proxy->RowIdx(),
-                                                   proxy->RowExtent())];
-      if ([attribute isEqualToString:NSAccessibilityColumnIndexRangeAttribute])
-        return [NSValue valueWithRange:NSMakeRange(proxy->ColIdx(),
-                                                   proxy->ColExtent())];
-      if ([attribute isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
-        nsTArray<ProxyAccessible*> headerCells;
-        proxy->RowHeaderCells(&headerCells);
-        return ConvertToNSArray(headerCells);
-      }
-      if ([attribute isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute]) {
-        nsTArray<ProxyAccessible*> headerCells;
-        proxy->ColHeaderCells(&headerCells);
-        return ConvertToNSArray(headerCells);
-      }
-    }
-  }
-
   switch (mRole) {
   case roles::MATHML_ROOT:
     if ([attribute isEqualToString:NSAccessibilityMathRootRadicandAttribute])
       return [self childAt:0];
     if ([attribute isEqualToString:NSAccessibilityMathRootIndexAttribute])
       return [self childAt:1];
     break;
   case roles::MATHML_SQUARE_ROOT:
@@ -937,20 +756,16 @@ ConvertToNSArray(nsTArray<ProxyAccessibl
     #ifdef DEBUG_A11Y
       NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap),
                    "Does not support Text when it should");
     #endif
   } else if (![self getProxyAccessible]) {
     return nil;
   }
 
-  if ([self isLayoutTablePart]) {
-    return NSAccessibilityGroupRole;
-  }
-
 #define ROLE(geckoRole, stringRole, atkRole, macRole, msaaRole, ia2Role, nameRule) \
   case roles::geckoRole: \
     return macRole;
 
   switch (mRole) {
 #include "RoleMap.h"
     default:
       NS_NOTREACHED("Unknown role.");
new file mode 100644
--- /dev/null
+++ b/accessible/mac/mozTableAccessible.h
@@ -0,0 +1,28 @@
+/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#import "mozAccessible.h"
+
+@interface mozTablePartAccessible : mozAccessible
+- (BOOL)isLayoutTablePart;
+- (NSString*)role;
+@end
+
+@interface mozTableAccessible : mozTablePartAccessible
+- (NSArray*)additionalAccessibilityAttributeNames;
+- (id)accessibilityAttributeValue:(NSString*)attribute;
+@end
+
+@interface mozTableRowAccessible : mozTablePartAccessible
+- (NSArray*)additionalAccessibilityAttributeNames;
+- (id)accessibilityAttributeValue:(NSString*)attribute;
+@end
+
+@interface mozTableCellAccessible : mozTablePartAccessible
+- (NSArray*)additionalAccessibilityAttributeNames;
+- (id)accessibilityAttributeValue:(NSString*)attribute;
+@end
new file mode 100644
--- /dev/null
+++ b/accessible/mac/mozTableAccessible.mm
@@ -0,0 +1,240 @@
+/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#import "mozTableAccessible.h"
+#import "nsCocoaUtils.h"
+
+@implementation mozTablePartAccessible
+- (BOOL)isLayoutTablePart;
+{
+  if (Accessible* accWrap = [self getGeckoAccessible]) {
+    while (accWrap) {
+      if (accWrap->IsTable()) {
+        return accWrap->AsTable()->IsProbablyLayoutTable();
+      }
+      accWrap = accWrap->Parent();
+    }
+    return false;
+  }
+
+  if (ProxyAccessible* proxy = [self getProxyAccessible]) {
+    while (proxy) {
+      if (proxy->IsTable()) {
+        return proxy->TableIsProbablyForLayout();
+      }
+      proxy = proxy->Parent();
+    }
+  }
+
+  return false;
+}
+
+- (NSString*)role
+{
+  return [self isLayoutTablePart] ? NSAccessibilityGroupRole : [super role];
+}
+@end
+
+@implementation mozTableAccessible
+- (NSArray*)additionalAccessibilityAttributeNames
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
+
+  NSArray* additionalAttributes = [super additionalAccessibilityAttributeNames];
+  if ([self isLayoutTablePart]) {
+    return additionalAttributes;
+  }
+
+  static NSArray* tableAttrs = nil;
+  if (!tableAttrs) {
+    NSMutableArray* tempArray = [NSMutableArray new];
+    [tempArray addObject:NSAccessibilityRowCountAttribute];
+    [tempArray addObject:NSAccessibilityColumnCountAttribute];
+    [tempArray addObject:NSAccessibilityRowsAttribute];
+    tableAttrs = [[NSArray alloc] initWithArray:tempArray];
+    [tempArray release];
+  }
+
+  return [additionalAttributes arrayByAddingObjectsFromArray:tableAttrs];
+
+  NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
+}
+
+- (id)accessibilityAttributeValue:(NSString*)attribute
+{
+  if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
+    TableAccessible* table = accWrap->AsTable();
+    if ([attribute isEqualToString:NSAccessibilityRowCountAttribute])
+      return @(table->RowCount());
+    if ([attribute isEqualToString:NSAccessibilityColumnCountAttribute])
+      return @(table->ColCount());
+    if ([attribute isEqualToString:NSAccessibilityRowsAttribute]) {
+      // Create a new array with the list of table rows.
+      NSMutableArray* nativeArray = [[NSMutableArray alloc] init];
+      uint32_t totalCount = accWrap->ChildCount();
+      for (uint32_t i = 0; i < totalCount; i++) {
+        if (accWrap->GetChildAt(i)->IsTableRow()) {
+          mozAccessible* curNative =
+            GetNativeFromGeckoAccessible(accWrap->GetChildAt(i));
+          if (curNative)
+            [nativeArray addObject:GetObjectOrRepresentedView(curNative)];
+        }
+      }
+      return nativeArray;
+    }
+  } else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
+    if ([attribute isEqualToString:NSAccessibilityRowCountAttribute])
+      return @(proxy->TableRowCount());
+    if ([attribute isEqualToString:NSAccessibilityColumnCountAttribute])
+      return @(proxy->TableColumnCount());
+    if ([attribute isEqualToString:NSAccessibilityRowsAttribute]) {
+      // Create a new array with the list of table rows.
+      NSMutableArray* nativeArray = [[NSMutableArray alloc] init];
+      uint32_t totalCount = proxy->ChildrenCount();
+      for (uint32_t i = 0; i < totalCount; i++) {
+        if (proxy->ChildAt(i)->IsTableRow()) {
+          mozAccessible* curNative =
+            GetNativeFromProxy(proxy->ChildAt(i));
+          if (curNative)
+            [nativeArray addObject:GetObjectOrRepresentedView(curNative)];
+        }
+      }
+      return nativeArray;
+    }
+  }
+
+  return [super accessibilityAttributeValue:attribute];
+}
+@end
+
+@implementation mozTableRowAccessible
+- (NSArray*)additionalAccessibilityAttributeNames
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
+
+  NSArray* additionalAttributes = [super additionalAccessibilityAttributeNames];
+  if ([self isLayoutTablePart]) {
+    return additionalAttributes;
+  }
+
+  static NSArray* tableRowAttrs = nil;
+  if (!tableRowAttrs) {
+    NSMutableArray* tempArray = [NSMutableArray new];
+    [tempArray addObject:NSAccessibilityIndexAttribute];
+    tableRowAttrs = [[NSArray alloc] initWithArray:tempArray];
+    [tempArray release];
+  }
+
+  return [additionalAttributes arrayByAddingObjectsFromArray:tableRowAttrs];
+
+  NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
+}
+
+- (id)accessibilityAttributeValue:(NSString*)attribute
+{
+  if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
+    if ([attribute isEqualToString:NSAccessibilityIndexAttribute]) {
+      // Count the number of rows before that one to obtain the row index.
+      uint32_t index = 0;
+      Accessible* parent = accWrap->Parent();
+      if (parent) {
+        for (int32_t i = accWrap->IndexInParent() - 1; i >= 0; i--) {
+          if (parent->GetChildAt(i)->IsTableRow()) {
+            index++;
+          }
+        }
+      }
+      return [NSNumber numberWithUnsignedInteger:index];
+    }
+  } else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
+    if ([attribute isEqualToString:NSAccessibilityIndexAttribute]) {
+      // Count the number of rows before that one to obtain the row index.
+      uint32_t index = 0;
+      ProxyAccessible* parent = proxy->Parent();
+      if (parent) {
+        for (int32_t i = proxy->IndexInParent() - 1; i >= 0; i--) {
+          if (parent->ChildAt(i)->IsTableRow()) {
+            index++;
+          }
+        }
+      }
+      return [NSNumber numberWithUnsignedInteger:index];
+    }
+  }
+
+  return [super accessibilityAttributeValue:attribute];
+}
+@end
+
+@implementation mozTableCellAccessible
+- (NSArray*)additionalAccessibilityAttributeNames
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
+
+  NSArray* additionalAttributes = [super additionalAccessibilityAttributeNames];
+  if ([self isLayoutTablePart]) {
+    return additionalAttributes;
+  }
+
+  static NSArray* tableCellAttrs = nil;
+  if (!tableCellAttrs) {
+    NSMutableArray* tempArray = [NSMutableArray new];
+    [tempArray addObject:NSAccessibilityRowIndexRangeAttribute];
+    [tempArray addObject:NSAccessibilityColumnIndexRangeAttribute];
+    [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute];
+    [tempArray addObject:NSAccessibilityColumnHeaderUIElementsAttribute];
+    tableCellAttrs = [[NSArray alloc] initWithArray:tempArray];
+    [tempArray release];
+  }
+
+  return [additionalAttributes arrayByAddingObjectsFromArray:tableCellAttrs];
+
+  NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
+}
+
+- (id)accessibilityAttributeValue:(NSString*)attribute
+{
+  if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
+    TableCellAccessible* cell = accWrap->AsTableCell();
+    if ([attribute isEqualToString:NSAccessibilityRowIndexRangeAttribute])
+      return [NSValue valueWithRange:NSMakeRange(cell->RowIdx(),
+                                                 cell->RowExtent())];
+    if ([attribute isEqualToString:NSAccessibilityColumnIndexRangeAttribute])
+      return [NSValue valueWithRange:NSMakeRange(cell->ColIdx(),
+                                                 cell->ColExtent())];
+    if ([attribute isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
+      nsAutoTArray<Accessible*, 10> headerCells;
+      cell->RowHeaderCells(&headerCells);
+      return ConvertToNSArray(headerCells);
+    }
+    if ([attribute isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute]) {
+      nsAutoTArray<Accessible*, 10> headerCells;
+      cell->ColHeaderCells(&headerCells);
+      return ConvertToNSArray(headerCells);
+    }
+  } else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
+    if ([attribute isEqualToString:NSAccessibilityRowIndexRangeAttribute])
+      return [NSValue valueWithRange:NSMakeRange(proxy->RowIdx(),
+                                                 proxy->RowExtent())];
+    if ([attribute isEqualToString:NSAccessibilityColumnIndexRangeAttribute])
+      return [NSValue valueWithRange:NSMakeRange(proxy->ColIdx(),
+                                                 proxy->ColExtent())];
+    if ([attribute isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
+      nsTArray<ProxyAccessible*> headerCells;
+      proxy->RowHeaderCells(&headerCells);
+      return ConvertToNSArray(headerCells);
+    }
+    if ([attribute isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute]) {
+      nsTArray<ProxyAccessible*> headerCells;
+      proxy->ColHeaderCells(&headerCells);
+      return ConvertToNSArray(headerCells);
+    }
+  }
+
+  return [super accessibilityAttributeValue:attribute];
+}
+@end