Bug 290344. Implement accessible DHTML descriptions and labels. r=timeless, sr=dmose, a=shaver

This commit is contained in:
aaronleventhal%moonset.net 2005-06-01 14:03:38 +00:00
parent 5bf10977f4
commit df7104eccc
18 changed files with 283 additions and 187 deletions

View File

@ -91,6 +91,10 @@ ACCESSIBILITY_ATOM(thead, "thead")
ACCESSIBILITY_ATOM(toolbaritem, "toolbaritem")
ACCESSIBILITY_ATOM(ul, "ul")
// DHTML accessibility relationship attributes
ACCESSIBILITY_ATOM(labelledby, "labelledby")
ACCESSIBILITY_ATOM(describedby, "describedby")
// Alphabetical list of attributes
ACCESSIBILITY_ATOM(acceltext, "acceltext")
ACCESSIBILITY_ATOM(accesskey, "accesskey")

View File

@ -70,6 +70,7 @@
#include "nsGUIEvent.h"
#include "nsIDOMHTMLInputElement.h"
#include "nsIDOMXULSelectCntrlEl.h"
#include "nsIDOMXULSelectCntrlItemEl.h"
#include "nsIDOMHTMLObjectElement.h"
#include "nsIDOMXULButtonElement.h"
@ -133,27 +134,21 @@ nsAccessible::~nsAccessible()
NS_IMETHODIMP nsAccessible::GetName(nsAString& aName)
{
aName.Truncate();
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (!content) {
return NS_ERROR_FAILURE; // Node shut down
}
if (mRoleMapEntry) {
if (mRoleMapEntry->nameRule == eNoName) {
return NS_OK;
}
if (mRoleMapEntry->nameRule == eNameFromSubtree) {
// DHTML accessible name method for focusable items such as menuitem, treeitem, gridcell, etc.
nsresult rv = AppendFlatStringFromSubtree(content, &aName);
if (NS_SUCCEEDED(rv) && !aName.IsEmpty()) {
return rv;
}
}
PRBool canAggregateName = !mRoleMapEntry ||
mRoleMapEntry->nameRule == eNameOkFromChildren;
if (content->IsContentOfType(nsIContent::eHTML)) {
return GetHTMLName(aName, canAggregateName);
}
if (NS_CONTENT_ATTR_NOT_THERE ==
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::title, aName)) {
aName.SetIsVoid(PR_TRUE);
if (content->IsContentOfType(nsIContent::eXUL)) {
return GetXULName(aName, canAggregateName);
}
return NS_OK;
@ -161,23 +156,31 @@ NS_IMETHODIMP nsAccessible::GetName(nsAString& aName)
NS_IMETHODIMP nsAccessible::GetDescription(nsAString& aDescription)
{
// There are 3 conditions that make an accessible have no accDescription:
// There are 4 conditions that make an accessible have no accDescription:
// 1. it's a text node; or
// 2. it doesn't have an accName; or
// 3. its title attribute equals to its accName nsAutoString name;
nsCOMPtr<nsITextContent> textContent(do_QueryInterface(mDOMNode));
if (!textContent) {
nsAutoString name;
GetName(name);
if (!name.IsEmpty()) {
// If there's already a name, we'll expose a description.if it's different than the name
// If there is no name, then we know the title should really be exposed there
nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(mDOMNode));
if (elt)
elt->GetAttribute(NS_LITERAL_STRING("title"), aDescription);
if (!elt || aDescription == name)
aDescription.Truncate();
// 2. It has no DHTML describedby property
// 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->IsContentOfType(nsIContent::eTEXT)) {
nsAutoString description;
if (!mRoleMapEntry ||
NS_FAILED(GetTextFromRelationID(nsAccessibilityAtoms::describedby, description))) {
if (NS_CONTENT_ATTR_HAS_VALUE !=
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::title, description)) {
nsAutoString name;
GetName(name);
if (name.IsEmpty() || description == name) {
// Has no name or description is not unique
description.Truncate();
}
}
}
description.CompressWhitespace();
aDescription = description;
}
return NS_OK;
@ -1193,7 +1196,6 @@ nsresult nsAccessible::AppendFlatStringFromSubtreeRecurse(nsIContent *aContent,
return NS_OK;
}
nsIContent* nsAccessible::GetXULLabelContent(nsIContent *aForNode)
{
nsAutoString controlID;
@ -1256,6 +1258,38 @@ nsIContent* nsAccessible::GetHTMLLabelContent(nsIContent *aForNode)
return nsnull;
}
nsresult nsAccessible::GetTextFromRelationID(nsIAtom *aIDAttrib, 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 id;
if (NS_CONTENT_ATTR_HAS_VALUE !=
content->GetAttr(kNameSpaceID_StatesWAI_Unofficial, aIDAttrib, id)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMDocument> domDoc;
mDOMNode->GetOwnerDocument(getter_AddRefs(domDoc));
NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMElement> labelElement;
domDoc->GetElementById(id, getter_AddRefs(labelElement));
content = do_QueryInterface(labelElement);
if (!content) {
return NS_OK;
}
// We have a label content
nsresult rv = AppendFlatStringFromSubtree(content, &aName);
if (NS_SUCCEEDED(rv)) {
aName.CompressWhitespace();
}
return rv;
}
// Pass in forAttrib == nsnull if any <label> will do
nsIContent *nsAccessible::GetLabelForId(nsIContent *aLookContent,
nsIAtom *forAttrib,
@ -1292,14 +1326,24 @@ nsIContent *nsAccessible::GetLabelForId(nsIContent *aLookContent,
*/
nsresult nsAccessible::GetHTMLName(nsAString& aLabel, PRBool aCanAggregateSubtree)
{
if (!mWeakShell || !mDOMNode) {
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (!content) {
return NS_ERROR_FAILURE; // Node shut down
}
nsIContent *labelContent;
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if ((labelContent = GetHTMLLabelContent(content)) != nsnull) {
nsAutoString label;
// Check for DHTML accessibility labelledby relationship property
nsAutoString label;
nsresult rv;
if (mRoleMapEntry) {
rv = GetTextFromRelationID(nsAccessibilityAtoms::labelledby, label);
if (NS_SUCCEEDED(rv)) {
aLabel = label;
return rv;
}
}
nsIContent *labelContent = GetHTMLLabelContent(content);
if (labelContent) {
AppendFlatStringFromSubtree(labelContent, &label);
label.CompressWhitespace();
if (!label.IsEmpty()) {
@ -1308,17 +1352,20 @@ nsresult nsAccessible::GetHTMLName(nsAString& aLabel, PRBool aCanAggregateSubtre
}
}
if (!aCanAggregateSubtree) {
if (aCanAggregateSubtree) {
// Don't use AppendFlatStringFromSubtree for container widgets like menulist
// Still try the title as as fallback method in that case.
if (NS_CONTENT_ATTR_NOT_THERE ==
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::title, aLabel)) {
aLabel.SetIsVoid(PR_TRUE);
nsresult rv = AppendFlatStringFromSubtree(content, &aLabel);
if (NS_SUCCEEDED(rv)) {
return NS_OK;
}
return NS_OK;
}
return nsAccessible::GetName(aLabel);
// Still try the title as as fallback method in that case.
if (NS_CONTENT_ATTR_NOT_THERE ==
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::title, aLabel)) {
aLabel.SetIsVoid(PR_TRUE);
}
return NS_OK;
}
/**
@ -1338,8 +1385,16 @@ nsresult nsAccessible::GetXULName(nsAString& aLabel, PRBool aCanAggregateSubtree
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
NS_ASSERTION(content, "No nsIContent for DOM node");
nsresult rv = NS_OK;
// First check for label override via accessibility labelledby relationship
nsAutoString label;
nsresult rv;
if (mRoleMapEntry) {
rv = GetTextFromRelationID(nsAccessibilityAtoms::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));
@ -1352,9 +1407,14 @@ nsresult nsAccessible::GetXULName(nsAString& aLabel, PRBool aCanAggregateSubtree
rv = itemEl->GetLabel(label);
}
else {
nsCOMPtr<nsIDOMXULElement> xulEl(do_QueryInterface(mDOMNode));
if (xulEl) {
rv = xulEl->GetAttribute(NS_LITERAL_STRING("label"), label);
nsCOMPtr<nsIDOMXULSelectControlElement> select(do_QueryInterface(mDOMNode));
// Use label if this is not a select control element which
// uses label attribute to indicate which option is selected
if (!select) {
nsCOMPtr<nsIDOMXULElement> xulEl(do_QueryInterface(mDOMNode));
if (xulEl) {
rv = xulEl->GetAttribute(NS_LITERAL_STRING("label"), label);
}
}
}
}
@ -1423,102 +1483,109 @@ nsRoleMapEntry nsAccessible::gWAIRoleMap[] =
// 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.
{"alert", ROLE_ALERT, eNameFromSubtree, eNoValue, eNoReqStates, END_ENTRY},
{"application", ROLE_APPLICATION, eNoName, eNoValue, eNoReqStates, END_ENTRY},
{"button", ROLE_PUSHBUTTON, eNameFromSubtree, eNoValue, eNoReqStates,
{"alert", ROLE_ALERT, eNameOkFromChildren, eNoValue, eNoReqStates, END_ENTRY},
{"application", ROLE_APPLICATION, eNameLabelOrTitle, eNoValue, eNoReqStates, END_ENTRY},
{"button", ROLE_PUSHBUTTON, eNameOkFromChildren, eNoValue, eNoReqStates,
{"pressed", BOOL_STATE, STATE_PRESSED},
{"haspopup", BOOL_STATE, STATE_HASPOPUP}, END_ENTRY},
{"button-submit", ROLE_PUSHBUTTON, eNameFromSubtree, eNoValue, STATE_DEFAULT, END_ENTRY},
{"checkbox", ROLE_CHECKBUTTON, eNameFromSubtree, eNoValue, eNoReqStates,
{"button-submit", ROLE_PUSHBUTTON, eNameOkFromChildren, eNoValue, STATE_DEFAULT, END_ENTRY},
{"checkbox", ROLE_CHECKBUTTON, eNameOkFromChildren, eNoValue, eNoReqStates,
{"checked", BOOL_STATE, STATE_CHECKED},
{"readonly", BOOL_STATE, STATE_READONLY},
{"invalid", BOOL_STATE, STATE_INVALID},
{"required", BOOL_STATE, STATE_REQUIRED}, END_ENTRY},
{"checkbox-tristate", ROLE_CHECKBUTTON, eNameFromSubtree, eNoValue, eNoReqStates,
{"checkbox-tristate", ROLE_CHECKBUTTON, eNameOkFromChildren, eNoValue, eNoReqStates,
{"checked", BOOL_STATE, STATE_CHECKED},
{"checked", "mixed", STATE_MIXED},
{"readonly", BOOL_STATE, STATE_READONLY},
{"invalid", BOOL_STATE, STATE_INVALID},
{"required", BOOL_STATE, STATE_REQUIRED}},
{"columnheader", ROLE_COLUMNHEADER, eNameFromSubtree, eNoValue, STATE_SELECTABLE,
{"columnheader", ROLE_COLUMNHEADER, eNameOkFromChildren, eNoValue, STATE_SELECTABLE,
{"selected", BOOL_STATE, STATE_SELECTED},
{"readonly", BOOL_STATE, STATE_READONLY}, END_ENTRY},
{"combobox", ROLE_COMBOBOX, eNameFromTitle, eNoValue, eNoReqStates,
{"readonly", BOOL_STATE, STATE_READONLY},
{"multiselect", BOOL_STATE, STATE_MULTISELECTABLE | STATE_EXTSELECTABLE}, END_ENTRY},
{"dialog", ROLE_DIALOG, eNoName, eNoValue, eNoReqStates, END_ENTRY},
{"document", ROLE_DOCUMENT, eNoName, eNoValue, eNoReqStates, END_ENTRY},
{"icon", ROLE_ICON, eNameFromSubtree, eNoValue, eNoReqStates, END_ENTRY},
{"list", ROLE_LIST, eNameFromTitle, eNoValue, eNoReqStates,
{"combobox", ROLE_COMBOBOX, eNameLabelOrTitle, eNoValue, eNoReqStates,
{"readonly", BOOL_STATE, STATE_READONLY},
{"multiselect", BOOL_STATE, STATE_MULTISELECTABLE | STATE_EXTSELECTABLE}, END_ENTRY},
{"listitem", ROLE_LISTITEM, eNameFromSubtree, eNoValue, STATE_SELECTABLE,
{"description", ROLE_STATICTEXT, eNameOkFromChildren, eNoValue, eNoReqStates, END_ENTRY},
{"dialog", ROLE_DIALOG, eNameLabelOrTitle, eNoValue, eNoReqStates, END_ENTRY},
{"document", ROLE_DOCUMENT, eNameLabelOrTitle, eNoValue, eNoReqStates, END_ENTRY},
{"icon", ROLE_ICON, eNameOkFromChildren, eNoValue, eNoReqStates, END_ENTRY},
{"label", ROLE_STATICTEXT, eNameOkFromChildren, eNoValue, eNoReqStates, END_ENTRY},
{"list", ROLE_LIST, eNameLabelOrTitle, eNoValue, eNoReqStates,
{"readonly", BOOL_STATE, STATE_READONLY},
{"multiselect", BOOL_STATE, STATE_MULTISELECTABLE | STATE_EXTSELECTABLE}, END_ENTRY},
{"listitem", ROLE_LISTITEM, eNameOkFromChildren, eNoValue, STATE_SELECTABLE, END_ENTRY},
{"listitem-checkbox", ROLE_LISTITEM, eNameOkFromChildren, eNoValue, STATE_SELECTABLE,
{"checked", BOOL_STATE, STATE_CHECKED}, END_ENTRY },
{"menu", ROLE_MENUPOPUP, eNameFromTitle, eNoValue, eNoReqStates, END_ENTRY},
{"menubar", ROLE_MENUBAR, eNameFromTitle, eNoValue, eNoReqStates, END_ENTRY},
{"menuitem", ROLE_MENUITEM, eNameFromSubtree, eNoValue, eNoReqStates,
{"menu", ROLE_MENUPOPUP, eNameLabelOrTitle, eNoValue, eNoReqStates, END_ENTRY},
{"menubar", ROLE_MENUBAR, eNameLabelOrTitle, eNoValue, eNoReqStates, END_ENTRY},
{"menuitem", ROLE_MENUITEM, eNameOkFromChildren, eNoValue, eNoReqStates,
{"haspopup", BOOL_STATE, STATE_HASPOPUP}, END_ENTRY},
{"menuitem-radio", ROLE_MENUITEM, eNameFromSubtree, eNoValue, eNoReqStates,
{"menuitem-radio", ROLE_MENUITEM, eNameOkFromChildren, eNoValue, eNoReqStates,
{"haspopup", BOOL_STATE, STATE_HASPOPUP},
{"checked", BOOL_STATE, STATE_CHECKED}, END_ENTRY},
{"menuitem-checkbox", ROLE_MENUITEM, eNameFromSubtree, eNoValue, eNoReqStates,
{"menuitem-checkbox", ROLE_MENUITEM, eNameOkFromChildren, eNoValue, eNoReqStates,
{"haspopup", BOOL_STATE, STATE_HASPOPUP},
{"checked", BOOL_STATE, STATE_CHECKED}, END_ENTRY},
{"grid", ROLE_TABLE, eNameFromTitle, eNoValue, STATE_FOCUSABLE,
{"grid", ROLE_TABLE, eNameLabelOrTitle, eNoValue, STATE_FOCUSABLE,
{"readonly", BOOL_STATE, STATE_READONLY}, END_ENTRY},
{"gridcell", ROLE_CELL, eNameFromSubtree, eHasValueMinMax, STATE_SELECTABLE,
{"gridcell", ROLE_CELL, eNameOkFromChildren, eHasValueMinMax, STATE_SELECTABLE,
{"selected", BOOL_STATE, STATE_SELECTED},
{"readonly", BOOL_STATE, STATE_READONLY},
{"readonly", BOOL_STATE, STATE_READONLY},
{"invalid", BOOL_STATE, STATE_INVALID},
{"required", BOOL_STATE, STATE_REQUIRED}, END_ENTRY},
{"group", ROLE_GROUPING, eNameFromTitle, eNoValue, eNoReqStates, END_ENTRY},
{"link", ROLE_LINK, eNameFromTitle, eNoValue, STATE_LINKED, END_ENTRY},
{"progressbar", ROLE_PROGRESSBAR, eNameFromTitle, eHasValueMinMax, STATE_READONLY,
{"group", ROLE_GROUPING, eNameLabelOrTitle, eNoValue, eNoReqStates, END_ENTRY},
{"link", ROLE_LINK, eNameLabelOrTitle, eNoValue, STATE_LINKED, END_ENTRY},
{"progressbar", ROLE_PROGRESSBAR, eNameLabelOrTitle, eHasValueMinMax, STATE_READONLY,
{"valuenow", "unknown", STATE_MIXED}, END_ENTRY},
{"radio", ROLE_RADIOBUTTON, eNameFromSubtree, eNoValue, eNoReqStates,
{"radio", ROLE_RADIOBUTTON, eNameOkFromChildren, eNoValue, eNoReqStates,
{"checked", BOOL_STATE, STATE_CHECKED}, END_ENTRY},
{"radiogroup", ROLE_GROUPING, eNameFromTitle, eNoValue, eNoReqStates,
{"radiogroup", ROLE_GROUPING, eNameLabelOrTitle, eNoValue, eNoReqStates,
{"invalid", BOOL_STATE, STATE_INVALID},
{"required", BOOL_STATE, STATE_REQUIRED}, END_ENTRY},
{"rowheader", ROLE_ROWHEADER, eNameFromSubtree, eNoValue, STATE_SELECTABLE,
{"rowheader", ROLE_ROWHEADER, eNameOkFromChildren, eNoValue, STATE_SELECTABLE,
{"selected", BOOL_STATE, STATE_SELECTED},
{"readonly", BOOL_STATE, STATE_READONLY}, END_ENTRY},
{"secret", ROLE_PASSWORD_TEXT, eNameFromTitle, eNoValue, STATE_PROTECTED,
{"secret", ROLE_PASSWORD_TEXT, eNameLabelOrTitle, eNoValue, STATE_PROTECTED,
{"invalid", BOOL_STATE, STATE_INVALID},
{"required", BOOL_STATE, STATE_REQUIRED}, END_ENTRY}, // XXX EXT_STATE_SINGLE_LINE
{"separator", ROLE_SEPARATOR, eNameFromTitle, eNoValue, eNoReqStates, END_ENTRY},
{"slider", ROLE_SLIDER, eNameFromTitle, eHasValueMinMax, eNoReqStates,
{"separator", ROLE_SEPARATOR, eNameLabelOrTitle, eNoValue, eNoReqStates, END_ENTRY},
{"slider", ROLE_SLIDER, eNameLabelOrTitle, eHasValueMinMax, eNoReqStates,
{"readonly", BOOL_STATE, STATE_READONLY},
{"invalid", BOOL_STATE, STATE_INVALID},
{"required", BOOL_STATE, STATE_REQUIRED}, END_ENTRY},
{"spinbutton", ROLE_SPINBUTTON, eNameFromTitle, eHasValueMinMax, eNoReqStates,
{"spinbutton", ROLE_SPINBUTTON, eNameLabelOrTitle, eHasValueMinMax, eNoReqStates,
{"readonly", BOOL_STATE, STATE_READONLY},
{"invalid", BOOL_STATE, STATE_INVALID},
{"required", BOOL_STATE, STATE_REQUIRED}, END_ENTRY},
{"spreadsheet", ROLE_TABLE, eNameFromTitle, eNoValue, STATE_MULTISELECTABLE | STATE_EXTSELECTABLE | STATE_FOCUSABLE,
{"spreadsheet", ROLE_TABLE, eNameLabelOrTitle, eNoValue, STATE_MULTISELECTABLE | STATE_EXTSELECTABLE | STATE_FOCUSABLE,
{"readonly", BOOL_STATE, STATE_READONLY}, END_ENTRY},
{"tab", ROLE_PAGETAB, eNameFromSubtree, eNoValue, eNoReqStates, END_ENTRY},
{"tablist", ROLE_PAGETABLIST, eNameFromSubtree, eNoValue, eNoReqStates, END_ENTRY},
{"tabpanel", ROLE_PROPERTYPAGE, eNameFromSubtree, eNoValue, eNoReqStates, END_ENTRY},
{"textarea", ROLE_TEXT, eNameFromTitle, eHasValueMinMax, eNoReqStates,
{"tab", ROLE_PAGETAB, eNameOkFromChildren, eNoValue, eNoReqStates, END_ENTRY},
{"tablist", ROLE_PAGETABLIST, eNameLabelOrTitle, eNoValue, eNoReqStates, END_ENTRY},
{"tabpanel", ROLE_PROPERTYPAGE, eNameLabelOrTitle, eNoValue, eNoReqStates, END_ENTRY},
{"textarea", ROLE_TEXT, eNameLabelOrTitle, eHasValueMinMax, eNoReqStates,
{"readonly", BOOL_STATE, STATE_READONLY},
{"invalid", BOOL_STATE, STATE_INVALID},
{"required", BOOL_STATE, STATE_REQUIRED}, END_ENTRY}, // XXX EXT_STATE_MULTI_LINE
{"textfield", ROLE_TEXT, eNameFromTitle, eHasValueMinMax, eNoReqStates,
{"textfield", ROLE_TEXT, eNameLabelOrTitle, eHasValueMinMax, eNoReqStates,
{"readonly", BOOL_STATE, STATE_READONLY},
{"invalid", BOOL_STATE, STATE_INVALID},
{"required", BOOL_STATE, STATE_REQUIRED},
{"haspopup", BOOL_STATE, STATE_HASPOPUP}, END_ENTRY}, // XXX EXT_STATE_SINGLE_LINE
{"toolbar", ROLE_TOOLBAR, eNoName, eNoValue, eNoReqStates, END_ENTRY},
{"tree", ROLE_OUTLINE, eNameFromTitle, eNoValue, eNoReqStates,
{"toolbar", ROLE_TOOLBAR, eNameLabelOrTitle, eNoValue, eNoReqStates, END_ENTRY},
{"tree", ROLE_OUTLINE, eNameLabelOrTitle, eNoValue, eNoReqStates,
{"readonly", BOOL_STATE, STATE_READONLY},
{"multiselectable", BOOL_STATE, STATE_MULTISELECTABLE | STATE_EXTSELECTABLE}, END_ENTRY},
{"treeitem", ROLE_OUTLINEITEM, eNameFromSubtree, eNoValue, STATE_SELECTABLE,
{"treeitem", ROLE_OUTLINEITEM, eNameOkFromChildren, eNoValue, STATE_SELECTABLE,
{"selected", BOOL_STATE, STATE_SELECTED},
{"expanded", BOOL_STATE, STATE_EXPANDED},
{"expanded", "false", STATE_COLLAPSED}, END_ENTRY},
{"treeitem-checkbox", ROLE_OUTLINEITEM, eNameOkFromChildren, eNoValue, STATE_SELECTABLE,
{"selected", BOOL_STATE, STATE_SELECTED},
{"expanded", BOOL_STATE, STATE_EXPANDED},
{"expanded", "false", STATE_COLLAPSED},
{"checked", BOOL_STATE, STATE_CHECKED}, END_ENTRY},
{nsnull, ROLE_NOTHING, eNoName, eNoValue, eNoReqStates, END_ENTRY} // Last item
{nsnull, ROLE_NOTHING, eNameLabelOrTitle, eNoValue, eNoReqStates, END_ENTRY} // Last item
};
// XHTML 2 roles
@ -1579,7 +1646,12 @@ NS_IMETHODIMP nsAccessible::GetFinalState(PRUint32 *aState)
PRUint32 finalState = *aState;
finalState &= ~STATE_READONLY; // Once DHTML role is used, we're only readonly if DHTML readonly used
if (gLastFocusedNode == mDOMNode && (mRoleMapEntry->state & STATE_SELECTABLE)) {
if (finalState & STATE_UNAVAILABLE) {
// Disabled elements are not selectable or focusable, even if disabled
// via DHTML accessibility disabled property
finalState &= ~(STATE_SELECTABLE | STATE_FOCUSABLE);
}
else if (gLastFocusedNode == mDOMNode && (mRoleMapEntry->state & STATE_SELECTABLE)) {
// If we're focused and selectable and not inside a multiselect,
// then we're also selected
nsCOMPtr<nsIAccessible> container = this;

View File

@ -64,9 +64,14 @@ struct nsStateMapEntry
};
enum ENameRule {
eNoName,
eNameFromSubtree, // Collect name from text & img descendents; use title if resulting name is "".
eNameFromTitle // Use the title attribute for a name
eNameLabelOrTitle, // Collect name if explicitly specified from
// 1) content subtree pointed to by labelledby
// which contains the ID for the label content, or
// 2) title attribute if specified
eNameOkFromChildren // Collect name from
// 1) labelledby attribute if specified, or
// 2) text & img descendents, or
// 3) title attribute if specified
};
enum EValueRule {
@ -136,7 +141,9 @@ protected:
virtual nsIFrame* GetBoundsFrame();
virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
PRBool IsPartiallyVisible(PRBool *aIsOffscreen);
static nsIContent *GetLabelForId(nsIContent *aLookContent, nsIAtom *forAttrib,
nsresult GetTextFromRelationID(nsIAtom *aIDAttrib, nsString &aName);
static nsIContent *GetLabelForId(nsIContent *aLookContent,
nsIAtom *forAttrib,
const nsAString *aId);
static nsIContent *GetXULLabelContent(nsIContent *aForNode);
static nsIContent *GetHTMLLabelContent(nsIContent *aForNode);

View File

@ -128,7 +128,16 @@ NS_IMPL_RELEASE_INHERITED(nsDocAccessible, nsBlockAccessible)
NS_IMETHODIMP nsDocAccessible::GetName(nsAString& aName)
{
return GetTitle(aName);
nsresult rv = NS_OK;
aName.Truncate();
if (mRoleMapEntry) {
rv = nsAccessible::GetName(aName);
}
if (aName.IsEmpty()) {
rv = GetTitle(aName);
}
return rv;
}
NS_IMETHODIMP nsDocAccessible::GetRole(PRUint32 *aRole)

View File

@ -55,20 +55,6 @@ nsAccessibleWrap(aNode, aShell)
NS_IMPL_ISUPPORTS_INHERITED0(nsFormControlAccessible, nsAccessible)
/**
* Will be called by both HTML and XUL elements, this method
* merely checks who is calling and then calls the appropriate
* protected method for the XUL or HTML element.
*/
NS_IMETHODIMP nsFormControlAccessible::GetName(nsAString& _retval)
{
nsCOMPtr<nsIDOMXULElement> xulFormElement(do_QueryInterface(mDOMNode));
if (xulFormElement)
return GetXULName(_retval);
else
return GetHTMLName(_retval);
}
/**
* No Children
*/

View File

@ -51,7 +51,6 @@ class nsFormControlAccessible : public nsAccessibleWrap
public:
nsFormControlAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
NS_DECL_ISUPPORTS_INHERITED
NS_IMETHOD GetName(nsAString& _retval);
NS_IMETHOD GetFirstChild(nsIAccessible **_retval);
NS_IMETHOD GetLastChild(nsIAccessible **_retval);
NS_IMETHOD GetChildCount(PRInt32 *_retval);

View File

@ -67,8 +67,9 @@ NS_IMETHODIMP nsOuterDocAccessible::GetName(nsAString& aName)
return NS_ERROR_FAILURE;
}
nsresult rv = accDoc->GetTitle(aName);
if (NS_FAILED(rv) || aName.IsEmpty())
rv = accDoc->GetURL(aName);
if (NS_FAILED(rv) || aName.IsEmpty()) {
rv = mRoleMapEntry ? nsAccessible::GetName(aName) : accDoc->GetURL(aName);
}
return rv;
}

View File

@ -122,6 +122,13 @@ NS_IMETHODIMP nsRootAccessible::GetName(nsAString& aName)
return NS_ERROR_FAILURE;
}
if (mRoleMapEntry) {
nsAccessible::GetName(aName);
if (!aName.IsEmpty()) {
return NS_OK;
}
}
nsIScriptGlobalObject *globalScript = mDocument->GetScriptGlobalObject();
nsIDocShell *docShell = nsnull;
if (globalScript) {
@ -660,7 +667,9 @@ NS_IMETHODIMP nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
// when the list is open, based on DOMMenuitemActive events
nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem;
selectControl->GetSelectedItem(getter_AddRefs(selectedItem));
targetNode = do_QueryInterface(selectedItem);
if (selectedItem) {
targetNode = do_QueryInterface(selectedItem);
}
if (!targetNode ||
NS_FAILED(mAccService->GetAccessibleInShell(targetNode, eventShell,

View File

@ -56,14 +56,21 @@ nsLinkableAccessible(aDomNode, aShell)
}
/* wstring getName (); */
NS_IMETHODIMP nsHTMLAreaAccessible::GetName(nsAString & _retval)
NS_IMETHODIMP nsHTMLAreaAccessible::GetName(nsAString & aName)
{
aName.Truncate();
if (mRoleMapEntry) {
nsresult rv = nsAccessible::GetName(aName);
if (!aName.IsEmpty()) {
return rv;
}
}
nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(mDOMNode));
if (elt) {
nsAutoString hrefString;
elt->GetAttribute(NS_LITERAL_STRING("title"), _retval);
if (_retval.IsEmpty())
GetValue(_retval);
elt->GetAttribute(NS_LITERAL_STRING("title"), aName);
if (aName.IsEmpty())
return GetValue(aName);
}
return NS_OK;
}

View File

@ -210,25 +210,31 @@ NS_IMETHODIMP nsHTMLButtonAccessible::GetName(nsAString& aName)
name) &&
NS_CONTENT_ATTR_HAS_VALUE != content->GetAttr(kNameSpaceID_None,
nsAccessibilityAtoms::alt,
name) &&
NS_CONTENT_ATTR_HAS_VALUE != content->GetAttr(kNameSpaceID_None,
nsAccessibilityAtoms::title,
name) &&
NS_CONTENT_ATTR_HAS_VALUE != content->GetAttr(kNameSpaceID_None,
nsAccessibilityAtoms::src,
name) &&
NS_CONTENT_ATTR_HAS_VALUE != content->GetAttr(kNameSpaceID_None,
nsAccessibilityAtoms::data,
name)) {
// Use anonymous text child of button if nothing else works.
// This is necessary for submit, reset and browse buttons.
nsCOMPtr<nsIPresShell> shell(GetPresShell());
NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
nsCOMPtr<nsISupportsArray> anonymousElements;
shell->GetAnonymousContentFor(content, getter_AddRefs(anonymousElements));
nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(anonymousElements, 0));
if (domNode) {
domNode->GetNodeValue(name);
if (mRoleMapEntry) {
// Use HTML label or DHTML accessibility's labelledby attribute for name
GetHTMLName(name, PR_FALSE);
}
if (name.IsEmpty()) {
// Use anonymous text child of button if nothing else works.
// This is necessary for submit, reset and browse buttons.
nsCOMPtr<nsIPresShell> shell(GetPresShell());
NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
nsCOMPtr<nsISupportsArray> anonymousElements;
shell->GetAnonymousContentFor(content, getter_AddRefs(anonymousElements));
nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(anonymousElements, 0));
if (domNode) {
domNode->GetNodeValue(name);
}
}
if (name.IsEmpty() &&
NS_CONTENT_ATTR_HAS_VALUE != content->GetAttr(kNameSpaceID_None,
nsAccessibilityAtoms::title,
name) &&
NS_CONTENT_ATTR_HAS_VALUE != content->GetAttr(kNameSpaceID_None,
nsAccessibilityAtoms::src,
name)) {
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::data, name);
}
}
@ -297,25 +303,6 @@ NS_IMETHODIMP nsHTML4ButtonAccessible::GetState(PRUint32 *_retval)
return NS_OK;
}
NS_IMETHODIMP nsHTML4ButtonAccessible::GetName(nsAString& _retval)
{
nsresult rv = NS_ERROR_FAILURE;
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
nsAutoString name;
if (content)
rv = AppendFlatStringFromSubtree(content, &name);
if (NS_SUCCEEDED(rv)) {
// Temp var needed until CompressWhitespace built for nsAString
name.CompressWhitespace();
_retval.Assign(name);
}
return rv;
}
// --- textfield -----
nsHTMLTextFieldAccessible::nsHTMLTextFieldAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
@ -433,8 +420,15 @@ NS_IMETHODIMP nsHTMLGroupboxAccessible::GetState(PRUint32 *_retval)
return NS_OK;
}
NS_IMETHODIMP nsHTMLGroupboxAccessible::GetName(nsAString& _retval)
NS_IMETHODIMP nsHTMLGroupboxAccessible::GetName(nsAString& aName)
{
if (mRoleMapEntry) {
nsAccessible::GetName(aName);
if (!aName.IsEmpty()) {
return NS_OK;
}
}
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(mDOMNode));
if (element) {
nsCOMPtr<nsIDOMNodeList> legends;
@ -447,8 +441,8 @@ NS_IMETHODIMP nsHTMLGroupboxAccessible::GetName(nsAString& _retval)
legends->Item(0, getter_AddRefs(legendNode));
nsCOMPtr<nsIContent> legendContent(do_QueryInterface(legendNode));
if (legendContent) {
_retval.Truncate(); // Default name is blank
return AppendFlatStringFromSubtree(legendContent, &_retval);
aName.Truncate(); // Default name is blank
return AppendFlatStringFromSubtree(legendContent, &aName);
}
}
}

View File

@ -81,7 +81,6 @@ class nsHTML4ButtonAccessible : public nsLeafAccessible
public:
nsHTML4ButtonAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
NS_IMETHOD GetRole(PRUint32 *_retval);
NS_IMETHOD GetName(nsAString& _retval);
NS_IMETHOD GetState(PRUint32 *_retval);
NS_IMETHOD GetNumActions(PRUint8 *_retval);
NS_IMETHOD GetActionName(PRUint8 index, nsAString& _retval);

View File

@ -111,11 +111,17 @@ NS_IMETHODIMP nsHTMLImageAccessible::GetName(nsAString& aName)
if (NS_CONTENT_ATTR_HAS_VALUE != content->GetAttr(kNameSpaceID_None,
nsAccessibilityAtoms::alt,
aName) &&
NS_CONTENT_ATTR_HAS_VALUE != content->GetAttr(kNameSpaceID_None,
aName)) {
if (mRoleMapEntry) {
// Use HTML label or DHTML accessibility's labelledby attribute for name
// GetHTMLName will also try title attribute as a last resort
return GetHTMLName(aName, PR_FALSE);
}
if (NS_CONTENT_ATTR_HAS_VALUE != content->GetAttr(kNameSpaceID_None,
nsAccessibilityAtoms::title,
aName)) {
aName.SetIsVoid(PR_TRUE); // No alt or title
aName.SetIsVoid(PR_TRUE); // No alt or title
}
}
return NS_OK;

View File

@ -108,9 +108,16 @@ NS_IMETHODIMP nsHTMLTableAccessible::GetState(PRUint32 *aResult)
return NS_OK;
}
NS_IMETHODIMP nsHTMLTableAccessible::GetName(nsAString& aResult)
NS_IMETHODIMP nsHTMLTableAccessible::GetName(nsAString& aName)
{
aResult.Truncate(); // Default name is blank
aName.Truncate(); // Default name is blank
if (mRoleMapEntry) {
nsAccessible::GetName(aName);
if (!aName.IsEmpty()) {
return NS_OK;
}
}
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(mDOMNode));
if (element) {
@ -124,7 +131,7 @@ NS_IMETHODIMP nsHTMLTableAccessible::GetName(nsAString& aResult)
captions->Item(0, getter_AddRefs(captionNode));
if (captionNode) {
nsCOMPtr<nsIContent> captionContent(do_QueryInterface(captionNode));
AppendFlatStringFromSubtree(captionContent, &aResult);
AppendFlatStringFromSubtree(captionContent, &aName);
}
}
}

View File

@ -282,7 +282,16 @@ NS_IMETHODIMP nsAccessibleWrap::GetDescription(nsAString& aDescription)
(currentRole != ROLE_LISTITEM && currentRole != ROLE_MENUITEM &&
currentRole != ROLE_RADIOBUTTON && currentRole != ROLE_PAGETAB &&
currentRole != ROLE_OUTLINEITEM)) {
return rv;
nsAutoString description;
nsAccessible::GetDescription(description);
if (!description.IsEmpty()) {
// Signal to screen readers that this description is speakable
// and is not a formatted positional information description
// Don't localize the "Description: " part of this string, it will be
// parsed out by assistive technologies.
aDescription = NS_LITERAL_STRING("Description: ") + description;
}
return NS_OK;
}
nsCOMPtr<nsIAccessible> parent;

View File

@ -64,11 +64,6 @@ nsAccessibleWrap(aNode, aShell)
{
}
NS_IMETHODIMP nsXULButtonAccessible::GetName(nsAString& aResult)
{
return GetXULName(aResult);
}
/**
* Only one actions available
*/
@ -410,10 +405,16 @@ NS_IMETHODIMP nsXULGroupboxAccessible::GetState(PRUint32 *_retval)
return NS_OK;
}
NS_IMETHODIMP nsXULGroupboxAccessible::GetName(nsAString& _retval)
NS_IMETHODIMP nsXULGroupboxAccessible::GetName(nsAString& aName)
{
_retval.Truncate(); // Default name is blank
aName.Truncate(); // Default name is blank
if (mRoleMapEntry) {
nsAccessible::GetName(aName);
if (!aName.IsEmpty()) {
return NS_OK;
}
}
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(mDOMNode));
if (element) {
nsCOMPtr<nsIDOMNodeList> captions;
@ -427,7 +428,7 @@ NS_IMETHODIMP nsXULGroupboxAccessible::GetName(nsAString& _retval)
if (captionNode) {
element = do_QueryInterface(captionNode);
NS_ASSERTION(element, "No nsIDOMElement for caption node!");
element->GetAttribute(NS_LITERAL_STRING("label"), _retval) ;
element->GetAttribute(NS_LITERAL_STRING("label"), aName) ;
}
}
}

View File

@ -49,7 +49,6 @@ class nsXULButtonAccessible : public nsAccessibleWrap
{
public:
nsXULButtonAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
NS_IMETHOD GetName(nsAString& aResult);
NS_IMETHOD GetRole(PRUint32 *_retval);
NS_IMETHOD GetState(PRUint32 *_retval);
NS_IMETHOD GetNumActions(PRUint8 *_retval);
@ -150,7 +149,6 @@ class nsXULTextFieldAccessible : public nsLeafAccessible
{
public:
nsXULTextFieldAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
NS_IMETHOD GetName(nsAString& aName) { return GetXULName(aName); }
NS_IMETHOD GetValue(nsAString& aValue);
NS_IMETHOD GetState(PRUint32 *aState);
NS_IMETHOD GetExtState(PRUint32 *aExtState);

View File

@ -54,17 +54,6 @@ nsLeafAccessible(aNode, aShell)
{
}
/**
* Might need to use the GetXULName method from nsFormControlAcc.cpp
*/
NS_IMETHODIMP nsXULTabAccessible::GetName(nsAString& _retval)
{
nsCOMPtr<nsIDOMXULSelectControlItemElement> tab(do_QueryInterface(mDOMNode));
if (tab)
return GetXULName(_retval);
return NS_ERROR_FAILURE;
}
/** Only one action available */
NS_IMETHODIMP nsXULTabAccessible::GetNumActions(PRUint8 *_retval)
{

View File

@ -49,7 +49,6 @@ class nsXULTabAccessible : public nsLeafAccessible
public:
nsXULTabAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
NS_IMETHOD GetRole(PRUint32 *_retval);
NS_IMETHOD GetName(nsAString& _retval);
NS_IMETHOD GetState(PRUint32 *_retval);
NS_IMETHOD GetNumActions(PRUint8 *_retval);
NS_IMETHOD GetActionName(PRUint8 index, nsAString& _retval);