Bug 559764 - make input@type=range accessible, r=tbsaunde, roc, smaug

This commit is contained in:
Alexander Surkov 2013-04-28 09:54:54 +09:00
parent 1a836e54f6
commit c58428f754
12 changed files with 290 additions and 24 deletions

View File

@ -34,6 +34,7 @@ enum AccType {
eHTMLSelectListType,
eHTMLMediaType,
eHTMLRadioButtonType,
eHTMLRangeType,
eHTMLTableType,
eHTMLTableCellType,
eHTMLTableRowType,

View File

@ -425,6 +425,20 @@ nsAccessibilityService::TreeViewChanged(nsIPresShell* aPresShell,
}
}
void
nsAccessibilityService::RangeValueChanged(nsIPresShell* aPresShell,
nsIContent* aContent)
{
DocAccessible* document = GetDocAccessible(aPresShell);
if (document) {
Accessible* accessible = document->GetAccessible(aContent);
if (accessible) {
document->FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
accessible);
}
}
}
void
nsAccessibilityService::UpdateListBullet(nsIPresShell* aPresShell,
nsIContent* aHTMLListItemContent,
@ -1509,6 +1523,9 @@ nsAccessibilityService::CreateAccessibleByFrameType(nsIFrame* aFrame,
case eHTMLRadioButtonType:
newAcc = new HTMLRadioButtonAccessible(aContent, document);
break;
case eHTMLRangeType:
newAcc = new HTMLRangeAccessible(aContent, document);
break;
case eHTMLTableType:
newAcc = new HTMLTableAccessibleWrap(aContent, document);
break;

View File

@ -99,6 +99,11 @@ public:
void TreeViewChanged(nsIPresShell* aPresShell, nsIContent* aContent,
nsITreeView* aView);
/**
* Notify of input@type="element" value change.
*/
void RangeValueChanged(nsIPresShell* aPresShell, nsIContent* aContent);
/**
* Update list bullet accessible.
*/

View File

@ -543,6 +543,91 @@ HTMLFileInputAccessible::HandleAccEvent(AccEvent* aEvent)
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// HTMLRangeAccessible
////////////////////////////////////////////////////////////////////////////////
NS_IMPL_ISUPPORTS_INHERITED1(HTMLRangeAccessible, LeafAccessible,
nsIAccessibleValue)
role
HTMLRangeAccessible::NativeRole()
{
return roles::SLIDER;
}
bool
HTMLRangeAccessible::IsWidget() const
{
return true;
}
void
HTMLRangeAccessible::Value(nsString& aValue)
{
LeafAccessible::Value(aValue);
if (!aValue.IsEmpty())
return;
HTMLInputElement::FromContent(mContent)->GetValue(aValue);
}
NS_IMETHODIMP
HTMLRangeAccessible::GetMaximumValue(double* aMaximumValue)
{
nsresult rv = LeafAccessible::GetMaximumValue(aMaximumValue);
if (rv != NS_OK_NO_ARIA_VALUE)
return rv;
*aMaximumValue = HTMLInputElement::FromContent(mContent)->GetMaximum();
return NS_OK;
}
NS_IMETHODIMP
HTMLRangeAccessible::GetMinimumValue(double* aMinimumValue)
{
nsresult rv = LeafAccessible::GetMinimumValue(aMinimumValue);
if (rv != NS_OK_NO_ARIA_VALUE)
return rv;
*aMinimumValue = HTMLInputElement::FromContent(mContent)->GetMinimum();
return NS_OK;
}
NS_IMETHODIMP
HTMLRangeAccessible::GetMinimumIncrement(double* aMinimumIncrement)
{
nsresult rv = LeafAccessible::GetMinimumIncrement(aMinimumIncrement);
if (rv != NS_OK_NO_ARIA_VALUE)
return rv;
*aMinimumIncrement = HTMLInputElement::FromContent(mContent)->GetStep();
return NS_OK;
}
NS_IMETHODIMP
HTMLRangeAccessible::GetCurrentValue(double* aCurrentValue)
{
nsresult rv = LeafAccessible::GetCurrentValue(aCurrentValue);
if (rv != NS_OK_NO_ARIA_VALUE)
return rv;
*aCurrentValue = HTMLInputElement::FromContent(mContent)->GetValueAsDouble();
return NS_OK;
}
NS_IMETHODIMP
HTMLRangeAccessible::SetCurrentValue(double aValue)
{
ErrorResult er;
HTMLInputElement::FromContent(mContent)->SetValueAsNumber(aValue, er);
return er.ErrorCode();
}
////////////////////////////////////////////////////////////////////////////////
// HTMLGroupboxAccessible
////////////////////////////////////////////////////////////////////////////////

View File

@ -145,6 +145,31 @@ public:
virtual nsresult HandleAccEvent(AccEvent* aAccEvent);
};
/**
* Used for input@type="range" element.
*/
class HTMLRangeAccessible : public LeafAccessible
{
public:
HTMLRangeAccessible(nsIContent* aContent, DocAccessible* aDoc) :
LeafAccessible(aContent, aDoc)
{
mStateFlags |= eHasNumericValue;
}
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIACCESSIBLEVALUE
// Accessible
virtual void Value(nsString& aValue);
virtual mozilla::a11y::role NativeRole();
// Widgets
virtual bool IsWidget() const;
};
/**
* Accessible for HTML fieldset element.
*/

View File

@ -8,6 +8,8 @@
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript"
src="../common.js"></script>
@ -79,21 +81,46 @@
}
}
function changeProcessValue(aID, aValue) {
this.DOMNode = getNode(aID);
function changeProgressValue(aID, aValue)
{
this.DOMNode = getNode(aID);
this.invoke = function changeProcessValue_invoke() {
this.DOMNode.value = aValue;
}
this.invoke = function changeProgressValue_invoke()
{
this.DOMNode.value = aValue;
}
this.check = function changeProcessValue_check() {
var acc = getAccessible(this.DOMNode);
is(acc.value, aValue+"%", "Wrong value for " + prettyName(aID));
}
this.check = function changeProgressValue_check()
{
var acc = getAccessible(this.DOMNode);
is(acc.value, aValue+"%", "Wrong value for " + prettyName(aID));
}
this.getID = function changeProcessValue_getID() {
return prettyName(aID) + " value changed";
}
this.getID = function changeProgressValue_getID()
{
return prettyName(aID) + " value changed";
}
}
function changeRangeValue(aID)
{
this.DOMNode = getNode(aID);
this.invoke = function changeRangeValue_invoke()
{
synthesizeMouse(getNode(aID), 5, 5, { });
}
this.finalCheck = function changeRangeValue_finalCheck()
{
var acc = getAccessible(this.DOMNode);
is(acc.value, "0", "Wrong value for " + prettyName(aID));
}
this.getID = function changeRangeValue_getID()
{
return prettyName(aID) + " range value changed";
}
}
function doTests()
@ -104,6 +131,7 @@
testValue("slider_vt", "hi", 0, 0, 3, 0);
testValue("scrollbar", "5", 5, 0, 1000, 0);
testValue("progress", "22%", 22, 0, 100, 0);
testValue("range", "6", 6, 0, 10, 1);
// Test value change events
gQueue = new eventQueue(nsIAccessibleEvent.EVENT_VALUE_CHANGE);
@ -115,7 +143,8 @@
gQueue.push(new changeValue("combobox", "hello"));
gQueue.push(new changeProcessValue("progress", "50"));
gQueue.push(new changeProgressValue("progress", "50"));
gQueue.push(new changeRangeValue("range"));
gQueue.invoke(); // Will call SimpleTest.finish();
}
@ -137,6 +166,11 @@
title="We dont expose new aria role 'scrollbar' and property aria-orientation">
Mozilla Bug 529289
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=559764"
title="Make HTML5 input@type=range element accessible">
Mozilla Bug 559764
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=703202"
title="ARIA comboboxes don't fire value change events">
@ -175,5 +209,8 @@
<!-- progress bar -->
<progress id="progress" value="22" max="100"></progress>
<!-- input@type="range" -->
<input type="range" id="range" min="0" max="10" value="6">
</body>
</html>

View File

@ -59,6 +59,11 @@
};
testAccessibleTree("image_submit", accTree);
// input@type="range"
accTree = { SLIDER: [ ] };
testAccessibleTree("range", accTree);
// output
accTree = {
role: ROLE_SECTION,
children: [
@ -81,17 +86,22 @@
<a target="_blank"
title="Fix O(n^2) access to all the children of a container"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=342045">
Mozilla Bug 342045
Bug 342045
</a>
<a target="_blank"
title="add test for role of input type='image'"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=524521">
Mozilla Bug 524521
Bug 524521
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=558036"
title="make HTML <output> accessible">
Mozilla Bug 558036
Bug 558036
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=559764"
title="make HTML5 input@type=range element accessible">
Bug 559764
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
@ -105,6 +115,8 @@
<input type="submit" id="submit">
<input type="image" id="image_submit">
<input type="range" id="range">
<output id="output">1337</output>
</body>
</html>

View File

@ -15,6 +15,7 @@ MOCHITEST_A11Y_FILES =\
test_general.html \
test_progress.html \
test_progress.xul \
test_range.html \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,59 @@
<html>
<head>
<title>nsIAccessible value testing for input@type=range element</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../value.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/chrome-harness.js"></script>
<script type="application/javascript">
function doTest()
{
// HTML5 progress element tests
testValue("range", "50", 50, 0, 100, 1);
testValue("range_value", "1", 1, 0, 100, 1);
testValue("range_step", "50", 50, 0, 100, 1);
testValue("range_min42", "71", 71, 42, 100, 1);
testValue("range_max42", "21", 21, 0, 42, 1);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=559764"
title="make HTML5 input@type=range element accessible">
Bug 559764
</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<!-- HTML5 input@type=range element -->
<input type="range" id="range">
<input type="range" id="range_value" value="1">
<input type="range" id="range_step" step="1">
<input type="range" id="range_min42" min="42">
<input type="range" id="range_max42" max="42">
</body>
</html>

View File

@ -602,6 +602,14 @@ public:
aRv = ApplyStep(-aN);
}
/**
* Returns the current step value.
* Returns kStepAny if the current step is "any" string.
*
* @return the current step value.
*/
double GetStep() const;
void GetValidationMessage(nsAString& aValidationMessage, ErrorResult& aRv);
// XPCOM GetCustomVisibility() is OK
@ -1027,14 +1035,6 @@ protected:
*/
double GetStepScaleFactor() const;
/**
* Returns the current step value.
* Returns kStepAny if the current step is "any" string.
*
* @return the current step value.
*/
double GetStep() const;
/**
* Return the base used to compute if a value matches step.
* Basically, it's the min attribute if present and a default value otherwise.

View File

@ -26,6 +26,10 @@
#include <algorithm>
#ifdef ACCESSIBILITY
#include "nsAccessibilityService.h"
#endif
#define LONG_SIDE_TO_SHORT_SIDE_RATIO 10
using namespace mozilla;
@ -349,6 +353,14 @@ nsRangeFrame::ReflowAnonymousContent(nsPresContext* aPresContext,
return NS_OK;
}
#ifdef ACCESSIBILITY
a11y::AccType
nsRangeFrame::AccessibleType()
{
return a11y::eHTMLRangeType;
}
#endif
double
nsRangeFrame::GetValueAsFractionOfRange()
{
@ -489,6 +501,14 @@ nsRangeFrame::UpdateForValueChange()
// theming is applied, so we just repaint the entire range.
InvalidateFrame();
}
#ifdef ACCESSIBILITY
nsAccessibilityService* accService = nsIPresShell::AccService();
if (accService) {
accService->RangeValueChanged(PresContext()->PresShell(), mContent);
}
#endif
SchedulePaint();
}

View File

@ -52,6 +52,10 @@ public:
virtual bool IsLeaf() const MOZ_OVERRIDE { return true; }
#ifdef ACCESSIBILITY
virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE;
#endif
// nsIAnonymousContentCreator
virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) MOZ_OVERRIDE;
virtual void AppendAnonymousContentTo(nsBaseContentList& aElements,