From 4b182e53ccb4dda3ba1c5f28a56d96a356d31e16 Mon Sep 17 00:00:00 2001 From: "aaronleventhal@moonset.net" Date: Mon, 24 Sep 2007 18:19:03 -0700 Subject: [PATCH] Bug 396632. Don't require namespaces when using ARIA properties in text/html --- accessible/public/nsIAccessibleDocument.idl | 25 +- accessible/src/base/nsARIAMap.cpp | 205 +++++----- accessible/src/base/nsARIAMap.h | 11 +- accessible/src/base/nsARIAPropertyList.h | 74 ++++ accessible/src/base/nsAccessibilityAtomList.h | 46 +-- .../src/base/nsAccessibilityService.cpp | 50 ++- accessible/src/base/nsAccessibilityService.h | 10 + accessible/src/base/nsAccessibilityUtils.cpp | 226 +++++++++++ accessible/src/base/nsAccessibilityUtils.h | 88 +++++ accessible/src/base/nsAccessible.cpp | 352 ++++++------------ accessible/src/base/nsAccessible.h | 66 +--- accessible/src/base/nsDocAccessible.cpp | 56 ++- accessible/src/base/nsDocAccessible.h | 1 + accessible/src/base/nsRootAccessible.cpp | 8 +- accessible/src/xforms/nsXFormsAccessible.cpp | 5 +- .../xforms/nsXFormsFormControlsAccessible.cpp | 5 +- 16 files changed, 764 insertions(+), 464 deletions(-) create mode 100644 accessible/src/base/nsARIAPropertyList.h diff --git a/accessible/public/nsIAccessibleDocument.idl b/accessible/public/nsIAccessibleDocument.idl index 4582d6427d3..7227d3af509 100644 --- a/accessible/public/nsIAccessibleDocument.idl +++ b/accessible/public/nsIAccessibleDocument.idl @@ -58,7 +58,7 @@ interface nsIDOMWindow; * * @status UNDER_REVIEW */ -[scriptable, uuid(6cc11286-e02d-4a8d-960a-e7a61161b230)] +[scriptable, uuid(d118c0e9-b5e7-4671-854a-65b4713d9552)] interface nsIAccessibleDocument : nsISupports { /** @@ -121,4 +121,27 @@ interface nsIAccessibleDocument : nsISupports * to the document root. */ nsIAccessible getAccessibleInParentChain(in nsIDOMNode aDOMNode); + + /** + * A bit flag representing the type of ARIA properties which should be + * checked in this document: + * either eUnknownPropType, eCheckNamespaced, eCheckHyphenated or eCheckAny + */ + readonly attribute unsigned long ariaPropTypes; + + /** + * Check attributes in the form of: + * [someprefix]:[propname] (e.g. aria:live) where ancestor defines: + * xmlns:[someprefix]="http://www.w3.org/2005/07/aaa" + */ + const unsigned long eCheckNamespaced = 1; + + /** + * Check hyphenated attributes in the form of aria-[propname]. + * This is the default in text/html documents. + * Can be combined with eCheckNamespaced flag. This may + * change during the life of the document, if setAttributeNS() + * is used to set an ARIA property. + */ + const unsigned long eCheckHyphenated = 2; }; diff --git a/accessible/src/base/nsARIAMap.cpp b/accessible/src/base/nsARIAMap.cpp index 66d93071ddb..14936905f78 100644 --- a/accessible/src/base/nsARIAMap.cpp +++ b/accessible/src/base/nsARIAMap.cpp @@ -41,15 +41,26 @@ #include "nsIAccessibleRole.h" #include "nsIAccessibleStates.h" +#define ARIA_PROPERTY(atom) &nsAccessibilityAtoms::##atom, +nsIAtom** nsARIAMap::gAriaAtomPtrsNS[eAria_none] = { +#include "nsAriaPropertyList.h" +}; +#undef ARIA_PROPERTY + +#define ARIA_PROPERTY(atom) &nsAccessibilityAtoms::aria_##atom, +nsIAtom** nsARIAMap::gAriaAtomPtrsHyphenated[eAria_none] = { +#include "nsAriaPropertyList.h" +}; +#undef ARIA_PROPERTY + /** * This list of WAI-defined roles are currently hardcoded. * Eventually we will most likely be loading an RDF resource that contains this information * Using RDF will also allow for role extensibility. See bug 280138. * - * XXX Should we store attribute names in this table as atoms instead of strings? * Definition of nsRoleMapEntry and nsStateMapEntry contains comments explaining this table. * - * When no nsIAccessibleRole neum mapping exists for an ARIA role, the + * When no nsIAccessibleRole enum mapping exists for an ARIA role, the * role will be exposed via the object attribute "xml-roles". * In addition, in MSAA, the unmapped role will also be exposed as a BSTR string role. * @@ -57,7 +68,7 @@ * banner, contentinfo, main, navigation, note, search, secondary, seealso, breadcrumbs */ -static const nsStateMapEntry kEndEntry = {0, 0, 0}; // To fill in array of state mappings +static const nsStateMapEntry kEndEntry = {eAria_none, 0, 0}; // To fill in array of state mappings nsRoleMapEntry nsARIAMap::gWAIRoleMap[] = { @@ -65,141 +76,141 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] = {"alertdialog", nsIAccessibleRole::ROLE_ALERT, eNameOkFromChildren, eNoValue, kNoReqStates, kEndEntry}, {"application", nsIAccessibleRole::ROLE_APPLICATION, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry}, {"button", nsIAccessibleRole::ROLE_PUSHBUTTON, eNameOkFromChildren, eNoValue, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"pressed", kBoolState, nsIAccessibleStates::STATE_PRESSED}, - {"pressed", "mixed", nsIAccessibleStates::STATE_MIXED}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_pressed, kBoolState, nsIAccessibleStates::STATE_PRESSED}, + {eAria_pressed, "mixed", nsIAccessibleStates::STATE_MIXED}, kEndEntry}, {"checkbox", nsIAccessibleRole::ROLE_CHECKBUTTON, eNameOkFromChildren, eNoValue, nsIAccessibleStates::STATE_CHECKABLE, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"checked", kBoolState, nsIAccessibleStates::STATE_CHECKED}, - {"checked", "mixed", nsIAccessibleStates::STATE_MIXED}, - {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED}, + {eAria_checked, "mixed", nsIAccessibleStates::STATE_MIXED}, + {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry}, {"columnheader", nsIAccessibleRole::ROLE_COLUMNHEADER, eNameOkFromChildren, eNoValue, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"selected", kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE}, - {"selected", "false", nsIAccessibleStates::STATE_SELECTABLE}, - {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE}, + {eAria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE}, + {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry}, {"combobox", nsIAccessibleRole::ROLE_COMBOBOX, eNameLabelOrTitle, eHasValueMinMax, nsIAccessibleStates::STATE_COLLAPSED | nsIAccessibleStates::STATE_HASPOPUP, // Manually map EXT_STATE_SUPPORTS_AUTOCOMPLETION aaa:autocomplete - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, - {"expanded", kBoolState, nsIAccessibleStates::STATE_EXPANDED}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, + {eAria_expanded, kBoolState, nsIAccessibleStates::STATE_EXPANDED}, kEndEntry}, {"description", nsIAccessibleRole::ROLE_TEXT_CONTAINER, eNameOkFromChildren, eNoValue, kNoReqStates, kEndEntry}, {"dialog", nsIAccessibleRole::ROLE_DIALOG, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry}, {"document", nsIAccessibleRole::ROLE_DOCUMENT, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry}, {"grid", nsIAccessibleRole::ROLE_TABLE, eNameLabelOrTitle, eNoValue, nsIAccessibleStates::STATE_FOCUSABLE, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"multiselectable", kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, - {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, + {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry}, {"gridcell", nsIAccessibleRole::ROLE_CELL, eNameOkFromChildren, eNoValue, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"expanded", kBoolState, nsIAccessibleStates::STATE_EXPANDED}, - {"expanded", "false", nsIAccessibleStates::STATE_COLLAPSED}, - {"selected", kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE}, - {"selected", "false", nsIAccessibleStates::STATE_SELECTABLE}, - {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_expanded, kBoolState, nsIAccessibleStates::STATE_EXPANDED}, + {eAria_expanded, "false", nsIAccessibleStates::STATE_COLLAPSED}, + {eAria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE}, + {eAria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE}, + {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry}, {"group", nsIAccessibleRole::ROLE_GROUPING, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry}, {"heading", nsIAccessibleRole::ROLE_HEADING, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry}, {"img", nsIAccessibleRole::ROLE_GRAPHIC, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry}, {"label", nsIAccessibleRole::ROLE_LABEL, eNameOkFromChildren, eNoValue, kNoReqStates, kEndEntry}, {"link", nsIAccessibleRole::ROLE_LINK, eNameOkFromChildren, eNoValue, nsIAccessibleStates::STATE_LINKED, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry}, {"list", nsIAccessibleRole::ROLE_LIST, eNameLabelOrTitle, eNoValue, kNoReqStates, - {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, - {"multiselectable", kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry}, + {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, + {eAria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry}, {"listbox", nsIAccessibleRole::ROLE_LIST, eNameLabelOrTitle, eNoValue, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, - {"multiselectable", kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, + {eAria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry}, {"listitem", nsIAccessibleRole::ROLE_LISTITEM, eNameOkFromChildren, eNoValue, kNoReqStates, - {"selected", kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE}, - {"selected", "false", nsIAccessibleStates::STATE_SELECTABLE}, - {"checked", kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE}, - {"checked", "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE}, - {"checked", "false", nsIAccessibleStates::STATE_CHECKABLE}, kEndEntry}, + {eAria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE}, + {eAria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE}, + {eAria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE}, + {eAria_checked, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE}, + {eAria_checked, "false", nsIAccessibleStates::STATE_CHECKABLE}, kEndEntry}, {"menu", nsIAccessibleRole::ROLE_MENUPOPUP, eNameLabelOrTitle, eNoValue, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry}, {"menubar", nsIAccessibleRole::ROLE_MENUBAR, eNameLabelOrTitle, eNoValue, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry}, {"menuitem", nsIAccessibleRole::ROLE_MENUITEM, eNameOkFromChildren, eNoValue, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"checked", kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE}, - {"checked", "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE}, - {"checked", "false", nsIAccessibleStates::STATE_CHECKABLE}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE}, + {eAria_checked, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE}, + {eAria_checked, "false", nsIAccessibleStates::STATE_CHECKABLE}, kEndEntry}, {"menuitemcheckbox", nsIAccessibleRole::ROLE_CHECK_MENU_ITEM, eNameOkFromChildren, eNoValue, nsIAccessibleStates::STATE_CHECKABLE, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"checked", kBoolState, nsIAccessibleStates::STATE_CHECKED }, - {"checked", "mixed", nsIAccessibleStates::STATE_MIXED}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED }, + {eAria_checked, "mixed", nsIAccessibleStates::STATE_MIXED}, kEndEntry}, {"menuitemradio", nsIAccessibleRole::ROLE_RADIO_MENU_ITEM, eNameOkFromChildren, eNoValue, nsIAccessibleStates::STATE_CHECKABLE, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"checked", kBoolState, nsIAccessibleStates::STATE_CHECKED }, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED }, kEndEntry}, {"option", nsIAccessibleRole::ROLE_LISTITEM, eNameOkFromChildren, eNoValue, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"selected", kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE}, - {"selected", "false", nsIAccessibleStates::STATE_SELECTABLE}, - {"checked", kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE}, - {"checked", "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE}, - {"checked", "false", nsIAccessibleStates::STATE_CHECKABLE}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE}, + {eAria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE}, + {eAria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE}, + {eAria_checked, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE}, + {eAria_checked, "false", nsIAccessibleStates::STATE_CHECKABLE}, kEndEntry}, {"progressbar", nsIAccessibleRole::ROLE_PROGRESSBAR, eNameLabelOrTitle, eHasValueMinMax, nsIAccessibleStates::STATE_READONLY, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry}, {"radio", nsIAccessibleRole::ROLE_RADIOBUTTON, eNameOkFromChildren, eNoValue, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"checked", kBoolState, nsIAccessibleStates::STATE_CHECKED}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED}, kEndEntry}, {"radiogroup", nsIAccessibleRole::ROLE_GROUPING, eNameLabelOrTitle, eNoValue, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry}, {"region", nsIAccessibleRole::ROLE_PANE, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry}, {"row", nsIAccessibleRole::ROLE_ROW, eNameOkFromChildren, eNoValue, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"selected", kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE}, - {"selected", "false", nsIAccessibleStates::STATE_SELECTABLE}, - {"expanded", kBoolState, nsIAccessibleStates::STATE_EXPANDED}, - {"expanded", "false", nsIAccessibleStates::STATE_COLLAPSED}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE}, + {eAria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE}, + {eAria_expanded, kBoolState, nsIAccessibleStates::STATE_EXPANDED}, + {eAria_expanded, "false", nsIAccessibleStates::STATE_COLLAPSED}, kEndEntry}, {"rowheader", nsIAccessibleRole::ROLE_ROWHEADER, eNameOkFromChildren, eNoValue, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"selected", kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE}, - {"selected", "false", nsIAccessibleStates::STATE_SELECTABLE}, - {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE}, + {eAria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE}, + {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry}, {"section", nsIAccessibleRole::ROLE_SECTION, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry}, {"separator", nsIAccessibleRole::ROLE_SEPARATOR, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry}, {"slider", nsIAccessibleRole::ROLE_SLIDER, eNameLabelOrTitle, eHasValueMinMax, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry}, {"spinbutton", nsIAccessibleRole::ROLE_SPINBUTTON, eNameLabelOrTitle, eHasValueMinMax, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry}, {"status", nsIAccessibleRole::ROLE_STATUSBAR, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry}, {"tab", nsIAccessibleRole::ROLE_PAGETAB, eNameOkFromChildren, eNoValue, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry}, {"tablist", nsIAccessibleRole::ROLE_PAGETABLIST, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry}, {"tabpanel", nsIAccessibleRole::ROLE_PROPERTYPAGE, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry}, {"textbox", nsIAccessibleRole::ROLE_ENTRY, eNameLabelOrTitle, eNoValue, kNoReqStates, // Manually map EXT_STATE_SINGLE_LINE and EXT_STATE_MULTI_LINE FROM aaa:multiline // Manually map EXT_STATE_SUPPORTS_AUTOCOMPLETION aaa:autocomplete - {"autocomplete", "list", nsIAccessibleStates::STATE_HASPOPUP}, - {"autocomplete", "both", nsIAccessibleStates::STATE_HASPOPUP}, - {"secret", kBoolState, nsIAccessibleStates::STATE_PROTECTED}, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry}, + {eAria_autocomplete, "list", nsIAccessibleStates::STATE_HASPOPUP}, + {eAria_autocomplete, "both", nsIAccessibleStates::STATE_HASPOPUP}, + {eAria_secret, kBoolState, nsIAccessibleStates::STATE_PROTECTED}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry}, {"toolbar", nsIAccessibleRole::ROLE_TOOLBAR, eNameLabelOrTitle, eNoValue, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry}, {"tooltip", nsIAccessibleRole::ROLE_TOOLTIP, eNameOkFromChildren, eNoValue, kNoReqStates, kEndEntry}, {"tree", nsIAccessibleRole::ROLE_OUTLINE, eNameLabelOrTitle, eNoValue, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, - {"multiselectable", kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, + {eAria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry}, {"treegrid", nsIAccessibleRole::ROLE_TREE_TABLE, eNameLabelOrTitle, eNoValue, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, - {"multiselectable", kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY}, + {eAria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE}, kEndEntry}, {"treeitem", nsIAccessibleRole::ROLE_OUTLINEITEM, eNameOkFromChildren, eNoValue, kNoReqStates, - {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, - {"selected", kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE}, - {"selected", "false", nsIAccessibleStates::STATE_SELECTABLE}, - {"expanded", kBoolState, nsIAccessibleStates::STATE_EXPANDED}, - {"expanded", "false", nsIAccessibleStates::STATE_COLLAPSED}, - {"checked", kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE}, - {"checked", "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE}, - {"checked", "false", nsIAccessibleStates::STATE_CHECKABLE},}, + {eAria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, + {eAria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE}, + {eAria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE}, + {eAria_expanded, kBoolState, nsIAccessibleStates::STATE_EXPANDED}, + {eAria_expanded, "false", nsIAccessibleStates::STATE_COLLAPSED}, + {eAria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE}, + {eAria_checked, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE}, + {eAria_checked, "false", nsIAccessibleStates::STATE_CHECKABLE},}, {nsnull, nsIAccessibleRole::ROLE_NOTHING, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry} // Last item }; @@ -209,11 +220,11 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] = * whether there is an ARIA role or not: */ nsStateMapEntry nsARIAMap::gWAIUnivStateMap[] = { - {"required", kBoolState, nsIAccessibleStates::STATE_REQUIRED}, - {"invalid", kBoolState, nsIAccessibleStates::STATE_INVALID}, - {"haspopup", kBoolState, nsIAccessibleStates::STATE_HASPOPUP}, - {"busy", "true", nsIAccessibleStates::STATE_BUSY}, - {"busy", "error", nsIAccessibleStates::STATE_INVALID}, + {eAria_required, kBoolState, nsIAccessibleStates::STATE_REQUIRED}, + {eAria_invalid, kBoolState, nsIAccessibleStates::STATE_INVALID}, + {eAria_haspopup, kBoolState, nsIAccessibleStates::STATE_HASPOPUP}, + {eAria_busy, "true", nsIAccessibleStates::STATE_BUSY}, + {eAria_busy, "error", nsIAccessibleStates::STATE_INVALID}, kEndEntry }; diff --git a/accessible/src/base/nsARIAMap.h b/accessible/src/base/nsARIAMap.h index b03a222ca26..ada01812ace 100644 --- a/accessible/src/base/nsARIAMap.h +++ b/accessible/src/base/nsARIAMap.h @@ -41,6 +41,13 @@ #define _nsARIAMap_H_ #include "prtypes.h" +#include "nsAccessibilityAtoms.h" + +#define ARIA_PROPERTY(atom) eAria_##atom, +enum EAriaProperty { +#include "nsAriaPropertyList.h" + eAria_none }; +#undef ARIA_PROPERTY // Name mapping rule: can the name be computed from descendants? enum ENameRule @@ -79,7 +86,7 @@ enum EValueRule // nsStateMapEntry.state struct nsStateMapEntry { - const char* attributeName; // magic value of nsnull means last entry in map + EAriaProperty attributeName; // eARIA_none indicates last entry in map const char* attributeValue; // magic value of kBoolState (0) means supports "true" and "false" PRUint32 state; // If match, this is the nsIAccessibleStates to map to }; @@ -124,6 +131,8 @@ struct nsRoleMapEntry */ struct nsARIAMap { + static nsIAtom** gAriaAtomPtrsNS[eAria_none]; + static nsIAtom** gAriaAtomPtrsHyphenated[eAria_none]; static nsRoleMapEntry gWAIRoleMap[]; static nsStateMapEntry gWAIUnivStateMap[]; }; diff --git a/accessible/src/base/nsARIAPropertyList.h b/accessible/src/base/nsARIAPropertyList.h new file mode 100644 index 00000000000..e5391f12352 --- /dev/null +++ b/accessible/src/base/nsARIAPropertyList.h @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* ***** 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 IBM Corporation + * Portions created by the Initial Developer are Copyright (C)2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Aaron Leventhal + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + + // ARIA properties +ARIA_PROPERTY(activedescendant) +ARIA_PROPERTY(atomic) +ARIA_PROPERTY(autocomplete) +ARIA_PROPERTY(busy) +ARIA_PROPERTY(channel) +ARIA_PROPERTY(checked) +ARIA_PROPERTY(controls) +ARIA_PROPERTY(datatype) +ARIA_PROPERTY(describedby) +ARIA_PROPERTY(disabled) +ARIA_PROPERTY(dropeffect) +ARIA_PROPERTY(expanded) +ARIA_PROPERTY(flowto) +ARIA_PROPERTY(grab) +ARIA_PROPERTY(haspopup) +ARIA_PROPERTY(invalid) +ARIA_PROPERTY(labelledby) +ARIA_PROPERTY(level) +ARIA_PROPERTY(live) +ARIA_PROPERTY(multiline) +ARIA_PROPERTY(multiselectable) +ARIA_PROPERTY(owns) +ARIA_PROPERTY(posinset) +ARIA_PROPERTY(pressed) +ARIA_PROPERTY(readonly) +ARIA_PROPERTY(relevant) +ARIA_PROPERTY(required) +ARIA_PROPERTY(secret) +ARIA_PROPERTY(selected) +ARIA_PROPERTY(setsize) +ARIA_PROPERTY(sort) +ARIA_PROPERTY(valuenow) +ARIA_PROPERTY(valuemin) +ARIA_PROPERTY(valuemax) diff --git a/accessible/src/base/nsAccessibilityAtomList.h b/accessible/src/base/nsAccessibilityAtomList.h index aa4f8e4c636..48f0d37ec83 100755 --- a/accessible/src/base/nsAccessibilityAtomList.h +++ b/accessible/src/base/nsAccessibilityAtomList.h @@ -140,25 +140,16 @@ ACCESSIBILITY_ATOM(tooltip, "tooltip") // XUL ACCESSIBILITY_ATOM(tr, "tr") ACCESSIBILITY_ATOM(ul, "ul") - // DHTML accessibility relationship attributes -ACCESSIBILITY_ATOM(controls, "controls") -ACCESSIBILITY_ATOM(describedby, "describedby") -ACCESSIBILITY_ATOM(flowto, "flowto") -ACCESSIBILITY_ATOM(labelledby, "labelledby") -ACCESSIBILITY_ATOM(owns, "owns") - // Alphabetical list of attributes ACCESSIBILITY_ATOM(acceltext, "acceltext") ACCESSIBILITY_ATOM(accesskey, "accesskey") ACCESSIBILITY_ATOM(alt, "alt") ACCESSIBILITY_ATOM(anonid, "anonid") // Used for ID's in XBL -ACCESSIBILITY_ATOM(autocomplete, "autocomplete") // Used as attribute value too ACCESSIBILITY_ATOM(contenteditable, "contenteditable") ACCESSIBILITY_ATOM(control, "control") ACCESSIBILITY_ATOM(cycles, "cycles") // used for XUL cycler attribute ACCESSIBILITY_ATOM(curpos, "curpos") // XUL ACCESSIBILITY_ATOM(data, "data") -ACCESSIBILITY_ATOM(disabled, "disabled") ACCESSIBILITY_ATOM(droppable, "droppable") // XUL combo box ACCESSIBILITY_ATOM(editable, "editable") ACCESSIBILITY_ATOM(_for, "for") @@ -168,10 +159,8 @@ ACCESSIBILITY_ATOM(increment, "increment") // XUL ACCESSIBILITY_ATOM(lang, "lang") ACCESSIBILITY_ATOM(maxpos, "maxpos") // XUL ACCESSIBILITY_ATOM(minpos, "minpos") // XUL -ACCESSIBILITY_ATOM(multiline, "multiline") ACCESSIBILITY_ATOM(name, "name") ACCESSIBILITY_ATOM(onclick, "onclick") -ACCESSIBILITY_ATOM(readonly, "readonly") ACCESSIBILITY_ATOM(src, "src") ACCESSIBILITY_ATOM(summary, "summary") ACCESSIBILITY_ATOM(tabindex, "tabindex") @@ -181,31 +170,18 @@ ACCESSIBILITY_ATOM(type, "type") ACCESSIBILITY_ATOM(value, "value") // ARIA (DHTML accessibility) attributes -ACCESSIBILITY_ATOM(atomic, "atomic") -ACCESSIBILITY_ATOM(busy, "busy") -ACCESSIBILITY_ATOM(channel, "channel") -ACCESSIBILITY_ATOM(activedescendant, "activedescendant") -ACCESSIBILITY_ATOM(checked, "checked") -ACCESSIBILITY_ATOM(datatype, "datatype") -ACCESSIBILITY_ATOM(dropeffect, "dropeffect") -ACCESSIBILITY_ATOM(expanded, "expanded") -ACCESSIBILITY_ATOM(grab, "grab") -ACCESSIBILITY_ATOM(haspopup, "haspopup") -ACCESSIBILITY_ATOM(invalid, "invalid") -ACCESSIBILITY_ATOM(level, "level") -ACCESSIBILITY_ATOM(live, "live") -ACCESSIBILITY_ATOM(multiselectable, "multiselectable") -ACCESSIBILITY_ATOM(posinset, "posinset") -ACCESSIBILITY_ATOM(pressed, "pressed") -ACCESSIBILITY_ATOM(relevant, "relevant") -ACCESSIBILITY_ATOM(required, "required") + // Also add to nsARIAMap.cpp and nsARIAMap.h + // ARIA role attribute ACCESSIBILITY_ATOM(role, "role") -ACCESSIBILITY_ATOM(secret, "secret") -ACCESSIBILITY_ATOM(selected, "selected") -ACCESSIBILITY_ATOM(setsize, "setsize") -ACCESSIBILITY_ATOM(valuenow, "valuenow") // For DHTML widget values -ACCESSIBILITY_ATOM(valuemin, "valuemin") -ACCESSIBILITY_ATOM(valuemax, "valuemax") + + // ARIA properties +#define ARIA_PROPERTY(atom) ACCESSIBILITY_ATOM(atom, #atom) +#include "nsAriaPropertyList.h" +#undef ARIA_PROPERTY + +#define ARIA_PROPERTY(atom) ACCESSIBILITY_ATOM(aria_##atom, "aria-"#atom) +#include "nsAriaPropertyList.h" +#undef ARIA_PROPERTY // misc atoms // a form property used to obtain the default label diff --git a/accessible/src/base/nsAccessibilityService.cpp b/accessible/src/base/nsAccessibilityService.cpp index 63331bcf28b..be0ca1d2174 100644 --- a/accessible/src/base/nsAccessibilityService.cpp +++ b/accessible/src/base/nsAccessibilityService.cpp @@ -1431,22 +1431,7 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode, if (!newAcc && content->Tag() != nsAccessibilityAtoms::body && content->GetParent() && (content->IsFocusable() || (isHTML && nsAccUtils::HasListener(content, NS_LITERAL_STRING("click"))) || - content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::describedby) || - content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::labelledby) || - content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::flowto) || - content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::controls) || - content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::atomic) || - content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::busy) || - content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::channel) || - content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::datatype) || - content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::dropeffect) || - content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::grab) || - content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::haspopup) || - content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::live) || - content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::relevant) || - content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::required) || - content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::invalid) || - !role.IsEmpty())) { + HasUniversalAriaProperty(content, aWeakShell) || !role.IsEmpty())) { // This content is focusable or has an interesting dynamic content accessibility property. // If it's interesting we need it in the accessibility hierarchy so that events or // other accessibles can point to it, or so that it can hold a state, etc. @@ -1463,6 +1448,39 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode, return InitAccessible(newAcc, aAccessible); } +PRBool +nsAccessibilityService::HasUniversalAriaProperty(nsIContent *aContent, + nsIWeakReference *aWeakShell) +{ + nsCOMPtr docAccessible = + nsAccessNode::GetDocAccessibleFor(aWeakShell); + if (!docAccessible) { + return PR_FALSE; + } + + // Precalculate |ariaPropTypes| so that HasAriaProperty() doesn't have to do that each time + PRUint32 ariaPropTypes; + docAccessible->GetAriaPropTypes(&ariaPropTypes); + + return nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_atomic, ariaPropTypes) || + nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_busy, ariaPropTypes) || + nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_channel, ariaPropTypes) || + nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_controls, ariaPropTypes) || + nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_datatype, ariaPropTypes) || + nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_describedby, ariaPropTypes) || + nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_dropeffect, ariaPropTypes) || + nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_flowto, ariaPropTypes) || + nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_grab, ariaPropTypes) || + nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_haspopup, ariaPropTypes) || + nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_invalid, ariaPropTypes) || + nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_labelledby, ariaPropTypes) || + nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_live, ariaPropTypes) || + nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_owns, ariaPropTypes) || + nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_relevant, ariaPropTypes) || + nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_required, ariaPropTypes) || + nsAccUtils::HasAriaProperty(aContent, aWeakShell, eAria_sort, ariaPropTypes); +} + NS_IMETHODIMP nsAccessibilityService::GetRelevantContentNodeFor(nsIDOMNode *aNode, nsIDOMNode **aRelevantNode) diff --git a/accessible/src/base/nsAccessibilityService.h b/accessible/src/base/nsAccessibilityService.h index 341266c068d..42704ef2b27 100644 --- a/accessible/src/base/nsAccessibilityService.h +++ b/accessible/src/base/nsAccessibilityService.h @@ -119,6 +119,16 @@ private: nsIAccessible **aAccessible); static nsAccessibilityService *gAccessibilityService; + + /** + * Does this content node have a universal ARIA property set on it? + * A universal ARIA property is one that can be defined on any element even if there is no role. + * + * @param aContent The content node to test + * @param aWeakShell A weak reference to the pres shell + * @return PR_TRUE if there is a universal ARIA property set on the node + */ + PRBool HasUniversalAriaProperty(nsIContent *aContent, nsIWeakReference *aWeakShell); }; /** diff --git a/accessible/src/base/nsAccessibilityUtils.cpp b/accessible/src/base/nsAccessibilityUtils.cpp index 328ca9668a4..1ea88750254 100755 --- a/accessible/src/base/nsAccessibilityUtils.cpp +++ b/accessible/src/base/nsAccessibilityUtils.cpp @@ -42,10 +42,14 @@ #include "nsPIAccessible.h" #include "nsAccessibleEventData.h" +#include "nsAccessNode.h" +#include "nsARIAMap.h" #include "nsIDocument.h" #include "nsIDOMAbstractView.h" #include "nsIDOMDocument.h" #include "nsIDOMDocumentView.h" +#include "nsIDOMDocumentXBL.h" +#include "nsIDOMNodeList.h" #include "nsIDOMRange.h" #include "nsIDOMXULSelectCntrlEl.h" #include "nsIDOMXULSelectCntrlItemEl.h" @@ -410,3 +414,225 @@ nsAccUtils::GetID(nsIContent *aContent, nsAString& aID) nsIAtom *idAttribute = aContent->GetIDAttributeName(); return idAttribute ? aContent->GetAttr(kNameSpaceID_None, idAttribute, aID) : PR_FALSE; } + +PRUint32 +nsAccUtils::GetAriaPropTypes(nsIContent *aContent, nsIWeakReference *aWeakShell) +{ + NS_ENSURE_ARG_POINTER(aContent); + + PRUint32 ariaPropTypes = 0; + + // Get the doc accessible using the optimsal methodology + nsCOMPtr docAccessible; + if (aWeakShell) { + docAccessible = nsAccessNode::GetDocAccessibleFor(aWeakShell); + } + else { + nsCOMPtr node = do_QueryInterface(aContent); + if (node) { + docAccessible = nsAccessNode::GetDocAccessibleFor(node); + } + } + if (docAccessible) { + docAccessible->GetAriaPropTypes(&ariaPropTypes); + } + return ariaPropTypes; +} + +PRBool +nsAccUtils::HasAriaProperty(nsIContent *aContent, nsIWeakReference *aWeakShell, + EAriaProperty aProperty, PRUint32 aAriaPropTypes) +{ + if (!aAriaPropTypes) { + // The property types to check for is unknown, get it from the doc accessible + aAriaPropTypes = GetAriaPropTypes(aContent, aWeakShell); + } + + return ((aAriaPropTypes & nsIAccessibleDocument::eCheckNamespaced) && + aContent->HasAttr(kNameSpaceID_WAIProperties, + *nsARIAMap::gAriaAtomPtrsNS[aProperty])) || + ((aAriaPropTypes & nsIAccessibleDocument::eCheckHyphenated) && + aContent->HasAttr(kNameSpaceID_None, + *nsARIAMap::gAriaAtomPtrsHyphenated[aProperty])); +} + +PRBool +nsAccUtils::GetAriaProperty(nsIContent *aContent, nsIWeakReference *aWeakShell, + EAriaProperty aProperty, nsAString& aValue, + PRUint32 aAriaPropTypes) +{ + aValue.Truncate(); + if (!aAriaPropTypes) { + // The property types to check for is unknown, get it from the doc accessible + aAriaPropTypes = GetAriaPropTypes(aContent, aWeakShell); + } + return ((aAriaPropTypes & nsIAccessibleDocument::eCheckNamespaced) && + aContent->GetAttr(kNameSpaceID_WAIProperties, + *nsARIAMap::gAriaAtomPtrsNS[aProperty], + aValue)) || + ((aAriaPropTypes & nsIAccessibleDocument::eCheckHyphenated) && + aContent->GetAttr(kNameSpaceID_None, + *nsARIAMap::gAriaAtomPtrsHyphenated[aProperty], + aValue)); +} + +nsIContent* +nsAccUtils::FindNeighbourPointingToNode(nsIContent *aForNode, + EAriaProperty aAriaProperty, + nsIAtom *aTagName, + nsIAtom *aRelationAttr, + PRUint32 aAncestorLevelsToSearch) +{ + NS_ASSERTION(aAriaProperty == eAria_none || !aRelationAttr, + "Cannot pass in both an ARIA relation property and an atom relation. Choose one"); + NS_ASSERTION(aAriaProperty != eAria_none || !aTagName, + "Cannot use aTagName with ARIA relation property, because ARIA relations apply to any tag"); + nsCOMPtr binding; + nsAutoString controlID; + if (!nsAccUtils::GetID(aForNode, controlID)) { + binding = aForNode->GetBindingParent(); + if (binding == aForNode) + return nsnull; + + aForNode->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::anonid, controlID); + if (controlID.IsEmpty()) + return nsnull; + } + + // Look for label in subtrees of nearby ancestors + PRUint32 count = 0; + nsIContent *labelContent = nsnull; + nsIContent *prevSearched = nsnull; + + while (!labelContent && ++count <= aAncestorLevelsToSearch && + (aForNode = aForNode->GetParent()) != nsnull) { + + if (aForNode == binding) { + // When we reach the binding parent, make sure to check + // all of its anonymous child subtrees + nsCOMPtr doc = aForNode->GetCurrentDoc(); + nsCOMPtr xblDoc(do_QueryInterface(doc)); + if (!xblDoc) + return nsnull; + + nsCOMPtr nodes; + nsCOMPtr forElm(do_QueryInterface(aForNode)); + xblDoc->GetAnonymousNodes(forElm, getter_AddRefs(nodes)); + if (!nodes) + return nsnull; + + PRUint32 length; + nsresult rv = nodes->GetLength(&length); + if (NS_FAILED(rv)) + return nsnull; + + for (PRUint32 index = 0; index < length && !labelContent; index++) { + nsCOMPtr node; + rv = nodes->Item(index, getter_AddRefs(node)); + if (NS_FAILED(rv)) + return nsnull; + + nsCOMPtr content = do_QueryInterface(node); + if (!content) + return nsnull; + + if (content != prevSearched) { + labelContent = FindDescendantPointingToID(&controlID, content, aAriaProperty, + aRelationAttr, nsnull, aTagName); + } + } + break; + } + + labelContent = FindDescendantPointingToID(&controlID, aForNode, aAriaProperty, + aRelationAttr, prevSearched, aTagName); + prevSearched = aForNode; + } + + return labelContent; +} + +// Pass in aAriaProperty = null and aRelationAttr == nsnull if any