diff --git a/accessible/src/base/nsTextEquivUtils.cpp b/accessible/src/base/nsTextEquivUtils.cpp index d036fb49605..98a7f318d42 100644 --- a/accessible/src/base/nsTextEquivUtils.cpp +++ b/accessible/src/base/nsTextEquivUtils.cpp @@ -32,7 +32,7 @@ nsTextEquivUtils::GetNameFromSubtree(Accessible* aAccessible, return NS_OK; gInitiatorAcc = aAccessible; - if (GetRoleRule(aAccessible->Role()) == eFromSubtree) { + if (IsNameFromSubtreeAllowed(aAccessible)) { //XXX: is it necessary to care the accessible is not a document? if (aAccessible->IsContent()) { nsAutoString name; diff --git a/accessible/src/base/nsTextEquivUtils.h b/accessible/src/base/nsTextEquivUtils.h index ec5cb83df09..391bd55cfba 100644 --- a/accessible/src/base/nsTextEquivUtils.h +++ b/accessible/src/base/nsTextEquivUtils.h @@ -89,6 +89,14 @@ public: static nsresult AppendTextEquivFromTextContent(nsIContent *aContent, nsAString *aString); + /** + * Return true if the given accessible allows name from subtree. + */ + static bool IsNameFromSubtreeAllowed(Accessible* aAccessible) + { + return GetRoleRule(aAccessible->Role()) == eFromSubtree; + } + private: /** * Iterates accessible children and calculates text equivalent from each diff --git a/accessible/src/generic/Accessible.cpp b/accessible/src/generic/Accessible.cpp index 828cf3a3b1d..879f74348a3 100644 --- a/accessible/src/generic/Accessible.cpp +++ b/accessible/src/generic/Accessible.cpp @@ -275,7 +275,7 @@ Accessible::Name(nsString& aName) ENameValueFlag nameFlag = NativeName(aName); if (!aName.IsEmpty()) - return eNameOK; + return nameFlag; // In the end get the name from tooltip. if (mContent->IsHTML()) { @@ -288,14 +288,12 @@ Accessible::Name(nsString& aName) aName.CompressWhitespace(); return eNameFromTooltip; } - } else { - return eNameOK; } if (nameFlag != eNoNameOnPurpose) aName.SetIsVoid(true); - return eNameOK; + return nameFlag; } NS_IMETHODIMP @@ -1055,7 +1053,7 @@ Accessible::TakeFocus() return NS_OK; } -void +ENameValueFlag Accessible::GetHTMLName(nsString& aLabel) { Accessible* labelAcc = nullptr; @@ -1066,8 +1064,11 @@ Accessible::GetHTMLName(nsString& aLabel) aLabel.CompressWhitespace(); } - if (aLabel.IsEmpty()) - nsTextEquivUtils::GetNameFromSubtree(this, aLabel); + if (!aLabel.IsEmpty()) + return eNameOK; + + nsTextEquivUtils::GetNameFromSubtree(this, aLabel); + return aLabel.IsEmpty() ? eNameOK : eNameFromSubtree; } /** @@ -1082,7 +1083,7 @@ Accessible::GetHTMLName(nsString& aLabel) * the control that uses the control="controlID" syntax will use * the child label for its Name. */ -void +ENameValueFlag Accessible::GetXULName(nsString& aName) { // CASE #1 (via label attribute) -- great majority of the cases @@ -1125,10 +1126,9 @@ Accessible::GetXULName(nsString& aName) } } - // XXX If CompressWhiteSpace worked on nsAString we could avoid a copy aName.CompressWhitespace(); if (!aName.IsEmpty()) - return; + return eNameOK; // Can get text from title of if we're a child of a nsIContent *bindingParent = mContent->GetBindingParent(); @@ -1138,12 +1138,13 @@ Accessible::GetXULName(nsString& aName) if (parent->Tag() == nsGkAtoms::toolbaritem && parent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) { aName.CompressWhitespace(); - return; + return eNameOK; } parent = parent->GetParent(); } nsTextEquivUtils::GetNameFromSubtree(this, aName); + return aName.IsEmpty() ? eNameOK : eNameFromSubtree; } nsresult @@ -1229,6 +1230,13 @@ Accessible::GetAttributes(nsIPersistentProperties **aAttributes) if (State() & states::CHECKABLE) nsAccUtils::SetAccAttr(attributes, nsGkAtoms::checkable, NS_LITERAL_STRING("true")); + // Expose 'explicit-name' attribute. + if (!nsTextEquivUtils::IsNameFromSubtreeAllowed(this) || + Name(oldValueUnused) != eNameFromSubtree) { + attributes->SetStringProperty(NS_LITERAL_CSTRING("explicit-name"), + NS_LITERAL_STRING("true"), oldValueUnused); + } + // Group attributes (level/setsize/posinset) GroupPos groupPos = GroupPosition(); nsAccUtils::SetAccGroupAttrs(attributes, groupPos.level, @@ -2420,23 +2428,18 @@ Accessible::Shutdown() // Accessible protected void -Accessible::ARIAName(nsAString& aName) +Accessible::ARIAName(nsString& aName) { - nsAutoString label; - // aria-labelledby now takes precedence over aria-label nsresult rv = nsTextEquivUtils:: - GetTextEquivFromIDRefs(this, nsGkAtoms::aria_labelledby, label); + GetTextEquivFromIDRefs(this, nsGkAtoms::aria_labelledby, aName); if (NS_SUCCEEDED(rv)) { - label.CompressWhitespace(); - aName = label; + aName.CompressWhitespace(); } - if (label.IsEmpty() && - mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_label, - label)) { - label.CompressWhitespace(); - aName = label; + if (aName.IsEmpty() && + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_label, aName)) { + aName.CompressWhitespace(); } } @@ -2445,9 +2448,10 @@ ENameValueFlag Accessible::NativeName(nsString& aName) { if (mContent->IsHTML()) - GetHTMLName(aName); - else if (mContent->IsXUL()) - GetXULName(aName); + return GetHTMLName(aName); + + if (mContent->IsXUL()) + return GetXULName(aName); return eNameOK; } diff --git a/accessible/src/generic/Accessible.h b/accessible/src/generic/Accessible.h index 9d28155d1e9..ec163c2274c 100644 --- a/accessible/src/generic/Accessible.h +++ b/accessible/src/generic/Accessible.h @@ -58,6 +58,11 @@ enum ENameValueFlag { */ eNoNameOnPurpose, + /** + * Name was computed from the subtree. + */ + eNameFromSubtree, + /** * Tooltip was used as a name. */ @@ -805,13 +810,13 @@ protected: /** * Returns the accessible name specified by ARIA. */ - void ARIAName(nsAString& aName); + void ARIAName(nsString& aName); /** * Compute the name of HTML/XUL node. */ - void GetHTMLName(nsString& aName); - void GetXULName(nsString& aName); + mozilla::a11y::ENameValueFlag GetHTMLName(nsString& aName); + mozilla::a11y::ENameValueFlag GetXULName(nsString& aName); // helper method to verify frames static nsresult GetFullKeyName(const nsAString& aModifierName, const nsAString& aKeyName, nsAString& aStringOut); diff --git a/accessible/src/generic/HyperTextAccessible.cpp b/accessible/src/generic/HyperTextAccessible.cpp index 678d9163d40..67fed260d0a 100644 --- a/accessible/src/generic/HyperTextAccessible.cpp +++ b/accessible/src/generic/HyperTextAccessible.cpp @@ -1953,12 +1953,14 @@ HyperTextAccessible::ScrollSubstringToPoint(int32_t aStartIndex, ENameValueFlag HyperTextAccessible::NativeName(nsString& aName) { - AccessibleWrap::NativeName(aName); + ENameValueFlag nameFlag = AccessibleWrap::NativeName(aName); + if (!aName.IsEmpty()) + return nameFlag; // Get name from title attribute for HTML abbr and acronym elements making it // a valid name from markup. Otherwise their name isn't picked up by recursive // name computation algorithm. See NS_OK_NAME_FROM_TOOLTIP. - if (aName.IsEmpty() && IsAbbreviation() && + if (IsAbbreviation() && mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) aName.CompressWhitespace(); diff --git a/accessible/src/generic/ImageAccessible.cpp b/accessible/src/generic/ImageAccessible.cpp index 6aba1d40353..b0b7acbe69c 100644 --- a/accessible/src/generic/ImageAccessible.cpp +++ b/accessible/src/generic/ImageAccessible.cpp @@ -77,16 +77,15 @@ ImageAccessible::NativeName(nsString& aName) if (!aName.IsEmpty()) return eNameOK; - Accessible::NativeName(aName); - if (aName.IsEmpty() && hasAltAttrib) { - // No accessible name but empty 'alt' attribute is present. If further name - // computation algorithm doesn't provide non empty name then it means - // an empty 'alt' attribute was used to indicate a decorative image (see - // nsIAccessible::name attribute for details). - return eNoNameOnPurpose; - } + ENameValueFlag nameFlag = Accessible::NativeName(aName); + if (!aName.IsEmpty()) + return nameFlag; - return eNameOK; + // No accessible name but empty 'alt' attribute is present. If further name + // computation algorithm doesn't provide non empty name then it means + // an empty 'alt' attribute was used to indicate a decorative image (see + // Accessible::Name() method for details). + return hasAltAttrib ? eNoNameOnPurpose : eNameOK; } role diff --git a/accessible/src/html/HTMLElementAccessibles.cpp b/accessible/src/html/HTMLElementAccessibles.cpp index d5a5e63f148..f921c5b4fe9 100644 --- a/accessible/src/html/HTMLElementAccessibles.cpp +++ b/accessible/src/html/HTMLElementAccessibles.cpp @@ -58,7 +58,7 @@ ENameValueFlag HTMLLabelAccessible::NativeName(nsString& aName) { nsTextEquivUtils::GetNameFromSubtree(this, aName); - return eNameOK; + return aName.IsEmpty() ? eNameOK : eNameFromSubtree; } role diff --git a/accessible/src/html/HTMLFormControlAccessible.cpp b/accessible/src/html/HTMLFormControlAccessible.cpp index 64deaf6a559..daa72c8451a 100644 --- a/accessible/src/html/HTMLFormControlAccessible.cpp +++ b/accessible/src/html/HTMLFormControlAccessible.cpp @@ -259,13 +259,13 @@ HTMLButtonAccessible::NativeRole() ENameValueFlag HTMLButtonAccessible::NativeName(nsString& aName) { - Accessible::NativeName(aName); + ENameValueFlag nameFlag = Accessible::NativeName(aName); if (!aName.IsEmpty() || mContent->Tag() != nsGkAtoms::input) - return eNameOK; + return nameFlag; - // No name from HTML or ARIA - if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aName) && - !mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName)) { + // Note: No need to check @value attribute since it results in anonymous text + // node. The name is calculated from subtree in this case. + if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName)) { // Use the button's (default) label if nothing else works nsIFrame* frame = GetFrame(); if (frame) { @@ -323,9 +323,9 @@ HTMLTextFieldAccessible::NativeRole() ENameValueFlag HTMLTextFieldAccessible::NativeName(nsString& aName) { - Accessible::NativeName(aName); + ENameValueFlag nameFlag = Accessible::NativeName(aName); if (!aName.IsEmpty()) - return eNameOK; + return nameFlag; if (mContent->GetBindingParent()) { // XXX: bug 459640 @@ -613,9 +613,9 @@ HTMLGroupboxAccessible::GetLegend() ENameValueFlag HTMLGroupboxAccessible::NativeName(nsString& aName) { - Accessible::NativeName(aName); + ENameValueFlag nameFlag = Accessible::NativeName(aName); if (!aName.IsEmpty()) - return eNameOK; + return nameFlag; nsIContent* legendContent = GetLegend(); if (legendContent) @@ -696,9 +696,9 @@ HTMLFigureAccessible::NativeRole() ENameValueFlag HTMLFigureAccessible::NativeName(nsString& aName) { - HyperTextAccessibleWrap::NativeName(aName); + ENameValueFlag nameFlag = HyperTextAccessibleWrap::NativeName(aName); if (!aName.IsEmpty()) - return eNameOK; + return nameFlag; nsIContent* captionContent = Caption(); if (captionContent) diff --git a/accessible/src/html/HTMLImageMapAccessible.cpp b/accessible/src/html/HTMLImageMapAccessible.cpp index 261ed297494..c9a36b5b4a1 100644 --- a/accessible/src/html/HTMLImageMapAccessible.cpp +++ b/accessible/src/html/HTMLImageMapAccessible.cpp @@ -163,9 +163,9 @@ HTMLAreaAccessible:: ENameValueFlag HTMLAreaAccessible::NativeName(nsString& aName) { - Accessible::NativeName(aName); + ENameValueFlag nameFlag = Accessible::NativeName(aName); if (!aName.IsEmpty()) - return eNameOK; + return nameFlag; if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName)) GetValue(aName); diff --git a/accessible/src/html/HTMLSelectAccessible.cpp b/accessible/src/html/HTMLSelectAccessible.cpp index f4f4a9dcbe5..83a8b003de4 100644 --- a/accessible/src/html/HTMLSelectAccessible.cpp +++ b/accessible/src/html/HTMLSelectAccessible.cpp @@ -200,6 +200,7 @@ HTMLSelectOptionAccessible::NativeName(nsString& aName) if (text && text->IsNodeOfType(nsINode::eTEXT)) { nsTextEquivUtils::AppendTextEquivFromTextContent(text, &aName); aName.CompressWhitespace(); + return aName.IsEmpty() ? eNameOK : eNameFromSubtree; } return eNameOK; diff --git a/accessible/src/html/HTMLTableAccessible.cpp b/accessible/src/html/HTMLTableAccessible.cpp index e15033670a9..f369024bab9 100644 --- a/accessible/src/html/HTMLTableAccessible.cpp +++ b/accessible/src/html/HTMLTableAccessible.cpp @@ -388,9 +388,9 @@ HTMLTableAccessible::NativeState() ENameValueFlag HTMLTableAccessible::NativeName(nsString& aName) { - Accessible::NativeName(aName); + ENameValueFlag nameFlag = Accessible::NativeName(aName); if (!aName.IsEmpty()) - return eNameOK; + return nameFlag; // Use table caption as a name. Accessible* caption = Caption(); diff --git a/accessible/src/xul/XULElementAccessibles.cpp b/accessible/src/xul/XULElementAccessibles.cpp index 2442bafcabb..93bf28c384e 100644 --- a/accessible/src/xul/XULElementAccessibles.cpp +++ b/accessible/src/xul/XULElementAccessibles.cpp @@ -125,10 +125,11 @@ ENameValueFlag XULLinkAccessible::NativeName(nsString& aName) { mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aName); - if (aName.IsEmpty()) - nsTextEquivUtils::GetNameFromSubtree(this, aName); + if (!aName.IsEmpty()) + return eNameOK; - return eNameOK; + nsTextEquivUtils::GetNameFromSubtree(this, aName); + return aName.IsEmpty() ? eNameOK : eNameFromSubtree; } role diff --git a/accessible/src/xul/XULListboxAccessible.cpp b/accessible/src/xul/XULListboxAccessible.cpp index 87efd8a0f6c..435c27b311c 100644 --- a/accessible/src/xul/XULListboxAccessible.cpp +++ b/accessible/src/xul/XULListboxAccessible.cpp @@ -634,8 +634,7 @@ XULListitemAccessible::NativeName(nsString& aName) } } - GetXULName(aName); - return eNameOK; + return GetXULName(aName); } role diff --git a/accessible/tests/mochitest/name/markup.js b/accessible/tests/mochitest/name/markup.js index 308894f147a..9c73853ab37 100644 --- a/accessible/tests/mochitest/name/markup.js +++ b/accessible/tests/mochitest/name/markup.js @@ -188,6 +188,11 @@ function testNameForAttrRule(aElm, aRule) var msg = "Attribute '" + attr + "' test. "; testName(aElm, name, msg); + if (aRule.getAttribute("explict-name") != "false") + testAttrs(aElm, {"explicit-name" : "true"}, true); + else + testAbsentAttrs(aElm, {"explicit-name" : "true"}); + aElm.removeAttribute(attr); gTestIterator.iterateNext(); @@ -235,6 +240,7 @@ function testNameForElmRule(aElm, aRule) var msg = "Element '" + tagname + "' test."; testName(aElm, labelElm.getAttribute("a11yname"), msg); + testAttrs(aElm, {"explicit-name" : "true"}, true); var parentNode = labelElm.parentNode; @@ -252,6 +258,7 @@ function testNameForSubtreeRule(aElm, aRule) { var msg = "From subtree test."; testName(aElm, aElm.getAttribute("a11yname"), msg); + testAbsentAttrs(aElm, {"explicit-name" : "true"}); if (gDumpToConsole) { dump("\nProcessed from subtree rule. Wait for reorder event on " + diff --git a/accessible/tests/mochitest/name/markuprules.xml b/accessible/tests/mochitest/name/markuprules.xml index 1d8dad81ddb..73fd19daa00 100644 --- a/accessible/tests/mochitest/name/markuprules.xml +++ b/accessible/tests/mochitest/name/markuprules.xml @@ -125,7 +125,7 @@ - + diff --git a/accessible/tests/mochitest/name/test_markup.html b/accessible/tests/mochitest/name/test_markup.html index 63f341bf29c..b7f74b67a8c 100644 --- a/accessible/tests/mochitest/name/test_markup.html +++ b/accessible/tests/mochitest/name/test_markup.html @@ -13,6 +13,8 @@ src="../events.js"> +