https://bugs.webkit.org/show_bug.cgi?id=178523
Reviewed by Chris Fleizach.
Source/WebCore:
When the aria-activedescendant of an element changes, emit object:state-changed:focused.
When a focused element has a valid active descendant, do not expose the focused state on
the element, but rather on the active descendant. Also expose the focusable state on the
active descendant.
Tests: accessibility/gtk/aria-activedescendant-changed-notification.html
accessibility/gtk/aria-activedescendant.html
* accessibility/AccessibilityObject.cpp:
(WebCore::AccessibilityObject::isActiveDescendantOfFocusedContainer const):
(WebCore::AccessibilityObject::ariaActiveDescendantReferencingElements const):
* accessibility/AccessibilityObject.h:
* accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::shouldNotifyActiveDescendant const):
* accessibility/atk/AXObjectCacheAtk.cpp:
(WebCore::AXObjectCache::postPlatformNotification):
* accessibility/atk/WebKitAccessibleWrapperAtk.cpp:
(setAtkStateSetFromCoreObject):
LayoutTests:
* accessibility/gtk/aria-activedescendant-changed-notification-expected.txt: Added.
* accessibility/gtk/aria-activedescendant-changed-notification.html: Added.
* accessibility/gtk/aria-activedescendant-expected.txt: Added.
* accessibility/gtk/aria-activedescendant.html: Added.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@223766
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2017-10-20 Joanmarie Diggs <jdiggs@igalia.com>
+
+ AX: [ATK] Events missing and state incorrect for aria-activedescendant
+ https://bugs.webkit.org/show_bug.cgi?id=178523
+
+ Reviewed by Chris Fleizach.
+
+ * accessibility/gtk/aria-activedescendant-changed-notification-expected.txt: Added.
+ * accessibility/gtk/aria-activedescendant-changed-notification.html: Added.
+ * accessibility/gtk/aria-activedescendant-expected.txt: Added.
+ * accessibility/gtk/aria-activedescendant.html: Added.
+
2017-10-20 Per Arne Vollan <pvollan@apple.com>
[Win] Mark http/tests/navigation/keyboard-events-during-provisional-navigation.html and
--- /dev/null
+This tests that changing the aria-activedescendant value results in a state-changed notification.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+AXFocusedUIElementChanged: AXRole: AXEmbedded
+AXFocusedUIElementChanged: AXRole: AXTextField
+AXFocusedUIElementChanged: AXRole: AXGroup
+AXFocusedUIElementChanged: AXRole: AXGroup
+AXFocusedUIElementChanged: AXRole: AXGroup
+AXFocusedUIElementChanged: AXRole: AXCheckBox
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="content">
+ <div id="test1" tabindex="0" role="application">
+ <div id="child1" role="group">test</div>
+ </div>
+ <div id="test2" tabindex="0" role="searchbox">
+ <div id="child2" role="group">test</div>
+ </div>
+ <div id="test3" tabindex="0" role="group">
+ <div id="child3" role="checkbox">test</div>
+ </div>
+</div>
+<p id="description"></p>
+<div id="console"></div>
+<script>
+window.jsTestIsAsync = true;
+description("This tests that changing the aria-activedescendant value results in a state-changed notification.");
+
+if (window.testRunner && window.accessibilityController) {
+ accessibilityController.addNotificationListener(function(element, notification) {
+ if (notification != "AXFocusedUIElementChanged")
+ return;
+ debug(notification + ": " + element.role);
+ });
+
+ for (var i = 1; i <= 3; i++) {
+ var container = document.getElementById("test" + i);
+ container.focus();
+ container.setAttribute("aria-activedescendant", "child" + i);
+ }
+
+ document.getElementById("content").style.visibility = "hidden";
+
+ window.setTimeout(function() {
+ accessibilityController.removeNotificationListener();
+ finishJSTest();
+ }, 0);
+}
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+This tests the exposure of aria-activedescendant
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+
+test1 descendant: ''
+parent AXRole: AXEmbedded, isFocusable: true, isFocused: true
+child1 AXRole: AXGroup, isFocusable: false, isFocused: false
+
+test2 descendant: 'child2'
+parent AXRole: AXEmbedded, isFocusable: true, isFocused: false
+child2 AXRole: AXGroup, isFocusable: true, isFocused: true
+
+test3 descendant: ''
+parent AXRole: AXTextField, isFocusable: true, isFocused: true
+child3 AXRole: AXGroup, isFocusable: false, isFocused: false
+
+test4 descendant: 'child4'
+parent AXRole: AXTextField, isFocusable: true, isFocused: false
+child4 AXRole: AXGroup, isFocusable: true, isFocused: true
+
+test5 descendant: ''
+parent AXRole: AXGroup, isFocusable: true, isFocused: true
+child5 AXRole: AXCheckBox, isFocusable: false, isFocused: false
+
+test6 descendant: 'child6'
+parent AXRole: AXCheckBox, isFocusable: true, isFocused: true
+child6 AXRole: AXCheckBox, isFocusable: true, isFocused: true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body id="body">
+<div id="content">
+ <div id="test1" tabindex="0" aria-activedescendant="" role="application">
+ <div id="child1" role="group">test</div>
+ </div>
+ <div id="test2" tabindex="0" aria-activedescendant="child2" role="application">
+ <div id="child2" role="group">test</div>
+ </div>
+ <div id="test3" tabindex="0" aria-activedescendant="" role="searchbox">
+ <div id="child3" role="group">test</div>
+ </div>
+ <div id="test4" tabindex="0" aria-activedescendant="child4" role="searchbox">
+ <div id="child4" role="group">test</div>
+ </div>
+ <div id="test5" tabindex="0" aria-activedescendant="" role="group">
+ <div id="child5" role="checkbox">test</div>
+ </div>
+ <div id="test6" tabindex="0" aria-activedescendant="child6" role="group">
+ <div id="child6" role="checkbox">test</div>
+ </div>
+</div>
+<p id="description"></p>
+<div id="console"></div>
+<script>
+ description("This tests the exposure of aria-activedescendant");
+ if (window.accessibilityController) {
+ for (var i = 1; i <= 6; i++) {
+ var container = document.getElementById("test" + i);
+ debug("\ntest" + i + " descendant: '" + container.getAttribute("aria-activedescendant") + "'");
+
+ container.focus();
+ var axContainer = accessibilityController.focusedElement;
+ debug("parent " + axContainer.role + ", " +
+ "isFocusable: " + axContainer.isFocusable + ", " +
+ "isFocused: " + axContainer.isFocused);
+
+ var axChild = accessibilityController.accessibleElementById("child" + i);
+ debug("child" + i + " " + axChild.role + ", " +
+ "isFocusable: " + axChild.isFocusable + ", " +
+ "isFocused: " + axChild.isFocused);
+ }
+
+ document.getElementById("content").style.visibility = "hidden";
+ }
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
+
+2017-10-20 Joanmarie Diggs <jdiggs@igalia.com>
+
+ AX: [ATK] Events missing and state incorrect for aria-activedescendant
+ https://bugs.webkit.org/show_bug.cgi?id=178523
+
+ Reviewed by Chris Fleizach.
+
+ When the aria-activedescendant of an element changes, emit object:state-changed:focused.
+ When a focused element has a valid active descendant, do not expose the focused state on
+ the element, but rather on the active descendant. Also expose the focusable state on the
+ active descendant.
+
+ Tests: accessibility/gtk/aria-activedescendant-changed-notification.html
+ accessibility/gtk/aria-activedescendant.html
+
+ * accessibility/AccessibilityObject.cpp:
+ (WebCore::AccessibilityObject::isActiveDescendantOfFocusedContainer const):
+ (WebCore::AccessibilityObject::ariaActiveDescendantReferencingElements const):
+ * accessibility/AccessibilityObject.h:
+ * accessibility/AccessibilityRenderObject.cpp:
+ (WebCore::AccessibilityRenderObject::shouldNotifyActiveDescendant const):
+ * accessibility/atk/AXObjectCacheAtk.cpp:
+ (WebCore::AXObjectCache::postPlatformNotification):
+ * accessibility/atk/WebKitAccessibleWrapperAtk.cpp:
+ (setAtkStateSetFromCoreObject):
+
2017-10-20 Ms2ger <Ms2ger@igalia.com>
Add the MAX_CLIENT_WAIT_TIMEOUT_WEBGL constant to WebGL2RenderingContext.
}
}
+bool AccessibilityObject::isActiveDescendantOfFocusedContainer() const
+{
+ AccessibilityChildrenVector containers;
+ ariaActiveDescendantReferencingElements(containers);
+ for (auto& container : containers) {
+ if (container->isFocused())
+ return true;
+ }
+
+ return false;
+}
+
+void AccessibilityObject::ariaActiveDescendantReferencingElements(AccessibilityChildrenVector& containers) const
+{
+ ariaElementsReferencedByAttribute(containers, aria_activedescendantAttr);
+}
+
void AccessibilityObject::ariaControlsElements(AccessibilityChildrenVector& ariaControls) const
{
ariaElementsFromAttribute(ariaControls, aria_controlsAttr);
static bool isARIAInput(AccessibilityRole);
virtual bool supportsARIAOwns() const { return false; }
+ bool isActiveDescendantOfFocusedContainer() const;
+ void ariaActiveDescendantReferencingElements(AccessibilityChildrenVector&) const;
void ariaControlsElements(AccessibilityChildrenVector&) const;
void ariaControlsReferencingElements(AccessibilityChildrenVector&) const;
void ariaDescribedByElements(AccessibilityChildrenVector&) const;
bool AccessibilityRenderObject::shouldNotifyActiveDescendant() const
{
+#if PLATFORM(GTK)
+ // According to the Core AAM spec, ATK expects object:state-changed:focused notifications
+ // whenever the active descendant changes.
+ return true;
+#endif
// We want to notify that the combo box has changed its active descendant,
// but we do not want to change the focus, because focus should remain with the combo box.
if (isComboBox())
atk_object_notify_state_change(axObject, ATK_STATE_REQUIRED, coreObject->isRequired());
break;
+ case AXActiveDescendantChanged:
+ if (AccessibilityObject* descendant = coreObject->activeDescendant())
+ platformHandleFocusedUIElementChanged(nullptr, descendant->node());
+ break;
+
default:
break;
}
if (coreObject->canSetFocusAttribute())
atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
- if (coreObject->isFocused() || isTextWithCaret(coreObject))
+ // According to the Core AAM, if the element which is focused has a valid aria-activedescendant,
+ // we should not expose the focused state on the element which is actually focused, but instead
+ // on its active descendant.
+ if ((coreObject->isFocused() && !coreObject->activeDescendant()) || isTextWithCaret(coreObject))
atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
+ else if (coreObject->isActiveDescendantOfFocusedContainer()) {
+ atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
+ atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
+ }
if (coreObject->orientation() == AccessibilityOrientationHorizontal)
atk_state_set_add_state(stateSet, ATK_STATE_HORIZONTAL);