зеркало из https://github.com/mozilla/gecko-dev.git
Bug 391490. Every single <option> shows up in JAWS virtual cursor mode. Terrible for screen reader usability. r=ginn.chen, a=dsicore
This commit is contained in:
Родитель
30909d3979
Коммит
9a82827216
|
@ -741,17 +741,32 @@ interface nsIAccessibleRole : nsISupports
|
|||
/**
|
||||
* A item of list that is shown by combobox;
|
||||
*/
|
||||
const unsigned long ROLE_COMBOBOX_LISTITEM = 115;
|
||||
const unsigned long ROLE_COMBOBOX_OPTION = 115;
|
||||
|
||||
/**
|
||||
* An image map -- has child links representing the areas
|
||||
*/
|
||||
const unsigned long ROLE_IMAGE_MAP = 116;
|
||||
|
||||
/**
|
||||
* An option in a listbox
|
||||
*/
|
||||
const unsigned long ROLE_OPTION = 117;
|
||||
|
||||
/**
|
||||
* A rich option in a listbox, it can have other widgets as children
|
||||
*/
|
||||
const unsigned long ROLE_RICH_OPTION = 118;
|
||||
|
||||
/**
|
||||
* A list of options
|
||||
*/
|
||||
const unsigned long ROLE_LISTBOX = 119;
|
||||
|
||||
/**
|
||||
* It's not role actually. This contanst is important to help ensure
|
||||
* nsRoleMap's are synchronized.
|
||||
*/
|
||||
const unsigned long ROLE_LAST_ENTRY = 117;
|
||||
const unsigned long ROLE_LAST_ENTRY = 120;
|
||||
};
|
||||
|
||||
|
|
|
@ -161,8 +161,11 @@ static const PRUint32 atkRoleMap[] = {
|
|||
ATK_ROLE_MENU, // nsIAccessibleRole::ROLE_PARENT_MENUITEM 112
|
||||
ATK_ROLE_CALENDAR, // nsIAccessibleRole::ROLE_CALENDAR 113
|
||||
ATK_ROLE_MENU, // nsIAccessibleRole::ROLE_COMBOBOX_LIST 114
|
||||
ATK_ROLE_MENU_ITEM, // nsIAccessibleRole::ROLE_COMBOBOX_LISTITEM 115
|
||||
ATK_ROLE_MENU_ITEM, // nsIAccessibleRole::ROLE_COMBOBOX_OPTION 115
|
||||
ATK_ROLE_IMAGE, // nsIAccessibleRole::ROLE_IMAGE_MAP 116
|
||||
ATK_ROLE_LIST_ITEM, // nsIAccessibleRole::ROLE_OPTION 117
|
||||
ATK_ROLE_LIST_ITEM, // nsIAccessibleRole::ROLE_RICH_OPTION 118
|
||||
ATK_ROLE_LIST, // nsIAccessibleRole::ROLE_LISTBOX 119
|
||||
kROLE_ATK_LAST_ENTRY // nsIAccessibleRole::ROLE_LAST_ENTRY
|
||||
};
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
{"list", nsIAccessibleRole::ROLE_LIST, eNameLabelOrTitle, eNoValue, kNoReqStates,
|
||||
{eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
|
||||
{eAria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry},
|
||||
{"listbox", nsIAccessibleRole::ROLE_LIST, eNameLabelOrTitle, eNoValue, kNoReqStates,
|
||||
{"listbox", nsIAccessibleRole::ROLE_LISTBOX, eNameLabelOrTitle, eNoValue, kNoReqStates,
|
||||
{eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
|
||||
{eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
|
||||
{eAria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry},
|
||||
|
@ -144,7 +144,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
{"menuitemradio", nsIAccessibleRole::ROLE_RADIO_MENU_ITEM, eNameOkFromChildren, eNoValue, nsIAccessibleStates::STATE_CHECKABLE,
|
||||
{eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
|
||||
{eAria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED }, kEndEntry},
|
||||
{"option", nsIAccessibleRole::ROLE_LISTITEM, eNameOkFromChildren, eNoValue, kNoReqStates,
|
||||
{"option", nsIAccessibleRole::ROLE_OPTION, eNameOkFromChildren, eNoValue, kNoReqStates,
|
||||
{eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
|
||||
{eAria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
|
||||
{eAria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
|
||||
|
|
|
@ -257,7 +257,7 @@ static const char kRoleNames[][20] = {
|
|||
"parent menuitem", //ROLE_PARENT_MENUITEM
|
||||
"calendar", //ROLE_CALENDAR
|
||||
"combobox list", //ROLE_COMBOBOX_LIST
|
||||
"combobox listitem", //ROLE_COMBOBOX_LISTITEM
|
||||
"combobox option", //ROLE_COMBOBOX_OPTION
|
||||
"image map" //ROLE_IMAGE_MAP
|
||||
};
|
||||
|
||||
|
|
|
@ -1991,7 +1991,22 @@ NS_IMETHODIMP nsAccessible::GetFinalRole(PRUint32 *aRole)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (*aRole == nsIAccessibleRole::ROLE_LISTBOX) {
|
||||
// A listbox inside of a combo box needs a special role because of ATK mapping to menu
|
||||
nsCOMPtr<nsIAccessible> parent;
|
||||
GetParent(getter_AddRefs(parent));
|
||||
if (parent && Role(parent) == nsIAccessibleRole::ROLE_COMBOBOX) {
|
||||
*aRole = nsIAccessibleRole::ROLE_COMBOBOX_LIST;
|
||||
}
|
||||
}
|
||||
else if (*aRole == nsIAccessibleRole::ROLE_OPTION) {
|
||||
nsCOMPtr<nsIAccessible> parent;
|
||||
GetParent(getter_AddRefs(parent));
|
||||
if (parent && Role(parent) == nsIAccessibleRole::ROLE_COMBOBOX_LIST) {
|
||||
*aRole = nsIAccessibleRole::ROLE_COMBOBOX_OPTION;
|
||||
}
|
||||
}
|
||||
|
||||
if (*aRole != nsIAccessibleRole::ROLE_NOTHING) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -3311,6 +3326,8 @@ PRBool nsAccessible::MustPrune(nsIAccessible *aAccessible)
|
|||
{
|
||||
PRUint32 role = Role(aAccessible);
|
||||
return role == nsIAccessibleRole::ROLE_MENUITEM ||
|
||||
role == nsIAccessibleRole::ROLE_COMBOBOX_OPTION ||
|
||||
role == nsIAccessibleRole::ROLE_OPTION ||
|
||||
role == nsIAccessibleRole::ROLE_ENTRY ||
|
||||
role == nsIAccessibleRole::ROLE_PASSWORD_TEXT ||
|
||||
role == nsIAccessibleRole::ROLE_PUSHBUTTON ||
|
||||
|
|
|
@ -333,6 +333,16 @@ nsHTMLSelectListAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
|
|||
|
||||
nsCOMPtr<nsIDOMHTMLSelectElement> select (do_QueryInterface(mDOMNode));
|
||||
if (select) {
|
||||
if (*aState | nsIAccessibleStates::STATE_FOCUSED) {
|
||||
// Treat first focusable option node as actual focus, in order
|
||||
// to avoid confusing JAWS, which needs focus on the option
|
||||
nsCOMPtr<nsIDOMNode> focusedOption;
|
||||
nsHTMLSelectOptionAccessible::GetFocusedOptionNode(mDOMNode,
|
||||
getter_AddRefs(focusedOption));
|
||||
if (focusedOption) { // Clear focused state since it is on option
|
||||
*aState &= ~nsIAccessibleStates::STATE_FOCUSED;
|
||||
}
|
||||
}
|
||||
PRBool multiple;
|
||||
select->GetMultiple(&multiple);
|
||||
if ( multiple )
|
||||
|
@ -485,10 +495,10 @@ nsHyperTextAccessibleWrap(aDOMNode, aShell)
|
|||
NS_IMETHODIMP nsHTMLSelectOptionAccessible::GetRole(PRUint32 *aRole)
|
||||
{
|
||||
if (mParent && Role(mParent) == nsIAccessibleRole::ROLE_COMBOBOX_LIST) {
|
||||
*aRole = nsIAccessibleRole::ROLE_COMBOBOX_LISTITEM;
|
||||
*aRole = nsIAccessibleRole::ROLE_COMBOBOX_OPTION;
|
||||
}
|
||||
else {
|
||||
*aRole = nsIAccessibleRole::ROLE_LISTITEM;
|
||||
*aRole = nsIAccessibleRole::ROLE_OPTION;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -622,6 +632,18 @@ nsHTMLSelectOptionAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
|
|||
if (0 == (*aState & nsIAccessibleStates::STATE_UNAVAILABLE)) {
|
||||
*aState |= (nsIAccessibleStates::STATE_FOCUSABLE |
|
||||
nsIAccessibleStates::STATE_SELECTABLE);
|
||||
// When the list is focused but no option is actually focused,
|
||||
// Firefox draws a focus ring around the first non-disabled option.
|
||||
// We need to indicated STATE_FOCUSED in that case, because it
|
||||
// prevents JAWS from ignoring the list
|
||||
// GetFocusedOptionNode() ensures that an option node is
|
||||
// returned in this case, as long as some focusable option exists
|
||||
// in the listbox
|
||||
nsCOMPtr<nsIDOMNode> focusedOptionNode;
|
||||
GetFocusedOptionNode(selectNode, getter_AddRefs(focusedOptionNode));
|
||||
if (focusedOptionNode == mDOMNode) {
|
||||
*aState |= nsIAccessibleStates::STATE_FOCUSED;
|
||||
}
|
||||
}
|
||||
|
||||
// Are we selected?
|
||||
|
@ -788,6 +810,22 @@ nsresult nsHTMLSelectOptionAccessible::GetFocusedOptionNode(nsIDOMNode *aListNod
|
|||
// when there is more than 1 item selected. We need the focused item, not
|
||||
// the first selected item.
|
||||
focusedOptionIndex = listFrame->GetSelectedIndex();
|
||||
if (focusedOptionIndex == -1) {
|
||||
nsCOMPtr<nsIDOMNode> nextOption;
|
||||
while (PR_TRUE) {
|
||||
++ focusedOptionIndex;
|
||||
options->Item(focusedOptionIndex, getter_AddRefs(nextOption));
|
||||
nsCOMPtr<nsIDOMHTMLOptionElement> optionElement = do_QueryInterface(nextOption);
|
||||
if (!optionElement) {
|
||||
break;
|
||||
}
|
||||
PRBool disabled;
|
||||
optionElement->GetDisabled(&disabled);
|
||||
if (!disabled) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Combo boxes can only have 1 selected option, so they can use the dom interface for this
|
||||
rv = selectElement->GetSelectedIndex(&focusedOptionIndex);
|
||||
|
|
|
@ -157,7 +157,10 @@ static const NSString* AXRoles [] = {
|
|||
NSAccessibilityMenuItemRole, // ROLE_PARENT_MENUITEM
|
||||
NSAccessibilityGroupRole, // ROLE_CALENDAR
|
||||
NSAccessibilityMenuRole, // ROLE_COMBOBOX_LIST
|
||||
NSAccessibilityMenuItemRole, // ROLE_COMBOBOX_LISTITEM
|
||||
NSAccessibilityMenuItemRole, // ROLE_COMBOBOX_OPTION
|
||||
NSAccessibilityImageRole, // ROLE_IMAGE_MAP
|
||||
NSAccessibilityRowRole, // ROLE_OPTION
|
||||
NSAccessibilityRowRole, // ROLE_RICH_OPTION
|
||||
NSAccessibilityListRole, // ROLE_LISTBOX
|
||||
@"ROLE_LAST_ENTRY" // ROLE_LAST_ENTRY. bogus role that will never be shown (just marks the end of this array)!
|
||||
};
|
||||
|
|
|
@ -419,12 +419,21 @@ static const WindowsRoleMapItem gWindowsRoleMap[] = {
|
|||
// nsIAccessibleRole::ROLE_COMBOBOX_LIST
|
||||
{ ROLE_SYSTEM_LIST, ROLE_SYSTEM_LIST },
|
||||
|
||||
// nsIAccessibleRole::ROLE_COMBOBOX_LISTITEM
|
||||
// nsIAccessibleRole::ROLE_COMBOBOX_OPTION
|
||||
{ ROLE_SYSTEM_LISTITEM, ROLE_SYSTEM_LISTITEM },
|
||||
|
||||
// nsIAccessibleRole::ROLE_IMAGE_MAP
|
||||
{ ROLE_SYSTEM_GRAPHIC, ROLE_SYSTEM_GRAPHIC },
|
||||
|
||||
// nsIAccessibleRole::ROLE_OPTION
|
||||
{ ROLE_SYSTEM_LISTITEM, ROLE_SYSTEM_LISTITEM },
|
||||
|
||||
// nsIAccessibleRole::ROLE_RICH_OPTION
|
||||
{ ROLE_SYSTEM_LIST, ROLE_SYSTEM_LIST },
|
||||
|
||||
// nsIAccessibleRole::ROLE_LISTBOX
|
||||
{ ROLE_SYSTEM_LIST, ROLE_SYSTEM_LIST },
|
||||
|
||||
// nsIAccessibleRole::ROLE_LAST_ENTRY
|
||||
{ ROLE_WINDOWS_LAST_ENTRY, ROLE_WINDOWS_LAST_ENTRY }
|
||||
};
|
||||
|
|
|
@ -318,7 +318,7 @@ nsXULMenuitemAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
|
|||
}
|
||||
|
||||
// Combo box listitem
|
||||
if (Role(this) == nsIAccessibleRole::ROLE_COMBOBOX_LISTITEM) {
|
||||
if (Role(this) == nsIAccessibleRole::ROLE_COMBOBOX_OPTION) {
|
||||
// Is selected?
|
||||
PRBool isSelected = PR_FALSE;
|
||||
nsCOMPtr<nsIDOMXULSelectControlItemElement>
|
||||
|
@ -363,7 +363,7 @@ nsXULMenuitemAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
|
|||
}
|
||||
} // isCollapsed
|
||||
} // isSelected
|
||||
} // ROLE_COMBOBOX_LISTITEM
|
||||
} // ROLE_COMBOBOX_OPTION
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -461,7 +461,7 @@ NS_IMETHODIMP nsXULMenuitemAccessible::GetRole(PRUint32 *aRole)
|
|||
{
|
||||
*aRole = nsIAccessibleRole::ROLE_MENUITEM;
|
||||
if (mParent && Role(mParent) == nsIAccessibleRole::ROLE_COMBOBOX_LIST) {
|
||||
*aRole = nsIAccessibleRole::ROLE_COMBOBOX_LISTITEM;
|
||||
*aRole = nsIAccessibleRole::ROLE_COMBOBOX_OPTION;
|
||||
return NS_OK;
|
||||
}
|
||||
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(mDOMNode));
|
||||
|
|
|
@ -250,7 +250,7 @@ NS_IMETHODIMP nsXULListitemAccessible::GetRole(PRUint32 *aRole)
|
|||
if (mIsCheckbox)
|
||||
*aRole = nsIAccessibleRole::ROLE_CHECKBUTTON;
|
||||
else
|
||||
*aRole = nsIAccessibleRole::ROLE_LISTITEM;
|
||||
*aRole = nsIAccessibleRole::ROLE_RICH_OPTION;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче