Skip to content
Permalink
Browse files
AX: Control value is not updated after dynamic changes to color input…
…s, textareas, or progress elements

https://bugs.webkit.org/show_bug.cgi?id=249283
rdar://103272091

Reviewed by Chris Fleizach and Andres Gonzalez.

When textarea elements, progress elements, and type="color" inputs update,
we aren't submitting value changed notifications, which also means we aren't
updating the ITM cache. This patch fixes that.

* LayoutTests/accessibility/color-input-value-changes-expected.txt: Added.
* LayoutTests/accessibility/color-input-value-changes.html: Added.
* LayoutTests/accessibility/progress-element-value-changes-expected.txt: Added.
* LayoutTests/accessibility/progress-element-value-changes.html: Added.
* LayoutTests/accessibility/textarea-value-changes-expected.txt: Added.
* LayoutTests/accessibility/textarea-value-changes.html: Added.
Add tests.

* LayoutTests/platform/glib/TestExpectations:
Skip accessibility/progress-element-value-changes.html because it's timing out.
* LayoutTests/platform/glib/accessibility/color-input-value-changes-expected.txt: Added.
* LayoutTests/platform/mac-wk1/TestExpectations:
Skip accessibility/color-input-value-changes.html because color inputs aren't supported in WK1.
* LayoutTests/platform/win/TestExpectations:
Skip accessibility/color-input-value-changes.html and accessibility/progress-element-value-changes.html.

* Source/WebCore/html/ColorInputType.cpp:
(WebCore::ColorInputType::attributeChanged):
(WebCore::ColorInputType::didChooseColor):
* Source/WebCore/html/HTMLTextAreaElement.cpp:
(WebCore::HTMLTextAreaElement::setValueCommon):
* Source/WebCore/html/HTMLProgressElement.cpp:
(WebCore::HTMLProgressElement::didElementStateChange):
Inform the AXObjectCache the control values have changed.

Canonical link: https://commits.webkit.org/257976@main
  • Loading branch information
twilco committed Dec 16, 2022
1 parent f44479d commit 40bfa0c8714b2f1ac59a941988d1c43d353ba891
Show file tree
Hide file tree
Showing 13 changed files with 199 additions and 1 deletion.
@@ -0,0 +1,14 @@
This test ensures accessibility properly responds to dynamic changes in a color input's value.

#color AXValue: rgb 0.00000 0.00000 0.00000 1

Updating #color value to '#ff0f00'.
#color AXValue: rgb 1.00000 0.0588235 0.00000 1

Updating #color value to '#000000'.
#color AXValue: rgb 0.00000 0.00000 0.00000 1

PASS successfullyParsed is true

TEST COMPLETE

@@ -0,0 +1,46 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../resources/accessibility-helper.js"></script>
<script src="../resources/js-test.js"></script>
</head>
<body>

<input type="color" id="color">

<script>
window.jsTestIsAsync = true;
var output = "This test ensures accessibility properly responds to dynamic changes in a color input's value.\n\n";

// There are a few layouts that happen when the page loads — run the test in window.onload to wait them out before changing
// the color value. If we change the color value before these layouts occur, we pass the test no matter
// what (even if our implementation is wrong). This is because a top-level children changed notification causes
// the color input AX object to be re-built with the correct value, making us pass the test on accident.
window.onload = () => {
if (!window.accessibilityController)
return;

var color = accessibilityController.accessibleElementById("color");
output += `#color ${color.stringValue}\n`;
setTimeout(async function() {
output += "\nUpdating #color value to '#ff0f00'.\n";
document.getElementById("color").setAttribute("value", "#ff0f00");
await waitFor(() => color.stringValue.includes("rgb 1.00000"));
output += `#color ${color.stringValue}\n`;

output += "\nUpdating #color value to '#000000'.\n";
// selectColorInColorChooser is explicitly used in this test as that is the same codepath exercised when
// an AT user (or non-AT user) selects an item from the color chooser grid UI.
internals.selectColorInColorChooser(document.getElementById("color"), "#000000");

await waitFor(() => !color.stringValue.includes("rgb 1.00000"));
output += `#color ${color.stringValue}\n`;

debug(output);
finishJSTest();
}, 0);
};
</script>
</body>
</html>

@@ -0,0 +1,11 @@
This test ensures accessibility properly responds to dynamic changes in a progress element's value.

#progress AXValue: 70

Updating #progress value to 50.
#progress AXValue: 50

PASS successfullyParsed is true

TEST COMPLETE

@@ -0,0 +1,39 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../resources/accessibility-helper.js"></script>
<script src="../resources/js-test.js"></script>
</head>
<body>

<progress id="progress" max="100" value="70"></progress>

<script>
window.jsTestIsAsync = true;
var output = "This test ensures accessibility properly responds to dynamic changes in a progress element's value.\n\n";

// There are a few layouts that happen when the page loads — run the test in window.onload to wait them out before changing
// the progress value. If we change the progress value before these layouts occur, we pass the test no matter
// what (even if our implementation is wrong). This is because a top-level children changed notification causes
// the progress to be re-built with the correct value, making us pass the test on accident.
window.onload = () => {
if (!window.accessibilityController)
return;

var progress = accessibilityController.accessibleElementById("progress");
output += `#progress ${progress.stringValue}\n`;
setTimeout(async function() {
output += "\nUpdating #progress value to 50.\n";
document.getElementById("progress").value = "50";

await waitFor(() => progress.stringValue.includes("50"));
output += `#progress ${progress.stringValue}\n`;

debug(output);
finishJSTest();
}, 0);
};
</script>
</body>
</html>

@@ -0,0 +1,11 @@
This test ensures accessibility properly responds to dynamic changes in a textarea element's value.

#textarea AXValue: Foo

Updating #textarea value to 'Bar'.
#textarea AXValue: Bar

PASS successfullyParsed is true

TEST COMPLETE

@@ -0,0 +1,39 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../resources/accessibility-helper.js"></script>
<script src="../resources/js-test.js"></script>
</head>
<body>

<textarea id="textarea">Foo</textarea>

<script>
window.jsTestIsAsync = true;
var output = "This test ensures accessibility properly responds to dynamic changes in a textarea element's value.\n\n";

// There are a few layouts that happen when the page loads — run the test in window.onload to wait them out before changing
// the textarea value. If we change the textarea value before these layouts occur, we pass the test no matter
// what (even if our implementation is wrong). This is because a top-level children changed notification causes
// the textarea to be re-built with the correct value, making us pass the test on accident.
window.onload = () => {
if (!window.accessibilityController)
return;

var textarea = accessibilityController.accessibleElementById("textarea");
output += `#textarea ${textarea.stringValue}\n`;
setTimeout(async function() {
output += "\nUpdating #textarea value to 'Bar'.\n";
document.getElementById("textarea").value = "Bar";

await waitFor(() => textarea.stringValue.includes("Bar"));
output += `#textarea ${textarea.stringValue}\n`;

debug(output);
finishJSTest();
}, 0);
};
</script>
</body>
</html>

@@ -348,6 +348,9 @@ webkit.org/b/239550 fast/text/simple-line-layout-hyphen-limit-before.html [ Pass
# Accessibility-related bugs
#////////////////////////////////////////////////////////////////////////////////////////

# Timing out since added in https://bugs.webkit.org/show_bug.cgi?id=249283.
accessibility/progress-element-value-changes.html [ Skip ]

accessibility/svg-font-face.html [ Skip ]

# Need to implement AccessibilityUIElement::insertText.
@@ -0,0 +1,14 @@
This test ensures accessibility properly responds to dynamic changes in a color input's value.

#color AXValue: rgb 0.00000 0.00000 0.00000 1

Updating #color value to '#ff0f00'.
#color AXValue: rgb 1.00000 0.05882 0.00000 1

Updating #color value to '#000000'.
#color AXValue: rgb 0.00000 0.00000 0.00000 1

PASS successfullyParsed is true

TEST COMPLETE

@@ -894,6 +894,7 @@ http/tests/security/contentSecurityPolicy/navigate-self-to-data-url.html [ Skip

# Color well is turned off.
accessibility/color-well.html [ Skip ]
accessibility/color-input-value-changes.html [ Skip ]
accessibility/mac/media-query-values-change.html [ Skip ]
editing/pasteboard/drag-and-drop-color-input-events.html [ Skip ]
editing/pasteboard/drag-and-drop-color-input.html [ Skip ]
@@ -492,6 +492,10 @@ fast/events/mouseover-button.html [ Skip ]
# TODO Accept header is handled by the browser
http/tests/misc/image-checks-for-accept.html [ Skip ]

# Failing since added in https://bugs.webkit.org/show_bug.cgi?id=249283.
accessibility/color-input-value-changes.html [ Skip ]
accessibility/progress-element-value-changes.html [ Skip ]

# Failing since added in https://bugs.webkit.org/show_bug.cgi?id=244126.
accessibility/dynamically-unignored-contenteditable.html [ Skip ]

@@ -35,6 +35,7 @@

#include "ColorInputType.h"

#include "AXObjectCache.h"
#include "CSSPropertyNames.h"
#include "Chrome.h"
#include "Color.h"
@@ -169,9 +170,13 @@ void ColorInputType::setValue(const String& value, bool valueChanged, TextFieldE

void ColorInputType::attributeChanged(const QualifiedName& name)
{
if (name == valueAttr)
if (name == valueAttr) {
updateColorSwatch();

if (auto* cache = element()->document().existingAXObjectCache())
cache->valueChanged(element());
}

InputType::attributeChanged(name);
}

@@ -237,6 +242,9 @@ void ColorInputType::didChooseColor(const Color& color)
element()->setValueFromRenderer(serializationForHTML(color));
updateColorSwatch();
element()->dispatchFormControlChangeEvent();

if (auto* cache = element()->document().existingAXObjectCache())
cache->valueChanged(element());
}

void ColorInputType::didEndChooser()
@@ -21,6 +21,7 @@
#include "config.h"
#include "HTMLProgressElement.h"

#include "AXObjectCache.h"
#include "ElementIterator.h"
#include "HTMLNames.h"
#include "HTMLParserIdioms.h"
@@ -138,6 +139,9 @@ void HTMLProgressElement::didElementStateChange()
m_value->setWidthPercentage(position() * 100);
if (RenderProgress* renderer = renderProgress())
renderer->updateFromElement();

if (auto* cache = document().existingAXObjectCache())
cache->valueChanged(this);
}

void HTMLProgressElement::didAddUserAgentShadowRoot(ShadowRoot& root)
@@ -26,6 +26,7 @@
#include "config.h"
#include "HTMLTextAreaElement.h"

#include "AXObjectCache.h"
#include "BeforeTextInsertedEvent.h"
#include "CSSValueKeywords.h"
#include "DOMFormData.h"
@@ -376,6 +377,9 @@ void HTMLTextAreaElement::setValueCommon(const String& newValue, TextFieldEventB
cacheSelection(std::min(endOfString, selectionStartValue), std::min(endOfString, selectionEndValue), SelectionHasNoDirection);

setTextAsOfLastFormControlChangeEvent(normalizedValue);

if (auto* cache = document().existingAXObjectCache())
cache->valueChanged(this);
}

String HTMLTextAreaElement::defaultValue() const

0 comments on commit 40bfa0c

Please sign in to comment.