mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-22 10:27:03 +00:00
Bug 536344 - posinset and setsize aren't calculated right for the flatter trees, r=marcoz, davidb
This commit is contained in:
parent
d55818f5b3
commit
75853371bc
@ -103,6 +103,46 @@ nsAccUtils::SetAccGroupAttrs(nsIPersistentProperties *aAttributes,
|
||||
}
|
||||
}
|
||||
|
||||
PRInt32
|
||||
nsAccUtils::GetDefaultLevel(nsAccessible *aAcc)
|
||||
{
|
||||
PRUint32 role = nsAccUtils::Role(aAcc);
|
||||
|
||||
if (role == nsIAccessibleRole::ROLE_OUTLINEITEM)
|
||||
return 1;
|
||||
|
||||
if (role == nsIAccessibleRole::ROLE_ROW) {
|
||||
nsCOMPtr<nsIAccessible> parent = aAcc->GetParent();
|
||||
if (Role(parent) == nsIAccessibleRole::ROLE_TREE_TABLE) {
|
||||
// It is a row inside flatten treegrid. Group level is always 1 until it
|
||||
// is overriden by aria-level attribute.
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PRInt32
|
||||
nsAccUtils::GetARIAOrDefaultLevel(nsIAccessible *aAcc)
|
||||
{
|
||||
nsRefPtr<nsAccessible> acc = nsAccUtils::QueryObject<nsAccessible>(aAcc);
|
||||
NS_ENSURE_TRUE(acc, 0);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> node;
|
||||
acc->GetDOMNode(getter_AddRefs(node));
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(node));
|
||||
NS_ENSURE_TRUE(content, 0);
|
||||
|
||||
PRInt32 level = 0;
|
||||
nsCoreUtils::GetUIntAttr(content, nsAccessibilityAtoms::aria_level, &level);
|
||||
|
||||
if (level != 0)
|
||||
return level;
|
||||
|
||||
return GetDefaultLevel(acc);
|
||||
}
|
||||
|
||||
void
|
||||
nsAccUtils::GetPositionAndSizeForXULSelectControlItem(nsIDOMNode *aNode,
|
||||
PRInt32 *aPosInSet,
|
||||
|
@ -92,6 +92,17 @@ public:
|
||||
PRInt32 aLevel, PRInt32 aSetSize,
|
||||
PRInt32 aPosInSet);
|
||||
|
||||
/**
|
||||
* Get default value of the level for the given accessible.
|
||||
*/
|
||||
static PRInt32 GetDefaultLevel(nsAccessible *aAcc);
|
||||
|
||||
/**
|
||||
* Return ARIA level value or the default one if ARIA is missed for the
|
||||
* given accessible.
|
||||
*/
|
||||
static PRInt32 GetARIAOrDefaultLevel(nsIAccessible *aAcc);
|
||||
|
||||
/**
|
||||
* Compute position in group (posinset) and group size (setsize) for
|
||||
* nsIDOMXULSelectControlItemElement node.
|
||||
|
@ -1644,29 +1644,12 @@ nsAccessible::GroupPosition(PRInt32 *aGroupLevel,
|
||||
if (!content)
|
||||
return NS_OK;
|
||||
|
||||
nsAutoString value;
|
||||
PRInt32 error = NS_OK;
|
||||
|
||||
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_level, value);
|
||||
if (!value.IsEmpty()) {
|
||||
PRInt32 level = value.ToInteger(&error);
|
||||
if (NS_SUCCEEDED(error))
|
||||
*aGroupLevel = level;
|
||||
}
|
||||
|
||||
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_posinset, value);
|
||||
if (!value.IsEmpty()) {
|
||||
PRInt32 posInSet = value.ToInteger(&error);
|
||||
if (NS_SUCCEEDED(error))
|
||||
*aPositionInGroup = posInSet;
|
||||
}
|
||||
|
||||
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_setsize, value);
|
||||
if (!value.IsEmpty()) {
|
||||
PRInt32 sizeSet = value.ToInteger(&error);
|
||||
if (NS_SUCCEEDED(error))
|
||||
*aSimilarItemsInGroup = sizeSet;
|
||||
}
|
||||
nsCoreUtils::GetUIntAttr(content, nsAccessibilityAtoms::aria_level,
|
||||
aGroupLevel);
|
||||
nsCoreUtils::GetUIntAttr(content, nsAccessibilityAtoms::aria_posinset,
|
||||
aPositionInGroup);
|
||||
nsCoreUtils::GetUIntAttr(content, nsAccessibilityAtoms::aria_setsize,
|
||||
aSimilarItemsInGroup);
|
||||
|
||||
// If ARIA is missed and the accessible is visible then calculate group
|
||||
// position from hierarchy.
|
||||
@ -3294,9 +3277,6 @@ nsAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet, PRInt32 *aSetSize)
|
||||
role != nsIAccessibleRole::ROLE_GRID_CELL)
|
||||
return;
|
||||
|
||||
PRInt32 positionInGroup = 0;
|
||||
PRInt32 setSize = 0;
|
||||
|
||||
PRUint32 baseRole = role;
|
||||
if (role == nsIAccessibleRole::ROLE_CHECK_MENU_ITEM ||
|
||||
role == nsIAccessibleRole::ROLE_RADIO_MENU_ITEM)
|
||||
@ -3305,36 +3285,70 @@ nsAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet, PRInt32 *aSetSize)
|
||||
nsAccessible* parent = GetParent();
|
||||
NS_ENSURE_TRUE(parent,);
|
||||
|
||||
PRBool foundCurrent = PR_FALSE;
|
||||
PRInt32 siblingCount = parent->GetChildCount();
|
||||
for (PRInt32 siblingIdx = 0; siblingIdx < siblingCount; siblingIdx++) {
|
||||
nsAccessible* sibling = parent->GetChildAt(siblingIdx);
|
||||
PRInt32 indexInParent = parent->GetIndexOf(this);
|
||||
PRInt32 level = nsAccUtils::GetARIAOrDefaultLevel(this);
|
||||
|
||||
// Compute 'posinset'.
|
||||
PRInt32 positionInGroup = 1;
|
||||
for (PRInt32 idx = indexInParent - 1; idx >= 0; idx--) {
|
||||
nsAccessible* sibling = parent->GetChildAt(idx);
|
||||
|
||||
PRUint32 siblingRole = siblingRole = nsAccUtils::Role(sibling);
|
||||
|
||||
// If the sibling is separator then the group is ended.
|
||||
if (siblingRole == nsIAccessibleRole::ROLE_SEPARATOR)
|
||||
break;
|
||||
|
||||
PRUint32 siblingBaseRole = siblingRole;
|
||||
if (siblingRole == nsIAccessibleRole::ROLE_CHECK_MENU_ITEM ||
|
||||
siblingRole == nsIAccessibleRole::ROLE_RADIO_MENU_ITEM)
|
||||
siblingBaseRole = nsIAccessibleRole::ROLE_MENUITEM;
|
||||
|
||||
// If sibling is visible and has the same base role.
|
||||
// If sibling is visible and has the same base role
|
||||
if (siblingBaseRole == baseRole &&
|
||||
!(nsAccUtils::State(sibling) & nsIAccessibleStates::STATE_INVISIBLE)) {
|
||||
++ setSize;
|
||||
if (!foundCurrent) {
|
||||
++ positionInGroup;
|
||||
if (sibling == this)
|
||||
foundCurrent = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// If the sibling is separator
|
||||
if (siblingRole == nsIAccessibleRole::ROLE_SEPARATOR) {
|
||||
if (foundCurrent) // the our group is ended
|
||||
// and check if it's hierarchical flatten structure, i.e. if the sibling
|
||||
// level is lesser than this one then group is ended, if the sibling level
|
||||
// is greater than this one then the group is splited by some child
|
||||
// elements (group will be continued).
|
||||
PRInt32 siblingLevel = nsAccUtils::GetARIAOrDefaultLevel(sibling);
|
||||
if (siblingLevel < level)
|
||||
break;
|
||||
else if (level == siblingLevel)
|
||||
++ positionInGroup;
|
||||
}
|
||||
}
|
||||
|
||||
// not our group, continue the searching
|
||||
positionInGroup = 0;
|
||||
setSize = 0;
|
||||
// Compute 'setsize'.
|
||||
PRInt32 setSize = positionInGroup;
|
||||
|
||||
PRInt32 siblingCount = parent->GetChildCount();
|
||||
for (PRInt32 idx = indexInParent + 1; idx < siblingCount; idx++) {
|
||||
nsAccessible* sibling = parent->GetChildAt(idx);
|
||||
NS_ENSURE_TRUE(sibling,);
|
||||
|
||||
PRUint32 siblingRole = nsAccUtils::Role(sibling);
|
||||
|
||||
// If the sibling is separator then the group is ended.
|
||||
if (siblingRole == nsIAccessibleRole::ROLE_SEPARATOR)
|
||||
break;
|
||||
|
||||
PRUint32 siblingBaseRole = siblingRole;
|
||||
if (siblingRole == nsIAccessibleRole::ROLE_CHECK_MENU_ITEM ||
|
||||
siblingRole == nsIAccessibleRole::ROLE_RADIO_MENU_ITEM)
|
||||
siblingBaseRole = nsIAccessibleRole::ROLE_MENUITEM;
|
||||
|
||||
// If sibling is visible and has the same base role
|
||||
if (siblingBaseRole == baseRole &&
|
||||
!(nsAccUtils::State(sibling) & nsIAccessibleStates::STATE_INVISIBLE)) {
|
||||
|
||||
// and check if it's hierarchical flatten structure.
|
||||
PRInt32 siblingLevel = nsAccUtils::GetARIAOrDefaultLevel(sibling);
|
||||
if (siblingLevel < level)
|
||||
break;
|
||||
else if (level == siblingLevel)
|
||||
++ setSize;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3345,6 +3359,8 @@ nsAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet, PRInt32 *aSetSize)
|
||||
PRInt32
|
||||
nsAccessible::GetLevelInternal()
|
||||
{
|
||||
PRInt32 level = nsAccUtils::GetDefaultLevel(this);
|
||||
|
||||
PRUint32 role = nsAccUtils::Role(this);
|
||||
nsAccessible* parent = GetParent();
|
||||
|
||||
@ -3352,7 +3368,8 @@ nsAccessible::GetLevelInternal()
|
||||
// Always expose 'level' attribute for 'outlineitem' accessible. The number
|
||||
// of nested 'grouping' accessibles containing 'outlineitem' accessible is
|
||||
// its level.
|
||||
PRInt32 level = 1;
|
||||
level = 1;
|
||||
|
||||
while (parent) {
|
||||
PRUint32 parentRole = nsAccUtils::Role(parent);
|
||||
|
||||
@ -3364,17 +3381,14 @@ nsAccessible::GetLevelInternal()
|
||||
parent = parent->GetParent();
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
if (role == nsIAccessibleRole::ROLE_LISTITEM) {
|
||||
} else if (role == nsIAccessibleRole::ROLE_LISTITEM) {
|
||||
// Expose 'level' attribute on nested lists. We assume nested list is a last
|
||||
// child of listitem of parent list. We don't handle the case when nested
|
||||
// lists have more complex structure, for example when there are accessibles
|
||||
// between parent listitem and nested list.
|
||||
|
||||
// Calculate 'level' attribute based on number of parent listitems.
|
||||
PRInt32 level = 0;
|
||||
level = 0;
|
||||
|
||||
while (parent) {
|
||||
PRUint32 parentRole = nsAccUtils::Role(parent);
|
||||
@ -3405,16 +3419,7 @@ nsAccessible::GetLevelInternal()
|
||||
} else {
|
||||
++ level; // level is 1-index based
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
if (role == nsIAccessibleRole::ROLE_ROW &&
|
||||
nsAccUtils::Role(parent) == nsIAccessibleRole::ROLE_TREE_TABLE) {
|
||||
// It is a row inside flatten treegrid. Group level is always 1 until it is
|
||||
// overriden by aria-level attribute.
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return level;
|
||||
}
|
||||
|
@ -581,6 +581,23 @@ nsCoreUtils::GetID(nsIContent *aContent, nsAString& aID)
|
||||
return idAttribute ? aContent->GetAttr(kNameSpaceID_None, idAttribute, aID) : PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsCoreUtils::GetUIntAttr(nsIContent *aContent, nsIAtom *aAttr, PRInt32 *aUInt)
|
||||
{
|
||||
nsAutoString value;
|
||||
aContent->GetAttr(kNameSpaceID_None, aAttr, value);
|
||||
if (!value.IsEmpty()) {
|
||||
PRInt32 error = NS_OK;
|
||||
PRInt32 integer = value.ToInteger(&error);
|
||||
if (NS_SUCCEEDED(error) && integer > 0) {
|
||||
*aUInt = integer;
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsCoreUtils::IsXLink(nsIContent *aContent)
|
||||
{
|
||||
|
@ -250,6 +250,13 @@ public:
|
||||
*/
|
||||
static PRBool GetID(nsIContent *aContent, nsAString& aID);
|
||||
|
||||
/**
|
||||
* Convert attribute value of the given node to positive integer. If no
|
||||
* attribute or wrong value then false is returned.
|
||||
*/
|
||||
static PRBool GetUIntAttr(nsIContent *aContent, nsIAtom *aAttr,
|
||||
PRInt32 *aUInt);
|
||||
|
||||
/**
|
||||
* Check if the given element is XLink.
|
||||
*
|
||||
|
@ -97,6 +97,17 @@
|
||||
testGroupAttrs("r2", 2, 3);
|
||||
testGroupAttrs("r3", 3, 3);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// ARIA tree
|
||||
testGroupAttrs("ti1", 1, 3, 1);
|
||||
testGroupAttrs("ti2", 1, 2, 2);
|
||||
testGroupAttrs("ti3", 2, 2, 2);
|
||||
testGroupAttrs("ti4", 2, 3, 1);
|
||||
testGroupAttrs("ti5", 1, 3, 2);
|
||||
testGroupAttrs("ti6", 2, 3, 2);
|
||||
testGroupAttrs("ti7", 3, 3, 2);
|
||||
testGroupAttrs("ti8", 3, 3, 1);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// ARIA grid
|
||||
testGroupAttrs("grid_row1", 1, 2);
|
||||
@ -109,15 +120,15 @@
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// ARIA treegrid
|
||||
testGroupAttrs("treegrid_row1", 1, 3, 1);
|
||||
testGroupAttrs("treegrid_row1", 1, 2, 1);
|
||||
testGroupAttrs("treegrid_cell1", 1, 2);
|
||||
testGroupAttrs("treegrid_cell2", 2, 2);
|
||||
|
||||
testGroupAttrs("treegrid_row2", 2, 3, 2);
|
||||
testGroupAttrs("treegrid_row2", 1, 1, 2);
|
||||
testGroupAttrs("treegrid_cell3", 1, 2);
|
||||
testGroupAttrs("treegrid_cell4", 2, 2);
|
||||
|
||||
testGroupAttrs("treegrid_row3", 3, 3, 1);
|
||||
testGroupAttrs("treegrid_row3", 2, 2, 1);
|
||||
testGroupAttrs("treegrid_cell5", 1, 2);
|
||||
testGroupAttrs("treegrid_cell6", 2, 2);
|
||||
|
||||
@ -234,6 +245,35 @@
|
||||
<li id="r3" role="radio" aria-checked="false">Jimmy Johns</li>
|
||||
</ul>
|
||||
|
||||
<table role="tree">
|
||||
<tr role="presentation">
|
||||
<td role="treeitem" aria-expanded="true" aria-level="1"
|
||||
id="ti1">vegetables</td>
|
||||
</tr>
|
||||
<tr role="presentation">
|
||||
<td role="treeitem" aria-level="2" id="ti2">cucumber</td>
|
||||
</tr>
|
||||
<tr role="presentation">
|
||||
<td role="treeitem" aria-level="2" id="ti3">carrot</td>
|
||||
</tr>
|
||||
<tr role="presentation">
|
||||
<td role="treeitem" aria-expanded="false" aria-level="1"
|
||||
id="ti4">cars</td>
|
||||
</tr>
|
||||
<tr role="presentation">
|
||||
<td role="treeitem" aria-level="2" id="ti5">mercedes</td>
|
||||
</tr>
|
||||
<tr role="presentation">
|
||||
<td role="treeitem" aria-level="2" id="ti6">BMW</td>
|
||||
</tr>
|
||||
<tr role="presentation">
|
||||
<td role="treeitem" aria-level="2" id="ti7">Audi</td>
|
||||
</tr>
|
||||
<tr role="presentation">
|
||||
<td role="treeitem" aria-level="1" id="ti8">people</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table role="grid">
|
||||
<tr role="row" id="grid_row1">
|
||||
<td role="gridcell" id="grid_cell1">cell1</td>
|
||||
|
Loading…
x
Reference in New Issue
Block a user