From ca9b894ddeecf42632a1318c6ea7a7e4d1a0ec28 Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Sun, 3 Feb 2013 13:49:18 +0900 Subject: [PATCH] Bug 786163 - sort out name calculation for HTML input buttons, r=tbsaunde --- .../src/html/HTMLFormControlAccessible.cpp | 31 +-- accessible/tests/mochitest/events.js | 16 +- accessible/tests/mochitest/name/Makefile.in | 1 - accessible/tests/mochitest/name/markup.js | 61 ++++- .../tests/mochitest/name/markuprules.xml | 247 ++++++++++++------ .../tests/mochitest/name/test_button.html | 145 ---------- .../tests/mochitest/name/test_general.html | 45 ++-- .../tests/mochitest/name/test_markup.html | 9 +- 8 files changed, 261 insertions(+), 294 deletions(-) delete mode 100644 accessible/tests/mochitest/name/test_button.html diff --git a/accessible/src/html/HTMLFormControlAccessible.cpp b/accessible/src/html/HTMLFormControlAccessible.cpp index 976409265360..09691fd2f7e6 100644 --- a/accessible/src/html/HTMLFormControlAccessible.cpp +++ b/accessible/src/html/HTMLFormControlAccessible.cpp @@ -259,26 +259,23 @@ HTMLButtonAccessible::NativeRole() ENameValueFlag HTMLButtonAccessible::NativeName(nsString& aName) { + // No need to check @value attribute for buttons since this attribute results + // in native anonymous text node and the name is calculated from subtree. + // The same magic works for @alt and @value attributes in case of type="image" + // element that has no valid @src (note if input@type="image" has an image + // then neither @alt nor @value attributes are used to generate a visual label + // and thus we need to obtain the accessible name directly from attribute + // value). Also the same algorithm works in case of default labels for + // type="submit"/"reset"/"image" elements. + ENameValueFlag nameFlag = Accessible::NativeName(aName); - if (!aName.IsEmpty() || mContent->Tag() != nsGkAtoms::input) + if (!aName.IsEmpty() || mContent->Tag() != nsGkAtoms::input || + !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, + nsGkAtoms::image, eCaseMatters)) return nameFlag; - // 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) { - nsIFormControlFrame* fcFrame = do_QueryFrame(frame); - if (fcFrame) - fcFrame->GetFormProperty(nsGkAtoms::defaultLabel, aName); - } - } - - if (aName.IsEmpty() && - !mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, aName)) { - mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, aName); - } + if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName)) + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aName); aName.CompressWhitespace(); return eNameOK; diff --git a/accessible/tests/mochitest/events.js b/accessible/tests/mochitest/events.js index 61f129d37650..cfe1733ececa 100644 --- a/accessible/tests/mochitest/events.js +++ b/accessible/tests/mochitest/events.js @@ -68,18 +68,22 @@ var gA11yEventDumpFeature = ""; * @param aArg1 [in, optional] argument passed into the function * @param aArg2 [in, optional] argument passed into the function */ -function waitForEvent(aEventType, aTarget, aFunc, aContext, aArg1, aArg2) +function waitForEvent(aEventType, aTargetOrFunc, aFunc, aContext, aArg1, aArg2) { var handler = { handleEvent: function handleEvent(aEvent) { - if (aTarget) { - if (aTarget instanceof nsIAccessible && - aTarget != aEvent.accessible) + var target = aTargetOrFunc; + if (typeof aTargetOrFunc == "function") + target = aTargetOrFunc.call(); + + if (target) { + if (target instanceof nsIAccessible && + target != aEvent.accessible) return; - if (aTarget instanceof nsIDOMNode && - aTarget != aEvent.DOMNode) + if (target instanceof nsIDOMNode && + target != aEvent.DOMNode) return; } diff --git a/accessible/tests/mochitest/name/Makefile.in b/accessible/tests/mochitest/name/Makefile.in index 4739731aaf5e..7482cf17e574 100644 --- a/accessible/tests/mochitest/name/Makefile.in +++ b/accessible/tests/mochitest/name/Makefile.in @@ -15,7 +15,6 @@ MOCHITEST_A11Y_FILES =\ general.css \ general.xbl \ markup.js \ - test_button.html \ test_general.html \ test_general.xul \ test_link.html \ diff --git a/accessible/tests/mochitest/name/markup.js b/accessible/tests/mochitest/name/markup.js index a133bb7a142c..d412d2a93390 100644 --- a/accessible/tests/mochitest/name/markup.js +++ b/accessible/tests/mochitest/name/markup.js @@ -41,11 +41,15 @@ var gTestIterator = this.iterateNext(); }, - iterateRules: function gTestIterator_iterateRules(aElm, aContainer, aRuleElms) + iterateRules: function gTestIterator_iterateRules(aElm, aContainer, + aRuleSetElm, aRuleElms, + aTestID) { + this.ruleSetElm = aRuleSetElm; this.ruleElms = aRuleElms; this.elm = aElm; this.container = aContainer; + this.testID = aTestID; this.iterateNext(); }, @@ -61,7 +65,10 @@ var gTestIterator = this.ruleIdx++; if (this.ruleIdx == this.ruleElms.length) { // When test is finished then name is empty and no explict-name. - testName(this.elm, null, "No name test. "); + var defaultName = this.ruleSetElm.hasAttribute("defaultName") ? + this.ruleSetElm.getAttribute("defaultName") : null; + testName(this.elm, defaultName, + "Default name test (" + gTestIterator.testID + "). "); testAbsentAttrs(this.elm, {"explicit-name" : "true"}); this.markupIdx++; @@ -89,10 +96,12 @@ var gTestIterator = markupElms: null, markupIdx: -1, + rulesetElm: null, ruleElms: null, ruleIdx: -1, elm: null, - container: null + container: null, + testID: "" }; /** @@ -126,8 +135,9 @@ function testNamesForMarkup(aMarkupElm) function testNamesForMarkupRules(aMarkupElm, aContainer) { + var testID = aMarkupElm.getAttribute("id"); if (gDumpToConsole) - dump("\nProcessing markup rules '" + aMarkupElm.getAttribute("id") + "'\n"); + dump("\nProcessing markup rules '" + testID + "'\n"); var serializer = new XMLSerializer(); @@ -135,14 +145,17 @@ function testNamesForMarkupRules(aMarkupElm, aContainer) var elm = evaluateXPath(document, expr, htmlDocResolver)[0]; var ruleId = aMarkupElm.getAttribute("ruleset"); + var ruleElm = gRuleDoc.querySelector("[id='" + ruleId + "']"); var ruleElms = getRuleElmsByRulesetId(ruleId); var processMarkupRules = - gTestIterator.iterateRules.bind(gTestIterator, elm, aContainer, ruleElms); + gTestIterator.iterateRules.bind(gTestIterator, elm, aContainer, + ruleElm, ruleElms, testID); // Images may be recreated after we append them into subtree. We need to wait // in this case. If we are on profiling enabled build then stack tracing - // works and thus let's log instead. + // works and thus let's log instead. Note, that works if you enabled logging + // (refer to testNames() function). if (isAccessible(elm) || isLogged("stack")) processMarkupRules(); else @@ -198,20 +211,40 @@ function testNameForAttrRule(aElm, aRule) if (name != "") name += " "; - name += labelElm.getAttribute("a11yname"); + name += labelElm.getAttribute("textequiv"); } } - var msg = "Attribute '" + attr + "' test. "; + var msg = "Attribute '" + attr + "' test (" + gTestIterator.testID + "). "; 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); + // If @recreated attribute is used then this attribute change recreates an + // accessible. Wait for reorder event in this case or otherwise proceed next + // test immediately. + if (aRule.hasAttribute("recreated")) { + waitForEvent(EVENT_REORDER, aElm.parentNode, + gTestIterator.iterateNext, gTestIterator); + aElm.removeAttribute(attr); - gTestIterator.iterateNext(); + } else if (aRule.hasAttribute("textchanged")) { + waitForEvent(EVENT_TEXT_INSERTED, aElm, + gTestIterator.iterateNext, gTestIterator); + aElm.removeAttribute(attr); + + } else if (aRule.hasAttribute("contentchanged")) { + waitForEvent(EVENT_REORDER, aElm, + gTestIterator.iterateNext, gTestIterator); + aElm.removeAttribute(attr); + + } else { + aElm.removeAttribute(attr); + gTestIterator.iterateNext(); + } } function testNameForElmRule(aElm, aRule) @@ -254,8 +287,8 @@ function testNameForElmRule(aElm, aRule) return; } - var msg = "Element '" + tagname + "' test."; - testName(aElm, labelElm.getAttribute("a11yname"), msg); + var msg = "Element '" + tagname + "' test (" + gTestIterator.testID + ")."; + testName(aElm, labelElm.getAttribute("textequiv"), msg); testAttrs(aElm, {"explicit-name" : "true"}, true); var parentNode = labelElm.parentNode; @@ -272,8 +305,8 @@ function testNameForElmRule(aElm, aRule) function testNameForSubtreeRule(aElm, aRule) { - var msg = "From subtree test."; - testName(aElm, aElm.getAttribute("a11yname"), msg); + var msg = "From subtree test (" + gTestIterator.testID + ")."; + testName(aElm, aElm.getAttribute("textequiv"), msg); testAbsentAttrs(aElm, {"explicit-name" : "true"}); if (gDumpToConsole) { diff --git a/accessible/tests/mochitest/name/markuprules.xml b/accessible/tests/mochitest/name/markuprules.xml index 255fa64d253f..d3bf29127521 100644 --- a/accessible/tests/mochitest/name/markuprules.xml +++ b/accessible/tests/mochitest/name/markuprules.xml @@ -63,7 +63,7 @@ - test2 + test2 it's a div @@ -76,7 +76,7 @@ Then we check accessible name for the test element and remove 'aria-label' attribute. After we get the second rule which means we should get IDs from 'aria-labelledby' attribute and compose accessible name from values of - 'a11yname' attributes (that are supposed to give the desired name for each + 'textequiv' attributes (that are supposed to give the desired name for each element that is being pointed to by aria-labelledby). Check accessible name and finish test. --> @@ -87,125 +87,198 @@ - + - - + + - - - - - - - - - - - - - - - - - + + + + + - - - + + + - - - - - - - + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + - - - + + + - - + + - + - - test2 - test3 - test4 + + test2 + test3 + test4 press me + textequiv="press me">press me - - test2 - test3 - test4 + + test2 + test3 + test4 + value="name from value" + alt="no name from al" + src="no name from src" + data="no name from data" + title="name from title"/> - - test2 - test3 + + test2 + test3 + test4 + + + + + test2 + test3 + test4 + + + + + test2 + test3 + test4 + + + + + test2 + test3 + test4 + + + + + test2 + test3 option1 + textequiv="option1">option1 option2 - - test2 - test3 + + test2 + test3 - - id="markupHTMLImageEmptyAltTest" - test2 - test3 + + test2 + test3 - - test2 - test3 - test4 + + test2 + test3 + test4 - - test2 - test3 - test4 + + test2 + test3 + test4 This is a paragraph This is a link @@ -271,11 +344,11 @@ - - lby_tst6_1 - lby_tst6_2 - label_tst6 + + lby_tst6_1 + lby_tst6_2 + label_tst6 - -
- - - text - - -
- - - - - - - - - - - - - - - - -
- - - text - - -
- - - - - - - - - - - - - - - - - - - - - - - - diff --git a/accessible/tests/mochitest/name/test_general.html b/accessible/tests/mochitest/name/test_general.html index c14dee3a2c73..1827afbe5618 100644 --- a/accessible/tests/mochitest/name/test_general.html +++ b/accessible/tests/mochitest/name/test_general.html @@ -125,6 +125,9 @@ // children. testName("btn_children", "14"); + // html:button, no name from content + testName("btn_nonamefromcontent", null); + // ARIA role option is presented allowing the name calculation from // visible children (bug 443081). testName("lb_opt1_children_hidden", "i am visible"); @@ -158,12 +161,6 @@ testName("textareawithchild", "Story Bar is ended."); - ////////////////////////////////////////////////////////////////////////// - // button name (specific cases not covered by test_name_markup.html) - - testName("submit", "Submit Query"); - testName("image_submit", "Submit Query"); - ////////////////////////////////////////////////////////////////////////// // controls having a value used as a part of computed name @@ -223,42 +220,47 @@ - Mozilla Bug 428479 -
+ Bug 428479 + - Mozilla Bug 429666 -
+ Bug 429666 + - Mozilla Bug 444279 -
+ Bug 444279 + + + Bug 459635 + - Mozilla Bug 530081 + title="Clean up our tree walker"> + Bug 530081
- Mozilla Bug 604391 + Bug 604391 - Mozilla Bug 669312 + Bug 669312 - Mozilla Bug 704416 + Bug 704416 - Mozilla Bug 812041 + Bug 812041

@@ -418,6 +420,9 @@ 14 + + +
@@ -455,10 +460,6 @@ - - - -