Bug 1618705: Construct column containers and list them as children of our table accessible. r=eeejay

Differential Revision: https://phabricator.services.mozilla.com/D67900

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Morgan Reschenberg 2020-04-06 16:51:11 +00:00
Родитель 1407b0c42b
Коммит 945f2ee931
6 изменённых файлов: 294 добавлений и 4 удалений

Просмотреть файл

@ -1269,8 +1269,10 @@ struct RoleDescrComparator {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
// make room for new children
[mChildren release];
mChildren = nil;
if (mChildren) {
[mChildren release];
mChildren = nil;
}
NS_OBJC_END_TRY_ABORT_BLOCK;
}

Просмотреть файл

@ -7,15 +7,39 @@
#import "mozAccessible.h"
@interface mozColumnContainer : NSObject {
uint32_t mIndex;
mozAccessible* mParent;
NSMutableArray* mChildren;
}
- (id)initWithIndex:(uint32_t)aIndex andParent:(id<mozAccessible>)aParent;
- (NSString*)accessibilityRole;
- (NSString*)accessibilityRoleDescription;
- (mozAccessible*)accessibilityParent;
- (NSArray*)accessibilityChildren;
- (BOOL)accessibilityIsIgnored;
- (void)invalidateChildren;
- (void)dealloc;
- (void)expire;
- (BOOL)isExpired;
- (BOOL)accessibilityNotifiesWhenDestroyed;
@end
@interface mozTablePartAccessible : mozAccessible
- (id)accessibilityAttributeValue:(NSString*)attribute;
- (BOOL)isLayoutTablePart;
- (NSString*)role;
@end
@interface mozTableAccessible : mozTablePartAccessible
@interface mozTableAccessible : mozTablePartAccessible {
NSMutableArray* mColContainers;
}
- (NSArray*)children;
- (NSArray*)additionalAccessibilityAttributeNames;
- (id)accessibilityAttributeValue:(NSString*)attribute;
- (void)invalidateChildren;
- (void)dealloc;
@end
@interface mozTableRowAccessible : mozTablePartAccessible

Просмотреть файл

@ -7,6 +7,111 @@
#import "mozTableAccessible.h"
#import "nsCocoaUtils.h"
#import "AccIterator.h"
#import "TableAccessible.h"
@implementation mozColumnContainer
- (id)initWithIndex:(uint32_t)aIndex andParent:(mozAccessible*)aParent {
self = [super init];
mIndex = aIndex;
mParent = aParent;
return self;
}
- (NSString*)accessibilityRole {
return NSAccessibilityColumnRole;
}
- (NSString*)accessibilityRoleDescription {
return NSAccessibilityRoleDescription(NSAccessibilityColumnRole, nil);
}
- (mozAccessible*)accessibilityParent {
return mParent;
}
- (NSArray*)accessibilityChildren {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
if (mChildren) return mChildren;
mChildren = [[NSMutableArray alloc] init];
if (AccessibleWrap* accWrap = [mParent getGeckoAccessible]) {
TableAccessible* table = accWrap->AsTable();
NSAssert(table, @"Got null table when fetching column children!");
uint32_t numRows = table->RowCount();
for (uint32_t j = 0; j < numRows; j++) {
Accessible* cell = table->CellAt(j, mIndex);
if (cell) {
[mChildren addObject:GetNativeFromGeckoAccessible(cell)];
}
}
} else if (ProxyAccessible* proxy = [mParent getProxyAccessible]) {
uint32_t numRows = proxy->TableRowCount();
for (uint32_t j = 0; j < numRows; j++) {
ProxyAccessible* cell = proxy->TableCellAt(j, mIndex);
if (cell) {
[mChildren addObject:GetNativeFromProxy(cell)];
}
}
}
return mChildren;
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
- (BOOL)accessibilityIsIgnored {
return NO;
}
- (void)invalidateChildren {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
// make room for new children
if (mChildren) {
[mChildren release];
mChildren = nil;
}
NS_OBJC_END_TRY_ABORT_BLOCK;
}
- (void)dealloc {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
[self invalidateChildren];
[super dealloc];
NS_OBJC_END_TRY_ABORT_BLOCK;
}
- (void)expire {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
[self invalidateChildren];
mParent = nil;
NSAccessibilityPostNotification(self, NSAccessibilityUIElementDestroyedNotification);
NS_OBJC_END_TRY_ABORT_BLOCK;
}
- (BOOL)isExpired {
return (mChildren == nil) && (mParent == nil);
}
- (BOOL)accessibilityNotifiesWhenDestroyed {
return YES;
}
@end
@implementation mozTablePartAccessible
@ -50,6 +155,28 @@
@end
@implementation mozTableAccessible
- (void)invalidateChildren {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
if (mColContainers) {
[mColContainers release];
mColContainers = nil;
}
[super invalidateChildren];
NS_OBJC_END_TRY_ABORT_BLOCK;
}
- (void)dealloc {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
[self invalidateChildren];
[super dealloc];
NS_OBJC_END_TRY_ABORT_BLOCK;
}
- (NSArray*)additionalAccessibilityAttributeNames {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
@ -64,6 +191,7 @@
[tempArray addObject:NSAccessibilityRowCountAttribute];
[tempArray addObject:NSAccessibilityColumnCountAttribute];
[tempArray addObject:NSAccessibilityRowsAttribute];
[tempArray addObject:NSAccessibilityColumnsAttribute];
tableAttrs = [[NSArray alloc] initWithArray:tempArray];
[tempArray release];
}
@ -91,6 +219,9 @@
}
return nativeArray;
}
if ([attribute isEqualToString:NSAccessibilityColumnsAttribute]) {
return [self getColContainerList];
}
} else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
if ([attribute isEqualToString:NSAccessibilityRowCountAttribute])
return @(proxy->TableRowCount());
@ -108,10 +239,44 @@
}
return nativeArray;
}
if ([attribute isEqualToString:NSAccessibilityColumnsAttribute]) {
return [self getColContainerList];
}
}
return [super accessibilityAttributeValue:attribute];
}
- (NSArray*)children {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
return [[super children] arrayByAddingObjectsFromArray:[self getColContainerList]];
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
- (NSArray*)getColContainerList {
if (mColContainers) {
return mColContainers;
}
mColContainers = [[NSMutableArray alloc] init];
uint32_t numCols = 0;
if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
numCols = accWrap->AsTable()->ColCount();
} else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
numCols = proxy->TableColumnCount();
}
for (uint32_t i = 0; i < numCols; i++) {
mozColumnContainer* container = [[mozColumnContainer alloc] initWithIndex:i andParent:self];
[mColContainers addObject:container];
}
return mColContainers;
}
@end
@implementation mozTableRowAccessible

Просмотреть файл

@ -14,5 +14,6 @@ support-files =
[browser_details_summary.js]
[browser_label_title.js]
[browser_range.js]
[browser_table.js]
[browser_selectables.js]
[browser_toggle_radio_check.js]

Просмотреть файл

@ -0,0 +1,96 @@
/* 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/. */
"use strict";
/* import-globals-from ../../mochitest/role.js */
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
/**
* Test table, columns, rows
*/
addAccessibleTask(
`<table id="customers">
<tbody>
<tr><th>Company</th><th>Contact</th><th>Country</th></tr>
<tr><td>Alfreds Futterkiste</td><td>Maria Anders</td><td>Germany</td></tr>
<tr><td>Centro comercial Moctezuma</td><td>Francisco Chang</td><td>Mexico</td></tr>
<tr><td>Ernst Handel</td><td>Roland Mendel</td><td>Austria</td></tr>
</tbody>
</table>`,
async (browser, accDoc) => {
let table = getNativeInterface(accDoc, "customers");
is(table.getAttributeValue("AXRole"), "AXTable", "Correct role for table");
let tableChildren = table.getAttributeValue("AXChildren");
// XXX: Should be 8 children, rows (incl headers) + cols + headers
// if we're trying to match Safari.
is(tableChildren.length, 7, "Table has children = rows (4) + cols (3)");
for (let i = 0; i < tableChildren.length; i++) {
let currChild = tableChildren[i];
if (i < 4) {
is(
currChild.getAttributeValue("AXRole"),
"AXRow",
"Correct role for row"
);
} else {
is(
currChild.getAttributeValue("AXRole"),
"AXColumn",
"Correct role for col"
);
is(
currChild.getAttributeValue("AXRoleDescription"),
"column",
"Correct role desc for col"
);
}
}
is(
table.getAttributeValue("AXColumnCount"),
3,
"Table has correct column count."
);
is(
table.getAttributeValue("AXRowCount"),
4,
"Table has correct row count."
);
let cols = table.getAttributeValue("AXColumns");
is(cols.length, 3, "Table has col list of correct length");
for (let i = 0; i < cols.length; i++) {
let currCol = cols[i];
let currChildren = currCol.getAttributeValue("AXChildren");
is(currChildren.length, 4, "Column has correct number of cells");
for (let j = 0; j < currChildren.length; j++) {
let currChild = currChildren[j];
is(
currChild.getAttributeValue("AXRole"),
"AXCell",
"Column child is cell"
);
}
}
let rows = table.getAttributeValue("AXRows");
is(rows.length, 4, "Table has row list of correct length");
for (let i = 0; i < rows.length; i++) {
let currRow = rows[i];
let currChildren = currRow.getAttributeValue("AXChildren");
is(currChildren.length, 3, "Row has correct number of cells");
for (let j = 0; j < currChildren.length; j++) {
let currChild = currChildren[j];
is(
currChild.getAttributeValue("AXRole"),
"AXCell",
"Row child is cell"
);
}
}
}
);

Просмотреть файл

@ -341,7 +341,9 @@ nsresult xpcAccessibleMacInterface::NSObjectToJsValue(id aObj, JSContext* aCx,
return NSObjectToJsValue(
@[ [NSNumber numberWithDouble:size.width], [NSNumber numberWithDouble:size.height] ], aCx,
aResult);
} else if ([aObj respondsToSelector:@selector(accessibilityAttributeNames)]) {
} else if ([aObj respondsToSelector:@selector(accessibilityIsIgnored)]) {
// We expect all of our accessibility objects to implement accessibilityIsIgnored
// at the very least. If it is implemented we will assume its an accessibility object.
nsCOMPtr<nsIAccessibleMacInterface> obj = new xpcAccessibleMacInterface(aObj);
return nsContentUtils::WrapNative(aCx, obj, &NS_GET_IID(nsIAccessibleMacInterface), aResult);
} else if ([aObj isKindOfClass:[NSArray class]]) {