Bug 480099 - If an html:label has both a title and inner text, title becomes acc name for control this label is labelling, r=marcoz, davidb

This commit is contained in:
Alexander Surkov 2009-02-27 18:54:39 +08:00
Родитель 8f64d4b704
Коммит ae4701c348
5 изменённых файлов: 132 добавлений и 43 удалений

Просмотреть файл

@ -308,10 +308,12 @@ nsAccessible::GetName(nsAString& aName)
if (content->GetAttr(kNameSpaceID_None, tooltipAttr, name)) {
name.CompressWhitespace();
aName = name;
} else if (rv != NS_OK_EMPTY_NAME) {
aName.SetIsVoid(PR_TRUE);
return NS_OK_NAME_FROM_TOOLTIP;
}
if (rv != NS_OK_EMPTY_NAME)
aName.SetIsVoid(PR_TRUE);
return NS_OK;
}

Просмотреть файл

@ -77,6 +77,10 @@ NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_GENERAL, 0x21)
#define NS_OK_EMPTY_NAME \
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_GENERAL, 0x23)
// see nsAccessible::GetNameInternal
#define NS_OK_NAME_FROM_TOOLTIP \
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_GENERAL, 0x25)
// Saves a data member -- if child count equals this value we haven't
// cached children or child count yet
enum { eChildCountUninitialized = -1 };

Просмотреть файл

@ -239,15 +239,16 @@ nsTextEquivUtils::AppendFromAccessibleChildren(nsIAccessible *aAccessible,
nsCOMPtr<nsIAccessible> accChild, accNextChild;
aAccessible->GetFirstChild(getter_AddRefs(accChild));
nsresult rv = NS_OK_NO_NAME_CLAUSE_HANDLED;
while (accChild) {
nsresult rv = AppendFromAccessible(accChild, aString);
rv = AppendFromAccessible(accChild, aString);
NS_ENSURE_SUCCESS(rv, rv);
accChild->GetNextSibling(getter_AddRefs(accNextChild));
accChild.swap(accNextChild);
}
return NS_OK;
return rv;
}
nsresult
@ -271,49 +272,88 @@ nsTextEquivUtils::AppendFromAccessible(nsIAccessible *aAccessible,
nsresult rv = aAccessible->GetName(text);
NS_ENSURE_SUCCESS(rv, rv);
AppendString(aString, text);
PRBool isEmptyTextEquiv = PR_TRUE;
PRUint32 role = nsAccUtils::Role(aAccessible);
PRUint32 nameRule = gRoleToNameRulesMap[role];
// If the name is from tooltip then append it to result string in the end
// (see h. step of name computation guide).
if (rv != NS_OK_NAME_FROM_TOOLTIP)
isEmptyTextEquiv = !AppendString(aString, text);
if (nameRule == eFromValue) {
// Implementation of step f) of text equivalent computation. If the given
// accessible is not root accessible (the accessible the text equivalent is
// computed for in the end) then append accessible value. Otherwise append
// value if and only if the given accessible is in the middle of its parent.
// Implementation of f. step.
rv = AppendFromValue(aAccessible, aString);
NS_ENSURE_SUCCESS(rv, rv);
if (aAccessible != gInitiatorAcc) {
rv = aAccessible->GetValue(text);
NS_ENSURE_SUCCESS(rv, rv);
AppendString(aString, text);
} else {
nsCOMPtr<nsIAccessible> nextSibling;
aAccessible->GetNextSibling(getter_AddRefs(nextSibling));
if (nextSibling) {
nsCOMPtr<nsIAccessible> parent;
aAccessible->GetParent(getter_AddRefs(parent));
if (parent) {
nsCOMPtr<nsIAccessible> firstChild;
parent->GetFirstChild(getter_AddRefs(firstChild));
if (firstChild && firstChild != aAccessible) {
rv = aAccessible->GetValue(text);
NS_ENSURE_SUCCESS(rv, rv);
AppendString(aString, text);
}
}
}
}
}
if (rv != NS_OK_NO_NAME_CLAUSE_HANDLED)
isEmptyTextEquiv = PR_FALSE;
// Implementation of g) step of text equivalent computation guide. Go down
// into subtree if accessible allows "text equivalent from subtree rule" or
// it's not root and not control.
if (text.IsEmpty() && (nameRule & eFromSubtreeIfRec))
return AppendFromAccessibleChildren(aAccessible, aString);
if (isEmptyTextEquiv) {
PRUint32 role = nsAccUtils::Role(aAccessible);
PRUint32 nameRule = gRoleToNameRulesMap[role];
return NS_OK;
if (nameRule & eFromSubtreeIfRec) {
rv = AppendFromAccessibleChildren(aAccessible, aString);
NS_ENSURE_SUCCESS(rv, rv);
if (rv != NS_OK_NO_NAME_CLAUSE_HANDLED)
isEmptyTextEquiv = PR_FALSE;
}
}
// Implementation of h. step
if (isEmptyTextEquiv && !text.IsEmpty()) {
AppendString(aString, text);
return NS_OK;
}
return rv;
}
nsresult
nsTextEquivUtils::AppendFromValue(nsIAccessible *aAccessible,
nsAString *aString)
{
PRUint32 role = nsAccUtils::Role(aAccessible);
PRUint32 nameRule = gRoleToNameRulesMap[role];
if (nameRule != eFromValue)
return NS_OK_NO_NAME_CLAUSE_HANDLED;
// Implementation of step f. of text equivalent computation. If the given
// accessible is not root accessible (the accessible the text equivalent is
// computed for in the end) then append accessible value. Otherwise append
// value if and only if the given accessible is in the middle of its parent.
nsAutoString text;
if (aAccessible != gInitiatorAcc) {
nsresult rv = aAccessible->GetValue(text);
NS_ENSURE_SUCCESS(rv, rv);
return AppendString(aString, text) ?
NS_OK : NS_OK_NO_NAME_CLAUSE_HANDLED;
}
nsCOMPtr<nsIAccessible> nextSibling;
aAccessible->GetNextSibling(getter_AddRefs(nextSibling));
if (nextSibling) {
nsCOMPtr<nsIAccessible> parent;
aAccessible->GetParent(getter_AddRefs(parent));
if (parent) {
nsCOMPtr<nsIAccessible> firstChild;
parent->GetFirstChild(getter_AddRefs(firstChild));
if (firstChild && firstChild != aAccessible) {
nsresult rv = aAccessible->GetValue(text);
NS_ENSURE_SUCCESS(rv, rv);
return AppendString(aString, text) ?
NS_OK : NS_OK_NO_NAME_CLAUSE_HANDLED;
}
}
}
return NS_OK_NO_NAME_CLAUSE_HANDLED;
}
nsresult
@ -364,18 +404,19 @@ nsTextEquivUtils::AppendFromDOMNode(nsIContent *aContent, nsAString *aString)
return AppendFromDOMChildren(aContent, aString);
}
void
PRBool
nsTextEquivUtils::AppendString(nsAString *aString,
const nsAString& aTextEquivalent)
{
// Insert spaces to insure that words from controls aren't jammed together.
if (aTextEquivalent.IsEmpty())
return;
return PR_FALSE;
if (!aString->IsEmpty())
aString->Append(PRUnichar(' '));
aString->Append(aTextEquivalent);
return PR_TRUE;
}
////////////////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -135,6 +135,11 @@ private:
static nsresult AppendFromAccessible(nsIAccessible *aAccessible,
nsAString *aString);
/**
* Calculates text equivalent from the value of given accessible.
*/
static nsresult AppendFromValue(nsIAccessible *aAccessible,
nsAString *aString);
/**
* Iterates DOM children and calculates text equivalent from each child node.
*/
@ -148,9 +153,11 @@ private:
static nsresult AppendFromDOMNode(nsIContent *aContent, nsAString *aString);
/**
* Concatenates strings and appends space between them.
* Concatenates strings and appends space between them. Returns true if
* text equivalent string was appended.
*/
static void AppendString(nsAString *aString, const nsAString& aTextEquivalent);
static PRBool AppendString(nsAString *aString,
const nsAString& aTextEquivalent);
/**
* Map array from roles to name rules (constants of ETextEquivRule).

Просмотреть файл

@ -79,6 +79,16 @@
// Gets the name from text nodes. Element br adds space between them.
testName("btn_labelledby_mixed_br", "text text");
// Gets the name from label content which allows name from subtree,
// ignore @title attribute on label
testName("from_label_ignoretitle", "Country:");
// Gets the name from html:p content, which doesn't allow name from
// subtree, ignore @title attribute on label
testName("from_p_ignoretitle", "Choose country from.");
// Gets the name from html:input value, ignore @title attribute on input
testName("from_input_ignoretitle", "Custom country");
//////////////////////////////////////////////////////////////////////////
// label element
@ -266,6 +276,31 @@
aria-labelledby="labelledby_mixed_br">9</button>
<br/>
<!-- the name from subtree, name from label content rather than from its title
attribute -->
<label for="from_label_ignoretitle"
title="Select your country of origin">Country:</label>
<select id="from_label_ignoretitle">
<option>Germany</option>
<option>Russia</option>
</select>
<!-- the name from subtree, name from html:p content rather than from its
title attribute -->
<p id="p_ignoretitle"
title="Select your country of origin">Choose country from.</p>
<select id="from_p_ignoretitle" aria-labelledby="p_ignoretitle">
<option>Germany</option>
<option>Russia</option>
</select>
<!-- the name from subtree, name from html:input value rather than from its
title attribute -->
<p id="from_input_ignoretitle" aria-labelledby="input_ignoretitle">Country</p>
<input id="input_ignoretitle"
value="Custom country"
title="Input your country of origin"/ >
<!-- label element, label contains the button -->
<label>text<button id="btn_label_inside">10</button>text</label>
<br/>