--- a/accessible/public/nsIAccessibleDocument.idl
+++ b/accessible/public/nsIAccessibleDocument.idl
@@ -53,17 +53,17 @@ interface nsIDOMWindow;
* You can QueryInterface to nsIAccessibleDocument from
* the nsIAccessible or nsIAccessNode for the root node
* of a document. You can also get one from
* nsIAccessNode::GetAccessibleDocument() or
* nsIAccessibleEvent::GetAccessibleDocument()
*
* @status UNDER_REVIEW
*/
-[scriptable, uuid(6cc11286-e02d-4a8d-960a-e7a61161b230)]
+[scriptable, uuid(d118c0e9-b5e7-4671-854a-65b4713d9552)]
interface nsIAccessibleDocument : nsISupports
{
/**
* The URL of the document
*/
readonly attribute AString URL;
/**
@@ -116,9 +116,32 @@ interface nsIAccessibleDocument : nsISup
* Guaranteed not to return nsnull if the DOM node is in a document.
* @param aDOMNode The DOM node we need an accessible for.
* @param aCanCreate Can accessibles be created or must it be the first
* cached accessible in the parent chain?
* @return An first nsIAccessible found by crawling up the DOM node
* 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;
};
--- a/accessible/src/base/nsARIAMap.cpp
+++ b/accessible/src/base/nsARIAMap.cpp
@@ -36,184 +36,195 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsARIAMap.h"
#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.
*
* There are no nsIAccessibleRole enums for the following landmark roles:
* 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[] =
{
{"alert", nsIAccessibleRole::ROLE_ALERT, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
{"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
};
/**
* Universal states:
* The following state rules are applied to any accessible element,
* 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
};
--- a/accessible/src/base/nsARIAMap.h
+++ b/accessible/src/base/nsARIAMap.h
@@ -36,16 +36,23 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef _nsARIAMap_H_
#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
{
// eNameLabelOrTitle:
// Collect name from:
// 1) The content subtrees pointed to by labelledby
// which contains the IDs for the label content, or if unspecified
@@ -74,17 +81,17 @@ enum EValueRule
// Used in nsRoleMapEntry.state if no nsIAccessibleStates are automatic for a given role
#define kNoReqStates 0
// For this name and value pair, what is the nsIAccessibleStates mapping.
// 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
};
// For each ARIA role, this maps the nsIAccessible information
struct nsRoleMapEntry
{
// ARIA role: string representation such as "button"
@@ -119,13 +126,15 @@ struct nsRoleMapEntry
/**
* These are currently initialized (hardcoded) in nsARIAMap.cpp,
* and provide the mappings for WAI-ARIA roles and properties using the
* structs defined in this file.
*/
struct nsARIAMap
{
+ static nsIAtom** gAriaAtomPtrsNS[eAria_none];
+ static nsIAtom** gAriaAtomPtrsHyphenated[eAria_none];
static nsRoleMapEntry gWAIRoleMap[];
static nsStateMapEntry gWAIUnivStateMap[];
};
#endif
new file mode 100644
--- /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 <aleventh@us.ibm.com>
+ *
+ * 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)
--- a/accessible/src/base/nsAccessibilityAtomList.h
+++ b/accessible/src/base/nsAccessibilityAtomList.h
@@ -135,79 +135,55 @@ ACCESSIBILITY_ATOM(textbox, "textbox")
ACCESSIBILITY_ATOM(toolbaritem, "toolbaritem") // XUL
ACCESSIBILITY_ATOM(toolbarseparator, "toolbarseparator") // XUL
ACCESSIBILITY_ATOM(toolbarspring, "toolbarspring") // XUL
ACCESSIBILITY_ATOM(toolbarspacer, "toolbarspacer") // XUL
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")
ACCESSIBILITY_ATOM(hidden, "hidden") // XUL tree columns
ACCESSIBILITY_ATOM(href, "href")
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")
ACCESSIBILITY_ATOM(title, "title")
ACCESSIBILITY_ATOM(tooltiptext, "tooltiptext")
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
// of an HTML button from the button frame
ACCESSIBILITY_ATOM(defaultLabel, "defaultLabel")
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -1426,48 +1426,66 @@ NS_IMETHODIMP nsAccessibilityService::Ge
// If no accessible, see if we need to create a generic accessible because
// of some property that makes this object interesting
// We don't do this for <body>, <html>, <window>, <dialog> etc. which
// correspond to the doc accessible and will be created in any case
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.
if (isHTML) {
// Interesting HTML container which may have selectable text and/or embedded objects
CreateHyperTextAccessible(frame, getter_AddRefs(newAcc));
}
else { // XUL, SVG, MathML etc.
// Interesting generic non-HTML container
newAcc = new nsAccessibleWrap(aNode, aWeakShell);
}
}
return InitAccessible(newAcc, aAccessible);
}
+PRBool
+nsAccessibilityService::HasUniversalAriaProperty(nsIContent *aContent,
+ nsIWeakReference *aWeakShell)
+{
+ nsCOMPtr<nsIAccessibleDocument> 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)
{
// The method returns node that is relevant for attached accessible check.
// Sometimes element that is XBL widget hasn't accessible children in
// anonymous content. This method check whether given node can be accessible
// by looking through all nested bindings that given node is anonymous for. If
--- a/accessible/src/base/nsAccessibilityService.h
+++ b/accessible/src/base/nsAccessibilityService.h
@@ -114,16 +114,26 @@ private:
* Return accessible object if parent is a deck frame.
*
* @param aNode - DOMNode that accessible is returned for.
*/
nsresult GetAccessibleForDeckChildren(nsIDOMNode *aNode,
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);
};
/**
* Map nsIAccessibleRole constants to strings. Used by
* nsIAccessibleRetrieval::getStringRole() method.
*/
static const char kRoleNames[][20] = {
"nothing", //ROLE_NOTHING
--- a/accessible/src/base/nsAccessibilityUtils.cpp
+++ b/accessible/src/base/nsAccessibilityUtils.cpp
@@ -37,20 +37,24 @@
* ***** END LICENSE BLOCK ***** */
#include "nsAccessibilityUtils.h"
#include "nsIAccessibleTypes.h"
#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"
#include "nsIDOMWindowInternal.h"
#include "nsIEventListenerManager.h"
#include "nsIPresShell.h"
#include "nsPresContext.h"
#include "nsIEventStateManager.h"
@@ -405,8 +409,230 @@ nsAccUtils::GetDocShellTreeItemFor(nsIDO
}
PRBool
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<nsIAccessibleDocument> docAccessible;
+ if (aWeakShell) {
+ docAccessible = nsAccessNode::GetDocAccessibleFor(aWeakShell);
+ }
+ else {
+ nsCOMPtr<nsIDOMNode> 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<nsIContent> 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<nsIDocument> doc = aForNode->GetCurrentDoc();
+ nsCOMPtr<nsIDOMDocumentXBL> xblDoc(do_QueryInterface(doc));
+ if (!xblDoc)
+ return nsnull;
+
+ nsCOMPtr<nsIDOMNodeList> nodes;
+ nsCOMPtr<nsIDOMElement> 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<nsIDOMNode> node;
+ rv = nodes->Item(index, getter_AddRefs(node));
+ if (NS_FAILED(rv))
+ return nsnull;
+
+ nsCOMPtr<nsIContent> 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 <label> will do
+nsIContent*
+nsAccUtils::FindDescendantPointingToID(const nsString *aId,
+ nsIContent *aLookContent,
+ EAriaProperty aAriaProperty,
+ nsIAtom *aRelationAttr,
+ nsIContent *aExcludeContent,
+ nsIAtom *aTagType)
+{
+ // Surround id with spaces for search
+ nsCAutoString idWithSpaces(' ');
+ LossyAppendUTF16toASCII(*aId, idWithSpaces);
+ idWithSpaces += ' ';
+ PRUint32 ariaPropTypes = (aAriaProperty == eAria_none) ? 0 :
+ nsAccUtils::GetAriaPropTypes(aLookContent);
+ return FindDescendantPointingToIDImpl(idWithSpaces, aLookContent,
+ aAriaProperty, ariaPropTypes,
+ aRelationAttr, aExcludeContent, aTagType);
+}
+
+nsIContent*
+nsAccUtils::FindDescendantPointingToIDImpl(nsCString& aIdWithSpaces,
+ nsIContent *aLookContent,
+ EAriaProperty aAriaProperty,
+ PRUint32 aAriaPropTypes,
+ nsIAtom *aRelationAttr,
+ nsIContent *aExcludeContent,
+ nsIAtom *aTagType)
+{
+ if (aAriaProperty != eAria_none) { // Tag ignored for ARIA properties, which can apply to anything
+ nsAutoString idList;
+ if (nsAccUtils::GetAriaProperty(aLookContent, nsnull, aAriaProperty,
+ idList, aAriaPropTypes)) {
+ idList.Insert(' ', 0); // Surround idlist with spaces for search
+ idList.Append(' ');
+ // idList is now a set of id's with spaces around each,
+ // and id also has spaces around it.
+ // If id is a substring of idList then we have a match
+ if (idList.Find(aIdWithSpaces) != -1) {
+ return aLookContent;
+ }
+ }
+ }
+ else if (!aTagType || aLookContent->Tag() == aTagType) {
+ // Tag matches
+ if (aRelationAttr) {
+ // Check for ID in the attribute aRelationAttr, which can be a list
+ nsAutoString idList;
+ if (aLookContent->GetAttr(kNameSpaceID_None, aRelationAttr, idList)) {
+ idList.Insert(' ', 0); // Surround idlist with spaces for search
+ idList.Append(' ');
+ // idList is now a set of id's with spaces around each,
+ // and id also has spaces around it.
+ // If id is a substring of idList then we have a match
+ if (idList.Find(aIdWithSpaces) != -1) {
+ return aLookContent;
+ }
+ }
+ }
+ if (aTagType) {
+ // Don't bother to search descendants of an element with matching tag.
+ // That would be like looking for a nested <label> or <description>
+ return nsnull;
+ }
+ }
+
+ // Recursively search descendants for match
+ PRUint32 count = 0;
+ nsIContent *child;
+ nsIContent *labelContent = nsnull;
+
+ while ((child = aLookContent->GetChildAt(count++)) != nsnull) {
+ if (child != aExcludeContent) {
+ labelContent = FindDescendantPointingToIDImpl(aIdWithSpaces, child,
+ aAriaProperty, aAriaPropTypes,
+ aRelationAttr, aExcludeContent, aTagType);
+ if (labelContent) {
+ return labelContent;
+ }
+ }
+ }
+ return nsnull;
+}
+
--- a/accessible/src/base/nsAccessibilityUtils.h
+++ b/accessible/src/base/nsAccessibilityUtils.h
@@ -36,23 +36,25 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsAccessibilityUtils_h_
#define nsAccessibilityUtils_h_
#include "nsAccessibilityAtoms.h"
#include "nsIAccessible.h"
+#include "nsARIAMap.h"
#include "nsIDOMNode.h"
#include "nsIPersistentProperties2.h"
#include "nsIContent.h"
#include "nsIFrame.h"
#include "nsIDocShellTreeItem.h"
#include "nsPoint.h"
+#include "nsIAccessibleDocument.h"
class nsAccUtils
{
public:
/**
* Returns value of attribute from the given attributes container.
*
* @param aAttributes - attributes container
@@ -183,12 +185,98 @@ public:
/**
* Get the ID for an element, in some types of XML this may not be the ID attribute
* @param aContent Node to get the ID for
* @param aID Where to put ID string
* @return PR_TRUE if there is an ID set for this node
*/
static PRBool GetID(nsIContent *aContent, nsAString& aID);
+
+ /**
+ * Find out what kinds of properties are checked for this content node's document
+ * @param aContent The content node we're going to look for ARIA properties on
+ * @param aWeakShell The presshell for the document we're looking for ARIA properties on (optional optimization)
+ * @return The types of properties checked
+ */
+ static PRUint32 GetAriaPropTypes(nsIContent *aContent, nsIWeakReference *aWeakShell = nsnull);
+
+ /**
+ * Check for the relevant ARIA property. Can check either for a properly namespaced property,
+ * or a fake hyphenated namespace using "aria-" as a prefix in HTML. Is optimized to only
+ * check for each type when it is possible to exist on a given node.
+ * @param aContent Node to check for property on
+ * @param aWeakShell The current pres shell if known (as an optimization), or nsnull if not known by caller
+ * @param aProperty An enumeration indicating which ARIA property we are checking
+ * @param aAriaPropTypes A bitflag for the property types to check for (namespaced, hyphenated or both), if known by caller
+ * @return PR_TRUE if the property is defined
+ */
+ static PRBool HasAriaProperty(nsIContent *aContent, nsIWeakReference *aWeakShell,
+ EAriaProperty aProperty,
+ PRUint32 aCheckFlags = 0);
+
+ /**
+ * Get the relevant ARIA property. Can check either for a properly namespaced property,
+ * or a fake hyphenated namespace using "aria-" as a prefix in HTML. Is optimized to only
+ * check for each type when it is possible to exist on a given node.
+ * @param aContent Node to check for property on
+ * @param aWeakShell The current pres shell if known (as an optimization), or nsnull if not known by caller
+ * @param aProperty An enumeration indicating which ARIA property we are checking
+ * @param aValue Where to store the property value
+ * @param aAriaPropTypes A bitflag for the property types to check for (namespaced, hyphenated or both), if known by caller
+ * @return PR_TRUE if the property is defined
+ */
+ static PRBool GetAriaProperty(nsIContent *aContent, nsIWeakReference *aWeakShell,
+ EAriaProperty aProperty, nsAString& aValue,
+ PRUint32 aCheckFlags = 0);
+
+ /**
+ * Search element in neighborhood of the given element by tag name and
+ * attribute value that equals to ID attribute of the given element.
+ * ID attribute can be either 'id' attribute or 'anonid' if the element is
+ * anonymous.
+ *
+ * @param aAriaProperty - the ARIA property to search for or eAria_none, if aRelationAttr is passed in
+ * @param aForNode - the given element the search is performed for
+ * @param aTagName - tag name of searched element, or nsnull for any -- ignored if aAriaProperty passed in
+ * @param aRelationAttr - attribute name of searched element, ignored if aAriaProperty passed in
+ * @param aAncestorLevelsToSearch - points how is the neighborhood of the
+ * given element big.
+ */
+ static nsIContent *FindNeighbourPointingToNode(nsIContent *aForNode,
+ EAriaProperty aAriaProperty,
+ nsIAtom *aTagName = nsnull,
+ nsIAtom *aRelationAttr = nsnull,
+ PRUint32 aAncestorLevelsToSearch = 5);
+
+ /**
+ * Search for element that satisfies the requirements in subtree of the given
+ * element. The requirements are tag name, attribute name and value of
+ * attribute.
+ *
+ * @param aId - value of searched attribute
+ * @param aLookContent - element that search is performed inside
+ * @param aAriaProperty - the ARIA property to search for or eAria_none, if aRelationAttr is passed in
+ * @param aRelationAttr - searched attribute-- ignored if aAriaProperty passed in
+ * @param if both aAriaProperty and aRelationAttr are null, then any element with aTagType will do
+ * @param aExcludeContent - element that is skiped for search
+ * @param aTagType - tag name of searched element, by default it is 'label' --
+ * ignored if aAriaProperty passed in
+ */
+ static nsIContent *FindDescendantPointingToID(const nsString *aId,
+ nsIContent *aLookContent,
+ EAriaProperty aAriaProperty,
+ nsIAtom *aRelationAttr = nsnull,
+ nsIContent *aExcludeContent = nsnull,
+ nsIAtom *aTagType = nsAccessibilityAtoms::label);
+
+ // Helper for FindDescendantPointingToID(), same args
+ static nsIContent *FindDescendantPointingToIDImpl(nsCString& aIdWithSpaces,
+ nsIContent *aLookContent,
+ EAriaProperty aAriaProperty,
+ PRUint32 aAriaPropTypes,
+ nsIAtom *aRelationAttr = nsnull,
+ nsIContent *aExcludeContent = nsnull,
+ nsIAtom *aTagType = nsAccessibilityAtoms::label);
};
#endif
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -70,16 +70,17 @@
#include "nsIPresShell.h"
#include "nsPresContext.h"
#include "nsIFrame.h"
#include "nsIViewManager.h"
#include "nsIDocShellTreeItem.h"
#include "nsXPIDLString.h"
#include "nsUnicharUtils.h"
+#include "nsReadableUtils.h"
#include "prdtoa.h"
#include "nsIAtom.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
#include "nsIURI.h"
#include "nsITimer.h"
#include "nsIMutableArray.h"
#include "nsIObserverService.h"
@@ -192,26 +193,23 @@ nsresult nsAccessible::QueryInterface(RE
if (aIID.Equals(NS_GET_IID(nsIAccessibleSelectable))) {
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (!content) {
return NS_ERROR_FAILURE; // This accessible has been shut down
}
if (HasRoleAttribute(content)) {
// If we have an XHTML role attribute present and the
- // waistate multiselectable attribute not empty or false, then we need
+ // waistate multiselectable attribute is true, then we need
// to support nsIAccessibleSelectable
// If either attribute (role or multiselectable) change, then we'll
// destroy this accessible so that we can follow COM identity rules.
- static nsIContent::AttrValuesArray strings[] =
- {&nsAccessibilityAtoms::_empty, &nsAccessibilityAtoms::_false, nsnull};
- if (content->FindAttrValueIn(kNameSpaceID_WAIProperties ,
- nsAccessibilityAtoms::multiselectable,
- strings, eCaseMatters) ==
- nsIContent::ATTR_VALUE_NO_MATCH) {
+ nsAutoString multiselectable;
+ if (nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_multiselectable, multiselectable) &&
+ multiselectable.EqualsLiteral("true")) {
*aInstancePtr = static_cast<nsIAccessibleSelectable*>(this);
NS_ADDREF_THIS();
return NS_OK;
}
}
}
if (aIID.Equals(NS_GET_IID(nsIAccessibleValue))) {
@@ -298,24 +296,25 @@ NS_IMETHODIMP nsAccessible::GetDescripti
// 3. it doesn't have an accName; or
// 4. its title attribute already equals to its accName nsAutoString name;
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (!content) {
return NS_ERROR_FAILURE; // Node shut down
}
if (!content->IsNodeOfType(nsINode::eTEXT)) {
nsAutoString description;
- nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::describedby, description);
+ nsresult rv = GetTextFromRelationID(eAria_describedby, description);
if (NS_FAILED(rv)) {
PRBool isXUL = content->IsNodeOfType(nsINode::eXUL);
if (isXUL) {
// Try XUL <description control="[id]">description text</description>
nsIContent *descriptionContent =
- FindNeighbourPointingToNode(content, nsAccessibilityAtoms::description,
- nsAccessibilityAtoms::control);
+ nsAccUtils::FindNeighbourPointingToNode(content, eAria_none,
+ nsAccessibilityAtoms::description,
+ nsAccessibilityAtoms::control);
if (descriptionContent) {
// We have a description content node
AppendFlatStringFromSubtree(descriptionContent, &description);
}
}
if (description.IsEmpty()) {
nsIAtom *descAtom = isXUL ? nsAccessibilityAtoms::tooltiptext :
@@ -1372,20 +1371,34 @@ NS_IMETHODIMP nsAccessible::SetSelected(
if (state & nsIAccessibleStates::STATE_SELECTABLE) {
nsCOMPtr<nsIAccessible> multiSelect = GetMultiSelectFor(mDOMNode);
if (!multiSelect) {
return aSelect ? TakeFocus() : NS_ERROR_FAILURE;
}
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
NS_ASSERTION(content, "Called for dead accessible");
- // For DHTML widgets use WAI namespace
- PRUint32 nameSpaceID = mRoleMapEntry ? kNameSpaceID_WAIProperties : kNameSpaceID_None;
+ // For ARIA widgets use WAI namespace or hyphenated property, depending on what doc accepts
+ PRUint32 nameSpaceID = kNameSpaceID_None; // Default
+ if (mRoleMapEntry) {
+ if (0 == (nsAccUtils::GetAriaPropTypes(content, mWeakShell) &
+ nsIAccessibleDocument::eCheckNamespaced)) {
+ // No WAI namespaced properties used in this doc, use hyphenated property
+ if (aSelect) {
+ return content->SetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_selected,
+ NS_LITERAL_STRING("true"), PR_TRUE);
+ }
+ return content->UnsetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_selected, PR_TRUE);
+ }
+ nameSpaceID = kNameSpaceID_WAIProperties;
+ }
+ // Use normal property
if (aSelect) {
- return content->SetAttr(nameSpaceID, nsAccessibilityAtoms::selected, NS_LITERAL_STRING("true"), PR_TRUE);
+ return content->SetAttr(nameSpaceID, nsAccessibilityAtoms::selected,
+ NS_LITERAL_STRING("true"), PR_TRUE);
}
return content->UnsetAttr(nameSpaceID, nsAccessibilityAtoms::selected, PR_TRUE);
}
return NS_ERROR_FAILURE;
}
/* void takeSelection (); */
@@ -1628,18 +1641,19 @@ nsresult nsAccessible::AppendFlatStringF
AppendFlatStringFromSubtreeRecurse(aContent->GetChildAt(index), aFlatString);
}
return NS_OK;
}
nsIContent *nsAccessible::GetLabelContent(nsIContent *aForNode)
{
if (aForNode->IsNodeOfType(nsINode::eXUL))
- return FindNeighbourPointingToNode(aForNode, nsAccessibilityAtoms::label,
- nsAccessibilityAtoms::control);
+ return nsAccUtils::FindNeighbourPointingToNode(aForNode, eAria_none,
+ nsAccessibilityAtoms::label,
+ nsAccessibilityAtoms::control);
return GetHTMLLabelContent(aForNode);
}
nsIContent* nsAccessible::GetHTMLLabelContent(nsIContent *aForNode)
{
// Get either <label for="[id]"> element which explictly points to aForNode, or
// <label> ancestor which implicitly point to it
@@ -1657,33 +1671,33 @@ nsIContent* nsAccessible::GetHTMLLabelCo
// There can be a label targeted at this control using the
// for="control_id" attribute. To save computing time, only
// look for those inside of a form element
nsAutoString forId;
if (!nsAccUtils::GetID(aForNode, forId)) {
break;
}
// Actually we'll be walking down the content this time, with a depth first search
- return FindDescendantPointingToID(&forId, walkUpContent,
- nsAccessibilityAtoms::_for);
+ return nsAccUtils::FindDescendantPointingToID(&forId, walkUpContent, eAria_none,
+ nsAccessibilityAtoms::_for);
}
}
return nsnull;
}
-nsresult nsAccessible::GetTextFromRelationID(nsIAtom *aIDAttrib, nsString &aName)
+nsresult nsAccessible::GetTextFromRelationID(EAriaProperty aIDProperty, nsString &aName)
{
// Get DHTML name from content subtree pointed to by ID attribute
aName.Truncate();
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
NS_ASSERTION(content, "Called from shutdown accessible");
nsAutoString ids;
- if (!content->GetAttr(kNameSpaceID_WAIProperties, aIDAttrib, ids)) {
+ if (!nsAccUtils::GetAriaProperty(content, mWeakShell, aIDProperty, ids)) {
return NS_ERROR_FAILURE;
}
ids.CompressWhitespace(PR_TRUE, PR_TRUE);
nsCOMPtr<nsIDOMDocument> domDoc;
mDOMNode->GetOwnerDocument(getter_AddRefs(domDoc));
NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
@@ -1716,154 +1730,31 @@ nsresult nsAccessible::GetTextFromRelati
if (NS_SUCCEEDED(rv)) {
aName.CompressWhitespace();
}
}
return rv;
}
-nsIContent*
-nsAccessible::FindNeighbourPointingToNode(nsIContent *aForNode,
- nsIAtom *aTagName, nsIAtom *aRelationAttr,
- PRUint32 aRelationNameSpaceID,
- PRUint32 aAncestorLevelsToSearch)
-{
- nsCOMPtr<nsIContent> 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<nsIDocument> doc = aForNode->GetCurrentDoc();
- nsCOMPtr<nsIDOMDocumentXBL> xblDoc(do_QueryInterface(doc));
- if (!xblDoc)
- return nsnull;
-
- nsCOMPtr<nsIDOMNodeList> nodes;
- nsCOMPtr<nsIDOMElement> 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<nsIDOMNode> node;
- rv = nodes->Item(index, getter_AddRefs(node));
- if (NS_FAILED(rv))
- return nsnull;
-
- nsCOMPtr<nsIContent> content = do_QueryInterface(node);
- if (!content)
- return nsnull;
-
- if (content != prevSearched) {
- labelContent = FindDescendantPointingToID(&controlID, content, aRelationAttr,
- aRelationNameSpaceID, nsnull,
- aTagName);
- }
- }
- break;
- }
-
- labelContent = FindDescendantPointingToID(&controlID, aForNode,
- aRelationAttr, aRelationNameSpaceID,
- prevSearched, aTagName);
- prevSearched = aForNode;
- }
-
- return labelContent;
-}
-
-// Pass in aRelationAttr == nsnull if any <label> will do
-nsIContent*
-nsAccessible::FindDescendantPointingToID(const nsAString *aId,
- nsIContent *aLookContent,
- nsIAtom *aRelationAttr,
- PRUint32 aRelationNameSpaceID,
- nsIContent *aExcludeContent,
- nsIAtom *aTagType)
-{
- if (!aTagType || aLookContent->Tag() == aTagType) {
- if (aRelationAttr) {
- // Check for ID in the attribute aRelationAttr, which can be a list
- nsAutoString idList;
- if (aLookContent->GetAttr(aRelationNameSpaceID, aRelationAttr, idList)) {
- idList.Insert(' ', 0); // Surround idlist with spaces for search
- idList.Append(' ');
- nsAutoString id(*aId);
- id.Insert(' ', 0); // Surround id with spaces for search
- id.Append(' ');
- // idList is now a set of id's with spaces around each,
- // and id also has spaces around it.
- // If id is a substring of idList then we have a match
- if (idList.Find(id) != -1) {
- return aLookContent;
- }
- }
- }
- if (aTagType) {
- return nsnull;
- }
- }
-
- // Recursively search descendants for labels
- PRUint32 count = 0;
- nsIContent *child;
- nsIContent *labelContent = nsnull;
-
- while ((child = aLookContent->GetChildAt(count++)) != nsnull) {
- if (child != aExcludeContent) {
- labelContent = FindDescendantPointingToID(aId, child, aRelationAttr,
- aRelationNameSpaceID, aExcludeContent,
- aTagType);
- if (labelContent) {
- return labelContent;
- }
- }
- }
- return nsnull;
-}
-
/**
* Only called if the element is not a nsIDOMXULControlElement. Initially walks up
* the DOM tree to the form, concatonating label elements as it goes. Then checks for
* labels with the for="controlID" property.
*/
nsresult nsAccessible::GetHTMLName(nsAString& aLabel, PRBool aCanAggregateSubtree)
{
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (!content) {
return NS_ERROR_FAILURE; // Node shut down
}
// Check for DHTML accessibility labelledby relationship property
nsAutoString label;
- nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::labelledby, label);
+ nsresult rv = GetTextFromRelationID(eAria_labelledby, label);
if (NS_SUCCEEDED(rv)) {
aLabel = label;
return rv;
}
nsIContent *labelContent = GetHTMLLabelContent(content);
if (labelContent) {
AppendFlatStringFromSubtree(labelContent, &label);
@@ -1904,17 +1795,17 @@ nsresult nsAccessible::GetHTMLName(nsASt
*/
nsresult nsAccessible::GetXULName(nsAString& aLabel, PRBool aCanAggregateSubtree)
{
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
NS_ASSERTION(content, "No nsIContent for DOM node");
// First check for label override via accessibility labelledby relationship
nsAutoString label;
- nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::labelledby, label);
+ nsresult rv = GetTextFromRelationID(eAria_labelledby, label);
if (NS_SUCCEEDED(rv)) {
aLabel = label;
return rv;
}
// CASE #1 (via label attribute) -- great majority of the cases
nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl(do_QueryInterface(mDOMNode));
if (labeledEl) {
@@ -1937,18 +1828,19 @@ nsresult nsAccessible::GetXULName(nsAStr
}
}
}
// CASES #2 and #3 ------ label as a child or <label control="id" ... > </label>
if (NS_FAILED(rv) || label.IsEmpty()) {
label.Truncate();
nsIContent *labelContent =
- FindNeighbourPointingToNode(content, nsAccessibilityAtoms::label,
- nsAccessibilityAtoms::control);
+ nsAccUtils::FindNeighbourPointingToNode(content, eAria_none,
+ nsAccessibilityAtoms::label,
+ nsAccessibilityAtoms::control);
nsCOMPtr<nsIDOMXULLabelElement> xulLabel(do_QueryInterface(labelContent));
// Check if label's value attribute is used
if (xulLabel && NS_SUCCEEDED(xulLabel->GetValue(label)) && label.IsEmpty()) {
// If no value attribute, a non-empty label must contain
// children that define it's text -- possibly using HTML
AppendFlatStringFromSubtree(labelContent, &label);
}
@@ -2035,35 +1927,38 @@ NS_IMETHODIMP nsAccessible::GetFinalRole
if (mRoleMapEntry) {
*aRole = mRoleMapEntry->role;
// These unfortunate exceptions don't fit into the ARIA table
// This is where the nsIAccessible role depends on both the role and ARIA state
if (*aRole == nsIAccessibleRole::ROLE_ENTRY) {
nsCOMPtr<nsIContent> content = do_QueryInterface(mDOMNode);
- if (content &&
- content->AttrValueIs(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::secret,
- nsAccessibilityAtoms::_true, eCaseMatters)) {
+ nsAutoString secret;
+ if (content && nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_secret, secret) &&
+ secret.EqualsLiteral("true")) {
// For entry field with aaa:secret="true"
*aRole = nsIAccessibleRole::ROLE_PASSWORD_TEXT;
}
}
else if (*aRole == nsIAccessibleRole::ROLE_PUSHBUTTON) {
nsCOMPtr<nsIContent> content = do_QueryInterface(mDOMNode);
if (content) {
- if (content->HasAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::pressed)) {
+ if (nsAccUtils::HasAriaProperty(content, mWeakShell, eAria_pressed)) {
// For aaa:pressed="false" or aaa:pressed="true"
// For simplicity, any pressed attribute indicates it's a toggle button
*aRole = nsIAccessibleRole::ROLE_TOGGLE_BUTTON;
}
- else if (content->AttrValueIs(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::haspopup,
- nsAccessibilityAtoms::_true, eCaseMatters)) {
- // For button with aaa:haspopup="true"
- *aRole = nsIAccessibleRole::ROLE_BUTTONMENU;
+ else {
+ nsAutoString haspopup;
+ if (nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_haspopup, haspopup) &&
+ haspopup.EqualsLiteral("true")) {
+ // For button with aaa:haspopup="true"
+ *aRole = nsIAccessibleRole::ROLE_BUTTONMENU;
+ }
}
}
}
if (*aRole != nsIAccessibleRole::ROLE_NOTHING) {
return NS_OK;
}
}
@@ -2094,47 +1989,51 @@ nsAccessible::GetAttributes(nsIPersisten
attributes->SetStringProperty(NS_LITERAL_CSTRING("id"), id, oldValueUnused);
// XXX In the future we may need to expose the dynamic content role inheritance chain
// through this attribute
nsAutoString xmlRole;
if (GetARIARole(content, xmlRole)) {
attributes->SetStringProperty(NS_LITERAL_CSTRING("xml-roles"), xmlRole, oldValueUnused);
}
- char *ariaProperties[] = { "live", "channel", "atomic", "relevant", "datatype", "level",
+ // Make sure to keep these two arrays in sync
+ PRUint32 ariaPropTypes = nsAccUtils::GetAriaPropTypes(content, mWeakShell);
+ char *ariaPropertyString[] = { "live", "channel", "atomic", "relevant", "datatype", "level",
"posinset", "setsize", "sort", "grab", "dropeffect"};
-
- for (PRUint32 index = 0; index < NS_ARRAY_LENGTH(ariaProperties); index ++) {
+ EAriaProperty ariaPropertyEnum[] = { eAria_live, eAria_channel, eAria_atomic, eAria_relevant,
+ eAria_datatype, eAria_level, eAria_posinset, eAria_setsize,
+ eAria_sort, eAria_grab, eAria_dropeffect};
+ NS_ASSERTION(NS_ARRAY_LENGTH(ariaPropertyString) == NS_ARRAY_LENGTH(ariaPropertyEnum),
+ "ARIA attributes and object property name arrays out of sync");
+ for (PRUint32 index = 0; index < NS_ARRAY_LENGTH(ariaPropertyString); index ++) {
nsAutoString value;
- nsCOMPtr<nsIAtom> attr = do_GetAtom(ariaProperties[index]);
- NS_ENSURE_TRUE(attr, NS_ERROR_OUT_OF_MEMORY);
- if (content->GetAttr(kNameSpaceID_WAIProperties, attr, value)) {
+ if (nsAccUtils::GetAriaProperty(content, mWeakShell, ariaPropertyEnum[index], value, ariaPropTypes)) {
ToLowerCase(value);
- attributes->SetStringProperty(nsDependentCString(ariaProperties[index]), value, oldValueUnused);
+ attributes->SetStringProperty(nsDependentCString(ariaPropertyString[index]), value, oldValueUnused);
}
}
// Get container-foo computed live region properties based on the closest container with
// the live region attribute
nsAutoString atomic, live, relevant, channel, busy;
while (content) {
- if (relevant.IsEmpty() &&
- content->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::relevant, relevant))
+ if (relevant.IsEmpty() &&
+ nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_relevant, relevant, ariaPropTypes))
attributes->SetStringProperty(NS_LITERAL_CSTRING("container-relevant"), relevant, oldValueUnused);
if (live.IsEmpty() &&
- content->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::live, live))
+ nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_live, live, ariaPropTypes))
attributes->SetStringProperty(NS_LITERAL_CSTRING("container-live"), live, oldValueUnused);
if (channel.IsEmpty() &&
- content->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::channel, channel))
+ nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_channel, channel, ariaPropTypes))
attributes->SetStringProperty(NS_LITERAL_CSTRING("container-channel"), channel, oldValueUnused);
if (atomic.IsEmpty() &&
- content->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::atomic, atomic))
+ nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_atomic, atomic, ariaPropTypes))
attributes->SetStringProperty(NS_LITERAL_CSTRING("container-atomic"), atomic, oldValueUnused);
if (busy.IsEmpty() &&
- content->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::busy, busy))
+ nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_busy, busy, ariaPropTypes))
attributes->SetStringProperty(NS_LITERAL_CSTRING("container-busy"), busy, oldValueUnused);
content = content->GetParent();
}
}
if (!nsAccUtils::HasAccGroupAttrs(attributes)) {
// The role of an accessible can be pointed by ARIA attribute but ARIA
// posinset, level, setsize may be skipped. Therefore we calculate here
@@ -2259,24 +2158,22 @@ nsAccessible::GroupPosition(PRInt32 *aGr
return NS_OK;
}
PRBool nsAccessible::MappedAttrState(nsIContent *aContent, PRUint32 *aStateInOut,
nsStateMapEntry *aStateMapEntry)
{
// Return true if we should continue
- if (!aStateMapEntry->attributeName) {
+ if (aStateMapEntry->attributeName == eAria_none) {
return PR_FALSE; // Stop looking -- no more states
}
nsAutoString attribValue;
- nsCOMPtr<nsIAtom> attribAtom = do_GetAtom(aStateMapEntry->attributeName); // XXX put atoms directly in entry
- NS_ENSURE_TRUE(attribAtom, NS_ERROR_OUT_OF_MEMORY);
- if (aContent->GetAttr(kNameSpaceID_WAIProperties, attribAtom, attribValue)) {
+ if (nsAccUtils::GetAriaProperty(aContent, mWeakShell, aStateMapEntry->attributeName, attribValue)) {
if (aStateMapEntry->attributeValue == kBoolState) {
// No attribute value map specified in state map entry indicates state cleared
if (attribValue.EqualsLiteral("false")) {
*aStateInOut &= ~aStateMapEntry->state;
}
else {
*aStateInOut |= aStateMapEntry->state;
}
@@ -2330,29 +2227,28 @@ nsAccessible::GetFinalState(PRUint32 *aS
if (role == nsIAccessibleRole::ROLE_ENTRY ||
role == nsIAccessibleRole::ROLE_PASSWORD_TEXT ||
role == nsIAccessibleRole::ROLE_COMBOBOX) {
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
NS_ENSURE_STATE(content);
nsAutoString autocomplete;
- if (content->GetAttr(kNameSpaceID_WAIProperties,
- nsAccessibilityAtoms::autocomplete, autocomplete) &&
+ if (nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_autocomplete, autocomplete) &&
(autocomplete.EqualsIgnoreCase("inline") ||
autocomplete.EqualsIgnoreCase("list") ||
autocomplete.EqualsIgnoreCase("both"))) {
*aExtraState |= nsIAccessibleStates::EXT_STATE_SUPPORTS_AUTOCOMPLETION;
}
// XXX We can remove this hack once we support RDF-based role & state maps
if (mRoleMapEntry && mRoleMapEntry->role == nsIAccessibleRole::ROLE_ENTRY) {
- if (content->AttrValueIs(kNameSpaceID_WAIProperties,
- nsAccessibilityAtoms::multiline,
- nsAccessibilityAtoms::_true, eCaseMatters)) {
+ nsAutoString multiline;
+ if (nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_multiline, multiline) &&
+ multiline.EqualsLiteral("true")) {
*aExtraState |= nsIAccessibleStates::EXT_STATE_MULTI_LINE;
}
else {
*aExtraState |= nsIAccessibleStates::EXT_STATE_SINGLE_LINE;
}
}
}
@@ -2388,18 +2284,17 @@ nsAccessible::GetARIAState()
// Test for universal states first
nsIContent *content = GetRoleContent(mDOMNode);
if (!content) {
return 0;
}
PRUint32 ariaState = 0;
PRUint32 index = 0;
- while (nsARIAMap::gWAIUnivStateMap[index].attributeName != nsnull) {
- MappedAttrState(content, &ariaState, &nsARIAMap::gWAIUnivStateMap[index]);
+ while (MappedAttrState(content, &ariaState, &nsARIAMap::gWAIUnivStateMap[index])) {
++ index;
}
if (!mRoleMapEntry)
return ariaState;
// Once DHTML role is used, we're only readonly if DHTML readonly used
ariaState &= ~nsIAccessibleStates::STATE_READONLY;
@@ -2433,54 +2328,50 @@ NS_IMETHODIMP nsAccessible::GetValue(nsA
if (!mDOMNode) {
return NS_ERROR_FAILURE; // Node already shut down
}
if (mRoleMapEntry) {
if (mRoleMapEntry->valueRule == eNoValue) {
return NS_OK;
}
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
- if (content && content->GetAttr(kNameSpaceID_WAIProperties,
- nsAccessibilityAtoms::valuenow, aValue)) {
+ if (content && nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_valuenow, aValue)) {
return NS_OK;
}
}
return NS_OK;
}
// nsIAccessibleValue
NS_IMETHODIMP
nsAccessible::GetMaximumValue(double *aMaximumValue)
{
- return GetAttrValue(kNameSpaceID_WAIProperties,
- nsAccessibilityAtoms::valuemax, aMaximumValue);
+ return GetAttrValue(eAria_valuemax, aMaximumValue);
}
NS_IMETHODIMP
nsAccessible::GetMinimumValue(double *aMinimumValue)
{
- return GetAttrValue(kNameSpaceID_WAIProperties,
- nsAccessibilityAtoms::valuemin, aMinimumValue);
+ return GetAttrValue(eAria_valuemin, aMinimumValue);
}
NS_IMETHODIMP
nsAccessible::GetMinimumIncrement(double *aMinIncrement)
{
NS_ENSURE_ARG_POINTER(aMinIncrement);
*aMinIncrement = 0;
// No mimimum increment in dynamic content spec right now
return NS_OK_NO_ARIA_VALUE;
}
NS_IMETHODIMP
nsAccessible::GetCurrentValue(double *aValue)
{
- return GetAttrValue(kNameSpaceID_WAIProperties,
- nsAccessibilityAtoms::valuenow, aValue);
+ return GetAttrValue(eAria_valuenow, aValue);
}
NS_IMETHODIMP
nsAccessible::SetCurrentValue(double aValue)
{
if (!mDOMNode)
return NS_ERROR_FAILURE; // Node already shut down
@@ -2501,16 +2392,22 @@ nsAccessible::SetCurrentValue(double aVa
if (NS_SUCCEEDED(GetMaximumValue(&maxValue)) && aValue > maxValue)
return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
NS_ENSURE_STATE(content);
nsAutoString newValue;
newValue.AppendFloat(aValue);
+ if (0 == (nsAccUtils::GetAriaPropTypes(content, mWeakShell) &
+ nsIAccessibleDocument::eCheckNamespaced)) {
+ // No WAI namespaced properties used in this doc
+ return content->SetAttr(kNameSpaceID_None,
+ nsAccessibilityAtoms::aria_valuenow, newValue, PR_TRUE);
+ }
return content->SetAttr(kNameSpaceID_WAIProperties,
nsAccessibilityAtoms::valuenow, newValue, PR_TRUE);
}
/* void setName (in DOMString name); */
NS_IMETHODIMP nsAccessible::SetName(const nsAString& name)
{
return NS_ERROR_NOT_IMPLEMENTED;
@@ -2607,49 +2504,26 @@ NS_IMETHODIMP nsAccessible::GetAccessibl
}
/* nsIAccessible getAccessibleBelow(); */
NS_IMETHODIMP nsAccessible::GetAccessibleBelow(nsIAccessible **_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
-already_AddRefed<nsIDOMNode>
-nsAccessible::FindNeighbourPointingToThis(nsIAtom *aRelationAttr,
- PRUint32 aRelationNameSpaceID,
- PRUint32 aAncestorLevelsToSearch)
-{
- nsIContent *content = GetRoleContent(mDOMNode);
- if (!content)
- return nsnull; // Node shut down
-
- nsIContent* description = FindNeighbourPointingToNode(content, nsnull,
- aRelationAttr,
- aRelationNameSpaceID,
- aAncestorLevelsToSearch);
-
- if (!description)
- return nsnull;
-
- nsIDOMNode *relatedNode;
- CallQueryInterface(description, &relatedNode);
- return relatedNode;
-}
-
nsIDOMNode* nsAccessible::GetAtomicRegion()
{
nsCOMPtr<nsIContent> content = do_QueryInterface(mDOMNode);
nsIContent *loopContent = content;
nsAutoString atomic;
-
- while (loopContent) {
- loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::atomic, atomic);
- if (!atomic.IsEmpty()) {
- break;
- }
+ PRUint32 ariaPropTypes = nsAccUtils::GetAriaPropTypes(content, mWeakShell);
+
+ while (loopContent && !nsAccUtils::GetAriaProperty(loopContent, mWeakShell,
+ eAria_atomic, atomic,
+ ariaPropTypes)) {
loopContent = loopContent->GetParent();
}
nsCOMPtr<nsIDOMNode> atomicRegion;
if (atomic.EqualsLiteral("true")) {
atomicRegion = do_QueryInterface(loopContent);
}
return atomicRegion;
@@ -2678,95 +2552,82 @@ NS_IMETHODIMP nsAccessible::GetAccessibl
case nsIAccessibleRelation::RELATION_LABEL_FOR:
{
if (content->Tag() == nsAccessibilityAtoms::label) {
nsIAtom *relatedIDAttr = content->IsNodeOfType(nsINode::eHTML) ?
nsAccessibilityAtoms::_for : nsAccessibilityAtoms::control;
content->GetAttr(kNameSpaceID_None, relatedIDAttr, relatedID);
}
if (relatedID.IsEmpty()) {
- const PRUint32 kAncestorLevelsToSearch = 3;
- relatedNode = FindNeighbourPointingToThis(nsAccessibilityAtoms::labelledby,
- kNameSpaceID_WAIProperties,
- kAncestorLevelsToSearch);
+ relatedNode =
+ do_QueryInterface(nsAccUtils::FindNeighbourPointingToNode(content, eAria_labelledby));
}
break;
}
case nsIAccessibleRelation::RELATION_LABELLED_BY:
{
- content->GetAttr(kNameSpaceID_WAIProperties,
- nsAccessibilityAtoms::labelledby, relatedID);
- if (relatedID.IsEmpty()) {
+ if (!nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_labelledby, relatedID)) {
relatedNode = do_QueryInterface(GetLabelContent(content));
}
break;
}
case nsIAccessibleRelation::RELATION_DESCRIBED_BY:
{
- content->GetAttr(kNameSpaceID_WAIProperties,
- nsAccessibilityAtoms::describedby, relatedID);
- if (relatedID.IsEmpty()) {
- nsIContent *description =
- FindNeighbourPointingToNode(content,
- nsAccessibilityAtoms::description,
- nsAccessibilityAtoms::control);
-
- relatedNode = do_QueryInterface(description);
+ if (!nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_describedby, relatedID)) {
+ relatedNode = do_QueryInterface(
+ nsAccUtils::FindNeighbourPointingToNode(content, eAria_none,
+ nsAccessibilityAtoms::description,
+ nsAccessibilityAtoms::control));
+
}
break;
}
case nsIAccessibleRelation::RELATION_DESCRIPTION_FOR:
{
- const PRUint32 kAncestorLevelsToSearch = 3;
relatedNode =
- FindNeighbourPointingToThis(nsAccessibilityAtoms::describedby,
- kNameSpaceID_WAIProperties,
- kAncestorLevelsToSearch);
+ do_QueryInterface(nsAccUtils::FindNeighbourPointingToNode(content, eAria_describedby));
if (!relatedNode && content->Tag() == nsAccessibilityAtoms::description &&
content->IsNodeOfType(nsINode::eXUL)) {
// This affectively adds an optional control attribute to xul:description,
// which only affects accessibility, by allowing the description to be
// tied to a control.
content->GetAttr(kNameSpaceID_None,
nsAccessibilityAtoms::control, relatedID);
}
break;
}
case nsIAccessibleRelation::RELATION_NODE_CHILD_OF:
{
- relatedNode = FindNeighbourPointingToThis(nsAccessibilityAtoms::owns,
- kNameSpaceID_WAIProperties);
+ relatedNode =
+ do_QueryInterface(nsAccUtils::FindNeighbourPointingToNode(content, eAria_owns));
break;
}
case nsIAccessibleRelation::RELATION_CONTROLLED_BY:
{
- relatedNode = FindNeighbourPointingToThis(nsAccessibilityAtoms::controls,
- kNameSpaceID_WAIProperties);
+ relatedNode =
+ do_QueryInterface(nsAccUtils::FindNeighbourPointingToNode(content, eAria_controls));
break;
}
case nsIAccessibleRelation::RELATION_CONTROLLER_FOR:
{
- content->GetAttr(kNameSpaceID_WAIProperties,
- nsAccessibilityAtoms::controls, relatedID);
+ nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_controls, relatedID);
break;
}
case nsIAccessibleRelation::RELATION_FLOWS_TO:
{
- content->GetAttr(kNameSpaceID_WAIProperties,
- nsAccessibilityAtoms::flowto, relatedID);
+ nsAccUtils::GetAriaProperty(content, mWeakShell, eAria_flowto, relatedID);
break;
}
case nsIAccessibleRelation::RELATION_FLOWS_FROM:
{
- relatedNode = FindNeighbourPointingToThis(nsAccessibilityAtoms::flowto,
- kNameSpaceID_WAIProperties);
+ relatedNode =
+ do_QueryInterface(nsAccUtils::FindNeighbourPointingToNode(content, eAria_flowto));
break;
}
-
case nsIAccessibleRelation::RELATION_DEFAULT_BUTTON:
{
if (content->IsNodeOfType(nsINode::eHTML)) {
// HTML form controls implements nsIFormControl interface.
nsCOMPtr<nsIFormControl> control(do_QueryInterface(content));
if (control) {
nsCOMPtr<nsIDOMHTMLFormElement> htmlform;
control->GetForm(getter_AddRefs(htmlform));
@@ -3341,34 +3202,33 @@ PRBool nsAccessible::CheckVisibilityInPa
document = parentDoc;
}
return PR_TRUE;
}
nsresult
-nsAccessible::GetAttrValue(PRUint32 aNameSpaceID, nsIAtom *aName,
- double *aValue)
+nsAccessible::GetAttrValue(EAriaProperty aProperty, double *aValue)
{
NS_ENSURE_ARG_POINTER(aValue);
*aValue = 0;
if (!mDOMNode)
return NS_ERROR_FAILURE; // Node already shut down
if (!mRoleMapEntry || mRoleMapEntry->valueRule == eNoValue)
return NS_OK_NO_ARIA_VALUE;
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
NS_ENSURE_STATE(content);
PRInt32 result = NS_OK;
nsAutoString value;
- if (content->GetAttr(aNameSpaceID, aName, value) && !value.IsEmpty())
+ if (nsAccUtils::GetAriaProperty(content, mWeakShell, aProperty, value))
*aValue = value.ToFloat(&result);
return result;
}
PRBool nsAccessible::MustPrune(nsIAccessible *aAccessible)
{
PRUint32 role = Role(aAccessible);
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -163,73 +163,26 @@ public:
protected:
PRBool MappedAttrState(nsIContent *aContent, PRUint32 *aStateInOut, nsStateMapEntry *aStateMapEntry);
virtual nsIFrame* GetBoundsFrame();
virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
PRBool IsVisible(PRBool *aIsOffscreen);
// Relation helpers
- nsresult GetTextFromRelationID(nsIAtom *aIDAttrib, nsString &aName);
-
- /**
- * Search element in neighborhood of the given element by tag name and
- * attribute value that equals to ID attribute of the current element.
- * ID attribute can be either 'id' attribute or 'anonid' if the element is
- * anonymous.
- *
- * @param aRelationAttr - attribute name of searched element
- * @param aRelationNamespaceID - namespace id of searched attribute, by default
- * empty namespace
- * @param aAncestorLevelsToSearch - points how is the neighborhood of the
- * given element big.
- */
- already_AddRefed<nsIDOMNode> FindNeighbourPointingToThis(nsIAtom *aRelationAttr,
- PRUint32 aRelationNameSpaceID = kNameSpaceID_None,
- PRUint32 aAncestorLevelsToSearch = 0);
/**
- * Search element in neighborhood of the given element by tag name and
- * attribute value that equals to ID attribute of the given element.
- * ID attribute can be either 'id' attribute or 'anonid' if the element is
- * anonymous.
+ * For a given ARIA relation, such as labelledby or describedby, get the collated text
+ * for the subtree that's pointed to.
*
- * @param aForNode - the given element the search is performed for
- * @param aTagName - tag name of searched element
- * @param aRelationAttr - attribute name of searched element
- * @param aRelationNamespaceID - namespace id of searched attribute, by default
- * empty namespace
- * @param aAncestorLevelsToSearch - points how is the neighborhood of the
- * given element big.
+ * @param aIDProperty The ARIA relationship property to get the text for
+ * @param aName Where to put the text
+ * @return error or success code
*/
- static nsIContent *FindNeighbourPointingToNode(nsIContent *aForNode,
- nsIAtom *aTagName,
- nsIAtom *aRelationAttr,
- PRUint32 aRelationNameSpaceID = kNameSpaceID_None,
- PRUint32 aAncestorLevelsToSearch = 5);
-
- /**
- * Search for element that satisfies the requirements in subtree of the given
- * element. The requirements are tag name, attribute name and value of
- * attribute.
- *
- * @param aId - value of searched attribute
- * @param aLookContent - element that search is performed inside
- * @param aRelationAttr - searched attribute
- * @param aRelationNamespaceID - namespace id of searched attribute, by default
- * empty namespace
- * @param aExcludeContent - element that is skiped for search
- * @param aTagType - tag name of searched element, by default it is 'label'
- */
- static nsIContent *FindDescendantPointingToID(const nsAString *aId,
- nsIContent *aLookContent,
- nsIAtom *aRelationAttr,
- PRUint32 aRelationNamespaceID = kNameSpaceID_None,
- nsIContent *aExcludeContent = nsnull,
- nsIAtom *aTagType = nsAccessibilityAtoms::label);
+ nsresult GetTextFromRelationID(EAriaProperty aIDProperty, nsString &aName);
static nsIContent *GetHTMLLabelContent(nsIContent *aForNode);
static nsIContent *GetLabelContent(nsIContent *aForNode);
static nsIContent *GetRoleContent(nsIDOMNode *aDOMNode);
// Name helpers
nsresult GetHTMLName(nsAString& _retval, PRBool aCanAggregateSubtree = PR_TRUE);
nsresult GetXULName(nsAString& aName, PRBool aCanAggregateSubtree = PR_TRUE);
@@ -279,25 +232,24 @@ protected:
/**
* Get the container node for an atomic region, defined by aria:atomic="true"
* @return the container node
*/
nsIDOMNode* GetAtomicRegion();
/**
- * Get numeric value of the given attribute.
+ * Get numeric value of the given ARIA attribute.
*
- * @param aNameSpaceID - namespace ID of the attribute
- * @param aName - name of the attribute
+ * @param aAriaProperty - the ARIA property we're using
* @param aValue - value of the attribute
*
* @return - NS_OK_NO_ARIA_VALUE if there is no setted ARIA attribute
*/
- nsresult GetAttrValue(PRUint32 aNameSpaceID, nsIAtom *aName, double *aValue);
+ nsresult GetAttrValue(EAriaProperty aAriaProperty, double *aValue);
// Data Members
nsCOMPtr<nsIAccessible> mParent;
nsIAccessible *mFirstChild, *mNextSibling;
nsRoleMapEntry *mRoleMapEntry; // Non-null indicates author-supplied role; possibly state & value as well
PRInt32 mAccChildCount;
};
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -79,30 +79,48 @@
PRUint32 nsDocAccessible::gLastFocusedAccessiblesState = 0;
//-----------------------------------------------------
// construction
//-----------------------------------------------------
nsDocAccessible::nsDocAccessible(nsIDOMNode *aDOMNode, nsIWeakReference* aShell):
nsHyperTextAccessibleWrap(aDOMNode, aShell), mWnd(nsnull),
- mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE)
+ mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE),
+ mAriaPropTypes(eCheckNamespaced)
{
// For GTK+ native window, we do nothing here.
if (!mDOMNode)
return;
// Because of the way document loading happens, the new nsIWidget is created before
// the old one is removed. Since it creates the nsDocAccessible, for a brief moment
// there can be 2 nsDocAccessible's for the content area, although for 2 different
// pres shells.
nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mWeakShell));
if (shell) {
+ // Find mDocument
mDocument = shell->GetDocument();
+ // Find mAriaPropTypes: the initial type of ARIA properties that should be checked for
+ if (!mDocument) {
+ NS_WARNING("No document!");
+ return;
+ }
+
+ nsCOMPtr<nsIDOMNSHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
+ if (htmlDoc) {
+ nsAutoString mimeType;
+ GetMimeType(mimeType);
+ mAriaPropTypes = eCheckHyphenated;
+ if (! mimeType.EqualsLiteral("text/html")) {
+ mAriaPropTypes |= eCheckNamespaced;
+ }
+ }
+ // Find mWnd
nsIViewManager* vm = shell->GetViewManager();
if (vm) {
nsCOMPtr<nsIWidget> widget;
vm->GetWidget(getter_AddRefs(widget));
if (widget) {
mWnd = widget->GetNativeData(NS_NATIVE_WINDOW);
}
}
@@ -899,17 +917,24 @@ NS_IMETHODIMP nsDocAccessible::Observe(n
new nsAccStateChangeEvent(this, nsIAccessibleStates::EXT_STATE_EDITABLE,
PR_TRUE, PR_TRUE);
FireAccessibleEvent(event);
}
return NS_OK;
}
-///////////////////////////////////////////////////////////////////////
+NS_IMETHODIMP
+nsDocAccessible::GetAriaPropTypes(PRUint32 *aAriaPropTypes)
+{
+ *aAriaPropTypes = mAriaPropTypes;
+ return NS_OK;
+}
+
+ ///////////////////////////////////////////////////////////////////////
// nsIDocumentObserver
NS_IMPL_NSIDOCUMENTOBSERVER_CORE_STUB(nsDocAccessible)
NS_IMPL_NSIDOCUMENTOBSERVER_LOAD_STUB(nsDocAccessible)
NS_IMPL_NSIDOCUMENTOBSERVER_STYLE_STUB(nsDocAccessible)
void
nsDocAccessible::AttributeChanged(nsIDocument *aDocument, nsIContent* aContent,
@@ -943,16 +968,24 @@ nsDocAccessible::AttributeChangedImpl(ns
// Otherwise it may just be a state change, for example an object changing
// its visibility
nsCOMPtr<nsISupports> container = mDocument->GetContainer();
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
if (!docShell) {
return;
}
+ if (aNameSpaceID == kNameSpaceID_WAIProperties) {
+ // Using setAttributeNS() in HTML to set namespaced ARIA properties.
+ // From this point forward, check namespaced properties, which
+ // take precedence over hyphenated properties, since in text/html
+ // that can only be set dynamically.
+ mAriaPropTypes |= eCheckNamespaced;
+ }
+
PRUint32 busyFlags;
docShell->GetBusyFlags(&busyFlags);
if (busyFlags) {
return; // Still loading, ignore setting of initial attributes
}
nsCOMPtr<nsIPresShell> shell = GetPresShell();
if (!shell) {
@@ -966,17 +999,18 @@ nsDocAccessible::AttributeChangedImpl(ns
}
// Since we're in synchronous code, we can store whether the current attribute
// change is from user input or not. If the attribute change causes an asynchronous
// layout change, that event can use the last known user input state
nsAccEvent::PrepareForEvent(targetNode);
// Universal boolean properties that don't require a role.
- if (aAttribute == nsAccessibilityAtoms::disabled) {
+ if (aAttribute == nsAccessibilityAtoms::disabled ||
+ (aAttribute == nsAccessibilityAtoms::aria_disabled && (mAriaPropTypes & eCheckHyphenated))) {
// Fire the state change whether disabled attribute is
// set for XUL, HTML or ARIA namespace.
// Checking the namespace would not seem to gain us anything, because
// disabled really is going to mean the same thing in any namespace.
// We use the attribute instead of the disabled state bit because
// ARIA's aaa:disabled does not affect the disabled state bit
nsCOMPtr<nsIAccessibleStateChangeEvent> enabledChangeEvent =
new nsAccStateChangeEvent(targetNode,
@@ -986,18 +1020,32 @@ nsDocAccessible::AttributeChangedImpl(ns
nsCOMPtr<nsIAccessibleStateChangeEvent> sensitiveChangeEvent =
new nsAccStateChangeEvent(targetNode,
nsIAccessibleStates::EXT_STATE_SENSITIVE,
PR_TRUE);
FireDelayedAccessibleEvent(sensitiveChangeEvent);
return;
}
+ // Check for namespaced ARIA attribute
+ nsCOMPtr<nsIAtom> ariaAttribute;
if (aNameSpaceID == kNameSpaceID_WAIProperties) {
- ARIAAttributeChanged(aContent, aAttribute);
+ ariaAttribute = aAttribute;
+ }
+ else if (mAriaPropTypes & eCheckHyphenated && aNameSpaceID == kNameSpaceID_None) {
+ // Check for hyphenated aria-foo property?
+ const char* attributeName;
+ aAttribute->GetUTF8String(&attributeName);
+ if (!PL_strncmp("aria-", attributeName, 5)) {
+ // Convert to WAI property atom attribute
+ ariaAttribute = do_GetAtom(attributeName + 5);
+ }
+ }
+ if (ariaAttribute) { // We have an ARIA attribute
+ ARIAAttributeChanged(aContent, ariaAttribute);
return;
}
if (aNameSpaceID == kNameSpaceID_XHTML2_Unofficial ||
aNameSpaceID == kNameSpaceID_XHTML) {
if (aAttribute == nsAccessibilityAtoms::role)
InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
return;
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -199,16 +199,17 @@ class nsDocAccessible : public nsHyperTe
nsCOMPtr<nsITimer> mFireEventTimer;
PRUint16 mScrollPositionChangedTicks; // Used for tracking scroll events
PRPackedBool mIsContentLoaded;
nsCOMArray<nsIAccessibleEvent> mEventsToFire;
protected:
PRBool mIsAnchor;
PRBool mIsAnchorJumped;
+ PRUint32 mAriaPropTypes;
static PRUint32 gLastFocusedAccessiblesState;
private:
static void DocLoadCallback(nsITimer *aTimer, void *aClosure);
nsCOMPtr<nsITimer> mDocLoadTimer;
};
#endif
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -383,16 +383,22 @@ void nsRootAccessible::TryFireEarlyLoadE
if (!treeItem) {
return;
}
PRInt32 itemType;
treeItem->GetItemType(&itemType);
if (itemType != nsIDocShellTreeItem::typeContent) {
return;
}
+
+ // At minimum, create doc accessible so that events are listened to,
+ // allowing us to see any mutations from a page load handler
+ nsCOMPtr<nsIAccessible> docAccessible;
+ GetAccService()->GetAccessibleFor(aDocNode, getter_AddRefs(docAccessible));
+
nsCOMPtr<nsIDocShellTreeNode> treeNode(do_QueryInterface(treeItem));
if (treeNode) {
PRInt32 subDocuments;
treeNode->GetChildCount(&subDocuments);
if (subDocuments) {
return;
}
}
@@ -455,17 +461,17 @@ PRBool nsRootAccessible::FireAccessibleF
}
// Check for aaa:activedescendant, which changes which element has focus
nsCOMPtr<nsIDOMNode> finalFocusNode = aNode;
nsCOMPtr<nsIAccessible> finalFocusAccessible = aAccessible;
nsCOMPtr<nsIContent> finalFocusContent = do_QueryInterface(aNode);
if (finalFocusContent) {
nsAutoString id;
- if (finalFocusContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::activedescendant, id)) {
+ if (nsAccUtils::GetAriaProperty(finalFocusContent, nsnull, eAria_activedescendant, id)) {
nsCOMPtr<nsIDOMDocument> domDoc;
aNode->GetOwnerDocument(getter_AddRefs(domDoc));
if (!domDoc) {
return PR_FALSE;
}
nsCOMPtr<nsIDOMElement> relatedEl;
domDoc->GetElementById(id, getter_AddRefs(relatedEl));
finalFocusNode = do_QueryInterface(relatedEl);
--- a/accessible/src/xforms/nsXFormsAccessible.cpp
+++ b/accessible/src/xforms/nsXFormsAccessible.cpp
@@ -211,32 +211,31 @@ nsXFormsAccessible::GetState(PRUint32 *a
return NS_OK;
}
NS_IMETHODIMP
nsXFormsAccessible::GetName(nsAString& aName)
{
nsAutoString name;
- nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::labelledby, name);
+ nsresult rv = GetTextFromRelationID(eAria_labelledby, name);
if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
aName = name;
return NS_OK;
}
// search the xforms:label element
return GetBoundChildElementValue(NS_LITERAL_STRING("label"), aName);
}
NS_IMETHODIMP
nsXFormsAccessible::GetDescription(nsAString& aDescription)
{
nsAutoString description;
- nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::describedby,
- description);
+ nsresult rv = GetTextFromRelationID(eAria_describedby, description);
if (NS_SUCCEEDED(rv) && !description.IsEmpty()) {
aDescription = description;
return NS_OK;
}
// search the xforms:hint element
return GetBoundChildElementValue(NS_LITERAL_STRING("hint"), aDescription);
--- a/accessible/src/xforms/nsXFormsFormControlsAccessible.cpp
+++ b/accessible/src/xforms/nsXFormsFormControlsAccessible.cpp
@@ -54,27 +54,26 @@ nsXFormsLabelAccessible::GetRole(PRUint3
*aRole = nsIAccessibleRole::ROLE_STATICTEXT;
return NS_OK;
}
NS_IMETHODIMP
nsXFormsLabelAccessible::GetName(nsAString& aName)
{
nsAutoString name;
- nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::labelledby, name);
+ nsresult rv = GetTextFromRelationID(eAria_labelledby, name);
aName = name;
return rv;
}
NS_IMETHODIMP
nsXFormsLabelAccessible::GetDescription(nsAString& aDescription)
{
nsAutoString description;
- nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::describedby,
- description);
+ nsresult rv = GetTextFromRelationID(eAria_describedby, description);
aDescription = description;
return rv;
}
// nsXFormsOutputAccessible
nsXFormsOutputAccessible::
nsXFormsOutputAccessible(nsIDOMNode *aNode, nsIWeakReference *aShell):