Diff
Modified: trunk/LayoutTests/ChangeLog (270332 => 270333)
--- trunk/LayoutTests/ChangeLog 2020-12-02 00:54:31 UTC (rev 270332)
+++ trunk/LayoutTests/ChangeLog 2020-12-02 00:55:04 UTC (rev 270333)
@@ -1,3 +1,16 @@
+2020-12-01 Chris Fleizach <[email protected]>
+
+ AX: VoiceOver does not announce the aria-checked state for ARIA treeitem
+ https://bugs.webkit.org/show_bug.cgi?id=218316
+ <rdar://problem/70787809>
+
+ Reviewed by Zalan Bujtas.
+
+ * accessibility/ios-simulator/checked-status-tree-items-expected.txt: Added.
+ * accessibility/ios-simulator/checked-status-tree-items.html: Added.
+ * accessibility/mac/checked-status-tree-items-expected.txt: Added.
+ * accessibility/mac/checked-status-tree-items.html: Added.
+
2020-12-01 Truitt Savell <[email protected]>
[macOS / iOS ] Layout Test imported/w3c/web-platform-tests/webrtc/RTCPeerConnection-getStats.https.html a flaky failure
Added: trunk/LayoutTests/accessibility/ios-simulator/checked-status-tree-items-expected.txt (0 => 270333)
--- trunk/LayoutTests/accessibility/ios-simulator/checked-status-tree-items-expected.txt (rev 0)
+++ trunk/LayoutTests/accessibility/ios-simulator/checked-status-tree-items-expected.txt 2020-12-02 00:55:04 UTC (rev 270333)
@@ -0,0 +1,13 @@
+item
+This tests that aria-checked is supported on tree items and changes generate notifications.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS addedNotification is true
+initial tree item value: AXValue: 1
+final tree item value: AXValue: 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/accessibility/ios-simulator/checked-status-tree-items.html (0 => 270333)
--- trunk/LayoutTests/accessibility/ios-simulator/checked-status-tree-items.html (rev 0)
+++ trunk/LayoutTests/accessibility/ios-simulator/checked-status-tree-items.html 2020-12-02 00:55:04 UTC (rev 270333)
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body id="body">
+
+<div id="tree" role="tree">
+<div id="treeitem" role="treeitem" aria-checked="true">item</div>
+</div>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+ var treeItem;
+ function notificationCallback(notification, userInfo) {
+ if (notification == "AXValueChanged") {
+ debug("final tree item value: " + treeItem.stringValue);
+ treeItem.removeNotificationListener();
+ finishJSTest();
+ }
+ }
+
+ description("This tests that aria-checked is supported on tree items and changes generate notifications.");
+ if (window.accessibilityController) {
+ jsTestIsAsync = true;
+ treeItem = accessibilityController.accessibleElementById("treeitem");
+
+ var addedNotification = treeItem.addNotificationListener(notificationCallback);
+ shouldBe("addedNotification", "true");
+
+ debug("initial tree item value: " + treeItem.stringValue);
+
+ document.getElementById("treeitem").ariaChecked = "false";
+ }
+
+</script>
+<script src=""
+</body>
+</html>
Modified: trunk/LayoutTests/accessibility/ios-simulator/toggle-button-expected.txt (270332 => 270333)
--- trunk/LayoutTests/accessibility/ios-simulator/toggle-button-expected.txt 2020-12-02 00:54:31 UTC (rev 270332)
+++ trunk/LayoutTests/accessibility/ios-simulator/toggle-button-expected.txt 2020-12-02 00:55:04 UTC (rev 270333)
@@ -5,7 +5,7 @@
Button1 : AXLabel: Bold
-Button1 : AXValue:
+Button1 : AXValue: 0
Button2 : AXLabel: Italic
Button2 : AXValue: 1
PASS successfullyParsed is true
Added: trunk/LayoutTests/accessibility/mac/checked-status-tree-items-expected.txt (0 => 270333)
--- trunk/LayoutTests/accessibility/mac/checked-status-tree-items-expected.txt (rev 0)
+++ trunk/LayoutTests/accessibility/mac/checked-status-tree-items-expected.txt 2020-12-02 00:55:04 UTC (rev 270333)
@@ -0,0 +1,16 @@
+item
+item
+This tests that aria-checked is supported on tree items and changes generate notifications.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS addedNotification is true
+tree item not checked: value attribute supported: false
+value attribute supported: true
+initial tree item value: 1
+final tree item value: 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/accessibility/mac/checked-status-tree-items.html (0 => 270333)
--- trunk/LayoutTests/accessibility/mac/checked-status-tree-items.html (rev 0)
+++ trunk/LayoutTests/accessibility/mac/checked-status-tree-items.html 2020-12-02 00:55:04 UTC (rev 270333)
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body id="body">
+
+<div id="tree" role="tree">
+<div id="treeitem_notchecked" role="treeitem">item</div>
+<div id="treeitem" role="treeitem" aria-checked="true">item</div>
+</div>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+ var webArea;
+ var treeItem;
+ function notificationCallback(notification, userInfo) {
+ if (notification == "AXValueChanged") {
+ debug("final tree item value: " + treeItem.intValue);
+ treeItem.removeNotificationListener();
+ finishJSTest();
+ }
+ }
+
+ description("This tests that aria-checked is supported on tree items and changes generate notifications.");
+ if (window.accessibilityController) {
+ jsTestIsAsync = true;
+ webArea = accessibilityController.rootElement.childAtIndex(0);
+ treeItem = accessibilityController.accessibleElementById("treeitem");
+
+ var addedNotification = treeItem.addNotificationListener(notificationCallback);
+ shouldBe("addedNotification", "true");
+
+ var treeItemNotChecked = accessibilityController.accessibleElementById("treeitem_notchecked");
+ debug("tree item not checked: value attribute supported: " + treeItemNotChecked.isAttributeSupported('AXValue'));
+
+ debug("value attribute supported: " + treeItem.isAttributeSupported('AXValue'));
+ debug("initial tree item value: " + treeItem.intValue);
+
+ document.getElementById("treeitem").ariaChecked = "false";
+ }
+
+</script>
+<script src=""
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (270332 => 270333)
--- trunk/Source/WebCore/ChangeLog 2020-12-02 00:54:31 UTC (rev 270332)
+++ trunk/Source/WebCore/ChangeLog 2020-12-02 00:55:04 UTC (rev 270333)
@@ -1,3 +1,44 @@
+2020-12-01 Chris Fleizach <[email protected]>
+
+ AX: VoiceOver does not announce the aria-checked state for ARIA treeitem
+ https://bugs.webkit.org/show_bug.cgi?id=218316
+ <rdar://problem/70787809>
+
+ Reviewed by Zalan Bujtas.
+
+ Tree items need to be able to support their aria-checked status according to WAI-ARIA.
+ In addition, when the value changes they need to be able to post an appropriate notification.
+ While working on this, I realized that if an attribute changes, the notification is not fired until the next layout change
+ which is problematic. Those need to fire immediately.
+
+ Test: accessibility/mac/checked-status-tree-items.html
+ accessibility/ios-simulator/checked-status-tree-items.html
+
+ * accessibility/AXObjectCache.cpp:
+ (WebCore::AXObjectCache::deferAttributeChangeIfNeeded):
+ * accessibility/AccessibilityNodeObject.cpp:
+ (WebCore::AccessibilityNodeObject::isChecked const):
+ * accessibility/AccessibilityObject.cpp:
+ (WebCore::AccessibilityObject::supportsCheckedState const):
+ * accessibility/AccessibilityObject.h:
+ * accessibility/AccessibilityObjectInterface.h:
+ * accessibility/AccessibilityTreeItem.cpp:
+ (WebCore::AccessibilityTreeItem::supportsCheckedState const):
+ * accessibility/AccessibilityTreeItem.h:
+ * accessibility/ios/AXObjectCacheIOS.mm:
+ (WebCore::AXObjectCache::postPlatformNotification):
+ * accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
+ (-[WebAccessibilityObjectWrapper accessibilityTraits]):
+ (-[WebAccessibilityObjectWrapper accessibilityValue]):
+ * accessibility/isolatedtree/AXIsolatedObject.cpp:
+ (WebCore::AXIsolatedObject::initializeAttributeData):
+ * accessibility/isolatedtree/AXIsolatedObject.h:
+ * accessibility/isolatedtree/AXIsolatedTree.h:
+ * accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
+ (AXAttributedStringAppendText):
+ (-[WebAccessibilityObjectWrapper ALLOW_DEPRECATED_IMPLEMENTATIONS_END]):
+ (-[WebAccessibilityObjectWrapper accessibilityAttributeValue:]):
+
2020-12-01 Andres Gonzalez <[email protected]>
Fix for multiple LayoutTests/accessibility tests in isolated tree mode that rely on PlainTextRange.
Modified: trunk/Source/WebCore/accessibility/AXObjectCache.cpp (270332 => 270333)
--- trunk/Source/WebCore/accessibility/AXObjectCache.cpp 2020-12-02 00:54:31 UTC (rev 270332)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.cpp 2020-12-02 00:55:04 UTC (rev 270333)
@@ -1699,8 +1699,11 @@
void AXObjectCache::deferAttributeChangeIfNeeded(const QualifiedName& attrName, Element* element)
{
- if (nodeAndRendererAreValid(element) && rendererNeedsDeferredUpdate(*element->renderer()))
+ if (nodeAndRendererAreValid(element) && rendererNeedsDeferredUpdate(*element->renderer())) {
m_deferredAttributeChange.add(element, attrName);
+ if (!m_performCacheUpdateTimer.isActive())
+ m_performCacheUpdateTimer.startOneShot(0_s);
+ }
else
handleAttributeChange(attrName, element);
}
Modified: trunk/Source/WebCore/accessibility/AccessibilityNodeObject.cpp (270332 => 270333)
--- trunk/Source/WebCore/accessibility/AccessibilityNodeObject.cpp 2020-12-02 00:54:31 UTC (rev 270332)
+++ trunk/Source/WebCore/accessibility/AccessibilityNodeObject.cpp 2020-12-02 00:55:04 UTC (rev 270333)
@@ -691,6 +691,7 @@
case AccessibilityRole::MenuItemCheckbox:
case AccessibilityRole::MenuItemRadio:
case AccessibilityRole::Switch:
+ case AccessibilityRole::TreeItem:
validRole = true;
break;
default:
Modified: trunk/Source/WebCore/accessibility/AccessibilityObject.cpp (270332 => 270333)
--- trunk/Source/WebCore/accessibility/AccessibilityObject.cpp 2020-12-02 00:54:31 UTC (rev 270332)
+++ trunk/Source/WebCore/accessibility/AccessibilityObject.cpp 2020-12-02 00:55:04 UTC (rev 270333)
@@ -1489,6 +1489,16 @@
return getAttribute(aria_readonlyAttr).string().convertToASCIILowercase();
}
+bool AccessibilityObject::supportsCheckedState() const
+{
+ auto role = roleValue();
+ return isCheckboxOrRadio()
+ || role == AccessibilityRole::MenuItemCheckbox
+ || role == AccessibilityRole::MenuItemRadio
+ || role == AccessibilityRole::Switch
+ || isToggleButton();
+}
+
bool AccessibilityObject::supportsAutoComplete() const
{
return (isComboBox() || isARIATextControl()) && hasAttribute(aria_autocompleteAttr);
Modified: trunk/Source/WebCore/accessibility/AccessibilityObject.h (270332 => 270333)
--- trunk/Source/WebCore/accessibility/AccessibilityObject.h 2020-12-02 00:54:31 UTC (rev 270332)
+++ trunk/Source/WebCore/accessibility/AccessibilityObject.h 2020-12-02 00:55:04 UTC (rev 270333)
@@ -275,7 +275,8 @@
int layoutCount() const override { return 0; }
double estimatedLoadingProgress() const override { return 0; }
WEBCORE_EXPORT static bool isARIAControl(AccessibilityRole);
-
+ bool supportsCheckedState() const override;
+
bool supportsARIAOwns() const override { return false; }
bool isActiveDescendantOfFocusedContainer() const override;
void ariaActiveDescendantReferencingElements(AccessibilityChildrenVector&) const override;
Modified: trunk/Source/WebCore/accessibility/AccessibilityObjectInterface.h (270332 => 270333)
--- trunk/Source/WebCore/accessibility/AccessibilityObjectInterface.h 2020-12-02 00:54:31 UTC (rev 270332)
+++ trunk/Source/WebCore/accessibility/AccessibilityObjectInterface.h 2020-12-02 00:55:04 UTC (rev 270333)
@@ -957,7 +957,8 @@
virtual void setIsExpanded(bool) = 0;
virtual FloatRect relativeFrame() const = 0;
virtual FloatRect convertFrameToSpace(const FloatRect&, AccessibilityConversionSpace) const = 0;
-
+ virtual bool supportsCheckedState() const = 0;
+
// In a multi-select list, many items can be selected but only one is active at a time.
virtual bool isSelectedOptionActive() const = 0;
Modified: trunk/Source/WebCore/accessibility/AccessibilityTreeItem.cpp (270332 => 270333)
--- trunk/Source/WebCore/accessibility/AccessibilityTreeItem.cpp 2020-12-02 00:54:31 UTC (rev 270332)
+++ trunk/Source/WebCore/accessibility/AccessibilityTreeItem.cpp 2020-12-02 00:55:04 UTC (rev 270333)
@@ -48,6 +48,11 @@
return adoptRef(*new AccessibilityTreeItem(renderer));
}
+bool AccessibilityTreeItem::supportsCheckedState() const
+{
+ return hasAttribute(aria_checkedAttr);
+}
+
AccessibilityRole AccessibilityTreeItem::determineAccessibilityRole()
{
Modified: trunk/Source/WebCore/accessibility/AccessibilityTreeItem.h (270332 => 270333)
--- trunk/Source/WebCore/accessibility/AccessibilityTreeItem.h 2020-12-02 00:54:31 UTC (rev 270332)
+++ trunk/Source/WebCore/accessibility/AccessibilityTreeItem.h 2020-12-02 00:55:04 UTC (rev 270333)
@@ -38,6 +38,7 @@
virtual ~AccessibilityTreeItem();
bool shouldIgnoreAttributeRole() const override { return !m_isTreeItemValid; }
+ bool supportsCheckedState() const override;
private:
explicit AccessibilityTreeItem(RenderObject*);
Modified: trunk/Source/WebCore/accessibility/ios/AXObjectCacheIOS.mm (270332 => 270333)
--- trunk/Source/WebCore/accessibility/ios/AXObjectCacheIOS.mm 2020-12-02 00:54:31 UTC (rev 270332)
+++ trunk/Source/WebCore/accessibility/ios/AXObjectCacheIOS.mm 2020-12-02 00:55:04 UTC (rev 270333)
@@ -75,14 +75,15 @@
case AXInvalidStatusChanged:
[obj->wrapper() postInvalidStatusChangedNotification];
break;
+ case AXCheckedStateChanged:
case AXValueChanged:
[obj->wrapper() postValueChangedNotification];
+ notificationString = @"AXValueChanged";
break;
case AXExpandedChanged:
[obj->wrapper() postExpandedChangedNotification];
break;
case AXSelectedChildrenChanged:
- case AXCheckedStateChanged:
default:
break;
}
Modified: trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm (270332 => 270333)
--- trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm 2020-12-02 00:54:31 UTC (rev 270332)
+++ trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm 2020-12-02 00:55:04 UTC (rev 270333)
@@ -851,6 +851,10 @@
if (!self.axBackingObject->isEnabled())
traits |= [self _axNotEnabledTrait];
+ // If the treeitem supports the checked state, then it should also be marked with toggle status.
+ if (self.axBackingObject->supportsCheckedState())
+ traits |= [self _axToggleTrait];
+
if (m_accessibilityTraitsFromAncestor == ULLONG_MAX)
m_accessibilityTraitsFromAncestor = [self _accessibilityTraitsFromAncestors];
@@ -1446,8 +1450,7 @@
if (value)
return value;
- AccessibilityRole role = self.axBackingObject->roleValue();
- if (self.axBackingObject->isCheckboxOrRadio() || role == AccessibilityRole::MenuItemCheckbox || role == AccessibilityRole::MenuItemRadio || role == AccessibilityRole::Switch) {
+ if (self.axBackingObject->supportsCheckedState()) {
switch (self.axBackingObject->checkboxOrRadioValue()) {
case AccessibilityButtonState::Off:
return [NSString stringWithFormat:@"%d", 0];
Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp (270332 => 270333)
--- trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp 2020-12-02 00:54:31 UTC (rev 270332)
+++ trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp 2020-12-02 00:55:04 UTC (rev 270333)
@@ -229,6 +229,7 @@
setProperty(AXPropertyName::IsKeyboardFocusable, object.isKeyboardFocusable());
setObjectProperty(AXPropertyName::NextSibling, object.nextSibling());
setObjectProperty(AXPropertyName::PreviousSibling, object.previousSibling());
+ setProperty(AXPropertyName::SupportsCheckedState, object.supportsCheckedState());
if (object.isTable()) {
setProperty(AXPropertyName::IsTable, true);
Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h (270332 => 270333)
--- trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h 2020-12-02 00:54:31 UTC (rev 270332)
+++ trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h 2020-12-02 00:55:04 UTC (rev 270333)
@@ -352,6 +352,7 @@
AXCoreObject* decrementButton() override { return objectAttributeValue(AXPropertyName::DecrementButton); }
bool isIncrementor() const override { return boolAttributeValue(AXPropertyName::IsIncrementor); }
AccessibilityChildrenVector documentLinks() override { return tree()->objectsForIDs(vectorAttributeValue<AXID>(AXPropertyName::DocumentLinks)); }
+ bool supportsCheckedState() const override { return boolAttributeValue(AXPropertyName::SupportsCheckedState); }
String stringValue() const override { return stringAttributeValue(AXPropertyName::StringValue); }
Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h (270332 => 270333)
--- trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h 2020-12-02 00:54:31 UTC (rev 270332)
+++ trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h 2020-12-02 00:55:04 UTC (rev 270333)
@@ -280,6 +280,7 @@
SupportsDragging,
SupportsDropping,
SupportsARIAOwns,
+ SupportsCheckedState,
SupportsCurrent,
SupportsDatetimeAttribute,
SupportsExpanded,
Modified: trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm (270332 => 270333)
--- trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm 2020-12-02 00:54:31 UTC (rev 270332)
+++ trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm 2020-12-02 00:55:04 UTC (rev 270333)
@@ -1147,7 +1147,7 @@
{
// skip invisible text
RenderObject* renderer = node->renderer();
- if (!renderer)
+ if (!renderer || !text.length())
return;
// easier to calculate the range before appending the string
@@ -1723,6 +1723,7 @@
[tempArray addObject:NSAccessibilityDisclosedByRowAttribute];
[tempArray addObject:NSAccessibilityDisclosureLevelAttribute];
[tempArray addObject:NSAccessibilityDisclosedRowsAttribute];
+ [tempArray removeObject:NSAccessibilityValueAttribute];
outlineRowAttrs = [[NSArray alloc] initWithArray:tempArray];
[tempArray release];
}
@@ -1759,8 +1760,12 @@
objectAttributes = tableRowAttrs;
} else if (backingObject->isTree())
objectAttributes = outlineAttrs;
- else if (backingObject->isTreeItem())
- objectAttributes = outlineRowAttrs;
+ else if (backingObject->isTreeItem()) {
+ if (backingObject->supportsCheckedState())
+ objectAttributes = [outlineRowAttrs arrayByAddingObject:NSAccessibilityValueAttribute];
+ else
+ objectAttributes = outlineRowAttrs;
+ }
else if (backingObject->isListBox())
objectAttributes = listBoxAttrs;
else if (backingObject->isList())
@@ -2472,7 +2477,7 @@
if (backingObject->isHeading())
return @(backingObject->headingLevel());
- if (backingObject->isCheckboxOrRadio() || backingObject->isMenuItem() || backingObject->isSwitch() || backingObject->isToggleButton()) {
+ if (backingObject->supportsCheckedState()) {
switch (backingObject->checkboxOrRadioValue()) {
case AccessibilityButtonState::Off:
return @(0);