Bug 1694789 - Map accessible value for input type color and password. r=dom-core,sefeng,Jamie,bolsson

Differential Revision: https://phabricator.services.mozilla.com/D216042
This commit is contained in:
Vincent Hilla 2024-10-22 13:23:18 +00:00
parent 91ed10a971
commit d3c8be80cd
11 changed files with 146 additions and 7 deletions

View File

@ -510,7 +510,8 @@ void Accessible::DebugPrint(const char* aPrefix,
#endif
void Accessible::TranslateString(const nsString& aKey, nsAString& aStringOut) {
void Accessible::TranslateString(const nsString& aKey, nsAString& aStringOut,
const nsTArray<nsString>& aParams) {
nsCOMPtr<nsIStringBundleService> stringBundleService =
components::StringBundle::Service();
if (!stringBundleService) return;
@ -522,8 +523,14 @@ void Accessible::TranslateString(const nsString& aKey, nsAString& aStringOut) {
if (!stringBundle) return;
nsAutoString xsValue;
nsresult rv = stringBundle->GetStringFromName(
NS_ConvertUTF16toUTF8(aKey).get(), xsValue);
nsresult rv = NS_OK;
if (aParams.IsEmpty()) {
rv = stringBundle->GetStringFromName(NS_ConvertUTF16toUTF8(aKey).get(),
xsValue);
} else {
rv = stringBundle->FormatStringFromName(NS_ConvertUTF16toUTF8(aKey).get(),
aParams, xsValue);
}
if (NS_SUCCEEDED(rv)) aStringOut.Assign(xsValue);
}

View File

@ -729,7 +729,8 @@ class Accessible {
/**
* Return the localized string for the given key.
*/
static void TranslateString(const nsString& aKey, nsAString& aStringOut);
static void TranslateString(const nsString& aKey, nsAString& aStringOut,
const nsTArray<nsString>& aParams = {});
protected:
// Some abstracted group utility methods.

View File

@ -173,6 +173,30 @@ void HTMLButtonAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) {
if (aIndex == eAction_Click) aName.AssignLiteral("press");
}
void HTMLButtonAccessible::Value(nsString& aValue) const {
if (HTMLInputElement* input = HTMLInputElement::FromNode(mContent)) {
if (input->IsInputColor()) {
nsAutoString value;
input->GetValue(value, CallerType::NonSystem);
Maybe<nscolor> maybeColor = HTMLInputElement::ParseSimpleColor(value);
if (maybeColor) {
const nscolor& color = maybeColor.ref();
Decimal r(static_cast<int>(NS_GET_R(color) / 2.55f)),
g(static_cast<int>(NS_GET_G(color) / 2.55f)),
b(static_cast<int>(NS_GET_B(color) / 2.55f));
nsAutoString rs(NS_ConvertUTF8toUTF16(r.toString()));
nsAutoString gs(NS_ConvertUTF8toUTF16(g.toString()));
nsAutoString bs(NS_ConvertUTF8toUTF16(b.toString()));
Accessible::TranslateString(u"inputColorValue"_ns, aValue,
{rs, gs, bs});
return;
}
}
}
HyperTextAccessible::Value(aValue);
}
uint64_t HTMLButtonAccessible::NativeState() const {
uint64_t state = HyperTextAccessible::NativeState();
@ -312,12 +336,10 @@ ENameValueFlag HTMLTextFieldAccessible::Name(nsString& aName) const {
void HTMLTextFieldAccessible::Value(nsString& aValue) const {
aValue.Truncate();
if (NativeState() & states::PROTECTED) { // Don't return password text!
return;
}
HTMLTextAreaElement* textArea = HTMLTextAreaElement::FromNode(mContent);
if (textArea) {
MOZ_ASSERT(!(NativeState() & states::PROTECTED));
textArea->GetValue(aValue);
return;
}
@ -327,6 +349,13 @@ void HTMLTextFieldAccessible::Value(nsString& aValue) const {
// Pass NonSystem as the caller type, to be safe. We don't expect to have a
// file input here.
input->GetValue(aValue, CallerType::NonSystem);
if (NativeState() & states::PROTECTED) { // Don't return password text!
const char16_t mask = TextEditor::PasswordMask();
for (size_t i = 0; i < aValue.Length(); i++) {
aValue.SetCharAt(mask, i);
}
}
}
}

View File

@ -59,6 +59,7 @@ class HTMLButtonAccessible : public HyperTextAccessible {
HTMLButtonAccessible(nsIContent* aContent, DocAccessible* aDoc);
// LocalAccessible
virtual void Value(nsString& aValue) const override;
virtual mozilla::a11y::role NativeRole() const override;
virtual uint64_t NativeState() const override;

View File

@ -3,6 +3,8 @@ support-files = "!/accessible/tests/mochitest/*.js"
["test_ariavalue.html"]
["test_color.html"]
["test_datetime.html"]
["test_general.html"]
@ -11,6 +13,8 @@ support-files = "!/accessible/tests/mochitest/*.js"
["test_number.html"]
["test_password.html"]
["test_progress.html"]
["test_range.html"]

View File

@ -0,0 +1,45 @@
<!doctype html>
<html>
<head>
<title>nsIAccessible value testing for input@type=color element</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script src="../common.js"></script>
<script src="../promisified-events.js"></script>
<script type="application/javascript">
async function doTest() {
const colorNode = getNode("color");
const color = getAccessible(colorNode);
colorNode.value = "#ff0000";
is(color.value, "100% red 0% green 0% blue");
colorNode.value = "#004000";
is(color.value, "0% red 25% green 0% blue");
colorNode.value = "#000080";
is(color.value, "0% red 0% green 50% blue");
colorNode.value = "#000000";
is(color.value, "0% red 0% green 0% blue");;
colorNode.value = "#4080ff";
is(color.value, "25% red 50% green 100% blue");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<!-- HTML5 input@type=color element -->
<input type="color" id="color">
</body>
</html>

View File

@ -0,0 +1,41 @@
<!doctype html>
<html>
<head>
<title>nsIAccessible value testing for input@type=password element</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script src="../common.js"></script>
<script src="../promisified-events.js"></script>
<script type="application/javascript">
async function doTest() {
const inpNode = getNode("password");
const inp = getAccessible(inpNode);
let editor = SpecialPowers.wrap(inpNode).editor;
let passwordMask = editor.passwordMask;
is(inp.value, "", "a11y value initially empty");
inpNode.value = "passw0rd";
is(inp.value, passwordMask.repeat(8), "a11y value is masked input value");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<!-- HTML5 input@type=password element -->
<input type="password" id="password">
</body>
</html>

View File

@ -480,6 +480,8 @@ class HTMLInputElement final : public TextControlElement,
mType == FormControlType::InputRadio;
}
bool IsInputColor() const { return mType == FormControlType::InputColor; }
bool Disabled() const { return GetBoolAttr(nsGkAtoms::disabled); }
void SetDisabled(bool aValue, ErrorResult& aRv) {

View File

@ -69,3 +69,6 @@ highlight = highlight
details = details
# The roleDescription for the summary element
summary = summary
# LOCALIZATION NOTE (inputColorValue): %1$S%%, %2$S%%, and %3$S%% represent the red, green, and blue color values as a percentage.
inputColorValue=%1$S%% red %2$S%% green %3$S%% blue

View File

@ -19,3 +19,6 @@ cycle = Cycle
# them to click an element when the click will be handled by a container
# (ancestor) element. This is not normally reported to users.
clickAncestor = Click ancestor
# LOCALIZATION NOTE (inputColorValue): %1$S%%, %2$S%%, and %3$S%% represent the red, green, and blue color values as a percentage.
inputColorValue=%1$S%% red %2$S%% green %3$S%% blue

View File

@ -28,3 +28,6 @@ banner = banner
complementary = complementary
contentinfo = content information
region = region
# LOCALIZATION NOTE (inputColorValue): %1$S%%, %2$S%%, and %3$S%% represent the red, green, and blue color values as a percentage.
inputColorValue=%1$S%% red %2$S%% green %3$S%% blue