Bug 249292 - Ensure accessible children for <toolbarbutton> types 'menu' and 'menu-button', r=marcoz, davidb

--HG--
rename : accessible/tests/mochitest/test_elm_filectrl.html => accessible/tests/mochitest/tree/test_filectrl.html
rename : accessible/tests/mochitest/test_elm_media.html => accessible/tests/mochitest/tree/test_media.html
rename : accessible/tests/mochitest/test_elm_select.html => accessible/tests/mochitest/tree/test_select.html
rename : accessible/tests/mochitest/test_elm_tree.xul => accessible/tests/mochitest/tree/test_tree.xul
rename : accessible/tests/mochitest/test_elm_txtcntnr.html => accessible/tests/mochitest/tree/test_txtctrl.html
This commit is contained in:
Alexander Surkov 2009-11-10 13:58:52 +08:00
parent dd80aa5a05
commit 4fe3532b6f
23 changed files with 976 additions and 157 deletions

View File

@ -902,13 +902,15 @@ nsAccUtils::MustPrune(nsIAccessible *aAccessible)
{
PRUint32 role = nsAccUtils::Role(aAccessible);
// We don't prune buttons any more however AT don't expect children inside of
// button in general, we allow menu buttons to have children to make them
// accessible.
return role == nsIAccessibleRole::ROLE_MENUITEM ||
role == nsIAccessibleRole::ROLE_COMBOBOX_OPTION ||
role == nsIAccessibleRole::ROLE_OPTION ||
role == nsIAccessibleRole::ROLE_ENTRY ||
role == nsIAccessibleRole::ROLE_FLAT_EQUATION ||
role == nsIAccessibleRole::ROLE_PASSWORD_TEXT ||
role == nsIAccessibleRole::ROLE_PUSHBUTTON ||
role == nsIAccessibleRole::ROLE_TOGGLE_BUTTON ||
role == nsIAccessibleRole::ROLE_GRAPHIC ||
role == nsIAccessibleRole::ROLE_SLIDER ||

View File

@ -61,6 +61,9 @@ ACCESSIBILITY_ATOM(col, "col")
ACCESSIBILITY_ATOM(_empty, "")
ACCESSIBILITY_ATOM(_false, "false")
ACCESSIBILITY_ATOM(image, "image")
ACCESSIBILITY_ATOM(menu, "menu")
ACCESSIBILITY_ATOM(menuButton, "menu-button")
ACCESSIBILITY_ATOM(menugenerated, "menugenerated")
ACCESSIBILITY_ATOM(password, "password")
ACCESSIBILITY_ATOM(reset, "reset")
ACCESSIBILITY_ATOM(row, "row")
@ -125,12 +128,12 @@ ACCESSIBILITY_ATOM(listhead, "listhead") // XUL
ACCESSIBILITY_ATOM(listheader, "listheader") // XUL
ACCESSIBILITY_ATOM(map, "map")
ACCESSIBILITY_ATOM(math, "math")
ACCESSIBILITY_ATOM(menu, "menu") // XUL
ACCESSIBILITY_ATOM(menupopup, "menupopup") // XUL
ACCESSIBILITY_ATOM(object, "object")
ACCESSIBILITY_ATOM(ol, "ol")
ACCESSIBILITY_ATOM(optgroup, "optgroup")
ACCESSIBILITY_ATOM(option, "option")
ACCESSIBILITY_ATOM(panel, "panel") // XUL
ACCESSIBILITY_ATOM(q, "q")
ACCESSIBILITY_ATOM(select, "select")
ACCESSIBILITY_ATOM(select1, "select1") // XForms
@ -164,6 +167,7 @@ ACCESSIBILITY_ATOM(_class, "class")
ACCESSIBILITY_ATOM(cycles, "cycles") // used for XUL cycler attribute
ACCESSIBILITY_ATOM(curpos, "curpos") // XUL
ACCESSIBILITY_ATOM(data, "data")
ACCESSIBILITY_ATOM(_default, "default") // XUL button
ACCESSIBILITY_ATOM(draggable, "draggable")
ACCESSIBILITY_ATOM(droppable, "droppable") // XUL combo box
ACCESSIBILITY_ATOM(editable, "editable")

View File

@ -1107,3 +1107,45 @@ nsCoreUtils::IsColumnHidden(nsITreeColumn *aColumn)
return content->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::hidden,
nsAccessibilityAtoms::_true, eCaseMatters);
}
void
nsCoreUtils::GeneratePopupTree(nsIDOMNode *aNode, PRBool aIsAnon)
{
// Set menugenerated="true" on the menupopup node to generate the sub-menu
// items if they have not been generated.
nsCOMPtr<nsIDOMNodeList> list;
if (aIsAnon) {
nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
nsIDocument* document = content->GetCurrentDoc();
if (document)
document->GetXBLChildNodesFor(content, getter_AddRefs(list));
} else {
aNode->GetChildNodes(getter_AddRefs(list));
}
PRUint32 length = 0;
if (!list || NS_FAILED(list->GetLength(&length)))
return;
for (PRUint32 idx = 0; idx < length; idx++) {
nsCOMPtr<nsIDOMNode> childNode;
list->Item(idx, getter_AddRefs(childNode));
nsCOMPtr<nsIContent> child(do_QueryInterface(childNode));
PRBool isPopup = child->NodeInfo()->Equals(nsAccessibilityAtoms::menupopup,
kNameSpaceID_XUL) ||
child->NodeInfo()->Equals(nsAccessibilityAtoms::panel,
kNameSpaceID_XUL);
if (isPopup && !child->AttrValueIs(kNameSpaceID_None,
nsAccessibilityAtoms::menugenerated,
nsAccessibilityAtoms::_true,
eCaseMatters)) {
child->SetAttr(kNameSpaceID_None, nsAccessibilityAtoms::menugenerated,
NS_LITERAL_STRING("true"), PR_TRUE);
return;
}
}
}

View File

@ -446,6 +446,15 @@ public:
return aContent->NodeInfo()->Equals(nsAccessibilityAtoms::th) ||
aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::scope);
}
/**
* Generates frames for popup subtree.
*
* @param aNode [in] DOM node containing the menupopup element as a child
* @param aIsAnon [in] specifies whether popup should be searched inside of
* anonymous or explicit content
*/
static void GeneratePopupTree(nsIDOMNode *aNode, PRBool aIsAnon = PR_FALSE);
};
#endif

View File

@ -36,26 +36,43 @@
*
* ***** END LICENSE BLOCK ***** */
// NOTE: alphabetically ordered
#include "nsXULColorPickerAccessible.h"
#include "nsAccessibleTreeWalker.h"
#include "nsIDOMElement.h"
/**
* XUL Color Picker Tile
*/
////////////////////////////////////////////////////////////////////////////////
// nsXULColorPickerTileAccessible
////////////////////////////////////////////////////////////////////////////////
/**
* Default Constructor
*/
nsXULColorPickerTileAccessible::nsXULColorPickerTileAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
nsFormControlAccessible(aNode, aShell)
{
nsXULColorPickerTileAccessible::
nsXULColorPickerTileAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell) :
nsAccessibleWrap(aNode, aShell)
{
}
/**
* We are a pushbutton
*/
////////////////////////////////////////////////////////////////////////////////
// nsXULColorPickerTileAccessible: nsIAccessible
NS_IMETHODIMP
nsXULColorPickerTileAccessible::GetValue(nsAString& aValue)
{
aValue.Truncate();
if (IsDefunct())
return NS_ERROR_FAILURE;
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::color, aValue);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsXULColorPickerTileAccessible: nsAccessible
nsresult
nsXULColorPickerTileAccessible::GetRoleInternal(PRUint32 *aRole)
{
@ -63,15 +80,14 @@ nsXULColorPickerTileAccessible::GetRoleInternal(PRUint32 *aRole)
return NS_OK;
}
/**
* Possible states: focused, focusable, selected
*/
nsresult
nsXULColorPickerTileAccessible::GetStateInternal(PRUint32 *aState,
PRUint32 *aExtraState)
{
// Possible states: focused, focusable, selected.
// get focus and disable status from base class
nsresult rv = nsFormControlAccessible::GetStateInternal(aState, aExtraState);
nsresult rv = nsAccessibleWrap::GetStateInternal(aState, aExtraState);
NS_ENSURE_A11Y_SUCCESS(rv, rv);
*aState |= nsIAccessibleStates::STATE_FOCUSABLE;
@ -92,19 +108,10 @@ nsXULColorPickerTileAccessible::GetStateInternal(PRUint32 *aState,
return NS_OK;
}
NS_IMETHODIMP nsXULColorPickerTileAccessible::GetValue(nsAString& _retval)
{
if (!mDOMNode)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(mDOMNode));
NS_ASSERTION(element, "No XUL Element for colorpicker");
return element->GetAttribute(NS_LITERAL_STRING("color"), _retval);
}
/**
* XUL Color Picker
*/
////////////////////////////////////////////////////////////////////////////////
// nsXULColorPickerAccessible
////////////////////////////////////////////////////////////////////////////////
/**
* Default Constructor
@ -114,15 +121,30 @@ nsXULColorPickerTileAccessible(aNode, aShell)
{
}
/**
* Possible states: focused, focusable, unavailable(disabled)
*/
////////////////////////////////////////////////////////////////////////////////
// nsXULColorPickerAccessible: nsAccessNode
nsresult
nsXULColorPickerAccessible::Init()
{
nsresult rv = nsXULColorPickerTileAccessible::Init();
NS_ENSURE_SUCCESS(rv, rv);
nsCoreUtils::GeneratePopupTree(mDOMNode, PR_TRUE);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsXULColorPickerAccessible: nsAccessible
nsresult
nsXULColorPickerAccessible::GetStateInternal(PRUint32 *aState,
PRUint32 *aExtraState)
{
// Possible states: focused, focusable, unavailable(disabled).
// get focus and disable status from base class
nsresult rv = nsFormControlAccessible::GetStateInternal(aState, aExtraState);
nsresult rv = nsAccessibleWrap::GetStateInternal(aState, aExtraState);
NS_ENSURE_A11Y_SUCCESS(rv, rv);
*aState |= nsIAccessibleStates::STATE_FOCUSABLE |
@ -138,3 +160,46 @@ nsXULColorPickerAccessible::GetRoleInternal(PRUint32 *aRole)
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsXULColorPickerAccessible: protected nsAccessible
void
nsXULColorPickerAccessible::CacheChildren()
{
if (IsDefunct()) {
mAccChildCount = eChildCountUninitialized;
return; // This outer doc node has been shut down
}
if (mAccChildCount != eChildCountUninitialized)
return;
mAccChildCount = 0; // Avoid reentry
nsCOMPtr<nsIAccessible> menupopupAccessible;
nsAccessibleTreeWalker walker(mWeakShell, mDOMNode, PR_TRUE);
walker.GetFirstChild();
while (walker.mState.accessible) {
PRUint32 role = nsAccUtils::Role(walker.mState.accessible);
if (role == nsIAccessibleRole::ROLE_ALERT) {
// Get an accessbile for menupopup or panel elements.
menupopupAccessible = walker.mState.accessible;
break;
}
walker.GetNextSibling();
}
if (!menupopupAccessible)
return;
SetFirstChild(menupopupAccessible);
nsRefPtr<nsAccessible> menupopupAcc =
nsAccUtils::QueryObject<nsAccessible>(menupopupAccessible);
menupopupAcc->SetParent(this);
mAccChildCount++;
}

View File

@ -40,9 +40,12 @@
#define _nsXULColorPickerAccessible_H_
// NOTE: alphabetically ordered
#include "nsFormControlAccessible.h"
#include "nsAccessibleWrap.h"
class nsXULColorPickerTileAccessible : public nsFormControlAccessible
/**
* Used for color button in colorpicker palette.
*/
class nsXULColorPickerTileAccessible : public nsAccessibleWrap
{
public:
nsXULColorPickerTileAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
@ -55,14 +58,26 @@ public:
virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
};
/**
* Used for colorpicker button (xul:colorpicker@type="button").
*/
class nsXULColorPickerAccessible : public nsXULColorPickerTileAccessible
{
public:
nsXULColorPickerAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
// nsAccessNode
virtual nsresult Init();
// nsAccessible
virtual nsresult GetRoleInternal(PRUint32 *aRole);
virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
protected:
// nsAccessible
virtual void CacheChildren();
};
#endif

View File

@ -58,7 +58,7 @@ nsresult
nsXULComboboxAccessible::Init()
{
nsresult rv = nsAccessibleWrap::Init();
nsXULMenupopupAccessible::GenerateMenu(mDOMNode);
nsCoreUtils::GeneratePopupTree(mDOMNode);
return rv;
}

View File

@ -56,33 +56,35 @@
#include "nsITextControlFrame.h"
#include "nsIPresShell.h"
/**
* XUL Button: can contain arbitrary HTML content
*/
////////////////////////////////////////////////////////////////////////////////
// nsXULButtonAccessible
////////////////////////////////////////////////////////////////////////////////
/**
* Default Constructor
*/
// Don't inherit from nsFormControlAccessible - it doesn't allow children and a button can have a dropmarker child
nsXULButtonAccessible::nsXULButtonAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
nsAccessibleWrap(aNode, aShell)
{
nsXULButtonAccessible::
nsXULButtonAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell) :
nsAccessibleWrap(aNode, aShell)
{
}
/**
* Only one actions available
*/
NS_IMETHODIMP nsXULButtonAccessible::GetNumActions(PRUint8 *_retval)
////////////////////////////////////////////////////////////////////////////////
// nsXULButtonAccessible: nsISupports
NS_IMPL_ISUPPORTS_INHERITED0(nsXULButtonAccessible, nsAccessible)
////////////////////////////////////////////////////////////////////////////////
// nsXULButtonAccessible: nsIAccessible
NS_IMETHODIMP
nsXULButtonAccessible::GetNumActions(PRUint8 *aCount)
{
*_retval = 1;
NS_ENSURE_ARG_POINTER(aCount);
*aCount = 1;
return NS_OK;
}
/**
* Return the name of our only action
*/
NS_IMETHODIMP nsXULButtonAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
NS_IMETHODIMP
nsXULButtonAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
{
if (aIndex == eAction_Click) {
aName.AssignLiteral("press");
@ -91,20 +93,33 @@ NS_IMETHODIMP nsXULButtonAccessible::GetActionName(PRUint8 aIndex, nsAString& aN
return NS_ERROR_INVALID_ARG;
}
/**
* Tell the button to do its action
*/
NS_IMETHODIMP nsXULButtonAccessible::DoAction(PRUint8 index)
NS_IMETHODIMP
nsXULButtonAccessible::DoAction(PRUint8 aIndex)
{
if (index == 0) {
if (aIndex == 0)
return DoCommand();
}
return NS_ERROR_INVALID_ARG;
}
/**
* We are a pushbutton
*/
////////////////////////////////////////////////////////////////////////////////
// nsXULButtonAccessible: nsAccessNode
nsresult
nsXULButtonAccessible::Init()
{
nsresult rv = nsAccessibleWrap::Init();
NS_ENSURE_SUCCESS(rv, rv);
if (ContainsMenu())
nsCoreUtils::GeneratePopupTree(mDOMNode);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsXULButtonAccessible: nsAccessible
nsresult
nsXULButtonAccessible::GetRoleInternal(PRUint32 *aRole)
{
@ -112,12 +127,11 @@ nsXULButtonAccessible::GetRoleInternal(PRUint32 *aRole)
return NS_OK;
}
/**
* Possible states: focused, focusable, unavailable(disabled)
*/
nsresult
nsXULButtonAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState)
{
// Possible states: focused, focusable, unavailable(disabled).
// get focus and disable status from base class
nsresult rv = nsAccessible::GetStateInternal(aState, aExtraState);
NS_ENSURE_A11Y_SUCCESS(rv, rv);
@ -152,63 +166,118 @@ nsXULButtonAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState)
}
}
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(mDOMNode));
if (element) {
PRBool isDefault = PR_FALSE;
element->HasAttribute(NS_LITERAL_STRING("default"), &isDefault) ;
if (isDefault)
*aState |= nsIAccessibleStates::STATE_DEFAULT;
if (ContainsMenu())
*aState |= nsIAccessibleStates::STATE_HASPOPUP;
nsAutoString type;
element->GetAttribute(NS_LITERAL_STRING("type"), type);
if (type.EqualsLiteral("menu") || type.EqualsLiteral("menu-button")) {
*aState |= nsIAccessibleStates::STATE_HASPOPUP;
}
}
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (content->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::_default))
*aState |= nsIAccessibleStates::STATE_DEFAULT;
return NS_OK;
}
void nsXULButtonAccessible::CacheChildren()
////////////////////////////////////////////////////////////////////////////////
// nsXULButtonAccessible: nsAccessible protected
void
nsXULButtonAccessible::CacheChildren()
{
// An XUL button accessible may have 1 child dropmarker accessible
// In general XUL button has not accessible children. Nevertheless menu
// buttons can have button (@type="menu-button") and popup accessibles
// (@type="menu-button" or @type="menu").
if (!mWeakShell) {
mAccChildCount = eChildCountUninitialized;
return; // This outer doc node has been shut down
}
if (mAccChildCount == eChildCountUninitialized) {
mAccChildCount = 0; // Avoid reentry
SetFirstChild(nsnull);
PRBool allowsAnonChildren = GetAllowsAnonChildAccessibles();
nsAccessibleTreeWalker walker(mWeakShell, mDOMNode, allowsAnonChildren);
// XXX: no children until the button is menu button. Probably it's not
// totally correct but in general AT wants to have leaf buttons.
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
PRBool isMenu = content->AttrValueIs(kNameSpaceID_None,
nsAccessibilityAtoms::type,
nsAccessibilityAtoms::menu,
eCaseMatters);
PRBool isMenuButton = isMenu ?
PR_FALSE :
content->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::type,
nsAccessibilityAtoms::menuButton, eCaseMatters);
if (!isMenu && !isMenuButton)
return;
nsCOMPtr<nsIAccessible> buttonAccessible;
nsCOMPtr<nsIAccessible> menupopupAccessible;
nsAccessibleTreeWalker walker(mWeakShell, mDOMNode, PR_TRUE);
walker.GetFirstChild();
nsCOMPtr<nsIAccessible> dropMarkerAccessible;
while (walker.mState.accessible) {
dropMarkerAccessible = walker.mState.accessible;
PRUint32 role = nsAccUtils::Role(walker.mState.accessible);
if (role == nsIAccessibleRole::ROLE_MENUPOPUP) {
// Get an accessbile for menupopup or panel elements.
menupopupAccessible = walker.mState.accessible;
} else if (isMenuButton && role == nsIAccessibleRole::ROLE_PUSHBUTTON) {
// Button type="menu-button" contains a real button. Get an accessible
// for it. Ignore dropmarker button what is placed as a last child.
buttonAccessible = walker.mState.accessible;
break;
}
walker.GetNextSibling();
}
// If the anonymous tree walker can find accessible children,
// and the last one is a push button, then use it as the only accessible
// child -- because this is the scenario where we have a dropmarker child
if (!menupopupAccessible)
return;
if (dropMarkerAccessible) {
if (nsAccUtils::RoleInternal(dropMarkerAccessible) ==
nsIAccessibleRole::ROLE_PUSHBUTTON) {
SetFirstChild(dropMarkerAccessible);
nsRefPtr<nsAccessible> childAcc =
nsAccUtils::QueryAccessible(dropMarkerAccessible);
childAcc->SetNextSibling(nsnull);
childAcc->SetParent(this);
mAccChildCount = 1;
}
SetFirstChild(menupopupAccessible);
nsRefPtr<nsAccessible> menupopupAcc =
nsAccUtils::QueryObject<nsAccessible>(menupopupAccessible);
menupopupAcc->SetParent(this);
mAccChildCount++;
if (buttonAccessible) {
if (menupopupAcc)
menupopupAcc->SetNextSibling(buttonAccessible);
else
SetFirstChild(buttonAccessible);
nsRefPtr<nsAccessible> buttonAcc =
nsAccUtils::QueryObject<nsAccessible>(buttonAccessible);
buttonAcc->SetParent(this);
mAccChildCount++;
}
}
}
/**
* XUL Dropmarker: can contain arbitrary HTML content
*/
////////////////////////////////////////////////////////////////////////////////
// nsXULButtonAccessible protected
PRBool
nsXULButtonAccessible::ContainsMenu()
{
static nsIContent::AttrValuesArray strings[] =
{&nsAccessibilityAtoms::menu, &nsAccessibilityAtoms::menuButton, nsnull};
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
return content->FindAttrValueIn(kNameSpaceID_None, nsAccessibilityAtoms::type,
strings, eCaseMatters) >= 0;
}
////////////////////////////////////////////////////////////////////////////////
// nsXULDropmarkerAccessible
////////////////////////////////////////////////////////////////////////////////
/**
* Default Constructor

View File

@ -46,26 +46,46 @@
#include "nsXULMenuAccessible.h"
#include "nsHyperTextAccessibleWrap.h"
/**
* Used for XUL button.
*
* @note Don't inherit from nsFormControlAccessible - it doesn't allow children
* and a button can have a dropmarker child.
*/
class nsXULButtonAccessible : public nsAccessibleWrap
// Don't inherit from nsFormControlAccessible - it doesn't allow children and a button can have a dropmarker child
{
public:
enum { eAction_Click = 0 };
nsXULButtonAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
// nsIAccessible
NS_IMETHOD GetNumActions(PRUint8 *_retval);
NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
NS_IMETHOD DoAction(PRUint8 index);
// nsAccessNode
virtual nsresult Init();
// nsAccessible
virtual nsresult GetRoleInternal(PRUint32 *aRole);
virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
protected:
// nsAccessible
void CacheChildren();
// nsXULButtonAccessible
PRBool ContainsMenu();
};
/**
* Used for XUL checkbox.
*/
class nsXULCheckboxAccessible : public nsFormControlAccessible
{
public:

View File

@ -273,7 +273,7 @@ nsresult
nsXULMenuitemAccessible::Init()
{
nsresult rv = nsAccessibleWrap::Init();
nsXULMenupopupAccessible::GenerateMenu(mDOMNode);
nsCoreUtils::GeneratePopupTree(mDOMNode);
return rv;
}
@ -642,46 +642,6 @@ nsXULMenupopupAccessible::GetStateInternal(PRUint32 *aState,
return NS_OK;
}
already_AddRefed<nsIDOMNode>
nsXULMenupopupAccessible::FindInNodeList(nsIDOMNodeList *aNodeList,
nsIAtom *aAtom, PRUint32 aNameSpaceID)
{
PRUint32 numChildren;
if (!aNodeList || NS_FAILED(aNodeList->GetLength(&numChildren))) {
return nsnull;
}
nsCOMPtr<nsIDOMNode> childNode;
for (PRUint32 childIndex = 0; childIndex < numChildren; childIndex++) {
aNodeList->Item(childIndex, getter_AddRefs(childNode));
nsCOMPtr<nsIContent> content = do_QueryInterface(childNode);
if (content && content->NodeInfo()->Equals(aAtom, kNameSpaceID_XUL)) {
nsIDOMNode *matchNode = childNode;
NS_ADDREF(matchNode);
return matchNode;
}
}
return nsnull;
}
void nsXULMenupopupAccessible::GenerateMenu(nsIDOMNode *aNode)
{
// Set menugenerated="true" on the menupopup node to generate the
// sub-menu items if they have not been generated
nsCOMPtr<nsIDOMNodeList> nodeList;
aNode->GetChildNodes(getter_AddRefs(nodeList));
nsCOMPtr<nsIDOMNode> menuPopup = FindInNodeList(nodeList, nsAccessibilityAtoms::menupopup,
kNameSpaceID_XUL);
nsCOMPtr<nsIDOMElement> popupElement(do_QueryInterface(menuPopup));
if (popupElement) {
nsAutoString attr;
popupElement->GetAttribute(NS_LITERAL_STRING("menugenerated"), attr);
if (!attr.EqualsLiteral("true")) {
popupElement->SetAttribute(NS_LITERAL_STRING("menugenerated"), NS_LITERAL_STRING("true"));
}
}
}
nsresult
nsXULMenupopupAccessible::GetNameInternal(nsAString& aName)
{
@ -704,15 +664,23 @@ nsXULMenupopupAccessible::GetRoleInternal(PRUint32 *aRole)
nsCOMPtr<nsIAccessible> parent;
GetParent(getter_AddRefs(parent));
if (parent) {
// Some widgets like the search bar have several popups, owned by buttons
PRUint32 role = nsAccUtils::Role(parent);
if (role == nsIAccessibleRole::ROLE_COMBOBOX ||
role == nsIAccessibleRole::ROLE_PUSHBUTTON ||
role == nsIAccessibleRole::ROLE_AUTOCOMPLETE) {
*aRole = nsIAccessibleRole::ROLE_COMBOBOX_LIST;
return NS_OK;
} else if (role == nsIAccessibleRole::ROLE_PUSHBUTTON) {
// Some widgets like the search bar have several popups, owned by buttons.
nsCOMPtr<nsIAccessible> grandParent;
parent->GetParent(getter_AddRefs(grandParent));
if (role == nsIAccessibleRole::ROLE_AUTOCOMPLETE) {
*aRole = nsIAccessibleRole::ROLE_COMBOBOX_LIST;
return NS_OK;
}
}
}
*aRole = nsIAccessibleRole::ROLE_MENUPOPUP;
return NS_OK;
}

View File

@ -113,6 +113,10 @@ public:
virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
};
/**
* Used for XUL menupopup and panel.
*/
class nsXULMenupopupAccessible : public nsXULSelectableAccessible
{
public:
@ -122,11 +126,6 @@ public:
virtual nsresult GetNameInternal(nsAString& aName);
virtual nsresult GetRoleInternal(PRUint32 *aRole);
virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
// nsXULMenupopupAccessible
static already_AddRefed<nsIDOMNode> FindInNodeList(nsIDOMNodeList *aNodeList,
nsIAtom *aAtom, PRUint32 aNameSpaceID);
static void GenerateMenu(nsIDOMNode *aNode);
};
class nsXULMenubarAccessible : public nsAccessibleWrap

View File

@ -42,6 +42,8 @@ srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = accessible
DIRS = tree
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
@ -88,13 +90,9 @@ _TEST_FILES =\
$(warning test_childAtPoint.xul temporarily disabled) \
test_cssattrs.html \
test_descr.html \
test_elm_filectrl.html \
test_elm_listbox.xul \
$(warning test_elm_media.html temporarily disabled) \
test_elm_plugin.html \
test_elm_select.html \
test_elm_tree.xul \
test_elm_txtcntnr.html \
test_events_caretmove.html \
test_events_coalescence.html \
test_events_doc.html \

View File

@ -4,6 +4,8 @@
const ROLE_ALERT = nsIAccessibleRole.ROLE_ALERT;
const ROLE_APPLICATION = nsIAccessibleRole.ROLE_APPLICATION;
const ROLE_APP_ROOT = nsIAccessibleRole.ROLE_APP_ROOT;
const ROLE_AUTOCOMPLETE = nsIAccessibleRole.ROLE_AUTOCOMPLETE;
const ROLE_BUTTONDROPDOWNGRID = nsIAccessibleRole.ROLE_BUTTONDROPDOWNGRID;
const ROLE_CAPTION = nsIAccessibleRole.ROLE_CAPTION;
const ROLE_CELL = nsIAccessibleRole.ROLE_CELL;
const ROLE_CHROME_WINDOW = nsIAccessibleRole.ROLE_CHROME_WINDOW;
@ -27,11 +29,14 @@ const ROLE_LINK = nsIAccessibleRole.ROLE_LINK;
const ROLE_LIST = nsIAccessibleRole.ROLE_LIST;
const ROLE_LISTBOX = nsIAccessibleRole.ROLE_LISTBOX;
const ROLE_LISTITEM = nsIAccessibleRole.ROLE_LISTITEM;
const ROLE_MENUITEM = nsIAccessibleRole.ROLE_MENUITEM;
const ROLE_MENUPOPUP = nsIAccessibleRole.ROLE_MENUPOPUP;
const ROLE_NOTHING = nsIAccessibleRole.ROLE_NOTHING;
const ROLE_OPTION = nsIAccessibleRole.ROLE_OPTION;
const ROLE_OUTLINE = nsIAccessibleRole.ROLE_OUTLINE;
const ROLE_OUTLINEITEM = nsIAccessibleRole.ROLE_OUTLINEITEM;
const ROLE_PARAGRAPH = nsIAccessibleRole.ROLE_PARAGRAPH;
const ROLE_PARENT_MENUITEM = nsIAccessibleRole.ROLE_PARENT_MENUITEM;
const ROLE_PASSWORD_TEXT = nsIAccessibleRole.ROLE_PASSWORD_TEXT;
const ROLE_PROGRESSBAR = nsIAccessibleRole.ROLE_PROGRESSBAR;
const ROLE_PUSHBUTTON = nsIAccessibleRole.ROLE_PUSHBUTTON;

View File

@ -0,0 +1,61 @@
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2009
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Alexander Surkov <surkov.alexander@gmail.com> (original author)
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = accessible/tree
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TEST_FILES =\
test_button.xul \
test_colorpicker.xul \
test_combobox.xul \
test_filectrl.html \
test_media.html \
test_menu.xul \
test_select.html \
test_tree.xul \
test_txtctrl.html \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)

View File

@ -0,0 +1,198 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="Accessible XUL button hierarchy tests">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/common.js" />
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/role.js" />
<script type="application/javascript">
<![CDATA[
////////////////////////////////////////////////////////////////////////////
// Test
function doTest()
{
//////////////////////////////////////////////////////////////////////////
// button1
var accTree = {
role: ROLE_PUSHBUTTON,
name: "hello",
children: [ ]
};
testAccessibleTree("button1", accTree);
//////////////////////////////////////////////////////////////////////////
// button2
accTree = {
role: ROLE_PUSHBUTTON,
name: "hello",
children: [
{
role: ROLE_MENUPOPUP,
children: [
{
role: ROLE_MENUITEM
},
{
role: ROLE_MENUITEM
}
]
}
]
};
testAccessibleTree("button2", accTree);
//////////////////////////////////////////////////////////////////////////
// button3
accTree = {
role: ROLE_PUSHBUTTON,
name: "hello",
children: [
{
role: ROLE_MENUPOPUP,
children: [
{
role: ROLE_MENUITEM
},
{
role: ROLE_MENUITEM
}
]
},
{
role: ROLE_PUSHBUTTON,
children: [
]
}
]
};
testAccessibleTree("button3", accTree);
//////////////////////////////////////////////////////////////////////////
// button4
var accTree = {
role: ROLE_PUSHBUTTON,
name: "hello",
children: [ ]
};
testAccessibleTree("button4", accTree);
//////////////////////////////////////////////////////////////////////////
// button5
accTree = {
role: ROLE_PUSHBUTTON,
name: "hello",
children: [
{
role: ROLE_MENUPOPUP,
children: [
{
role: ROLE_MENUITEM
},
{
role: ROLE_MENUITEM
}
]
}
]
};
testAccessibleTree("button5", accTree);
//////////////////////////////////////////////////////////////////////////
// button6
accTree = {
role: ROLE_PUSHBUTTON,
name: "hello",
children: [
{
role: ROLE_MENUPOPUP,
children: [
{
role: ROLE_MENUITEM
},
{
role: ROLE_MENUITEM
}
]
},
{
role: ROLE_PUSHBUTTON,
children: [
]
}
]
};
testAccessibleTree("button6", accTree);
SimpleTest.finish()
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
]]>
</script>
<hbox flex="1" style="overflow: auto;">
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=249292"
title="Ensure accessible children for toolbarbutton types 'menu' and 'menu-button'">
Mozilla Bug 249292
</a><br/>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
<vbox flex="1">
<button id="button1" label="hello"/>
<button id="button2" type="menu" label="hello">
<menupopup>
<menuitem label="menuitem"/>
<menuitem label="menuitem"/>
</menupopup>
</button>
<button id="button3" type="menu-button" label="hello">
<menupopup>
<menuitem label="menuitem"/>
<menuitem label="menuitem"/>
</menupopup>
</button>
<toolbarbutton id="button4" label="hello"/>
<toolbarbutton id="button5" type="menu" label="hello">
<menupopup>
<menuitem label="menuitem"/>
<menuitem label="menuitem"/>
</menupopup>
</toolbarbutton>
<toolbarbutton id="button6" type="menu-button" label="hello">
<menupopup>
<menuitem label="menuitem"/>
<menuitem label="menuitem"/>
</menupopup>
</toolbarbutton>
</vbox>
</hbox>
</window>

View File

@ -0,0 +1,75 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="Accessible XUL button hierarchy tests">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/common.js" />
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/role.js" />
<script type="application/javascript">
<![CDATA[
////////////////////////////////////////////////////////////////////////////
// Test
function doTest()
{
//////////////////////////////////////////////////////////////////////////
// button1
var accTree = {
role: ROLE_BUTTONDROPDOWNGRID,
children: [
{
role: ROLE_ALERT,
children: [ ]
}
]
};
var colorButtons = accTree.children[0].children;
for (var idx = 0; idx < 70; idx++) {
var obj = { role: ROLE_PUSHBUTTON };
colorButtons.push(obj);
}
testAccessibleTree("colorpicker", accTree);
SimpleTest.finish()
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
]]>
</script>
<hbox flex="1" style="overflow: auto;">
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=249292"
title="Ensure accessible children for toolbarbutton types 'menu' and 'menu-button'">
Mozilla Bug 249292
</a><br/>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
<vbox flex="1">
<colorpicker id="colorpicker" type="button"/>
</vbox>
</hbox>
</window>

View File

@ -0,0 +1,138 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="Accessible XUL menulist and textbox @autocomplete hierarchy tests">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/common.js" />
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/role.js" />
<script type="application/javascript">
<![CDATA[
////////////////////////////////////////////////////////////////////////////
// Test
function doTest()
{
//////////////////////////////////////////////////////////////////////////
// menulist
var accTree = {
role: ROLE_COMBOBOX,
children: [
{
role: ROLE_COMBOBOX_LIST,
children: [
{
role: ROLE_COMBOBOX_OPTION
},
{
role: ROLE_COMBOBOX_OPTION
}
]
}
]
};
testAccessibleTree("menulist", accTree);
//////////////////////////////////////////////////////////////////////////
// textbox@type=autocomplete #1 (history)
accTree = {
role: ROLE_AUTOCOMPLETE,
children: [
{
role: ROLE_ENTRY,
children: [
{
role: ROLE_TEXT_LEAF
}
]
},
{
role: ROLE_COMBOBOX_LIST, // context menu popup
children: [ ]
}
]
};
testAccessibleTree("autocomplete", accTree);
//////////////////////////////////////////////////////////////////////////
// textbox@type=autocomplete #2 (child menupoup)
accTree = {
role: ROLE_AUTOCOMPLETE,
children: [
{
role: ROLE_COMBOBOX_LIST, // autocomplete menu popup
children: [
{
role: ROLE_COMBOBOX_OPTION
}
]
},
{
role: ROLE_ENTRY,
children: [ ]
},
{
role: ROLE_COMBOBOX_LIST, // context menu popup
children: [ ]
}
]
};
testAccessibleTree("autocomplete2", accTree);
SimpleTest.finish()
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
]]>
</script>
<hbox flex="1" style="overflow: auto;">
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=249292"
title="Ensure accessible children for toolbarbutton types 'menu' and 'menu-button'">
Mozilla Bug 249292
</a><br/>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
<vbox flex="1">
<menulist id="menulist">
<menupopup>
<menuitem label="item"/>
<menuitem label="item"/>
</menupopup>
</menulist>
<textbox id="autocomplete" type="autocomplete"
autocompletesearch="history"
value="http://localhost:8888/redirect-a11y.html"/>
<textbox id="autocomplete2" type="autocomplete">
<menupopup>
<menuitem label="item1"/>
</menupopup>
</textbox>
</vbox>
</hbox>
</window>

View File

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=483573
-->
<head>
<title>HTML5 audio/video tests</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/common.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/role.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/states.js"></script>
<script type="application/javascript">
function doTest()
{
//////////////////////////////////////////////////////////////////////////
// test the accessible tree
var accTree = {
role: ROLE_GROUPING,
children: [
{ // start/stop button
role: ROLE_PUSHBUTTON
},
{ // buffer bar
role: ROLE_PROGRESSBAR
},
{ // progress bar
role: ROLE_PROGRESSBAR
},
{ // slider of progress bar
role: ROLE_SLIDER
},
{ // mute button
role: ROLE_PUSHBUTTON
}
]
};
testAccessibleTree("audio", accTree);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
title="Expose HTML5 video and audio elements' embedded controls through accessibility APIs"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=483573">Mozilla Bug 483573</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<audio id="audio" src="chrome://mochikit/content/a11y/accessible/bug461281.ogg"
controls="true"></audio>
<div id="eventDump"></div>
</body>
</html>

View File

@ -0,0 +1,78 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="Accessible XUL menu hierarchy tests">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/common.js" />
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/role.js" />
<script type="application/javascript">
<![CDATA[
////////////////////////////////////////////////////////////////////////////
// Test
function doTest()
{
var accTree = {
role: ROLE_PARENT_MENUITEM,
name: "menu",
children: [
{
role: ROLE_MENUPOPUP,
children: [
{
role: ROLE_MENUITEM
},
{
role: ROLE_MENUITEM
}
]
}
]
};
testAccessibleTree("menu", accTree);
SimpleTest.finish()
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
]]>
</script>
<hbox flex="1" style="overflow: auto;">
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=249292"
title="Ensure accessible children for toolbarbutton types 'menu' and 'menu-button'">
Mozilla Bug 249292
</a><br/>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
<vbox flex="1">
<menu id="menu" label="menu">
<menupopup>
<menuitem label="menuitem"/>
<menuitem label="menuitem"/>
</menupopup>
</menu>
</vbox>
</hbox>
</window>